之前分析过,在main_loop函数中,u-boot启动内核是两条语句:

s = getenv("bootcmd");

run_command(s, 0);

u-boot分析4:u-boot启动内核

查看u-boot环境变量可知:

bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0

即run_command(s, 0) 要执行的命令为:

nand read.jffs2 0x30007FC0 kernel; 

bootm 0x30007FC0

从Flash上的kernel分区将内核读到0x30007FC0,然后从0x30007FC0启动内核

u-boot分析4:u-boot启动内核


先说一下分区的概念:

嵌入式Linux的分区与PC机windows分区不一样,嵌入式Flash上没有分区表,这些分区是在源码中写死的,我们要关注的是分区起始地址和分区大小,而不是分区名。例如韦老师改写的u-boot中,u-boot配置文件100ask24x0.h中,nandflash的分区有bootloader、环境参数params、kernel分区、文件系统分区root分别占大小256k、128k、2M,剩下的全是root分区

u-boot分析4:u-boot启动内核

mtd命令查看下分区:

u-boot分析4:u-boot启动内核

从上图可以看出kernel分区从0x00060000 开始,大小 0x00200000 = 2*16^5 = 2097152 = 2*1024*1204 = 2M

nand read.jffs2 0x30007FC0 kernel; 也可以写为

nand read.jffs2 0x30007FC0 0x00060000 0x00200000

所以分区重要的是分区起始地址和分区大小! 

继续分析,

读出内核,do_nand()

nand read.jffs2 0x30007FC0 kernel这条指令怎么从Nandflash上读出内核,do_nand()这个函数读出内核

u-boot分析4:u-boot启动内核

启动内核: do_bootm

Flash上存放的内核为uImage,uImage的结构为 头部+真正的内核,头部占64个字节

看下头部有哪些内容:image_header_t *hdr = &header;

u-boot分析4:u-boot启动内核

主要关注两个参数:加载地址 uint32_t ih_load; /* Data Load  Address */

                              入口地址 uint32_t ih_ep;       /* Entry Point Address */  

加载地址:在要启动内核之前,内核应该放存放的位置。对于JZ2440,加载地址是0x30008000

入口地址:启动内核时,需跳到入口地址运行。

bootm 0x30007FC0 这条命令,执行do_bootm(),uImage存放在0x30007FC0,

启动内核过程:先读出uImage头部,得到加载地址和入口地址,若当前内核并不位于加载地址,则将内核移动到加载地址,然后设置内核启动参数,最后跳到入口地址去执行启动内核。

看代码:bootm 0x30007FC0  命令行参数为2个,故addr 为argv[1], addr = 0x30007FC0 ,uImage头部大小为64字节

            data = 0x30007FC0 + 0x40 = 0x30008000

所以从Nandflash内核分区将uImage读到0x30007FC0地址时,真正内核地址正好在JZ2440开发板的内核加载地址,无需再次去移动内核而浪费时间,直接启动内核即可。

u-boot分析4:u-boot启动内核

u-boot分析4:u-boot启动内核

下面是判断是否需要移动内核:

u-boot分析4:u-boot启动内核

把内核移动到合适的地址后,执行do_bootm_linux(),查看函数do_bootm_linux()

void (*theKernel)(int zero, int arch, uint params);

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

theKernel 是一个函数指针,指向内核入口地址ih_ep,设置好启动参数后,执行theKernel (跳到入口地址)启动内核。

bd->bi_arch_number :这个参数很重要,叫做机器ID,根据机器ID来判断是否支持该单板。

bd->bi_boot_params: 内核启动参数

u-boot分析4:u-boot启动内核

u-boot分析4:u-boot启动内核

u-boot分析4:u-boot启动内核

内核启动后,kernel就与u-boot没有联系了,那么在启动之前,u-boot如何给内核设置启动参数的呢?

事先约定好,在某个地址,以某种格式保存参数,内核启动时读取这些参数。

对于JZ2440开发板,该地址为0x30000100,保存参数的格式是TAG,如下设置启动参数:

u-boot分析4:u-boot启动内核

tag结构体:

u-boot分析4:u-boot启动内核


相关文章: