uboot: 2014.07
ref : http://blog.chinaunix.net/uid-30352139-id-5128405.html
U-boot相关文件
boards.cfg:
ARCH = ARM
CPU = ARMv7
SOC = exynos
BOARD = smdkc210
VENDER = samsung
files:
Include/configs/smdkc210.h
arch/$(ARCH)/cpu/$(CPU)/start.S
board/$(VENDER)/$(BOARD)/smdkc210.c
arch/$(ARCH)/lib/board.c
arch/$(ARCH)/lib/crto.S
arch/$(ARCH)/lib/relocate.S
初始化流程
-
start.S -> _start
-
start.S -> reset
-
crt0.S -> _main ==>> board.c -> board_init_f
-
relocate.S -> relocate_code
-
crt0.S -> here
-
board.c -> board_init_r
-
main.c -> main_loop
初始化实现(以ARM为例)
《ARM Cortex-A Series Programmer’s Guide》中列出了Cortex-A系列的初始化方法(第十三章:Boot Code)。
ARM启动时,会从异常向量表的reset异常处启动(0或0xffff0000)。对于u-boot,不需要实现所有启动流程,只需要实现几个必须的程:
-
Initialize exception vectors.
-
Initialize the memory system, including the MMU.
-
Initialize core mode stacks and registers.
-
Initialize any critical I/O devices.
-
Call the main()application.
代码分析
初始化中断向量表 (Initialize exception vectors)
.globl _start
_start: 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
_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
_pad: .word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
.balignl
16,0xdeadbeef
禁止中断 (FIQ and IRQ), 设置CPU模式为SVC32 (Initialize core mode stacks and registers.)
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
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
设置中断向量表 (Initialize exception vectors)
/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register
/* Setvector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
Invalidate L1 I/D cache (Initialize the memory system, including the MMU)
ENTRY(cpu_init_cp15)
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
禁止 MMU and caches (Initialize the memory system, including the MMU)
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
mcr p15, 0, r0, c1, c0, 0
mov pc, lr @ back to my caller
设置C运行环境 (Initialize core mode stacks and registers.)
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
mov r9, sp /* GD is above SP */
调用 board_init_f(0) 对串口进行初始化(Initialize any critical I/O devices)
mov r0, #0
bl board_init_f
设置临时运行环境
/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
代码重定向,保证u-boot迁入内存后能够正常运行 (Relocate the code)
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code
here:
接下来的这几步操作前面已经进行过,感觉可以去掉
ENTRY(c_runtime_cpu_setup)
/*
* invalidate I-cache
*/
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
由于u-boot经过了重定向,代码位置发生了改变,所以这里需要重新设置VBAR寄存器。
实际的代码如下: ldr r0, [pc, #736]
利用PC保证加载的是当前地址,而不是u-boot在ROM中的地址。
/*
* Move vector table
*/
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
把 .bss 段清零
ldr r0,
=__bss_start /* This is auto-relocated! */
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
调用 board_init_r(gd_t *id, ulong dest_addr它会初始化网口设备,然后调用main_loop进入u-boot控制台。(Call the main()application)
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
ldr pc, =board_init_r /* this is auto-relocated! */
board_init_f
下面是board_init_f执行的操作:
function | comments |
---|---|
arch_cpu_init | Do nothing on smdkc210 |
timer_init | Do nothing on smdkc210 |
env_init | 初始化环境变量, 实际上是把default_environment设置到gd->env_addr. default_environment是一个字符串数组,每一个字符串用一个宏表示,我们通过在“include/configs/smdkc210.h”定义这些宏的方式设置环境变量。 |
init_baudrate | 设置波特率,其实它来自于 gd->baud. |
serial_init | 调用串口初始化函数 |
dram_init | 设置RAM位置与大小 |
Set gd. | The most 设置gd表,用于保存配置 |