u-boot命令中,我们用print打印信息
看到u-boot启动命令:bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
这里包含两条信息:读内核和启动内核
分析
1.bootcmd=nand read.jffs2 0x30007FC0 kernel;
从Nand读出内核,从哪里读:从kernel分区(1)
放到哪里去:---0x30007FC0
(1)什么是分区
PC:硬盘有分区表
嵌入式Flash:没有分区表
但是我们要让FLASH实现的是有分区:
所以我们所谓的有分区,是在源码里写死了。
如:
我们也可以在u-boot命令端上输入:mtd参看分区
其中0x00060000 就是内核(uImage)存放的位置(相对于为我的开发版)
我们在u-boot命令输入bootm时,会输出0x30008000这个就是把内核读到SDRAM的位置
从FLASH的0x00060000 读到——> SDRAM 的0x30008000
nand read.jffs2 0x30007FC0 kernel --0x00020000 0x00060000
2.bootm 0x30007FC0
(1)怎么启动,我们参看u-boot-1.1.6\common\Cmd_bootm.c的
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
(2)我们先来说一下内核格式
内核是放在FLASH中,以uImage(64字节头部+真正内核组成)存在。
我们在do_bootm中看到有头部结构体
这里面定义了头部的各种信息,我们关系load和rp这两个。
load:加载地址(内核存放的地址)
ep:入口地址(启动内核时跳到的地址)
我们在u-boot命令中启动内核时一般是输入bootm 地址(uImage存放的地址)
我们想一下,bootm应该会去头部读出加载地址,如果它发现这个真正的内核不在它的加载地址的话,它就要把内核移到他的加载地址去,最后到入口地址去执行
代码里得到验证
如果内核刚好放在加载地址,就不用移动
我们的jz2440开发板设置的加载地址是0x30008000,64字节+0x30007FC0=0x30008000
所以,为什么一开始程序要
ootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
现在我们知道了是去头部地址开始读
(3)启动
我们一路把Cmd_bootm.c的do_bootm函数读下来,当移动内核到加载地址后,正式开始启动,由函数
do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify);完成
到这里,函数先要做的有两点:
{
| 1.u-boot告诉内核一些参数:设置启动参数
do_bootm_linux:
| 2.跳到入口地址启动内核
{
完成这两步,才是真正去启动内核
我们分析这个u-boot-1.1.6\lib_arm\Armlinux.c的do_bootm_linux函数定义
这些参数就在这里定义
发现
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
hdr->ih_ep就是头部的入口地址
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);这个就是真正的启动内核
(4)分析启动参数
这里我们又想到,我们启动内核后,之前的u-boot怎么和内核交互数据:在某个地址(我的开发板是0x30000100)按某种格式(TAG)保存数据(启动参数,就是上面的参数)
setup_start_tag (bd); 启动参数
setup_memory_tags (bd); 内存参数
setup_commandline_tag (bd, commandline); 命令参数
setup_end_tag (bd);
分析setup_start_tag (bd);
看看tag的定义
搜setup_start_tag里的bi_boot_params可得知参数是放在0x30000100和我们刚才说的一样
最终分析四个参数 setup_start_tag (bd); 启动参数
setup_memory_tags (bd); 内存参数
setup_commandline_tag (bd, commandline); 命令参数
setup_end_tag (bd);
得出,我们的内核启动前,会先到地址0x30000100读取启动参数,再去启动内核
在回顾u-boot的终极目的:启动内核
(1)从Flash读出内核(2)启动(1.设置启动参数,2.到入口地址启动)
是不是豁然开朗
(5)分析函数theKernel (0, bd->bi_arch_number, bd->bi_boot_params);这个函数启动了内核
参数bd->bi_boot_params:是我们刚才那些参数
参数bd->bi_arch_number:机器ID