本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe.hq@outlook.com
博客:fireaxe.blog.chinaunix.net
1.1 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
1.2 初始化流程
1) start.S -> _start
2) start.S -> reset
3) crt0.S -> _main ==>> board.c -> board_init_f
4) relocate.S -> relocate_code
5) crt0.S -> here
6) board.c -> board_init_r
7) main.c -> main_loop
1.3 初始化实现(以ARM为例)
《ARM Cortex-A Series Programmer’s Guide》中列出了Cortex-A系列的初始化方法(第十三章:Boot Code)。
ARM启动时,会从异常向量表的reset异常处启动(0或0xffff0000)。对于u-boot,不需要实现所有启动流程,只需要实现几个必须的程:
1) Initialize exception vectors.
1) Initialize the memory system, including the MMU.
1) Initialize core mode stacks and registers.
1) Initialize any critical I/O devices.
1) Call the main()application.
code |
comments |
.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 |
初始化中断向量表 (Initialize exception vectors) 中断向量表 |
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 |
禁止中断 (FIQ and IRQ), 设置CPU模式为SVC32 (Initialize core mode stacks and registers.)
|
/* 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
/* Set vector address in CP15 VBAR register */ ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR |
设置中断向量表 (Initialize exception vectors)
|
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 |
Invalidate L1 I/D cache (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 |
禁止 MMU and caches (Initialize the memory system, including the MMU) |
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 */ |
设置C运行环境 (Initialize core mode stacks and registers.)
|
mov r0, #0
bl board_init_f |
调用 board_init_f(0) 对串口进行初始化(Initialize any critical I/O devices) |
/* * 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 */ |
设置临时运行环境 |
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: |
代码重定向,保证u-boot迁入内存后能够正常运行 (Relocate the code) |
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 |
这几步操作前面已经进行过,感觉可以去掉 |
/* * Move vector table */ /* Set vector address in CP15 VBAR register */ ldr r0, =_start mcr p15, 0, r0, c12, c0, 0 @Set VBAR
|
This is auto-relocated! This is useful, cause the u-boot has been moved from ROM to RAM, the address of _start has changed. The reall assembly code is below: 由于u-boot经过了重定向,代码位置发生了改变,所以这里需要重新设置VBAR寄存器。 实际的代码如下: ldr r0, [pc, #736]
利用PC保证加载的是当前地址,而不是u-boot在ROM中的地址。 |
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 |
把 .bss 段清零 |
/* 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_r(gd_t *id, ulong dest_addr它会初始化网口设备,然后调用main_loop进入u-boot控制台。(Call the main()application) |
|
|
下面是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表,用于保存配置
本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe.hq@outlook.com
博客:fireaxe.blog.chinaunix.net
本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe.hq@outlook.com
博客:fireaxe.blog.chinaunix.net