分类: LINUX
2011-06-23 14:00:11
编写此文档记录学习uboot的过程,本文为系列第二篇
U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:
(1)第一阶段的功能
· 硬件设备初始化
· 加载U-Boot第二阶段代码到RAM空间
· 设置好栈
· 跳转到第二阶段代码入口
(2)第二阶段的功能
· 初始化本阶段使用的硬件设备
· 检测系统内存映射
· 将内核从Flash读取到RAM中
· 为内核设置启动参数
· 调用内核
本文主要分析启动的第一阶段
根据链接脚本(本系列第一篇)\u-boot-2008.10\cpu\arm926ejs\start.s 文件为cpu上电后执行的第一的文件(第一段代码)
Start.s代码开头如下:
3.1 设置异常向量.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 /* irq中断向量 */
ldr pc, _fiq /* 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
.balignl 16,0xdeadbeef //设置对齐方式为16位对齐方式,空白区域自动用0xdeafbeef填充
其中
_undefined_instruction;_software_interrupt为lable,和C语言里面的lable一样,lable的值为当前代码的地址。
.word为GCC汇编伪指令,表示在当前位置定义一个字的变量,变量的内容紧跟其后。
所以执行_undefined_instruction: .word undefined_instruction指令后的内存映像为:
地址 |
内容 |
大小 |
0x000000004 _undefined_instruction |
undefined_instruction |
Word(32) |
以上代码设置了ARM异常向量表,各个异常向量介绍如下:
表 2.1 ARM异常向量表
地址 |
异常 |
进入模式 |
描述 |
0x00000000 |
复位 |
管理模式 |
复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行 |
0x00000004 |
未定义指令 |
未定义模式 |
遇到不能处理的指令时,产生未定义指令异常 |
0x00000008 |
软件中断 |
管理模式 |
执行SWI指令产生,用于用户模式下的程序调用特权操作指令 |
0x0000000c |
预存指令 |
中止模式 |
处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常 |
0x00000010 |
数据操作 |
中止模式 |
处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常 |
0x00000014 |
未使用 |
未使用 |
未使用 |
0x00000018 |
IRQ |
IRQ |
外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常 |
0x0000001c |
FIQ |
FIQ |
快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常 |
在cpu\arm926ejs\start.s中还有这些异常对应的异常处理程序。当一个异常产生时,CPU根据异常号在异常向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU就跳转到对应的异常处理程序执行。
其中复位异常向量的指令“b start_code”决定了U-Boot启动后将自动跳转到标号“start_code”处执行。
3.2 设置定位lable_TEXT_BASE:
.word TEXT_BASE
TEXT_BASE在系列一中有分析,在MAKEFIE 中通过TEXT_BASE指定代码段的VMA地址偏移,其中TEXT_BASE保存于board\hi3515v100\config.mk 中,在这里用来计算其他的地址偏移
.globl _armboot_start
_armboot_start:
.word _start
.globl _img_end
_img_end:
.word __img_end
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
以上代码定义了一些断地址,并导出为全局变量(.globle),在连接文件里面有对这些变量赋值,在这里同样用于计算偏移
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
此处尚有疑问
#ifdef CONFIG_HISILICON
_clr_remap_rom_entry:
.word ROM_TEXT_ADRS + do_clr_remap - TEXT_BASE
_clr_remap_nand_entry:
.word NAND_TEXT_ADRS + do_clr_remap - TEXT_BASE
#endif
此处计算do_clr_remap的LMA,由于没有进行代码搬移前代码是执行在LMA地址上的(同时这一段代码也是地址无关的代码即PIC,关于地址无关的代码见博文http://hi.baidu.com/kinylei/blog/item/c7acf92235b8104493580795.html ),此处分别计算代码存储在norflash和nandflash里面的LMA.
3.3 设置其他相关reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
CPSR位图
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*
* 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 */
mcr p15, 0, r0, c1, c0, 0
以上禁止MMU
ldr r0, =REG_BASE_SCTL
ldr r1, [r0, #0x8c]
and r1, r1, #0x60
lsr r4, r1, #5
以上获取BOOT状态到R4
mov r0, pc, lsr#24s
cmp r0, #0x0
bne do_clr_remap
检测是否需要跳转,PC的高八位如果不为0(已经在ram中运行了)则跳转
cmp r4, #2 /* boot from nand flash*/
ldreq pc, _clr_remap_nand_entry
cmp r4, #0 /* boot from nor flash */
ldreq pc, _clr_remap_rom_entry
此处的_clr_remap_nand_entry与_clr_remap_rom_entry为LMA地址,前面已分析
do_clr_remap:
ldr r4, =REG_BASE_SCTL
@ldr r0, =REG_VALUE_SC_NOLOCK
@str r0, [r4, #REG_VALUE_SC_LOCKED]
ldr r0, [r4, #REG_SC_CTRL]
@Set clear remap bit.
orr r0, #(1<<8)
str r0, [r4, #REG_SC_CTRL]
@Setup ITCM (ENABLED, 4KB)
ldr r0, =( 1 | (MEM_CONF_ITCM_SIZE<<2) | MEM_BASE_ITCM)
mcr p15, 0, r0, c9, c1, 1
以上清除重映射,清除重映射后地址0x000000处安排为ITCM,此处有一个疑问,既然还运行在flash里面那么清重映射后就会运行在ITCM里面,但是ITCM里面保存有代码吗?
@enable I-Cache now
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
@Setup lowlevel sp
ldr sp, =(MEM_BASE_ITCM + MEM_SIZE_ITCM)
// @Check if I'm running in static mem bank
mov r0, pc, lsr#28
cmp r0, #(TEXT_BASE>>28)
/*
* Go setup Memory and board specific bits prior to relocation.
*/
beq relocate
bl lowlevel_init /* go setup pll,mux,memory */
#endif
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
ldr r0, =REG_BASE_SCTL
ldr r6, [r0, #0x8c]
and r6, #0x60
lsr r4, r6, #5
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
ldr r2, _armboot_start
ldr r3, _img_end
sub r2, r3, r2 /* r2 <- size of armboot */
cmp r4, #2
ldreq r2, =(CFG_NAND_U_BOOT_ONE_PART)
add r2, r0, r2 /* r2 <- source end address */
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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
以上重定位代码,既把代码段复制到ram空间里面
/* Set up the stack */
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 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
以上设置堆栈
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
以上清除BSS
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
以上跳转到第二段
下图是分析到目前为止存储空间的示意图
未完。。。