分类: 嵌入式
2011-10-22 22:43:49
表 1 ARM异常向量表
地址 |
异常 |
进入模式 |
描述 |
0x00000000 |
复位 |
管理模式 |
复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行 |
0x00000004 |
未定义指令 |
未定义模式 |
遇到不能处理的指令时,产生未定义指令异常 |
0x00000008 |
软件中断 |
管理模式 |
执行SWI指令产生,用于用户模式下的程序调用特权操作指令 |
0x0000000c |
预存指令 |
中止模式 |
处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常 |
0x00000010 |
数据操作 |
中止模式 |
处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常 |
0x00000014 |
未使用 |
未使用 |
未使用 |
0x00000018 |
IRQ |
IRQ |
外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常 |
0x0000001c |
FIQ |
FIQ |
快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常 |
_TEXT_BASE:
.word TEXT_BASE // TEXT_BASE是在board/smdk2410/config.mk中定义,为0x33F80000
.globl _armboot_start
_armboot_start:
.word _start // 这几行含义可用C语言表示为:*(_armboot_start) = _start
.globl _bss_start
_bss_start:
.word __bss_start // 这几行含义可用C语言表示为:*(_bss_start) = __bss_start__bss_start
// __bss_start是在u-boot.lds中定义的
.globl _bss_end
_bss_end:
.word _end // 这几行含义可用C语言表示为:*(_bss_end) = _end
// _end是在u-boot.lds中定义的
#ifdef CONFIG_USE_IRQ
.globl IRQ_STACK_START // 声明一个全局变量IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
.globl FIQ_STACK_START // 声明一个全局变量FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
reset:
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0 // 关闭中断,切换处理器到管理模式
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008
# define CLKDIVN 0x14800014
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 // 寄存器地址定义,可查看datasheet
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0] // 关闭看门狗
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0] // 屏蔽所有中断
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0] // 屏蔽所有子中断
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
#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 stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
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 */
/* 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
#if 0
/* try doing this stuff after the relocation */
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
mov r1, #0xffffffff
ldr r0, =INTMR
str r1, [r0]
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
ldr pc, _start_armboot
_start_armboot: .word start_armboot // 把_start_armboot地址处的值也就是start_armboot
// 绝对地址值移到pc,终于跳到C代码了
这部分代码还是很好理解的,注释也很详细,稍微懂点汇编的应该都能看懂吧,这里就不细说了,接着往下看代码:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /*使指令cache和数据cache无效 */
mcr p15, 0, r0, c8, c7, 0 /* 使TLB无效 */
// disable MMU stuff and caches
mrc p15, 0, r0, c1, c0, 0 // 读出c1控制寄存器的值
bic r0, r0, #0x00002300 // clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 // 小端对齐,关闭数据cache,关闭错误检测,关闭MMU
orr r0, r0, #0x00000002 // 使能错误检测
orr r0, r0, #0x00001000 // 使能指令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.
*/
/* 在把u-boot重定位到RAM前,我们必须先把RAM的时序设置好,内存时序是依板子而定 的,所以这里的初始化应该由我们提供,一般在我们的板子所在目录下有个lowlevel_init.S来负责这件事情*/
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
继续往下看代码:
#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
#ifdef CONFIG_USE_IRQ
.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs
.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
到这里start.S文件也就结束了,但我们还有两个函数没去分析,一个是C入口函数start_armboot,另一个就是内存的初始化函数lowlevel_init.S,下面继续逐个分析。