uboot load address、entry point、 bootm address以及kernel运行地址的意义及联系

本文解析了U-Boot引导Linux内核过程中涉及的关键地址及其相互关系,包括loadaddress、entrypoint等,并详细说明了不同场景下这些地址的作用及配置要点。

按各地址起作用的顺序,uboot引导linux内核启动涉及到以下地址:

  1. load address:
  2. entry point: 这两个地址是mkimage时指定的
  3. bootm address:bootm为uboot的一个命令,以此从address启动kernel
  4. kernel运行地址:在具体mach目录中的Makefile.boot中指定,为kernel启动后实际运行的物理地址
mkimage -n 'linux-3.2.1' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage uImage

理论上因为mkimage要为zImage加上0x40字节的header,所以entry point = load address + 0x40

但由于uboot 的bootm对uImage处理不是简单的go操作,其对前三个地址都有比较判断,所以在实际的操作中,就分为两种不同的情况:

1. bootm地址和load address一样

  此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行。因此此时的entry point必须设置为load address + 0x40。如果kernel boot过程没有到uncompressing the kernel,就可能是这里设置不对。

boom address == load address == entry point - 0x40

具体细节可参看uboot代码common/cmd_bootm.c中bootm_load_os函数的实现:

复制代码
        switch (comp) {
        case IH_COMP_NONE:
                if (load == blob_start || load == image_start) {
                        printf("   XIP %s ... ", type_name);
                        no_overlap = 1;
                } else {
                        printf("   Loading %s ... ", type_name);
                        memmove_wd((void *)load, (void *)image_start,
                                        image_len, CHUNKSZ);
                }
                *load_end = load + image_len;
                puts("OK\n");
                break;
复制代码

2. bootm地址和load address不一样(但需要避免出现memory move时出现覆盖导致zImage被破坏的情况)

  此种情况下,bootm会把uImage header后的zImage move到load address(见上方代码),然后go到entry point开始执行。 由此知道此时的load address必须等于entry point。

boom address != load address == entry point

因此,在mkimage以及设置uboot boot command的时候需要注意到以上两种情况。

 

至于kernel的运行地址,其与前3个地址没有关系,除了要避免内存覆盖导致解压后kernel不完整的情况。

zImage的头部有地址无关的自解压程序,因此刚开始执行的时候,zImage所在的内存地址(entry point)不需要同编译kernel的地址相同。自解压程序会把kernel解压到编译时指定的物理地址,然后开始地址相关代码的执行。在开启MMU之前,kernel都是直接使用物理地址(可参看System.map)。

----

1. if bootm address equal load address, don't mov and go (load address + 0x40) to excute, so entry point is load address +0x40.

2. if bootm address not equal load address, mov (bootm address + 0x40) to load address and excute here, so entry point is load address. 

====

http://www.cnblogs.com/sywtt/archive/2012/01/25/2329284.html

### U-Boot 命令语法使用方法 U-Boot(Universal Boot Loader)是一种广泛用于嵌入式系统的开源引导程序,支持多种处理器架构硬件平台。它提供了丰富的命令集,允许用户在启动阶段对系统进行配置调试。以下是关于 U-Boot 命令语法使用方法的详细介绍。 #### U-Boot 命令的基本语法结构 U-Boot 命令的基本语法格式如下: ``` command [arguments] ``` 其中 `command` 是要执行的命令名称,`[arguments]` 是命令的参数。参数可以是多个,具体取决于命令的需求。例如: ``` printenv bootcmd ``` 上述命令中,`printenv` 是命令名称,`bootcmd` 是参数,表示打印名为 `bootcmd` 的环境变量值。 #### 常用命令及其用途 1. **help 或 ?** 当不确定某个命令的用法时,可以使用 `help` 或 `?` 快速查找相关信息。例如: ``` help printenv ``` 这条命令会显示 `printenv` 的使用说明。对于初学者或需要熟悉 U-Boot 命令的人来说,这两个命令非常有用,可以帮助快速掌握 U-Boot 的命令集[^1]。 2. **printenv** 用于打印所有环境变量或指定环境变量的值。例如: ``` printenv ``` 这条命令会列出所有环境变量及其当前值。如果只想查看某个特定环境变量的值,可以指定变量名: ``` printenv bootcmd ``` 3. **setenv** 用于设置或修改环境变量的值。例如: ``` setenv bootcmd 'tftp 0x8000 uImage; bootm 0x8000' ``` 这条命令将 `bootcmd` 环境变量的值设置为 `'tftp 0x8000 uImage; bootm 0x8000'`。需要注意的是,`setenv` 修改的是 DRAM 中的环境变量值,如果希望将更改保存到外部 Flash 中,必须使用 `saveenv` 命令[^5]。 4. **saveenv** 用于将修改后的环境变量保存到外部 Flash 中。例如: ``` saveenv ``` 这条命令会将当前 DRAM 中的环境变量写入外部 Flash,确保下次启动时仍然生效。 5. **run** 用于执行某个环境变量中定义的命令序列。例如: ``` run bootcmd ``` 这条命令会执行 `bootcmd` 环境变量中定义的命令序列。 6. **bootm** 用于启动内核镜像。例如: ``` bootm 0x8000 ``` 这条命令会从地址 `0x8000` 开始加载启动内核镜像。 7. **tftp** 用于通过 TFTP 协议从网络服务器下载文件。例如: ``` tftp 0x8000 uImage ``` 这条命令会从 TFTP 服务器下载名为 `uImage` 的文件,并将其加载到内存地址 `0x8000` 处。 #### 自定义命令的添加 U-Boot 允许用户添加自定义命令。当用户在 U-Boot 的 shell 中输入命令时,系统会在 `.u_boot_list.cmd` 这个内存区域中查找(`_u_boot_list_cmd__start` 到 `_u_boot_list_cmd__end`),当该区域中某一个 `cmd_tbl_s` 命令结构体的 `cmd_tbl_s.name` 输入的命令字符串相符时,就会调用该命令结构体的 `cmd_tbl_s.cmd()` 函数[^2]。 要添加自定义命令,首先需要定义一个 `cmd_tbl_s` 结构体,并将其放置在 `.u_boot_list.cmd` 段中。例如: ```c U_BOOT_CMD( mycmd, /* 命令名称 */ 2, /* 最大参数个数 */ 1, /* 重复执行标志 */ do_mycmd, /* 命令处理函数 */ "mycmd - description of mycmd\n", "usage: mycmd [args...]\n" ); ``` 然后需要实现 `do_mycmd` 函数,处理命令的具体逻辑。 #### U-Boot 的生成规则 U-Boot 的生成规则涉及多个目标文件库文件的链接过程。生成 `u-boot` 可执行文件的规则如下: ```makefile $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT) UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) | sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p' | sort | uniq`; \ cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ -Map u-boot.map -o u-boot ``` 这段规则描述了如何将目标文件库文件链接成最终的 `u-boot` 可执行文件。其中,`UNDEF_SYM` 用于提取未定义的符号,确保链接器能够正确解析所有依赖关系[^3]。 #### U-Boot 镜像的构建依赖关系 U-Boot 的不同镜像文件之间存在一定的依赖关系。例如,`u-boot.stm32` 依赖于 `u-boot.bin`,而 `u-boot.bin` 又依赖于 `u-boot-dtb.bin`,`u-boot-dtb.bin` 则依赖于 `u-boot-nodtb.bin` 设备树文件 `dts/dt.dtb`。这些依赖关系确保了镜像文件能够正确构建[^4]。 ### 示例代码 以下是一个简单的 U-Boot 命令行交互示例: ```bash => printenv bootdelay=3 baudrate=115200 ethaddr=00:11:22:33:45:67 ipaddr=192.168.1.100 serverip=192.168.1.1 bootcmd=tftp 0x8000 uImage; bootm 0x8000 => setenv bootcmd 'tftp 0x8000 uImage; bootm 0x8000' => saveenv Saving Environment to Flash... Un-Protected 1 sectors Erasing Flash... Erased 1 sectors Writing to Flash... 100% done Protected 1 sectors => run bootcmd TFTP from server 192.168.1.1; our IP address is 192.168.1.100 Filename 'uImage'. Load address: 0x8000 Loading: T 1.5 MiB/s, 1517 blocks, 1517 KB done ## Booting kernel from Legacy Image at 00008000 ... Image Name: Linux-5.10.110 Created: 2023-08-15 10:00:00 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1517 KiB = 1.45 MiB = 0.00 MB Load Address: 80008000 Entry Point: 80008000 Verifying Checksum ... OK Loading Kernel Image ... OK Starting kernel ... ``` 在这段示例中,用户首先打印了所有环境变量,然后修改了 `bootcmd` 环境变量的值,并使用 `saveenv` 将其保存到外部 Flash 中。接着,用户通过 `run bootcmd` 执行了 `bootcmd` 中定义的命令,从 TFTP 服务器下载并启动内核镜像。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值