我们详细的分析了
uboot
的顶层
Makefile
,理清了
uboot
的编译流程。本章我们来详细的分析一下 uboot
的启动流程,理清
uboot
是如何启动的。通过对
uboot
启动流程的梳理,我们就可以掌握一些外设是在哪里被初始化的,这样当我们需要修改这些外设驱动的时候就会心里有数。另外,通过分析 uboot
的启动流程可以了解
Linux
内核是如何被启动的。
链接脚本
u-boot.lds
详解
要分析
uboot
的启动流程,首先要找到“入口”,找到第一行程序在哪里。程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口。如果没有编译过 uboot
的话链接脚本为arch/arm/cpu/u-boot.lds
。但是这个不是最终使用的链接脚本,最终的链接脚本是在这个链接脚本的基础上生成的。编译一下 uboot
,编译完成以后就会在
uboot
根目录下生成
u-boot.lds文件,如图所示:
打开u-boot.lds文件如下所示
第
3
行为代码当前入口点:
_start
,_start 在文件
arch/arm/lib/vectors.S
中有定义。
从图
32.1.2
中的代码可以看出,
_start
后面就是中断向量表,从图中的“
.section ".vectors",
"ax
”可以得到,此代码存放在
.vectors
段里面。
使用如下命令在 uboot
中查找“
__image_copy_start
”:
grep -nR "__image_copy_start"
u-boot.map
是
uboot
的映射文件,可以从此文件看到某个文件或者函数链接到了哪个地址,
从图
32.1.4
的
932
行可以看到
__image_copy_start
为
0X87800000
,而
.text
的起始地址也是
0X87800000。
继续回到示例代码 32.1.1
中,第
11
行是
vectors
段,
vectors
段保存中断向量表,从图
32.1.2 中我们知道了 vectors.S
的代码是存在
vectors
段中的。从图
32.1.4
可以看出,
vectors
段的起始地址也是 0X87800000
,说明整个
uboot
的起始地址就是
0X87800000
,这也是为什么我们裸机例程的链接起始地址选择 0X87800000
了,目的就是为了和
uboot
一致。
第
12
行将
arch/arm/cpu/armv7/start.s
编译出来的代码放到中断向量表后面。
第
13
行为
text
段,其他的代码段就放到这里
在
u-boot.lds
中有一些跟地址有关的“变量”需要我们注意一下,后面分析
u-boot
源码的
时候会用到,这些变量要最终编译完成才能确定的!!!比如我编译完成以后这些“变量”的值
如表
32.1.1
所示:
表
32.1.1
中的“变量”值可以在
u-boot.map
文件中查找,表
32.1.1
中除了
__image_copy_start
以外,其他的变量值每次编译的时候可能会变化,如果修改了
uboot
代码、修改了
uboot
配置、
选用不同的优化等级等等都会影响到这些值。所以,一切以实际值为准!
U-Boot
启动流程详解
reset
函数源码详解
从
u-boot.lds
中我们已经知道了入口点是
arch/arm/lib/vectors.S
文件中的
_start
,代码如下
第
48
行
_start
开始的是中断向量表,其中
54~61
行就是中断向量表,和我们裸机例程里面一样。
54
行跳转到
reset
函数里面,
reset
函数在
arch/arm/cpu/armv7/start.S
里面,代码如下:
第
35
行就是
reset
函数。
第
37
行从
reset
函数跳转到了
save_boot_params
函数,而
save_boot_params
函数同样定义
在
start.S
里面,定义如下:
save_boot_params
函数也是只有一句跳转语句,跳转到
save_boot_params_ret
函数,
save_boot_params_ret
函数代码如下:
第
43
行,读取寄存器
cpsr
中的值,并保存到
r0
寄存器中。
第
44
行,将寄存器
r0 中的值与 0X1F
进行与运算,结果保存到
r1
寄存器中,目的就是提
取
cpsr
的
bit0~bit4
这
5
位,这
5
位为
M4 M3 M2 M1 M0
,
M[4:0]
这五位用来设置处理器的工作
模式,如表
32.2.1.1
所示: