u-boot分析与使用—启动内核
- 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
- 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
- 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》
- 开发环境:Linux 2.6.22.6 内核、arm-linux-gcc-3.4.5-glibc-2.3.6工具链、u-boot-1.1.6
目录
一、前言
在上一篇博文【5.3 u-boot分析与使用—源码分析】中,我们对源码进行了分析,知道的u-boot为了实现做了以下的事情:
下面则对u-boot启动内核进行细致的分析。
二、把内核读入到FLASH中
- 对于
bootcmd
环境变量,进行拆分解读,再解读
bootcmd=nand read.jffs2 0x30007FC0 kernel;
- 具体的意思就是:从nand flash中把
kernel
读到0x30007FC0
,
1、从哪里读
根据指令可以知道,从kernel
分区读,但是对于嵌入式Linux是没有分区的,那如何表示?
- 在
100ask24x0.h
文件的代码中写死
- uboot执行
mtd
可以查看分区
kernel的所在地址为:0x00020000----0x00040000
2、读到哪里去
根据指令可以知道,读到去地址为0x30007FC0
的内存中去
3、总结
-
对于指令
nand read.jffs2 0x30007FC0 kernel
意思就是nand flash从kernel分区(地址为0x00020000----0x00040000)把内核读到地址为0x30007FC0
的内存中去 -
补充:使用r
.jffs2
后缀时,输入的起始地址与结束地址不需要块对齐或页对齐
三、启动内核
- 对于
bootcmd
环境变量,进行拆分解读,再解读
bootm 0x30007FC0
- 具体的意思就是:从
0x30007FC0
中启动内核
1、FLASH上存的内核的实质
FLASH上存的内核 = 头部 + 真正的内核,对于头部结构体,原型如下:
- booitm对应的操作函数为
do_bootm()
2、do_bootm()
函数分析
2.1 读出头部,做些相关的校验工作
对于头部信息的加载地址与入口地址,下面分析会使用到。
3、根据头部的加载信息把内核移动到合适的地方
3.1 如果内核位于加载地址
3.1 如果内核不位于加载地址
4、跳到入口地址启动内核
4.1 设置启动参数
在这里会对启动参数、内存参数、串口参数、命令行参数等等进行初始化设置,后面会具体分析。
4.2 启动内核
此时会调用theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
来启动内核
- theKernel 的由来:
1、定义一个theKernel函数指针
2、定义一个hdr结构体指向2.1 中所说的头部,用来获取入口地址
3、让theKernel = hdr->ih_op
,此时theKernel
就是入口地址了
5、总结
对于整个启动内核的流程总结如下:
-
读取头部,根据头部的加载信息把内核移动到合适的地方
1_1. 先从头部知道加载地址与入口地址
1_2. 如果发现内核不位于加载地址,则把内核移动到加载地址
1_3. 如果发现内核位于加载地址,则打印相关信息 -
启动内核
2_1. 设置启动参数
2_2. 跳到入口地址启动内核
6、分析启动参数
提问:当你跳到内核时,u-boot不存在,二者怎么交互数据?
解答:按照某种协议:在某个地址,按某种格式 ,对数据进行保存。
在这个分析中就是:在0x30000100
中把启动参数入栈保存,内核可以进入到0x30000100
内存空间读取数据。
6.1 setup_start_tag()
函数分析
这个函数的功能是设置启动的参数,找到栈中对应存放参数的起始地址,放入参数。
6.2 setup_memory_tag()
函数分析
这个函数设置的是内存的相关参数,如下图所示:
6.3 setup_commandline_tag()
函数分析
这个函数设置的是命令行参数bootcmd
6.4 setup_end_tag()
函数分析
在这个函数中设置的是参数结束设置的标志
6.5 总体的入栈分析
-
根据
start_tag
的参数tag:0x30000100
,在地址为0x30000100
的内存中进行入栈 -
在每设置完一个参数后,
params
指针移动到下一个tag的位置
,进行下一个参数的入栈
四、总结
u-boot会根据bootcmd
这个环境变量,对启动内核进行相关操作: