前一篇文章已经叙述完了引导内核的整个过程,但是对其中几个关键的地方我们还没有进行分析,例如 mkimge 命令中的地址等问题。这些对我们进一步学习很重要,所以我想在这篇文章里和大家一起探讨一下。
(一)mkimage 命令
对于mkimage命令来说,-a参数后是内核的运行地址(假设为addrA),-e参数后是入口地址(假设为addrB),这两个地址的关系可以是相同,也可以是B=A+0x40 ,我们分开讨论这两种情况。
提示:使用mkimage生成内核镜像文件的话,会在内核的前头加上了64byte的信息,供建立tag之用(tag是用于bootloader和内核之间传递参数的)。bootm命令会首先判断bootm xxxx 这个指定的地址xxxx是否与-a指定的加载地址相同:
(1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之。
(2)如果相同的话那就让其原封不同的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部。
1. A 等于 B (搬运代码方式)
mkimage -a addrA -e addrA
这种情况下,我们第一篇文章中介绍的“引导系统实验”的tftp 下载kernel 就一定不能下载到 addrA(addrB)处 。因为由上面的提示可知,那两个地址相同的情况下u-boot并不搬运kernel 代码,也就是没有把header去掉,所以内核无法启动,会直接 RESET。
当然也不能下到与 addrA 的地址相距小于 0x40 的地方, 否则搬运的时候会有一些覆盖, 导致搬运后的kernel不完整, bootm的时候,也会 RESET 的。
由于内核固化到Nand Flash后,在启动的过程中也要读到内存中,所以我们的“引导系统实验”和固化后的启动其实在某阶段上是一致的,因而得出一个结论。
结论:在编译内核的时候,如果 mkimage 命令的 -a 和 -e 后面的地址相同,那表示用搬运代码的方式启动内核,所以我们设置的环境变量 bootcmd 的地址必须与那两个相同的地址有一段距离(应该是大于0x40),这样才能正常启动系统。
如: mkimage ... -a 0x30008000 -e 0x30008000 ...
另外 nand read 0x31000000 0x50000 0x00200000;bootm 0x31000000
2. B=A+0x40 (不搬运代码方式)
mkimage -a addrA -e addrA+0x40 或者 mkimage -a addrA -x 两个是一回事。-x 的意思是在kernel所在地执行。表示不必搬运代码。
依上面的提示我们可知,不搬运代码的条件是 bootm 的地址和 mkimage 的 -a 指定的地址相同。所以,在我们的“引导系统实验”中 tftp 下kernel的地址应该是 addrA 处,然后直接 bootm addrA 就可以成功引导了。
结论:在编译内核的时候,如果 mkimage 命令的 -e 后面的地址是 -a 后面的地址加 0x40 ,那表示用不搬运代码的方式启动内核,所以我们设置的环境变量 bootcmd 的地址必须与 -a 后面的地址相同,这样才能正常启动系统。
如: mkimage ... -a 0x30008000 -e 0x30008040 ...
另外 nand read 0x30008000 0x50000 0x00200000;bootm 0x30008000
(二)env 参数的修改
本来以为修改U-Boot代码可以达到修改环境变量的目的,其实不然。依据U-Boot代码中的宏定义(在mini2440.h中)
#define CONFIG_ENV_OFFSET 0x30000 或者(#define CFG_ENV_OFFSET 0x30000)
可知环境变量在NAND FLASH的0x30000处,也就是处于我们的param分区。所以我们在U-Boot中修改环境变量并不起作用,不过第一次启动的时候可能例外,因为此时 Nand Flash 中的数据无效,U-Boot可能会把在U-Boot中设置的环境变量固化到Nand Flash 中。
env 在 u-boot 中通常有两种存在方式,即在永久性存储介质中( Flash NVRAM等)和在SDRAM中,也可以配置不使用 env 的永久存储方式,但这不常用。u-boot 在启动的时候会将存储在永久性存储介质中的 env 重新定位到 RAM 中,这样可以快速访问。所以如果要修改环境变量的话,只能通过 setenv 设置和通过 saveenv 将 RAM 中的 env 保存到永久性存储介质中。
阅读(847) | 评论(0) | 转发(0) |