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

2019-04-13 17:34发布

一、首先分析u-boot代码,u-boot启动过程分为两个阶段。在u-boot下,对于arm处理器来说,一上电执行的程序会在/cpu/920t/Start.S汇编文件。 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] bl cpu_init_crit cpu_init_crit: /* * flush v4 I/D caches */ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) orr r0, r0, #0x00000002 @ set bit 2 (A) Align orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15, 0, r0, c1, c0, 0 bl lowlevel_init mov ip, lr

在cpu_init_crit中会初始化内存SDRAM,主要在lowlevel_init.S中实现。

设置栈指针:

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: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot   */ sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */ sub 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; gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); memset ((void*)gd, 0, sizeof (gd_t)); gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); memset (gd->bd, 0, sizeof (bd_t)); for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } } ...} 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内存分布图:

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