一. uboot启动流程中函数
之前了解了uboot链接脚本文件 u-boot.lds。
从 u-boot.lds 中我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start。
本文了解 一下,uboot启动过程中涉及的 reset 函数。本文继上一篇文章学习,地址如下:
uboot启动流程-uboot链接脚本u-boot.lds_凌肖战的博客-CSDN博客
二. reset 函数源码详解
从 u-boot.lds 中,我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start,代码如下:
38 /*
39 *************************************************************
40 *
41 * Exception vectors as described in ARM reference manuals
42 *
43 * Uses indirect branch to allow reaching handlers anywhere in
44 * memory.
45 **************************************************************
46 */
47
48 _start:
49
50 #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
51 .word CONFIG_SYS_DV_NOR_BOOT_CFG
52 #endif
53
54 b reset
55 ldr pc, _undefined_instruction
56 ldr pc, _software_interrupt
57 ldr pc, _prefetch_abort
58 ldr pc, _data_abort
59 ldr pc, _not_used
60 ldr pc, _irq
61 ldr pc, _fiq
第 48 行: _start 开始的是中断向量表,其中 54~61 行就是中断向量表,和我们裸机例程里面一样。
1. start.S 文件中的 reset 函数
第 54
行跳转到
reset
函数里面,
reset
函数在
arch/arm/cpu/armv7/start.S
里面,代码如下:
32 .globl reset
33 .globl save_boot_params_ret
34
35 reset:
36 /* Allow the board to save important registers */
37 b save_boot_params
start.S 文件的第 35 行就是 reset 函数。
第 37 行从 reset 函数跳转到了 save_boot_params 函数,而 save_boot_params 函数同样定义在 start.S 里面,定义如下:
100 ENTRY ( save_boot_params )101 b save_boot_params_ret @ back to my caller
2. start.S文件中的save_boot_params_ret 函数
save_boot_params
函数也是只有一句跳转语句,跳转到
save_boot_params_ret
函数,
save_boot_params_ret
函数代码如下:
38 save_boot_params_ret:
39 /*
40 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32
41 * mode, except if in HYP mode already
42 */
43 mrs r0, cpsr
44 and r1, r0, #0x1f @ mask mode bits
45 teq r1, #0x1a @ test for HYP mode
46 bicne r0, r0, #0x1f @ clear all mode bits
47 orrne r0, r0, #0x13 @ set SVC mode
48 orr r0, r0, #0xc0 @ disable FIQ and IRQ
49 msr cpsr,r0
save_boot_params_ret 函数中,第43行~49行,将处理器设置为SVC模式,并且关闭FIQ和IRQ。
继续分析 start.S 下面的代码:
56 #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
57 /* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
58 mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
59 bic r0, #CR_V @ V = 0
60 mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
61
62 /* Set vector address in CP15 VBAR register */
63 ldr r0, =_start
64 mcr p15, 0, r0, c12, c0, 0 @Set VBAR
65 #endif
第
56
行,如果没有定义
CONFIG_OMAP44XX
和
CONFIG_SPL_BUILD
的话条件成立,此处条件成立。
第
58
行读取
CP15
中
c1
寄存器的值到
r0
寄存器中,根据
17.1.4
小节可知,这里是读取 SCTLR
寄存器的值。
第 59 行,CR_V 在 arch/arm/include/asm/system.h 中有如下所示定义:
#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
因此,第 59 行的目的就是清除
SCTLR
寄存器中的
bit13
,
SCTLR
寄存器结构
如下:
可以看出,
bit13
为
V
位,此位是向量表控制位,当为
0
的时候向量表基地址为
0X00000000
,软件可以重定位向量表。为
1
的时候向量表基地址为
0XFFFF0000
,软件不能
重定位向量表。这里将
V
清零,目的就是为了接下来的向量表重定位。
第 60 行将 r0 寄存器的值重写写入到寄存器 SCTLR 中。
第
63
行设置
r0
寄存器的值为
_start
,
_start
就是整个
uboot
的入口地址,其值为
0X87800000
,
相当于
uboot
的起始地址,因此
0x87800000
也是向量表的起始地址。
第
64
行将
r0
寄存器的值
(
向量表值
)
写入到
CP15
的
c12
寄存器中,也就是
VBAR
寄存器。
因此,第 58~64 行就是设置向量表重定位的。
继续分析 start.S 下面的代码:
67 /* the mask ROM code should have PLL and others stable */
68 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
69 bl cpu_init_cp15
70 bl cpu_init_crit
71 #endif
72
73 bl _main
第
68
行如果没有定义
CONFIG_SKIP_LOWLEVEL_INIT
的话条件成立。我们没有定义
CONFIG_SKIP_LOWLEVEL_INIT
,因此条件成立,执行下面的语句。
第
68
行~ 73行的内容比较简单,就是分别调用函数 cpu_init_cp15
、
cpu_init_crit
和
_main
。
函数
cpu_init_cp15
用来设置
CP15
相关的内容,比如关闭
MMU
啥的,此函数同样在
start.S
文件中定义的。可以自行查看,
函数
cpu_init_cp15
都是一些和
CP15
有关的内容,我们不用关心,有兴趣的可以详细的看
一下。
函数
cpu_init_crit
也在是定义在
start.S
文件中,函数内容如下:
268 ENTRY(cpu_init_crit)
269 /*
270 * Jump to board specific initialization...
271 * The Mask ROM will have already initialized
272 * basic memory. Go here to bump up clock rate and handle
273 * wake up conditions.
274 */
275 b lowlevel_init @ go setup pll,mux,memory
276 ENDPROC(cpu_init_crit)
可以看出函数
cpu_init_crit
内部仅仅是调用了函数
lowlevel_init
,接下来就是详细的分析一
下
lowlevel_init
和
_main
这两个函数。