一. uboot 启动流程
本文我们来详细的分析一下 uboot 的启动流程,理清 uboot 是如何启动的。通过对 uboot 启动流程的梳理。
我们就可以掌握一些外设是在哪里被初始化的,这样当我们需要修改这些外设驱动的时候就会心里有数。另外,通过分析 uboot 的启动流程可以了解 Linux 内核是如何被启动的。
注意: 分析 uboot启动流程的前提是,uboot源码需要经过编译。
二. 链接脚本 u-boot.lds
要分析 uboot 的启动流程,首先要找到“入口”,找到第一行程序在哪里。
程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口。连接脚本在uboot的根目录下u-boot.lds文件。
注意:如果没有编译过 uboot 的话链接脚本为 arch/arm/cpu/u-boot.lds。但这个不是最终使用的链接脚本,最终的链接脚本是在这个链接脚本的基础上生成的。编译一下 uboot,编译完成以后就会在 uboot 根目录下生成 u-boot.lds 文件。
只有编译
u-boot
以后才会在根目录下出现
u-boot.lds
文件!!!
打开链接脚本
u-boot.lds
,内容如下:
1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
2 OUTPUT_ARCH(arm)
3 ENTRY(_start)
4 SECTIONS
5 {
6 . = 0x00000000;
7 . = ALIGN(4);
8 .text :
9 {
10 *(.__image_copy_start)
11 *(.vectors)
12 arch/arm/cpu/armv7/start.o (.text*)
13 *(.text*)
14 }
15 . = ALIGN(4);
16 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
17 . = ALIGN(4);
18 .data : {
19 *(.data*)
20 }
21 . = ALIGN(4);
22 . = .;
23 . = ALIGN(4);
24 .u_boot_list : {
25 KEEP(*(SORT(.u_boot_list*)));
26 }
27 . = ALIGN(4);
28 .image_copy_end :
29 {
30 *(.__image_copy_end)
31 }
32 .rel_dyn_start :
33 {
34 *(.__rel_dyn_start)
35 }
36 .rel.dyn : {
37 *(.rel*)
38 }
39 .rel_dyn_end :
40 {
41 *(.__rel_dyn_end)
42 }
43 .end :
44 {
45 *(.__end)
46 }
47 _image_binary_end = .;
48 . = ALIGN(4096);
49 .mmutable : {
50 *(.mmutable)
51 }
52 .bss_start __rel_dyn_start (OVERLAY) : {
53 KEEP(*(.__bss_start));
54 __bss_base = .;
55 }
56 .bss __bss_base (OVERLAY) : {
57 *(.bss*)
58 . = ALIGN(4);
59 __bss_limit = .;
60 }
61 .bss_end __bss_limit (OVERLAY) : {
62 KEEP(*(.__bss_end));
63 }
......
73 .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
74 }
第
3
行为代码当前入口点:
_start
,_start
在文件 arch/arm/lib/vectors.S 中有定义。
vectors.S 如下所示:
/*
*************************************************************************
*
* Vectors have their own section so linker script can map them easily
*
*************************************************************************
*/
.section ".vectors", "ax"
/*
*************************************************************************
*
* Exception vectors as described in ARM reference manuals
*
* Uses indirect branch to allow reaching handlers anywhere in memory.
*
*************************************************************************
*/
_start:
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
.word CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
从 vectors.S 中
可以看出,
_start
后面就是中断向量表,从图中的 “
.section ".vectors", "ax
” 可以得到,此代码存放在
.vectors
段里面。
u-boot.map
是
uboot
的内存映射文件,打开 u-boot.map:
段 .text 的地址设置为 0x87800000
0x0000000000000000 . = 0x0
0x0000000000000000 . = ALIGN (0x4)
.text 0x0000000087800000 0x47aa0
*(.__image_copy_start)
.__image_copy_start
0x0000000087800000 0x0 arch/arm/lib/built-in.o
0x0000000087800000 __image_copy_start
*(.vectors)
.vectors 0x0000000087800000 0x300 arch/arm/lib/built-in.o
0x0000000087800000 _start
0x0000000087800020 _undefined_instruction
0x0000000087800024 _software_interrupt
0x0000000087800028 _prefetch_abort
0x000000008780002c _data_abort
0x0000000087800030 _not_used
0x0000000087800034 _irq
0x0000000087800038 _fiq
0x0000000087800040 IRQ_STACK_START_IN
从 u-boot.map 可以看到,某个文件或者函数链接到了哪个地址, 第 958
行可以看到
__image_copy_start
为
0X87800000
,而
.text
的起始地址也是
0X87800000
。
继续链接脚本
u-boot.lds,
u-boot.lds 文件的
第 11
行是
vectors
段,
vectors 段保存中断向表。
从vectors.S 中,我们知道了 vectors.S
的代码是存在 vectors 段中的。
从 u-boot.map 文件可以看出:vectors 段的起始地址也是
0X87800000
,说明整个
uboot
的起始地址就是
0X87800000
,这也是为什么我们裸机
例程的链接起始地址选择
0X87800000
了,目的就是为了和
uboot
一致。
从链接脚本 u-boot.lds看出: 第 12
行将
arch/arm/cpu/armv7/start.s
编译出来的代码放到中断向量表后面。
第
13
行为
text
段,其他的代码段就放到这里。
在
u-boot.lds
中有一些跟地址有关的“变量”需要我们注意一下,后面分析
u-boot
源码的
时候会用到,这些变量要最终编译完成才能确定的!!!例如,我编译完成以后这些“变量”的值。
如下所示:
变量 | 数值 | 描述 |
__image_copy_start | 0x87800000 | uboot拷贝的首地址 |
__image_copy_end | 0x8786b03c | uboot拷贝的结束地址 |
__rel_dyn_start
|
0x8786b03c |
.rel.dyn 段起始地址
|
__rel_dyn_end
|
0x8787459c |
.rel.dyn 段结束地址
|
_image_binary_end
|
0x8787459c |
镜像结束地址
|
__bss_start
|
0x8786b03c |
.bss 段起始地址
|
__bss_end
|
0x878b7314 |
.bss 段结束地址
|
上表中的 “变量” 值可以在 u-boot.map 文件中查找, 除了__image_copy_start 以外,其他的变量值每次编译的时候可能会变化,如果修改了 uboot 代码、修改了 uboot 配置、 选用不同的优化等级等等都会影响到这些值。所以,一切以实际值为准!