此前我对ZYNQ开发板上的ARM核也进行过Linux系统的移植,不过不太顺利,最后发现以太网驱动工作不正常,设备没有正常启用。最近又在rk3568上捣鼓了一下移植过程,又出现了这个问题,捣鼓了两天才发现原因出自make modules_install命令没有执行,导致驱动没有正常加载。我把内核移植总结为以下几个过程,下面我们逐一分析。

1、UBOOT制作 

注意:这里我使用官方提供的烧录工具,操作失败了(之前都还可以的)。所以以下只是理论上uboot.img或者uboot.bin的编译制作过程,具体如何烧录到sd卡中或者至emmc中,还需要你具体验证。

        或者你可以通过回车进入uboot界面后,观察有无saveenv命令,修改uboot启动方式至extlinux即可。这里我要重新烧录uboot也是因为板子上原来的uboot没有saveenv命令,如果有的话可以跳过这一步骤,直接开始内核制作,后续会介绍uboot参数修改方式。

        uboot的编译方式与内核编译方式大差不差。首先从官网下载uboot源码:UBOOT官网

执行下载命令: git clone git@github.com:u-boot/u-boot.git,开始下载:

        下载完成后首先根据自己的开发板选择对应配置文件,这里我用的是Bananapi-r2-pro

        或者你可以从目标开发板上尝试找到其配置文件。确认配置文件后,把该文件拷贝的/uboot目录下并命名为.config。或者直接在/uboot目录下执行 make bpi-r2-pro-rk3568_defconfig。有了.config文件后设置编译架构和交叉编译工具链,这里是arm64和aarch64-linux-gnu-gcc:

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

         配置完成后开始编译: make -j32。然后就会报错缺少关键文件:ddr.bin和bl31.bin。其中ddr.bin用于在uboot执行前初始化内存供uboot使用。

        此时需要我们去rk官网上找到对应开发板cpu型号的这两个文件,拷贝到任意目录,在make时指定文件所在目录即可。 

         我直接放在了uboot下创建的binman目录中:

        随后按照提示指定文件路径并进行编译:

make ROCKCHIP_TPL=./binman/rk3568_ddr_1560MHz_D4_LP4_4x_eyescan_v1.23.bin BL31=./binman/rk3568_bl31_v1.44.elf -j32

         编译成功后把u-boot-rockchip.bin文件烧录到启动设备中(emmc或者sd卡或者其他启动设备),随后启动可以看到进入uboot。

2、内核制作 

         uboot引导程序结束后会拉起linux内核,因此接下来需要我们制作内核镜像Image文件。要制作内核镜像的步骤和制作uboot的步骤也差不多。都是拉源码->配置文件->编译内核

        这里内核版本使用Linux官方的6.6.43版本。不过还有更新的版本,这里是因为很久之前已经下载过了,所以就用这个版本。进入linux源码下载地址:Index of /pub/linux/kernel/v6.x/;下载所需版本的源码。

        下载完成并解压后进入内核根路径,进行配置文件配置,这里我直接找到了开发板上存有的配置文件拷贝了一份到内核根路径,并重命名为 .config。

        和uboot配置过程一样,注意设置编译架构和交叉编译工具链:

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

        随后执行 make -j32, 等待编译完成后,就可以在  内核根路径/arch/指定架构/boot 路径下找到编译出来的内核镜像Image文件。

        至此内核编译完成。这里我选择采用extlinux启动方式,即将内核镜像Image和设备树.dtb等文件直接存放在根文件系统的/boot目录下,通过配置 /boot/extlinux/extlinux.conf 文件来实现启动管理。而非单独创建fat32分区来存储这些文件。因此,关于Image镜像的处理,将在后续根文件系统制作完成后进行详细说明。

3、根文件系统的制作

        制作根文件系统最典型的方式就是通过debootstrap工具。以构建debian根文件系统为例,首先安装必要的库:

sudo apt update
sudo apt install debootstrap qemu-user-static

        构建根文件系统(arm64架构):

sudo debootstrap --arch=arm64 --foreign bookworm rootfs-arm64 http://deb.debian.org/debian

        拷贝qemu模拟器到rootfs-arm64/usr/bin。因为需要在目标架构下完成根文件系统制作。

sudo cp /usr/bin/qemu-aarch64-static rootfs-arm64/usr/bin/

        进入chroot环境完成第二阶段安装,这里提供一个脚本,完成相关挂载操作并自动执行二阶段制:

#!/bin/bash

ROOTFS=$1

if [ -z "$ROOTFS" ]; then
  echo "Usage: $0 <path-to-rootfs>"
  exit 1
fi

echo "[*] Mounting /proc /sys /dev ..."
sudo mount -t proc /proc "$ROOTFS/proc"
sudo mount -t sysfs /sys "$ROOTFS/sys"
sudo mount --bind /dev "$ROOTFS/dev"
sudo mount --bind /dev/pts "$ROOTFS/dev/pts"

echo "[*] Entering chroot and running second stage ..."
sudo chroot "$ROOTFS" /debootstrap/debootstrap --second-stage

echo "[*] Cleaning up mounts ..."
sudo umount "$ROOTFS/dev/pts"
sudo umount "$ROOTFS/dev"
sudo umount "$ROOTFS/sys"
sudo umount "$ROOTFS/proc"

echo "[*] Done."

        假设脚本命名为:run-second-stage.sh,依次执行,即可完成根文件系统的制作。

chmod +x run-second-stage.sh
sudo ./run-second-stage.sh rootfs-arm64

4、制作/boot目录 

        前面我们提到,使用extlinux的方式拉起内核。使用这种方式需要在/boot目录下建立/extlinux/extlinux.conf配置文件,引导uboot拉起内核Image,并根据设备树进行硬件配置。extlinux.conf文件内容如下,标识默认启动的linux内核版本,对应的内核镜像文件、设备树文件,以及uboot启动时的命令参数。对应的文件在内核编译阶段生成,移动到/boot目录下就好。

TIMEOUT 50
DEFAULT linux-6.6.43

LABEL linux-6.6.43
    KERNEL /boot/Image-linux-6.6.43
    FDT /boot/rk3568-bpi-r2-pro.dtb
    APPEND root=/dev/mmcblk0p1 rootwait rw console=ttyS2,1500000 console=tty0 rw no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 splash plymouth.ignore-serial-consoles

        至此extlinux.conf制作完毕。还有很重要的一个步骤就是make modules_install。这条命令会把你通过make_modules编译出来的.ko文件根据INSALL_MOD_PATH参数复制到你指定的路径下 ,同时生成模块依赖信息文件。这需要你在内核源代码路径下依次执行make_modulesmake modules_install INSTALL_MOD_PATH=/path/to/rootfs这样相关没有编译到内核中的驱动文件,就会在内核启动时按照相关配置信息,动态加载到内核中。

        根文件系统制作完成后,按照以下脚本制作ext4根文件系统镜像:

dd if=/dev/zero of=rootfs.img bs=1M count=1024
mkfs.ext4 rootfs.img
sudo mkdir /mnt/rootfs
sudo mount -o loop rootfs.img /mnt/rootfs
sudo cp -a rootfs-arm64/* /mnt/rootfs/
sudo umount /mnt/rootfs

        随后把rootfs.img烧录到 sd卡即可。需要先在sd卡上创建ext4分区,然后把根文件系统镜像烧录到sd卡中。这一步涉及到wsl识别usb设备,可以参考ZYNQ开发板ARM核Linux系统移植中对此步骤的介绍。

sudo dd if=rootfs.img of=/dev/sdd1 bs=4M status=progress

5、配置uboot参数

        这里我们把sd卡插到bananapi r2-pro开发板上。这个板子好像默认先启动emmc中的uboot,没有找到相关启动方式设置按键。所以这里会从emmc的uboot拉起sd卡中的内核。上电后猛按回车进入emmc的uboot命令行界面,输入printenv命令,查看相关配置。与extlinux启动相关的配置有boot_targetsbootcmd。其中boot_targets指定了内核查找顺序,这里会先从mmc1(也就是sd卡)再从mmc0(也就是emmc)查找内核镜像文件。具体如何对应需要你自己确认一下。

        如果你的uboot不是这么配置的,那么执行setenv命令设置启动参数,随后saveenv保存即可。 

6、总结

        通过这次系统移植操作,对linux系统的启动过程和启动方式更加清晰了,也解决了驱动模块加载不正常的问题(之前zynq的移植以太网驱动是不正常工作的,估计也是这个原因)。但是uboot的制作方式正确性还没有验证,后续如果有机会会去验证一下(这里使用官方烧录工具失败)。不过对uboot的具体启动过程,内核的具体启动过程进行了什么操作还不得而知,后面可能也会看一些启动源码,进一步理解一下。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐