标签:
u-boot第一阶段分析:
第一阶段主要是在start.S中
.globl _start //声明_start是全局变量,和c语言中的extern相似,声明此变量,并且告诉链 接器此变量是全局的,外部可以访问。由board\100ask24x0\u-boot.lds中 ENTRY(_start)可知,_start是程序入口地址,一开始从nor_flash启动,_start 为0,当执行后面的地址重载后,_start就变为TEXT_BASE = 0x33F80000了
_start: b reset //b指令,就只是单纯的掉转到某处继续执行,而不能再通过mov pc, lr跳转回来了
/*处理器的异常处理向量表*/
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
//word的作用就是说在这个地址处放一个内容。
_irq: .word irq指令就是在_irq标号的地址处申请一个字的空间长度(4字节)来放一个irq标签的地址,当发生中断时候,根据这个标号处存放的地址来转到该地址去。
.balignl 16,0xdeadbeef意思就是要16字节对齐后,再存放接下来的代码。直到能被16字节整除的地址(33f80040能被16u整除)出现前都用0xdeadbeef这个值来填充。
根据反汇编得到的指令就可以很容易的看出。
33f80000 <_start>:
33f80000: ea000017 b 33f80064 <reset>
33f80004: e59ff014 ldr pc, [pc, #20] ; 33f80020 <_undefined_instruction>
33f80008: e59ff014 ldr pc, [pc, #20] ; 33f80024 <_software_interrupt>
33f8000c: e59ff014 ldr pc, [pc, #20] ; 33f80028 <_prefetch_abort>
33f80010: e59ff014 ldr pc, [pc, #20] ; 33f8002c <_data_abort>
33f80014: e59ff014 ldr pc, [pc, #20] ; 33f80030 <_not_used>
33f80018: e59ff014 ldr pc, [pc, #20] ; 33f80034 <_irq>
33f8001c: e59ff014 ldr pc, [pc, #20] ; 33f80038 <_fiq>
33f80020 <_undefined_instruction>:
33f80020: 33f80160 mvnccs r0, #24 ; 0x18
33f80024 <_software_interrupt>:
33f80024: 33f801c0 mvnccs r0, #48 ; 0x30
33f80028 <_prefetch_abort>:
33f80028: 33f80220 mvnccs r0, #2 ; 0x2
33f8002c <_data_abort>:
33f8002c: 33f80280 mvnccs r0, #8 ; 0x8
33f80030 <_not_used>:
33f80030: 33f802e0 mvnccs r0, #14 ; 0xe
33f80034 <_irq>:
33f80034: 33f80400 mvnccs r0, #0 ; 0x0
33f80038 <_fiq>:
33f80038: 33f80420 mvnccs r0, #536870912 ; 0x20000000
33f8003c: deadbeef cdple 14, 10, cr11, cr13, cr15, {7}
然后是
_TEXT_BASE:
.word TEXT_BASE //在board\100ask24x0\Config.mk文件中定义TEXT_BASE = 0x33F80000。及程序的链接地址。
.globl _armboot_start
_armboot_start:
.word _start //_start是程序入口,链接完毕它的值应该是TEXT_BASE=33f80000
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
/* __bss_start和_end在board\100ask24x0\u-boot.lds处定义*/
.globl FREE_RAM_END
FREE_RAM_END:
.word 0x0badc0de
.globl FREE_RAM_SIZE
FREE_RAM_SIZE:
.word 0x0badc0de
.globl PreLoadedONRAM
PreLoadedONRAM:
.word 0
#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
上面指令声明了_bss_start、_bss_end、FREE_RAM_END、FREE_RAM_SIZE、PreLoadedONRAM、IRQ_STACK_START、FIQ_STACK_START标号为全局 变量,下面会用到。
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr //mrs是读状态寄存器指令
bic r0,r0,#0x1f//bic是位清楚指令
orr r0,r0,#0xd3//orr是逻辑或指令
msr cpsr,r0//msr是写状态寄存器指令
这些指令执行后cpsr的低八位内容是110 10011,如下图可知为CPU进入Supervisor模式。且禁止中断和快中断,使用ARM指令。
cpsr寄存器格式如下
/* turn off the watchdog */
#if defined(CONFIG_S3C2400)//没有定义,所以该部分不执行
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410)//在include\configs\100ask24x0.h处定义,所以执行该部分语句
# define pWTCON 0x53000000
# define INTMOD 0X4A000004
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0] //往看门狗寄存器写0就可以关闭看门狗
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0] //中断屏蔽寄存器全部写1,禁止所有中断
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK//子中断寄存器写1,禁止。但是这里0x3ff不严谨,由下图 INTSUBMSK寄存器可以看出应该为0x7ff
str r1, [r0]
# endif
#if 0
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif //这里是不编译的,因为在后面的时钟初始化中初始化了。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
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 */
blne cpu_init_crit
#endif
此时_start仍然为0,_TEXT_BASE 为0x3F800000.两者肯定不相等,所以运行cpu_init_crit函数,这个函数具体是干嘛的,下面再说。
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area 256KB */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo 128字节 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl clock_init
#endif
CFG_MALLOC_LEN堆大小由128KB的环境变量大小和128KB的堆空间组成。
CFG_GBL_DATA_SIZE为全局变量区大小为128字节
CONFIG_STACKSIZE_IRQ和CONFIG_STACKSIZE_FIQ为IRQ和FIQ的堆栈,各为4K
最后还设置一个3字节大小的堆栈
所以最后
r0=_TEXT_BASE-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE-CONFIG_STACKSIZE_IRQ-CONFIG_STACKSIZE_FIQ-3
=0x33F80000-256KB-128-4K-4k-12=0x33F3EF74
#ifndef CONFIG_SKIP_LOWLEVEL_INIT//没有定义所以执行下面的语句
bl clock_init
#endif
clock_init是处理器时钟的初始化,因为这个函数是c语言函数,所以在调用的时候要设置栈,所以前面是设置栈的一些指令。而且前面提到的注释掉时钟初始化指令就是在这里添加的。
下面看一下clock_init函数,在uboot官方提供的源码中是没有这个函数的,这里是为了移植而添加的。(在board\100ask24x0\Boot_init.c中定义)
void clock_init(void)
{
S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;
/* support both of S3C2410 and S3C2440, by www.100ask.net */
/* FCLK:HCLK:PCLK = 1:2:4 */
clk_power->CLKDIVN = S3C2410_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFFFF;
/* configure UPLL */
clk_power->UPLLCON = S3C2410_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure MPLL */
clk_power->MPLLCON = S3C2410_MPLL_200MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
S3C24X0_CLOCK_POWER是定义的与时钟相关寄存器的结构体。
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
S3C24X0_REG32 CAMDIVN; /* for s3c2440, by www.100ask.net */
} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;这句代码是创建一个clk_power 指针,且指向地址0x4C000000;则LOCKTIME代表的地址为0x4C000000,MPLLCON代表的地址为0x4C000004,以此类推。这些地址正好是这些寄存器的地址。
#ifndef CONFIG_SKIP_RELOCATE_UBOOT//没有定义,执行下面的指令
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 clear_bss //如果_start和_TEXT_BASE相同则跳到下面的clear_bss 标号处清 bss段且不反悔,则紧接着的指令不会执行。如果不相等,则说明此 时代码仍然在flash中,并没有搬移到配ram中,则继续执行下面的 的指令,将flash中的代码拷贝到ram中,然后再请bss。
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
#if 1
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
//此时r0=_start,r1=r1, _TEXT_BASE,r2=_bss_start-_armboot_start=33fb0754-33f80000=193KB
//int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)函数的参数分别为r0,r1,r2.起始地址,目的地址,大小。
#else//下面的指令不执行
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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
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段每个地址处赋值0.
SetLoadFlag:
/* Set a global flag, PreLoadedONRAM */
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 */
ldr r2, =PreLoadedONRAM
mov r3, #1
streq r3, [r2]
ldr pc, _start_armboot
_start_armboot: .word start_armboot//跳转到start_armboot执行。
#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//在bvoard\100ask24x0\lowlevel_init.S中定义进行sdram相关的初始化。
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/
.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
ldmia r2, {r2 - r3} @ get pc, cpsr
add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp
.endm
.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
add r8, sp, #S_PC
stmdb r8, {sp, lr}^ @ Calling SP, LR
str lr, [r8, #0] @ Save calling PC
mrs r6, spsr
str r6, [r8, #4] @ Save CPSR
str r0, [r8, #8] @ Save OLD_R0
mov r0, sp
.endm
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm
.macro get_bad_stack
ldr r13, _armboot_start @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
str lr, [r13] @ save caller lr / spsr
mrs lr, spsr
str lr, [r13, #4]
mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13
mov lr, pc
movs pc, lr
.endm
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack //转到上面定义的获取栈
bad_save_user_regs//转到上面定义的保存栈
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack//转到上面定义的获取栈
bad_save_user_regs//转到上面定义的保存栈
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack//转到上面定义的获取栈
bad_save_user_regs//转到上面定义的保存栈
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack//转到上面定义的获取栈
bad_save_user_regs//转到上面定义的保存栈
bl do_data_abort
.align 5
not_used:
get_bad_stack//转到上面定义的获取栈
bad_save_user_regs//转到上面定义的保存栈
bl do_not_used
@ thisway.diy, 2006.06.24
.globl Launch
.align 4
Launch:
mov r7, r0
@ diable interrupt
@ disable watch dog timer
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
ldr r1,=INTMSK
ldr r2,=0xffffffff @ all interrupt disable
str r2,[r1]
ldr r1,=INTSUBMSK
ldr r2,=0x7ff @ all sub interrupt disable
str r2,[r1]
ldr r1, = INTMOD
mov r2, #0x0 @ set all interrupt as IRQ (not FIQ)
str r2, [r1]
@
mov ip, #0
mcr p15, 0, ip, c13, c0, 0 @ /* zero PID */
mcr p15, 0, ip, c7, c7, 0 @ /* invalidate I,D caches */
mcr p15, 0, ip, c7, c10, 4 @ /* drain write buffer */
mcr p15, 0, ip, c8, c7, 0 @ /* invalidate I,D TLBs */
mrc p15, 0, ip, c1, c0, 0 @ /* get control register */
bic ip, ip, #0x0001 @ /* disable MMU */
mcr p15, 0, ip, c1, c0, 0 @ /* write control register */
@ MMU_EnableICache
@mrc p15,0,r1,c1,c0,0
@orr r1,r1,#(1<<12)
@mcr p15,0,r1,c1,c0,0
@ clear SDRAM: the end of free mem(has wince on it now) to the end of SDRAM
ldr r3, FREE_RAM_END
ldr r4, =PHYS_SDRAM_1+PHYS_SDRAM_1_SIZE @ must clear all the memory unused to zero
mov r5, #0
ldr r1, _armboot_start
ldr r2, =On_Steppingstone
sub r2, r2, r1
mov pc, r2
On_Steppingstone:
2: stmia r3!, {r5}
cmp r3, r4
bne 2b
@ set sp = 0 on sys mode
mov sp, #0
@ add by thisway.diy 2006.06.26, switch to SVC mode
msr cpsr_c, #0xdf @ set the I-bit = 1, diable the IRQ interrupt
msr cpsr_c, #0xd3 @ set the I-bit = 1, diable the IRQ interrupt
ldr sp, =0x31ff5800
nop
nop
nop
nop
mov pc, r7 @ Jump to PhysicalAddress
nop
mov pc, lr
#ifdef CONFIG_USE_IRQ//定义了
.align 5
irq:
/* add by www.100ask.net to use IRQ for USB and DMA */
sub lr, lr, #4 @ the return address
ldr sp, IRQ_STACK_START @ the stack for irq设置栈
stmdb sp!, { r0-r12,lr } @ save registers保存栈
ldr lr, =int_return @ set the return addr保存返回地址
ldr pc, =IRQ_Handle @ call the isr调用中断服务函数在cpu\arm920t\s3c24x0\Interrupts.c中定义
int_return:
ldmia sp!, { r0-r12,pc }^ @ return from interrupt恢复栈
.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs
#else
.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif
综上可知uboot里区域设置如下
|
_TEXT_BASE |
GFG_MALLCO_LEN(256KB) |
GFG_GBL_DATA_SIZE(128B) |
CONFIG_STACK_SIZE_IRQ+CONFIG_STACK_SIZE_FIQ(8K) |
Aboart Stack 12byte |
|
标签:
原文地址:http://blog.csdn.net/u014104588/article/details/45568841