uboot启动流程(2)之reset函数源码详解

大部分转载了大神的博客:uboot启动流程(2)之reset函数源码详解_蒋文韬的博客-CSDN博客

部分穿插了对自身平台内容的理解。

=========================================================================

reset 函数源码详解

从 u-boot.lds 中我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的_start,代码如下:

								vectors.S 代码段
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

=========================================================================

(以下是我的平台的代码,上篇有介绍。这里的定义多了一个“_reset_vec”变量,但实际上该变量的值还是“.word reset”)

/*
 *************************************************************************
 *
 * Indirect vectors table
 *
 * Symbols referenced here must be defined somewhere else
 *
 *************************************************************************
 */

 /*
 *use _reset_vec as the variable name because the name "_reset" has been used in other place
 *export _reset_vec for fix the vector table after code relocate
 *modify by wangwei. 2014-12-01
 */
	.globl	_reset_vec
	.globl	_undefined_instruction
	.globl	_software_interrupt
	.globl	_prefetch_abort
	.globl	_data_abort
	.globl	_not_used
	.globl	_irq
	.globl	_fiq

_reset_vec:			.word reset
_undefined_instruction:	.word undefined_instruction
_software_interrupt:	.word software_interrupt
_prefetch_abort:	.word prefetch_abort
_data_abort:		.word data_abort
_not_used:		.word not_used
_irq:			.word irq
_fiq:			.word fiq

=========================================================================

第 48 行_start 开始的是中断向量表,其中 54~61 行就是中断向量表,和我们裸机例程里面一样。54 行跳转到 reset 函数里面,reset 函数在 arch/arm/cpu/armv7/start.S 里面,代码如下:

									start.S 代码段
22 /*****************************************************************
23 *
24 * Startup Code (reset vector)
25 *
26 * Do important init only if we don't start from memory!
27 * Setup memory and board specific bits prior to relocation.
28 * Relocate armboot to ram. Setup stack.
29 *
30 *****************************************************************/
31
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

(注:该文件中的代码视各平台而言各有不同)

第 35 行就是 reset 函数。
第 37 行从 reset 函数跳转到了 save_boot_params 函数,而 save_boot_params 函数同样定义
在 start.S 里面,定义如下:

								 start.S 代码段
91 /******************************************************************
92 *
93 * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
94 * __attribute__((weak));
95 *
96 * Stack pointer is not yet initialized at this moment
97 * Don't save anything to stack even if compiled with -O0
98 *
99 ******************************************************************/
100 ENTRY(save_boot_params)
101 b save_boot_params_ret @ back to my caller

save_boot_params 函数也是只有一句跳转语句,跳转到 save_boot_params_ret 函数,
save_boot_params_ret 函数代码如下:

								 start.S 代码段
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“ 基本上什么也没做)

/*************************************************************************
 *
 * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
 *	__attribute__((weak));
 *
 * Stack pointer is not yet initialized at this moment
 * Don't save anything to stack even if compiled with -O0
 *
 *************************************************************************/
ENTRY(save_boot_params)
	bx	lr			@ back to my caller
ENDPROC(save_boot_params)
	.weak	save_boot_params

关于原作者所提到的“save_boot_params_ret ”函数,我的平台就直接在“reset”函数开始的部分完成。

reset:
	bl	save_boot_params
	/*
	 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
	 * except if in HYP mode already
    		mrs r0, cpsr            <1.将cpsr寄存器的内容传送到r0寄存器>
    		and r1, r0, #0x1f       <2.标志位清零>
    		teq r1, #0x1a           <3.测试处理器是否处于HYP模式,HYP是armv-7a为cortex-A15处理器提供硬件虚拟化引进的管理模式>
    		bicne   r0, r0, #0x1f   <4.工作模式位清零>
    		orrne   r0, r0, #0x13   <5.设置成SVC管理模式>
    		orr r0, r0, #0xc0       <6.关闭FIQ和IRQ中断>
    		msr cpsr,r0             <7.将r0的值赋给cpsr>
	 */
	mrs	r0, cpsr
	and	r1, r0, #0x1f		@ mask mode bits
	teq	r1, #0x1a		@ test for HYP mode
	bicne	r0, r0, #0x1f		@ clear all mode bits
	orrne	r0, r0, #0x13		@ set SVC mode
	orr	r0, r0, #0xc0		@ disable FIQ and IRQ
	msr	cpsr,r0

=========================================================================第 43 行,读取寄存器 cpsr 中的值,并保存到 r0 寄存器中。第 44 行,将寄存器 r0 中的值与 0X1F 进行与运算,结果保存到 r1 寄存器中,目的就是提取 cpsr 的 bit0~bit4 这 5 位,这 5 位为 M4 M3 M2 M1 M0,M[4:0]这五位用来设置处理器的工作模式

(关于cpsr这部分内容我没有去深究,但大体内容就是初始化cpu的工作模式以及相关寄存器,其实主要是后面的“cpu_init_cp15”,“cpu_init_crit” 和 “_main” 三个函数,且关于“cpu_init_cp15”的协处理器的初始化也可以不需要深究)

M[4:0]模式
10000User
10001FIQ
10010IRQ
10011Supervisor
10110Monitor
10111Abort
11010Hyp
11011Undefined
11111System

第 45 行,判断 r1 寄存器的值是否等于 0X1A(0b11010),也就是判断当前处理器模式是否处于 Hyp 模式。
第 46 行,如果 r1 和 0X1A 不相等,也就是 CPU 不处于 Hyp 模式的话就将 r0 寄存器的bit0~5 进行清零,其实就是清除模式位
第 47 行,如果处理器不处于 Hyp 模式的话就将 r0 的寄存器的值与 0x13 进行或运算,0x13=0b10011,也就是设置处理器进入 SVC 模式。
第 48 行,r0 寄存器的值再与 0xC0 进行或运算,那么 r0 寄存器此时的值就是 0xD3,cpsr的 I 为和 F 位分别控制 IRQ 和 FIQ 这两个中断的开关,设置为 1 就关闭了 FIQ 和 IRQ!
第 49 行,将 r0 寄存器写回到 cpsr 寄存器中。完成设置 CPU 处于 SVC32 模式,并且关闭FIQ 和 IRQ 这两个中断。
继续执行执行下面的代码:

							 start.S 代码段
51 /*
52 * Setup vector:
53 * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
54 * Continue to use ROM code vector only in OMAP4 spl)
55 */
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 寄存器中,这里是读取SCTLR 寄存器的值。
第 59 行,CR_V 在 arch/arm/include/asm/system.h 中有如下所示定义:

#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */

因此这一行的目的就是清除 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,因此条件成立,执行下面的语句。示例代码中的内容比较简单,就是分别调用函数 cpu_init_cp15、cpu_init_crit 和_main。
函数 cpu_init_cp15 用来设置 CP15 相关的内容,比如关闭 MMU 啥的,此函数同样在 start.S文件中定义的,代码如下

					 32.2.1.7 start.S 代码段
105 /*****************************************************************
106 *
107 * cpu_init_cp15
108 *
109 * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on
110 * unless CONFIG_SYS_ICACHE_OFF is defined.
111 *
112 *****************************************************************/
113 ENTRY(cpu_init_cp15)
114 /*
115 * Invalidate L1 I/D
116 */
117 mov r0, #0 @ set up for MCR
118 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
119 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
120 mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
121 mcr p15, 0, r0, c7, c10,4 @ DSB
122 mcr p15, 0, r0, c7, c5, 4 @ ISB
123
124 /*
125 * disable MMU stuff and caches
126 */
127 mrc p15, 0, r0, c1, c0, 0
128 bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
129 bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
130 orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
131 orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
132 #ifdef CONFIG_SYS_ICACHE_OFF
133 bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
134 #else
135 orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
136 #endif
137 mcr p15, 0, r0, c1, c0, 0
138
......
255
256 mov pc, r5 @ back to my caller
257 ENDPROC(cpu_init_cp15)

函数 cpu_init_cp15 都是一些和 CP15 有关的内容,我们不用关心,有兴趣的可以详细的看一下。
函数 cpu_init_crit 也在是定义在 start.S 文件中,函数内容如下:

							start.S 代码段
/*****************************************************************
261 *
262 * CPU_init_critical registers
263 *
264 * setup important registers
265 * setup memory timing
266 *
267 *****************************************************************/
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 这两个函数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值