第3章的附录系统引导程序的代码
下面是一个基于S3C2410芯片的嵌入式系统引导(启动)程序Startup.s文件中的汇编源程序。
通过对这段程序的分析,巩固所学的汇编指令知识,并学习嵌入式系统引导程序的编写方法。
程序中各条指令及指示符的具体含义请参照3.1节和3.3.1小节中的说明。
;Startup Code for S3C2410 : Startup.s
;下面指令包含2410addr.s文件,该文件中定义了S3C2410内部寄存器地址对应的变量。
GET 2410addr.s
; 某些ARM920T CPSR寄存器位的定义,定义了部分常量。
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK E QU 0x1f
NOINT EQU 0xc0
I_Bit * 0x80
F_Bit * 0x40
; MMU寄存器定义。
CtrlMMU * 1
CtrlAlign * 2
CtrlCache * 4
CtrlWBuff * 8
CtrlBigEnd * 128
CtrlSystem * 256
CtrlROM * 512
TLB_L0_INIT * 0x0C02
;AREA指示汇编器汇编一段新的代码,为保证下面的代码为起始代码,应在ARM连接器的layout选项中指明Startup.o(Init) (如图1-33所示),或用scatter格式的描述性文件说明。
AREA Init,CODE,READONLY
;IMPORT提供汇编器在当前汇编中未曾定义的符号名。
IMPORT __use_no_semihosting_swi
IMPORT Enter_UNDEF
IMPORT Enter_SWI
IMPORT Enter_PABORT
IMPORT Enter_DABORT
IMPORT Enter_FIQ
;下面ENTRY指明了程序的入口,在应用程序中有且只有一个程序入口。
ENTRY
;下面是异常向量表,第一条语句是复位异常对应的跳转指令。
b ColdReset ;复位
b Enter_UNDEF ;未定义指令错误
b Enter_SWI ;软件中断
b Enter_PABORT ;预取指令错误
b Enter_DABORT ;数据存取错误
b . ;一个保留的中断向量
b IRQ_Handler ;IRQHandler
b Enter_FIQ ;FIQHandler
;deal with IRQ interrupt
EXPORT IRQ_Handler
IRQ_Handler
IMPORT ISR_IrqHandler
STMFD sp!, {r0-r12, lr}
BL ISR_IrqHandler
LDMFD sp!, {r0-r12, lr}
SUBS pc, lr, #4
;系统上电或复位后跳转到此处开始进行运行。
EXPORT ColdReset
ColdReset
;关看门狗定时器
ldr r0,=WTCON
ldr r1,=0x0
str r1,[r0]
;关所有中断
ldr r0,=INTMSK
ldr r1,=0xffffffff
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7ff ;all sub interrupt disable
str r1,[r0]
;初始化堆栈
bl InitStacks ;Stack Setup for each MODE
;复制excption table到SRAM0x0地址处
IMPORT |Load$$EXCEPTION_EXEC$$Base|
IMPORT |Image$$EXCEPTION_EXEC$$Base|
IMPORT |Image$$EXCEPTION_EXEC$$Length|
ldr r0, =|Load$$EXCEPTION_EXEC$$Base| ;源数据
ldr r1, =|Image$$EXCEPTION_EXEC$$Base| ;目的地址处
ldr r2, =|Image$$EXCEPTION_EXEC$$Length|
exception_cploop
sub r2, r2, #4
ldmia r0!, {r3}
stmia r1!, {r3}
cmp r2, #0
bge exception_cploop
;下面调转到C语言的主函数处
IMPORT __main
BL __main ;通常不能用main()作为主函数名
B .
;下面是初始化堆栈的子函数
IMPORT UserStack
IMPORT SVCStack
IMPORT UndefStack
IMPORT IRQStack
IMPORT AbortStack
IMPORT FIQStack
InitStacks
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1 ;UndefMode
ldr sp,=UndefStack
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack
orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1 ;FIQMode
ldr sp,=FIQStack
orr r1,r0,#SVCMODE|NOINT
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack
mov pc,lr ;The LR register may be not valid for the mode changes.
END ;Stratup.s程序结束
上述程序代码中,ENTRY指明了程序的入口。
因为,ARM920T要求中断向量表必须设置在从0x0地址开始,连续8×4字节的空间中,因此,在ENTRY的后面紧接着8条跳转指令,分别对应复位、未定义指令错误、软件中断、预取指令错误、数据存取错误、一个保留的中断向量、IRQ和FIQ等异常的处理。
系统上电或复位后,首先执行的是“b ColdReset”指令,系统跳转到标号为ColdReset 处接着执行,在完成了关看门狗定时器、关中断、初始化各模式的堆栈、初始化存储器等功能后,执行指令“BL __main”跳转到C语言的主函数处执行。
本例中,初始化堆栈的功能编写成了子函数,在该子函数中,没有对用户模式下的堆栈进行初始化。