启动代码startups分析
启动代码start.s(相当于bootloader的前端代码),开机就执行的代码,即0x0000处放置的代码。给CPU一个合适的工作环境。面向CPU内核和外围硬件,所以一般用汇编编写。
1、在起始地址分配中断向量表即中断处理函数(CPU要求的),以为向量空间只有4字节,所以一般只是一个跳转指令,去别处执行。
2、之后初始化存储器系统
3、初始多个模式下的堆栈(模式切换时,硬件给SP置位)
4、初始化有特殊要求的外围设备,如LED灯、看门狗
5、初始化用户的执行环境(在FLASH中运行太慢了,把代码整体搬迁到RAM中)
6、切换处理器的工作模式
7、调用主程序
(没见到有存储控制器的配置代码,也没见到有时钟初始化代码)
下面分析,所给的2410的启动代码实现了以上的那些功能,实现得显然不全,或者不需要,或者在工程代码的其它部分实现。
读程序时注意,所有程序都是逐行顺序执行的,要看清跳转指令。
GET 2410addr.s //用到了2410addr.s中的寄存器地址宏定义
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Some ARM920 CPSR bit discriptions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Pre-defined constants//预定义的变量,一下后续代码中使用方便,与CPSR相关USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f
NOINT EQU 0xc0
I_Bit * 0x80
F_Bit * 0x40
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; MMU Register discription ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;p15 CP 15
;c0 CN 0
;c1 CN 1
;c2 CN 2
;c3 CN 3
CtrlMMU * 1
CtrlAlign * 2
CtrlCache * 4
CtrlWBuff * 8
CtrlBigEnd * 128
CtrlSystem * 256
CtrlROM * 512
;initialization L0 is MMU FULL_ACCESS, DOMAIN, SECTION
TLB_L0_INIT * 0x0C02 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Start here //执行代码从这里开始;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//IMPORT ,定义表示这是一个外部变量的标号,不是在本程序定义的
//EXPORT ,表示本程序里面用到的变量提供给其他模块调用的。
//以上两个在汇编和C语言混合编程的时候用到
AREA Init,CODE,READONLY
IMPORT __use_no_semihosting_swi
IMPORT Enter_UNDEF //有点extern的感觉
IMPORT Enter_SWI
IMPORT Enter_PABORT
IMPORT Enter_DABORT
IMPORT Enter_FIQ
ENTRY //这是程序的入口
//中断/异常向量表(跳转),上电第一条就执行 b ColdReset,跳转到ColdReset。
b ColdReset
b Enter_UNDEF ;UndefinedInstruction
b Enter_SWI ;syscall_handler or SWI
b Enter_PABORT ;PrefetchAbort
b Enter_DABORT ;DataAbort
b . ;ReservedHandler
b IRQ_Handler ;IRQHandler
b Enter_FIQ ;FIQHandler
;deal with IRQ interrupt
EXPORT IRQ_Handler //IRQ中断处理子程序
IRQ_Handler
IMPORT ISR_IrqHandler //服务程序在外部定义
STMFD sp!, {r0-r12, lr}
BL ISR_IrqHandler //跳转至服务程序
LDMFD sp!, {r0-r12, lr}
SUBS pc, lr, #4
;=======
; ENTRY
;=======
EXPORT ColdReset
ColdReset //上电执行复位异常函数,就跳转到这里来ldr r0,=WTCON ;watch dog disable
//关闭看门狗,还没初始化完系统,防止没“喂狗”再次复位,写看门狗寄存器WTCON即可
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK //关闭所有中断
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
ldr r0,=INTSUBMSK//关闭所有次级中断
ldr r1,=0x7ff ;all sub interrupt disable, 2002/04/10
str r1,[r0]
;****************************************************
;* Initialize stacks * //进行堆栈初始化
;****************************************************
bl InitStacks ; Stack Setup for each MODE
//跳转到initstack,对各个模式下的堆栈进行初始化。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;; copy excption table to sram at 0x0//对堆栈初始化之后,进行域初始化;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IMPORT |Load$$EXCEPTION_EXEC$$Base|
IMPORT |Image$$EXCEPTION_EXEC$$Base|
IMPORT |Image$$EXCEPTION_EXEC$$Length|
ldr r0, =|Load$$EXCEPTION_EXEC$$Base| ;source data
ldr r1, =|Image$$EXCEPTION_EXEC$$Base| ;place exception talbe at 0x0
ldr r2, =|Image$$EXCEPTION_EXEC$$Length|
exception_cploop//这段没读明白,但是猜测是将flash中的程序代码拷贝到SDRAM中运行
sub r2, r2, #4
ldmia r0!, {r3}
stmia r1!, {r3}
cmp r2, #0
bge exception_cploop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;; start main function in C language//跳转到用户代码main() ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IMPORT __main
BL __main ;Don't use main() because ......
B .
;****************************************************
;* The function for initializing stack *
;****************************************************
IMPORT UserStack//堆栈指针的值是在外部就定义好的。
IMPORT SVCStack
IMPORT UndefStack
IMPORT IRQStack
IMPORT AbortStack
IMPORT FIQStack
InitStacks
;Don't use DRAM,such as stmfd,ldmfd......
;SVCstack is initialized before
;Under toolkit ver 2.50, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1' //每个模式下都有自己的堆栈指针SP,我们对其进行设置的前提就是进入该模式,即对CPSR 进行置位,才能访问这个模式下的SP,模式切换的时候,硬件会自动给SP置我们赋给的值。对CPSR的操作时按照“读出—修改—写入”的步骤进行的。即先用mrs读出,再用msr写入。
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1 ;UndefMode//未定义模式堆栈初始化
ldr sp,=UndefStack
//cpsr_cxsf 下划线后表示域,即操作哪些位。
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode//中止模式堆栈初始化
ldr sp,=AbortStack
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode//IRQ模式
ldr sp,=IRQStack
orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1 ;FIQMode//FIQ模式
ldr sp,=FIQStack
;bic r0,r0,#MODEMASK|NOINT//管理模式
orr r1,r0,#SVCMODE|NOINT
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack
;USER mode is not initialized.//没有对用户模式下的堆栈进行初始化。
mov pc,lr ;The LR register may be not valid for the mode changes. //之前使用的BL指令,可以用LR指令返回bl Initialize stacks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; End of Startup.c ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
各部分执行顺序如下图所示: