OrangePiZero3移植Linux

主要参考这两篇文章1.内核和根文件系统 2.uboot

一些需要的软件源码:

TF-A,arm可信固件

下载地址:https://github.com/ARM-software/arm-trusted-firmware

crust,全志电源管理固件

下载地址:https://github.com/crust-firmware/crust

uboot

下载地址:https://github.com/u-boot/u-boot

linux kernel

下载地址:https://github.com/torvalds/linux

buildroot

下载地址:https://github.com/buildroot/buildroot

工具链:

交叉编译链:

1.gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu,用于编译tf-a、uboot、kernel等

下载地址:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads/11-2-2022-02

2.or1k-linux-musl-cross,用于编译crust

下载地址:https://github.com/stffrdhrn/gcc/releases

用一个文件夹toolchain放相关的编译工具链

1.编译uboot相关代码

1.1编译arm信可固件

bash 复制代码
# 设置交叉编译环境(沿用你之前的工具链)
export PATH=$PATH:~/Repo/linux/my_linux_in/toolchain/arm-gnu-toolchain-11.2/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin
export CROSS_COMPILE=aarch64-none-linux-gnu-

# 针对 Orange Pi Zero 3 的芯片 (sun50i_h616) 编译
make PLAT=sun50i_h616 DEBUG=0 bl31

编译成功后,bl31.bin 会在 build/sun50i_h616/release/bl31.bin

1.2编译crust

bash 复制代码
# 进入 Crust 源码目录(你已经在了)
cd ~/Repo/linux/my_linux_in/crust

# 切换到 or1k 工具链
export PATH=$PATH:~/Repo/linux/my_linux_in/toolchain/or1k-gcc/bin
export CROSS_COMPILE=or1k-linux-musl-

# 配置并编译 Crust
make orangepi_3_defconfig
make

编译成功后,scp.bin 会在当前目录下生成,记下它的绝对路径。

1.3编译uboot

前面的步骤都是为了编译uboot

bash 复制代码
cd ~/Repo/linux/my_linux_in/u-boot

# 设置 aarch64 工具链
export PATH=$PATH:~/Repo/linux/my_linux_in/toolchain/arm-gnu-toolchain-11.2/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin
export CROSS_COMPILE=aarch64-none-linux-gnu-

# 设置 BL31 和 SCP 路径(使用绝对路径)
export BL31=~/Repo/linux/my_linux_in/arm-trusted-firmware/build/sun50i_h616/debug/bl31.bin
export SCP=~/Repo/linux/my_linux_in/crust/build/scp/scp.bin

编译uboot:

bash 复制代码
cd ~/Repo/linux/my_linux_in/u-boot
make orangepi_zero3_defconfig
make -j$(nproc)

编译结果为存放在uboot源码根目录下的u-boot-sunxi-with-spl.bin文件

小tips:aarch64就是arm64

2.编译linux内核

2.1linux内核裁剪

请细看第一篇文章的内容,按那个内容裁剪内核

然后编译

bash 复制代码
export PATH=$PATH:~/Repo/linux/my_linux_in/toolchain/arm-gnu-toolchain-11.2/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin
export CROSS_COMPILE=aarch64-none-linux-gnu-
make defconfig

编译完成后,会在arch/arm64/boot目录下生成Image和Image.gz文件,其中Image.gz文件即为旧版本kernel中的zImage,在arch/arm64/boot/dts/allwinner目录下生成sun50i-h618-orangepi-zero3.dtb,Image和设备树文件即可用来启动内核。

3.根文件系统构建

这里有两种选择:一是用buildroot,二是用ubuntu-base。我用的是buildroot(记得禁用linux内核和uboot的编译)

裁剪过程同样参考文章

或者可以用这个命令直接禁止kernel和uboot的编译:

bash 复制代码
sed -i 's/^BR2_LINUX_KERNEL=y/# BR2_LINUX_KERNEL is not set/' .config
sed -i 's/^BR2_TARGET_UBOOT=y/# BR2_TARGET_UBOOT is not set/' .config
make olddefconfig
bash 复制代码
make orangepi_zero3_defconfig    # 加载板级配置
make -j20                        # 20线程并行编译

编译,编译结果存放在output\images目录下

4.TF卡烧录

先用

bash 复制代码
lsblk

看一下tf卡的名字。像我的tf卡就是/dev/sdb

我们需要对tf卡进行分区,分为两个区,一个区放linux内核景象和设备树dtb,一个区放根文件系统

用fdisk工具分区

bash 复制代码
# 1. 卸载所有分区(如果已挂载)
sudo umount /dev/sdb1 2>/dev/null
sudo umount /dev/sdb2 2>/dev/null

# 2. 擦除分区表
sudo dd if=/dev/zero of=/dev/sdb bs=1M count=1

# 3. 重新分区(使用 fdisk)
sudo fdisk /dev/sdb
# 依次输入:
# o     (创建新的 DOS 分区表)
# n     (新建分区)
# p     (主分区)
# 1     (分区号 1)
# 回车  (默认起始扇区 2048)
# +100M (第一个分区大小 100MB,足够放 Image + dtb)
# t     (修改分区类型)
# c     (改为 FAT32 LBA)
# n     (新建分区)
# p     (主分区)
# 2     (分区号 2)
# 回车  (默认起始扇区)
# 回车  (默认结束扇区,占满剩余全部空间)
# w     (保存退出)

# 4. 格式化两个分区
sudo mkfs.vfat -F 32 /dev/sdb1
sudo mkfs.ext4 /dev/sdb2

烧录uboot:

bash 复制代码
sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8 conv=fsync

烧录内核、设备树、根文件系统:

bash 复制代码
mkdir -p ~/tf_boot ~/tf_rootfs
sudo mount /dev/sdb1 ~/tf_boot
sudo mount /dev/sdb2 ~/tf_rootfs

sudo cp ~/Repo/linux/my_linux_in/linux/arch/arm64/boot/Image ~/tf_boot/
sudo cp ~/Repo/linux/my_linux_in/linux/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero3.dtb ~/tf_boot/
sudo tar -xvf ~/Repo/linux/my_linux_in/buildroot/output/images/rootfs.tar -C ~/tf_rootfs/

sync
sudo umount ~/tf_boot
sudo umount ~/tf_rootfs

将tf插到开发板后,在uboot的启动阶段按任意键进入uboot命令行,输入:

bash 复制代码
setenv bootcmd 'fatload mmc 0:1 0x40200000 Image;fatload mmc 0:1 0x4fa00000 sun50i-h618-orangepi-zero3.dtb;booti 0x40200000 - 0x4fa00000'
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw  init=/sbin/init debug panic=30'
saveenv

这段话的作用

  • 自动找文件 → 从 SD 卡的第一个分区(FAT32)里,找到内核文件 Image 和板子配置文件 sun50i-h618-orangepi-zero3.dtb

  • 自动搬进内存 → 把这两个文件从 SD 卡读取出来,放到内存的指定位置(0x402000000x4fa00000)。

  • 自动启动内核 → 执行 booti 命令,把 CPU 的控制权交给刚刚加载到内存里的 Linux 内核。

  • 内核自动挂载系统 → 内核启动后,严格按照 bootargs 里的参数,去 SD 卡的第二个分区(/dev/mmcblk0p2)挂载根文件系统,最后启动你完整的 Linux 操作系统(比如 Debian/Ubuntu

我记得基本路径就是这样。可能有一些细节上的差错,后续会进行校对。