uboot加载kernel,ramdisk,dtb的内存布局问题

本文详细解析了U-Boot加载Kernel、Ramdisk和DTB时的内存布局,涉及load_uimage和load_zimage命令行使用,以及bootm和bootz命令在新版U-Boot中的操作差异。深入探讨了U-Boot如何处理不同类型的镜像,包括uImage和zImage,以及mkimage命令的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uboot在加载kernel,ramdisk,dtb时,要注意内存布局。
否则,会出现各种问题,例如
machine ID问题,calibrating delay 问题等等。
这些都是因为kernel在启动时,找不到dtb而产生的。
又例如
ramdisk could not found 问题。
这是因为kernel启动时,不能在initrd指定的问题找到有效格式的RAMDISK导致的。
这些问题,都涉及到uboot加载时的内存布局。

我们加载时,会用到
load_uimage或者load_zimage命令行。

load_uimage=fatload mmc 0 ${kernel_load_address} ${kernel_image} && fatload mmc 0 ${devicetree_load_address} ${devicetree_image} && fatload mmc 0 ${ramdisk_load_address} ${ramdisk_image}

load_zimage=fatload mmc 0 ${kernel_zimage_load_address} ${kernel_zimage} && fatload mmc 0 ${devicetree_load_address} ${devicetree_image} && fatload mmc 0 ${ramdisk_zimage_load_address} ${ramdisk_zimage}

kernel_load_address=0x2080000
ramdisk_load_address=0x7fffc0
devicetree_load_address=0x1000000
kernel_zimage_load_address=0x8000
ramdisk_zimage_load_address=0x800000

kernel_zimage=zImage
ramdisk_zimage=zramdisk.image.gz
ramdisk_image=uramdisk.image.gz

可以看到,他们都是用到fatload命令,从SD卡中读取文件到指定的内存地址中。

如果需要用uImage启动,那么uenvcmd如下:
uenvcmd=run mmc_loadbit_fat && echo Copying Linux from SD to RAM… && run load_uimage && echo run kernel_boot_uimage… && run kernel_bootm

如果需要从zImage启动,那么uenvcmd如下:
uenvcmd=run mmc_loadbit_fat && echo Copying Linux from SD to RAM… && run load_zimage && echo run kernel_boot_zimage… && run kernel_bootz

两者的区别在于:
uImage用的是bootm命令启动的。

kernel_bootm=bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}

而zImage用的是bootz命令启动的。
kernel_bootz=bootz ${kernel_zimage_load_address}

在新版uboot中,我们使用bootz命令,只是希望它取代go命令。并不希望它完成搬移RAMDISK和DTB的功能。
所以bootz的操作,就是在指定的地址上,解压zImage,然后跳转到start address,启动内核。

这里就涉及到bootm对uImage的处理方式的理解了。
bootm识别UBOOT格式的镜像,uImage相比zImage,多了0x40个字节的U_HEADER。
(1)当bootm识别出加载的是uImage时,且TYPE为kernel,那么会去比较source address 和load address。
如果两者相等,那么不执行move操作。
然后会记下entry address,之后start kernel时,会跳转到entry address。后续操作和bootz一样。
所以,此时,entry addr = 0x40 + load addr。
如果两者不相等,那么执行move操作。
注意,这个时候,bootm的特殊地方就来了。
为了避免跑飞,bootm在搬移kernel时,去掉了U_HEADER,然后把净剩载荷move到load address上。也就是说,zImage被move。
所以,此时,entry addr = load addr。

(2)当bootm识别出加载的是uImage时,且TYPE为RAMDISK
由于不是kernel,所以不记下load address 和 entry address。
然后move到RAM的高段地址区。并返回一个地址区间start和end,供内核进行虚拟地址映射使用。

(3)当bootm识别出加载的是DTB时,
由于不是UIMAGE格式,所以不存在load address和entry address。
然后move到RAM的高段地址区。并返回一个地址区间start和end,供内核进行虚拟地址映射使用。

由于TYPE的区别,我们在mkimage时,使用的选项是不同的。
生成kernel的命令如下:
mkimage -A arm -O linux -T kernel -C none -a 00008000 -e 00008000 -n linux-kernel -d ./zImage ./uImage
生成kernel的命令如下:
mkimage -A arm -O linux -T ramdisk -C gzip -n uboot ramdisk -d ./zramdisk.image.gz ./uramdisk.image.gz

### U-Boot 引导 Linux 内核教程和配置方法 #### 准备工作 为了成功使用 U-Boot 来引导 Linux 内核,需要准备几个关键文件:设备树二进制 (Device Tree Blob, dtb),内核镜像 (通常是 zImage 或 uImage),以及根文件系统映像。这些文件通常由开发板制造商提供或通过编译源码获得。 #### 加载内核到内存 U-Boot 提供命令来加载内核和其他必要的组件至 RAM 中。对于大多数平台而言,可以利用 `tftp` 命令从 TFTP 服务器下载所需文件;也可以采用 SD 卡或其他存储介质上的 `fatload` 或者 `ext4load` 等命令读取本地文件[^1]。 ```bash => tftpboot ${kernel_addr_r} zImage => tftpboot ${fdt_addr_r} imx6ul-var-som.dtb ``` 上述命令假设环境变量 `${kernel_addr_r}` 和 `${fdt_addr_r}` 已经被设置为合适的地址空间位置用于存放内核和 DTB 文件。 #### 设置启动参数 在实际执行 bootm 指令之前,还需要定义传递给新操作系统的一些重要参数,比如 rootfs 的路径、控制台输出端口等。这可以通过修改 `bootargs` 变量实现: ```bash => setenv bootargs console=ttymxc0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait ``` 这里指定了串行终端作为调试接口,并告知内核在哪里寻找根文件系统及其挂载选项。 #### 执行 Bootm 操作 当所有准备工作完成后,就可以调用 `bootm` 指令完成最终的引导过程了。该指令会按照指定顺序解析并运行先前加载好的各个部分——首先是解压后的压缩内核映像,接着是初始化 ramdisk(如果有),最后则是应用特定于硬件平台描述符即 device tree blob: ```bash => bootm ${kernel_addr_r} - ${fdt_addr_r} ``` 此命令中的连字符 `-` 表明没有额外的 initrd/initramfs 需要处理。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值