首页 > 代码库 > u-boot学习(五):u-boot启动内核
u-boot学习(五):u-boot启动内核
u-boot的目的是启动内核。内核位于Flash中,那么u-boot就要将内核转移到内存中。然后执行命令执行之。这些操作是由bootcmd命令完毕的。
bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0
nand read.jffs2 0x30007FC0 kernel 从Flash读出内核,kernel代表从kernel分区读出内核到0x30007FC0。
1、为什么会用0x30007FC0这么怪的地址呢,由于真实的内核映像文件是uImage文件。它包括:头部+真正的内核。而头部大小正好是64字节。64字节+0x30007FC0正好是0x30008000,这个0x30008000就是真正内核的载入地址,这样安排。就不用又一次移动内核了。
2、另一个概念就是kernel分区。事实上这是分区的概念,我们在include/configs/100ask24x0.h中将分区写死,分区的名字并不重要。重要的是起始地址以及分区的大小。
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," "128k(params)," "2m(kernel)," "-(root)"bootm 0x30007FC0命令在读取完内核后启动内核,调用do_bootm函数。它有零个作用:
1、依据头部移动内核到合适的位置(上面分析了,此处不需移动)。
2、启动do_bootm_linux。它也有两个作用:告诉内核一些參数,即设置启动參数;跳到入口地址启动内核。
Bootloader与内核的交互是单向的。Bootloader将各类參数传给内核。
因为它们不能同一时候执行。传递办法仅仅有一个:Bootloader将參数放在某个约定的地方后。再启动内核,内核启动后从这个地方获得參数。
除了约定好參数存放的地址外,还要规定參数的结构。内核期望以标记列表的形式来传递启动參数。
标记,就是一种数据结构;标记列表,就是挨着存放的多个标记。标记列表以标记ATAG_CORE開始,以标记ATAG_NONE结束。标记的数据结构为tag,它由一个tag_header结构和一个联合(union)组成。
tag_header结构表示标记的类型及长度,比方是表示内存还是表示命令行參数等。
对于不同类型的标记使用不同的联合(union)。比方表示内存时使用tag_mem32。表示命令时使用tag_cmdline。数据结构tag和tag_header定义在inlcude/asm/setup.h头文件里。
struct tag_header { u32 size; u32 tag; }; struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem32 mem; struct tag_videotext videotext; struct tag_ramdisk ramdisk; struct tag_initrd initrd; struct tag_serialnr serialnr; struct tag_revision revision; struct tag_videolfb videolfb; struct tag_cmdline cmdline; /* * Acorn specific */ struct tag_acorn acorn; /* * DC21285 specific */ struct tag_memclk memclk; } u; };能够利用这些结构设置标记ATAG_CORE、设置内存标记、设置命令行标记、设置标记ATAG_CORE。源代码中的setup_memory_tags、setup_commadnline_tag函数完毕内存标记和命令标记的设置,一般设置这两个标记就能够了。
设置完标记后,最后通过theKernel(0, bd->bi_arch_number, bd->bi_boot_params)调用内核。当中,theKernel指向内核存放的地址(对于ARM架构的CPU。一般是上面提到的0x30008000),bd->bi_arch_number就是第二阶段代码中board_init函数设置的机器类型ID,而bd->bi_boot_params就是标记列表的開始地址。
參考:韦东山 《嵌入式Linux应用开发全然手冊》
u-boot学习(五):u-boot启动内核