【学习总结】ARM cotex-a8 下 u-boot启动流程

<span style="font-size:18px;">一、首先分析u-boot代码,u-boot启动过程分为两个阶段。在u-boot下,对于arm处理器来说,一上电执行的程序会在/cpu/920t/Start.S汇编文件。</span>

1分析start.S汇编文件

start.S最开始是异常向量表,如下所示:

.globl _start
_start:	b       start_code
	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

正常情况下会执行异常向量表的第一个段跳转指令,跳转到start_code 执行,start_code处会设置cpu为SVC模式,代码如下:

start_code:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0,cpsr
	bic	r0,r0,#0x1f
	orr	r0,r0,#0xd3
	msr	cpsr,r0


之后进行关闭中断、关闭看门狗、代码如下:

/* turn off the watchdog */

# if defined(CONFIG_S3C2400)
#  define pWTCON		0x15300000
#  define INTMSK		0x14400008	/* Interupt-Controller base addresses */
#  define CLKDIVN	0x14800014	/* clock divisor register */
#else
#  define pWTCON		0x53000000
#  define INTMSK		0x4A000008	/* Interupt-Controller base addresses */
#  define INTSUBMSK	0x4A00001C
#  define CLKDIVN	0x4C000014	/* clock divisor register */
# endif
	ldr     r0, =pWTCON
	mov     r1, #0x0
	str     r1, [r0]

	/*
	 * mask all IRQs by setting all bits in the INTMR - default
	 */
	mov	r1, #0xffffffff
	ldr	r0, =INTMSK
	str	r1, [r0]
# if defined(CONFIG_S3C2410)
	ldr	r1, =0x3ff
	ldr	r0, =INTSUBMSK
	str	r1, [r0]
# endif

设置cpu时钟初始化CPU(关闭I/D cache 关闭MMU操作):

/* FCLK:HCLK:PCLK = 1:2:4 */
	/* default FCLK is 120 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #3
	str	r1, [r0]
<span style="white-space:pre">	</span>bl<span style="white-space:pre">	</span>cpu_init_crit
cpu_init_crit:
<span style="white-space:pre">	</span>/*
<span style="white-space:pre">	</span> * flush v4 I/D caches
<span style="white-space:pre">	</span> */
<span style="white-space:pre">	</span>mov<span style="white-space:pre">	</span>r0, #0
<span style="white-space:pre">	</span>mcr<span style="white-space:pre">	</span>p15, 0, r0, c7, c7, 0<span style="white-space:pre">	</span>/* flush v3/v4 cache */
<span style="white-space:pre">	</span>mcr<span style="white-space:pre">	</span>p15, 0, r0, c8, c7, 0<span style="white-space:pre">	</span>/* flush v4 TLB */
<span style="white-space:pre">	</span>/*
<span style="white-space:pre">	</span> * disable MMU stuff and caches
<span style="white-space:pre">	</span> */
<span style="white-space:pre">	</span>mrc<span style="white-space:pre">	</span>p15, 0, r0, c1, c0, 0
<span style="white-space:pre">	</span>bic<span style="white-space:pre">	</span>r0, r0, #0x00002300<span style="white-space:pre">	</span>@ clear bits 13, 9:8 (--V- --RS)
<span style="white-space:pre">	</span>bic<span style="white-space:pre">	</span>r0, r0, #0x00000087<span style="white-space:pre">	</span>@ clear bits 7, 2:0 (B--- -CAM)
<span style="white-space:pre">	</span>orr<span style="white-space:pre">	</span>r0, r0, #0x00000002<span style="white-space:pre">	</span>@ set bit 2 (A) Align
<span style="white-space:pre">	</span>orr<span style="white-space:pre">	</span>r0, r0, #0x00001000<span style="white-space:pre">	</span>@ set bit 12 (I) I-Cache
<span style="white-space:pre">	</span>mcr<span style="white-space:pre">	</span>p15, 0, r0, c1, c0, 0
<span style="white-space:pre">	bl<span style="white-space:pre">	</span>lowlevel_init</span>
<span style="white-space:pre">	</span>mov<span style="white-space:pre">	</span>ip, lr
</pre><p></p><p><span style="font-size:18px"><span style="font-size:18px">在cpu_init_crit中会初始化内存SDRAM,主要在lowlevel_init.S中实现。</span></span></p><p></p><p><span style="font-size:18px"><span style="font-size:18px">设置栈指针:</span></span></p><p><span style="font-size:18px"></span></p><pre name="code" class="plain">relocate:				/* relocate U-Boot to RAM	    */
	adr	r0, _start		/* r0 <- current position of code   */
	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
	cmp     r0, r1                  /* don't reloc during debug         */
	beq     stack_setup
stack_setup:
<span style="white-space:pre">	</span>ldr<span style="white-space:pre">	</span>r0, _TEXT_BASE<span style="white-space:pre">		</span>/* upper 128 KiB: relocated uboot   */
<span style="white-space:pre">	</span>sub<span style="white-space:pre">	</span>r0, r0, #CFG_MALLOC_LEN<span style="white-space:pre">	</span>/* malloc area                      */
<span style="white-space:pre">	</span>sub<span style="white-space:pre">	</span>r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
实现自拷贝

copy_loop:
	ldmia	r0!, {r3-r10}		/* copy from source address [r0]    */
	stmia	r1!, {r3-r10}		/* copy to   target address [r1]    */
	cmp	r0, r2			/* until source end addreee [r2]    */
	ble	copy_loop
之后跳转到下个阶段的start_armboot执行。

ldr	pc, _start_armboot


2.第二段代码在/lib_arm/board.c中

入口函数:

void start_armboot (void)
{
	init_fnc_t **init_fnc_ptr;
<span style="white-space:pre">	</span>gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
<span style="white-space:pre">	</span>memset ((void*)gd, 0, sizeof (gd_t));
<span style="white-space:pre">	</span>gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
<span style="white-space:pre">	</span>memset (gd->bd, 0, sizeof (bd_t));
<span style="white-space:pre">	</span>for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
<span style="white-space:pre">		</span>if ((*init_fnc_ptr)() != 0) {
<span style="white-space:pre">			</span>hang ();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>...
}

board.c所做工作主要是初始化板参数的全局变量golbal_data,在第二阶段入口函数start_armboot中,初始化这个全局变量gd (golbal_data),这是一个全局指针,存放所需初始化的函数指针,通过一个for循环来调用这些函数。这些函数的主要操作是开发板的基本设置,如串口波特率、设备序列号、mac地址、启动参数存储地址等。在初始化结束后跳到/common/main.c代码中循环的通过串口与u-boot进行交互,在此进行内核的引导或者其他参数的修改或者配置。至此u-boot结束工作,把管理权交给被引导的内核。

以上即是u-boot的启动流程。


二、s5pv210硬件上的操作

对于硬件来说,arm启动时,会先运行内部IROM中的固化代码进行一些必要的初始化,执行完后硬件上会自动读取NAND Flash或sd卡等启动设备的前16K的数据到IRAM中,这16K数据中的前16byte中保存了一个叫校验和的值,校验通过后,程序会继续运行,并且将第一阶段的代码拷贝到SDRAM中进而运行第二阶段。因此跳转后CPU就是从SDRAM中取址执行了。

附上ARM内存分布图:【学习总结】ARM cotex-a8 下 u-boot启动流程_第1张图片



以上为本人学习总结,仅供参考,如有不足还望指出,谢谢!




你可能感兴趣的:(硬件,u-boot,arm处理器)