http://www.cnblogs.com/zhangsufeng/archive/2011/08/11/2134362.html
重点是两个文件:
u-boot-2011.06\arch\arm\cpu\arm920t\start.S
u-boot-2011.06\board\samsung\smdk2410\lowlevel_init.S
C入口:
arch\arm\lib\board.c
初始化函数:board_init_f
启动函数:board_init_r
ARM指令集(汇编语言)基础:
1.运行状态(Processor Operating States)分为:ARM状态(32位以字对齐)和Thumb状态(16位以半字对齐) ,使用BX指令进行切换,寄存器的bit[0]为0时处于ARM状态,寄存器的bit[0]为1时,处于Thumb状态
2.运行模式(Operating Modes) ARM920T支持7种模式(在CPSR寄存器中设置M[4:0]位)
1) 用户(usr): 正常ARM程序执行状态 10000
2) 快中断(fiq): 为支持数据传输或通道处理设计 10001
3)中断(irq): 用于一般用途的中断处理 10010
4)管理(svc): 操作系统保护模式 10011
5)中止(abt): 数据或指令预取中止后进入 10111
6)系统(sys): 操作系统的特权用户模式 11011
7)未定义(und): 执行了一个未定义指令时进入 11111
2.The ARM State Register Set (ARM状态寄存器)
CPSR:程序状态寄存器(current program status register) ,cpsr在用户级编程时用于存储条件码。CPSR包含条件码标志,中断禁止位,当前处理器模式以及其他状态和控制信息。
SPSR:程序状态保存寄存器。SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。
操作cpsr寄存器的指令有:MRS和MSR
mrs r0, cpsr ;读出cpsr的值放入r0
msr cpsr, r0 ;存r0的值到cpsr
3.汇编语言的执行逻辑:
label:
#指令
定义label,做标记或跳转地址用
label:
.word another_label/value
将label定义为andother_label或者某个具体值
.macro my_macro_define
#指令
.endm
定义宏替换
汇编的执行从.globl _start开始,如果没有遇到跳转则一直顺序执行,包括执行label下的指令,但不执行宏替换下的指令
4.基本ARM指令集:
赋值:
MOV R0 ,R1 ;将R1值赋给R0 R0=R1
MVN R0 ,R1 ;R0=(-1)*(R1 +1)
LDR R0 ,[R1] ;将R1所存地址指向的值赋给R0
LDR R0 ,=0x0123 ;将0x0123赋给R0
STR R0 ,[R1] ;将R0的值存在R1所指地址
移位:
LSL 逻辑左移
LSR 逻辑右移
R0,LSL #3 ;将R0左移3位
R0,LSL R1 ;将R0左移R1位
SWP : 单一数据交换
SWP R1,R1,[R0] ; 将R1 的内容与R0 指向的存储单元的内容进行交换
SWP R1,R2,[R0] ; 将R0 指向的存储单元内容读取一字节数据到R1 中(高24 位清零),并将R2 的内容写入到该内存单元中(最低字节有效)
AND:逻辑与
AND R0,R1,R2 ;R0 = R1&R2
AND R0,R0,#3 ;R0 = R0&3(%0011)保留R0的第0位和第1位,其余位清0
BIC位清除:
BIC R0,R1,R2 ;R0 = R1& !R2 Dest = Op_1 AND Not Op_2
EOR:逻辑异或 1^1 = 0,两个数不同则为1,否则为0
EOR R0,R1,R2 ;R0 = R1^R2
ORR:逻辑或
ORR R0,R1,R2 ;R0 = R1|R2
逻辑运算:
ADD : 加法
ADD R0,R1,R2,LSL #1 ;R0 = R1 + (R2 << 1)
SUB : 减法
SUB R0,R1,R2,LSL #1 ;R0 = R1 - (R2 << 1)
MUL:乘法
MUL R0,R1,R2 ;R0=R1*R2
MLA R0,R1,R2,R3 ;R0=(R1*R2)+R3
逻辑指令:
CMP:比较
CMP R0,R1 ;status = R0-R1,return status
CMN R0,R1 ;status = R0-(-R1),return status,比较取负的值,将第二操作数取负后比较
比较语句常与条件语句一起使用
BEQ Branch if Equal 如果相等
BNE Branch if Not Equal 如果不相等
上面的B是跳转的意思
跳转指令:
B:分支 直接将PC(R15)指向Label
BL:带链接的分支 将PC(R15)保存到LR(R14)后指向Label,在label中通过mov pc, lr 返回调用处继续执行
伪指令:
ADR 装载地址
ADR R0,Label ;将label的地址装载到R0
上述指令都可以条件码拼合形成新的指令:
补充:
协处理器CP15指令:
见:http://www.cnblogs.com/gumptious/archive/2010/02/04/1663121.html
5.通过APCS实现调用含参的其他入口,如c函数
(略)
6.Uboot启动代码分析
.globl _start
_start: b start_code ;跳转到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
_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字节对齐,参考http://zqwt.012.blog.163.com/blog/static/12044684201031102956976/
/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
.globl _TEXT_BASE
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
/*
* These are defined in the board-specific linker script.
* Subtracting _start from them lets the linker put their
* relative position in the executable instead of leaving
* them null.
*/
//定义于board/smdk2410/u-boot.lds
.globl _bss_start_ofs
_bss_start_ofs:
.word __bss_start - _start
.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end__ - _start
.globl _end_ofs
_end_ofs:
.word _end - _start
切换到此启动:
start_code:
/*
* 设置cpu保护模式启动
*/
mrs r0, cpsr
bic r0, r0, #0x1f ;0x1f= 11111 ,将cpsr的m[4:0]清0
orr r0, r0, #0xd3 ;将cpsr的m[4:0]设置为0xd3(10011),即SVC模式
msr cpsr, r0
#ifdef CONFIG_S3C24X0
通过datasheet查下面的地址
# define pWTCON 0x53000000 /*watchdog timer control register */
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
/* 关闭看门狗 */
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0] 将pWTCON地址存0,0为关看门狗
/*
* 关所有的中断,1为使中断失效
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
/* 设置 FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
/*通过设置PLLCON 和CLKDIVN寄存器来实现超频*/
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C24X0 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
在此先插入该label的代码
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
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
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init ;转到board\samsung\smdk2410\lowlevel_init.S执行
mov lr, ip
mov pc, lr //返回调用处
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
再插代码:
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
定义在:board\samsung\smdk2400\config.mk中CONFIG_SYS_TEXT_BASE = 0x0CF80000
.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
见:http://weimenlove.blog.163.com/blog/static/1777547320110212134343/
;3. 设置存储相关寄存器
;这是设置SDRAM,flash ROM 存储器连接和工作时序的程序,片选定义的程序,SMRDATA map在下面的程序中定义
ldr r0, =SMRDATA ;存放了13个DCD数据,不附代码了
ldr r1, _TEXT_BASE
sub r0, r0, r1
ldr r1, =BWSCON /*存储管理器*/
add r2, r0, #13*4 ;End address of SMRDATA
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
;设置存储器控制寄存器从CONFIG_SYS_TEXT_BASE依次填入之前存储到13个DCD数据,这个是典型到汇编循环
/* everything is fine now */
mov pc, lr //返回调用处
参考:http://blog.163.com/jiangh_1982/blog/static/12195052010615511574/
继续start.S中执行
在此设置栈内存,(以前版本是在stack_setup这,将sp指向一块定义好的内存中)
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)//这个宏定义在include\configs\smdk2410.h ?
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000 //调用函数前,将参数a1(见APCS)置为0
bl board_init_f //进入C初始化
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
准备Uboot重定位代码
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start //ram启动的地址
cmp r0, r6 //判断当前是从flash启动还是从ram启动
beq clear_bss /* skip relocation */从ram启动则跳过Uboot重定位代码,执行BSS段空间清0
mov r1, r6 /* r1 <- scratch for copy_loop */ 此时R6为SMRDATA+13*4
ldr r3, _bss_start_ofs
add r2, r0, r3 /* r2 <- source end address 此处不明白? */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_PRELOADER
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
#endif
clear_bss:
#ifndef CONFIG_PRELOADER
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000 /* clear 清0 */
/*BSS段空间循环清0*/
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
bl coloured_LED_init
bl red_LED_on
#endif
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
#ifdef CONFIG_NAND_SPL
ldr r0, _nand_boot_ofs
mov pc, r0 //进入nandflash启动的C主函数
_nand_boot_ofs:
.word nand_boot
#else
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr //进入C主函数
_board_init_r_ofs:
.word board_init_r - _start
#endif
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
*/
准备Uboot重定位代码
.globl
mov r4, r0
mov r5, r1
mov r6, r2
/* Set up the stack
mov
adr r0, _start
cmp r0, r6
beq clear_bss
mov r1, r6
ldr
add r2, r0, r3 /* r2 <- source end address
relocate_coderelocate_code:/* save addr_sp *//* save addr of gd *//* save addr of destination */ */stack_setup:sp, r4//ram启动的地址//判断当前是从flash启动还是从ram启动/* skip relocation */从ram启动则跳过Uboot重定位代码,执行BSS段空间清0/* r1 <- scratch for copy_loop */r3, _bss_start_ofs */_dynsym_start_ofs:
.word __dynsym_start - _start
有几个疑问需请教各位大牛:
1.中间一段dynsym实在是看不懂
2.BSS段的copy和清0还不太明白
3.SMRDATA为何如此定义?