想用 uboot 来加载内核,就需要将 Kernel image 和 dtb 传给 uboot,这里还是用他官方 git 上的 kernel 代码。这里用 boot.src 来将这些信息传递给 uboot。而 boot.src 可以用 mkimage 工具生成。mkimage 工具在 uboot-tools 中,可以通过 manifest 来选也可以像我一样加在默认配置文件中。因为要在 host 上使用生成,所有要注意要选择 host 端的。
BR2_PACKAGE_HOST_UBOOT_TOOLS=y BR2_PACKAGE_HOST_UBOOT_TOOLS_BOOT_SCRIPT=y BR2_PACKAGE_HOST_UBOOT_TOOLS_BOOT_SCRIPT_SOURCE="board/raspberrypi4-64-magic/boot.cmd"
mkimage 工具生成 boot.src 需要 uboot 启动时的 kernel、dtb 以及 kernel cmdline ,启动命令等信息,这里写一个 boot.cmd 的 文件来作为生成 boot.src 的源。在上面配置中指定了文件的路径。
setenv bootargs coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1 bcm2708_fb.fbwidth=1024 bcm2708_fb.fbheight=768 bcm2708_fb.fbswap=1 smsc95xx.macaddr=DC:A6:32:6D:CC:7C vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 root=/dev/mmcblk0p2 rootwait console=tty1 console=ttyAMA0,115200 fdt addr ${fdt_addr} fdt move ${fdt_addr} ${fdt_addr_r} fatload mmc 0 $kernel_addr_r Image booti $kernel_addr_r - $fdt_addr_r
第一行是传给 kernel 的命令行,我先复制了原先 buildroot 中打印出来的命令行参数。里面前面的一些都是什么意思还没有研究。
用 fdt 命令将 GPU 处理过放在内存中的 dtb 文件读取。然后移动到内核启动时的指定 dtb 的地址处。
后面用 fatload 命令将内核文件读取到内核启动的地址中。
用 booti 命令指定内核和 dtb 所在的内存地址启动。
关于上面的内核和 dtb 的地址,在 uboot include/config/rpi.h 的代码中有描述。
/* * Memory layout for where various images get loaded by boot scripts: * * I suspect address 0 is used as the SMP pen on the RPi2, so avoid this. * * Older versions of the boot firmware place the firmware-loaded DTB at 0x100, * newer versions place it in high memory. So prevent U-Boot from doing its own * DTB + initrd relocation so that we won't accidentally relocate the initrd * over the firmware-loaded DTB and generally try to lay out things starting * from the bottom of RAM. * * kernel_addr_r has different constraints on ARM and Aarch64. For 32-bit ARM, * it must be within the first 128M of RAM in order for the kernel's * CONFIG_AUTO_ZRELADDR option to work. The kernel itself will be decompressed * to 0x8000 but the decompressor clobbers 0x4000-0x8000 as well. The * decompressor also likes to relocate itself to right past the end of the * decompressed kernel, so in total the sum of the compressed and and * decompressed kernel needs to be reserved. * * For Aarch64, the kernel image is uncompressed and must be loaded at * text_offset bytes (specified in the header of the Image) into a 2MB * boundary. The 'booti' command relocates the image if necessary. Linux uses * a default text_offset of 0x80000. In summary, loading at 0x80000 * satisfies all these constraints and reserving memory up to 0x02400000 * permits fairly large (roughly 36M) kernels. * * scriptaddr and pxefile_addr_r can be pretty much anywhere that doesn't * conflict with something else. Reserving 1M for each of them at * 0x02400000-0x02500000 and 0x02500000-0x02600000 should be plenty. * * On ARM, both the DTB and any possible initrd must be loaded such that they * fit inside the lowmem mapping in Linux. In practice, this usually means not * more than ~700M away from the start of the kernel image but this number can * be larger OR smaller depending on e.g. the 'vmalloc=xxxM' command line * parameter given to the kernel. So reserving memory from low to high * satisfies this constraint again. Reserving 1M at 0x02600000-0x02700000 for * the DTB leaves rest of the free RAM to the initrd starting at 0x02700000. * Even with the smallest possible CPU-GPU memory split of the CPU getting * only 64M, the remaining 25M starting at 0x02700000 should allow quite * large initrds before they start colliding with U-Boot. */ #define ENV_MEM_LAYOUT_SETTINGS \ "fdt_high=" FDT_HIGH "\0" \ "initrd_high=" INITRD_HIGH "\0" \ "kernel_addr_r=0x00080000\0" \ "scriptaddr=0x02400000\0" \ "pxefile_addr_r=0x02500000\0" \ "fdt_addr_r=0x02600000\0" \ "ramdisk_addr_r=0x02700000\0"
接下来就是把 boot.scr 打包进 boot 分区。在 genimage-raspberrypi4-64-magic.cfg 中 boot.vfat 分区文件中添加即可 。
image boot.vfat { vfat { files = { "bcm2711-rpi-4-b.dtb", "rpi-firmware-magic/cmdline.txt", "rpi-firmware-magic/config.txt", "rpi-firmware-magic/fixup.dat", "rpi-firmware-magic/start.elf", "rpi-firmware-magic/overlays", "Image", "boot.scr", "u-boot.bin" } } size = 100M }
这里我替换了 rpi-firware 换成了 git 上最新的版本。同时还将 boot 分区大小扩大到了 100M。
烧录后正常启动到内核。
串口无法输入问题排查
之前并没有注意到 GPU 加载了 overlays/miniuart-bt.dtbo 还是用 fatload 命令直接加载的 dtb 文件到 fdt_addr_r 地址启动,所有由于 bt 功能的影响,串口一直无法输入。这个问题查了好久,一路从用户态查到内核,才想到启动时 overlays 中 miniuart-bt.dtbo 被 GPU 应用,而我的 uboot 并没做这样的事情。
在 uboot 下用命令读取 miniuart-bt.dtbo 文件后用 fdt apply 命令应用该 dtbo 结果出错。而 uboot 中的 libfdt 没有任何 debug 开关,但在 内核下可以正常动态加载。后面才想到也许可以用 GPU 现成的 dtb。