1:总的来说内核的启动过程可以分为三个阶段:
第一阶段:内核的搬移,将启动介质中的静态内核搬移到DDR中相应的位置中去;
第二阶段:镜像文件头信息的校验,目的是确定烧录的是哪种image格式的镜像;
第三个阶段:启动内核,调用do_bootm_linux函数来完成的,最终是通过调用thekernel函数来往内核中传参,并启动内核
具体表现为:通过movi read kernel 0x30008000命令将内核搬移到DDR中,对应地址为0x30008000,然后使用bootm 0x30008000命令去启动内核。
2:具体步骤分析
第一阶段:搬移内核
(1)一开始DDR中并没有内核代码,内核代码在我们的启动介质的(我这里用的是SD卡)raw分区中,纯粹的linux在SD卡中有三个分区:uboot kernel rootfs,而kernel分区这个区域范围就是被设计用来存放内核镜像的
(2)在uboot中,uboot自身可以通过重定位(uboot启动的第一阶段)将uboot代码搬移到DDR中,而kernel中并没有设计重定位代码,所以kernel需要uboot将其从启动介质中搬移到DDR中。
(3)为什么是0x30008000这个地址处?
内核一定要放在链接地址处,链接地址在内核代码的链接脚本或者Makefile中可以找到。x210中是0x30008000
第二阶段:内核头信息校验
(1)linux内核经过编译之后会生成一个elf的可执行程序叫做vmlinux或vmlinuz(78M),使用objcopy工具制作课生成镜像格式的文件image(7.5M)(可烧录,uboot.bin一样,只是没有后缀.bin)。但是linux作者们还是image这个镜像太大了,所以进行了进一步压缩,并在镜像的头部添加了解压代码(解压代码未压缩),变成个一个自解压的镜像文件,叫做zImage
(2)uboot为了启动内核专门发明了一种uImage格式,uImage是由zImage加工得到的。(其实就是在zImage的头部添加64字节的头信息)
需要注意的是uImage和linux内核无关,内核只负责生成zImage,然后使用uboot工具mkimage将zImage加工生成uImage来给uboot启动。
由上面额分析可知,现在可以使用的镜像格式有两种分别是zImage和uImage,原则上uboot启动时应该使用uImage格式的内核镜像,但实际上uboot也可以支持zImage格式的内核镜像,这就取决于x210_sd.h中是否定义了CONFIG_ZIMAGE_BOOT这个宏,所以有些uboot只支持uImage启动,有些uboot支持uImage和zImage启动
(3)头信息的校验
uboot启动命令是bootm对应的函数是do_bootm,(这个函数在/common/Cmd_boot.c)这个函数中一直到397行的after_header_check这个符号处,都是在进行镜像的头部信息校验。校验时要根据不同类型的image类型进行不同的校验。如果校验通过,则去启动内核;如果校验失败,则不能启动。
(1)#ifdef CONFIG_ZIMAGE_BOOT来控制条件编译一段代码,这段代码是用来支持zImage格式的内核启动。
(2)#define LINUX_ZIMAGE_MAGIC 0x016f2818 :这个是一个定义的魔数,这个数等于0x016f2818,表示这个镜像是一个zImage。也就是说zImage格式的镜像中在头部的一个固定位置放了一个数作为格式标记。如果我们拿到一个image,去他的那个位置去取4字节判断它是否等于LINUX_ZIMAGE_MAGIC,则可以知道这个镜像是不是一个zImage。