一、前言
最近入手得一块树莓派3B+开发板,试着移植Uboot到其中作启动内核,练练手。
二、大致过程
1、准备一张8G以上microSD卡或U盘(树莓派3B+默认支持USB启动),在Windows环境,下载官方烧写程序Raspberry Pi Imager,烧写安装官方树莓派32位操作系统,
启动流程:
1、First stage bootloader
树莓派上电后,SoC 中的 bootloader 首先被执行,其作用是挂载 SD 卡上的 FAT32 分区,从而加载下一阶段的 bootloader。这部分程序被固化在 SoC 的 ROM 中,用户无法修改。
2、Second stage bootloader (bootcode.bin)
这个阶段的 bootloader 会从 SD 卡上检索 GPU 固件,将固件写入 GPU,随后启动 GPU。
3、GPU firmware (start.elf)
本阶段中,GPU 启动后会检索附加配置文件(config.txt、fixup.dat),根据其内容设置 CPU 运行参数及内存分配情况,随后将用户代码加载至内存,启动 CPU。
4、User code (kernel8.img)
通常情况下,CPU 启动后便开始执行 kernel8.img 中的指令,初始化操作系统内核,在某些情况下,也可以被 U-BOOT 代替,由 U-BOOT 来加载内核。在树莓派 1 代中,User code 部分被保存在 kernel.img 文件中,2 代中,该文件更名为 kernel7.img,3 代中,该文件更名为 kernel8.img
官方的启动流程介绍链接SD卡里的boot包含如下文件(官方链接):
overlays:存放设备树,不可少
bcm2710-rpi-3-b-plus.dtb: 设备树文件
bootcode.bin:bootloader文件
fixup.dat :GPU固件Videocore
start.elf :GPU内存
kernel.img :系统会先后搜寻config.txt中参数kernel=xxx指定的文件作为接下来接受系统控制权的对象,树莓派默认该文件是linux内核,我们可以替换为用uboot作为新一个bootloader然后再去启动linux内核。如果config.txt里没指定kernel参数,则默认是先后搜寻kernel8.img、kernel8-32.img、kernel7.img、kernel.img,分别对应ARMv8-aarch64、ARMv8-aarch32、ARMv7和之前版本的。
config.txt :如上面所说,该文件是启动过程第三阶段用来读取参数的。https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md
cmdline.txt :是树莓派原生系统启动时传给内核的参数,我们用uboot其实用不着这个
2、准备交叉编译工具(在unbutun20.10系统环境)
64位:
在主目录下新建目录:~/gcc_cros2021/aarch64
解压:tar -xvJf gcc-linaro-10.2.1-2021.04-x86_64_arm-linux-gnueabihf.tar.xz
32位:
在主目录下新建目录:~/gcc_cros2021/arm
解压:tar -xvJf gcc-linaro-10.2.1-2021.04-x86_64_arm-linux-gnueabihf.tar.xz
环境变量设置 :
sudo vi ~/.bashrc
# 交叉编译器aarch64
export PATH=~/gcc_cros2021/aarch64/bin:$PATH
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
## 交叉编译器arm32
#export PATH=~/gcc_cros2021/arm/bin:$PATH
#export CROSS_COMPILE=arm-linux-gnueabihf-
3、编译U-Boot
下载Uboot,用git工具,(git clone https://source.denx.de/u-boot/u-boot.git)
针对树莓派有如下配置可选(产生u-boot/.config文件):
lrg@lrg-virtual-machine:~/u-boot$ ls ./configs/ | grep rpi
rpi_0_w_defconfig
rpi_2_defconfig
rpi_3_32b_defconfig
rpi_3_b_plus_defconfig
rpi_3_defconfig
rpi_4_32b_defconfig
rpi_4_defconfig
rpi_arm64_defconfig
rpi_defconfig
编译aarch64版本u-boot(设置如上相应aarch64交叉编译器环境变量):
lrg@lrg-virtual-machine:~/u-boot$ make rpi_3_b_plus_defconfig
#
# configuration written to .config
#
lrg@lrg-virtual-machine:~/u-boot$ make -j4
编译arm32版本u-boot(设置如上相应arm32交叉编译器环境变量):
lrg@lrg-virtual-machine:~/u-boot$ make rpi_3_32b_defconfig
#
# configuration written to .config
#
lrg@lrg-virtual-machine:~/u-boot$ make -j4
scripts/kconfig/conf --syncconfig Kconfig
CHK include/config.h
CFG u-boot.cfg
......
LD u-boot
OBJCOPY u-boot.srec
OBJCOPY u-boot-nodtb.bin
SYM u-boot.sym
COPY u-boot.bin
===================== WARNING ======================
CONFIG_OF_EMBED is enabled. This option should only
be used for debugging purposes. Please use
CONFIG_OF_SEPARATE for boards in mainline.
See doc/README.fdt-control for more info.
====================================================
CFGCHK u-boot.cfg
lrg@lrg-virtual-machine:~/u-boot$
u-boot.bin为编译产生的u-boot启动内核二进制文件,将其拷入SD卡的boot分区根目录下,
sd卡的boot分区中config.txt设置(类似PC机的BIOS设置):
······
##64位
# arm_64bit=1
# kernel=u-boot64.bin
#32位
kernel=u-boot32.bin
······
其中u-boot64.bin、u-boot32.bin,就是前面编译生成相应aarch64版本及arm版本的u-boot.bin改名而来。
启动界面:
aarch64版本:
arm版本:
至此,移植U-boot操作告一段落。为测试一下是否通过U-boot启动引导原安装的树莓派系统,继续折腾。。。。。。
设置sd卡读取系统镜像(在32位arm版本U-boot环境):
方法一,开发板上电启动后进入U-boot,命令行设置启动命令与参数并保存(这种方法不便修改):
U-Boot> setenv bootcmd "fatload mmc 0:1 0x80000 kernel7.img;fatload mmc 0:1 0x2600000 bcm2710-rpi-3-b-plus.dtb;bootm 0x80000 - 0x2600000"
U-Boot> setenv bootargs "console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait noinitrd"
U-Boot> saveenv
U-Boot> boot
方法二,进入编译U-boot的Unbutun系统中编写U-boot启动脚本,利用U-boot工具mkimage生成脚本镜像boot.scr。
在用户目录下或者新一个目录,新建文件script_uboot,内容:
lrg@lrg-virtual-machine:~$ vi script_uboot
setenv fdtfile bcm2710-rpi-3-b-plus.dtb
setenv bootargs "earlyprintk console=tty0 console=ttyAMA0 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait noinitrd"
fatload mmc 0:1 ${kernel_addr_r} kernel7.img
fatload mmc 0:1 ${fdt_addr_r} ${fdtfile}
bootz ${kernel_addr_r} - ${fdt_addr_r}
再新建文件make_scr,内容:
mkimage -A arm -O linux -T script -C none -a 0x00000000 -e 0x00000000 -n "RPi3b+ Boot Script" -d script_uboot boot.scr
在终端下source出boot.scr
lrg@lrg-virtual-machine:~$ source make_scr
最后把boot.scr拷入SD卡的boot分区根目录下,重启,成功了!
启动界面:
启动后,声音及蓝牙没有被驱动,其他正常,小激动后有些遗憾。
经试验,换成kernel8.img内核不能启动,提示内核文件格式不对;
尝试用aarch64版本U-boot、kernel8.img内核,提示没有bootz命令,重新编译aarch64版本U-boot时在.config配置文件中打开bootz选项,编译出支持bootz的64位U-boot内核,还是提示内核格式不对,换成bootm命令也不能启动,kernel8.img换成kernel7.img,无限重启,反正在aarch64版本U-boot下,就是死活不启动原生树莓派系统。不折腾了...