1. ARM的工作模式
用户模式:权限低,只能访问一部分内存资源 系统模式:权限高,能访问很多资源 异常模式:当异常出现时,能够保证cpu不挂掉而去执行异常处理程序 Supervisor:管理模式,cpu一上电被视为是一种异常,进入该模式 Undefined:cpu遇到不认识的指令时会进入该模式 Abort:终止模式,取指令或取数据时,发现地址不存在则进入该模式 IRQ:普通中断模式,中断也被视为异常 FIQ:快速中断,对速度要求高 Secure monitor:v5指令集出来后的一种模式,进入该模式后只有一部分程序能运行
2. ARM寄存器组
每一种模式有对应的能够被操作的寄存器 带三角形的是有专用的、独立的寄存器
r11:fp 指向每个栈的栈顶 r12:ip 用来备份sp寄存器的 r13:常用作堆栈指针SP,但这只是一种习惯用法,用户也可使用其他的寄存器作为堆栈指针,而在Thumb指令集中,某些指令强制性的要求使用r13作为堆栈指针 r14:称为子程序链接寄存器lr,当执行子程序调用指令(bl)时,r14可得到r15(程序计数器pc)的备份 r15:程序计数器pc r16:CPSR 记录程序当前状态 高4位记录指令执行的结果,低5位记录当前工作模式。CPSR可在任何运行模式下被访问,它包括条件标志位、中断禁止位、当前处理器模式标志位,以及其他一些相关的控制和状态位。
每一种运行模式下又都有一个专用的物理状态寄存器,称为SPSR(Saved Program Status Register,备份的程序状态寄存器),当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复CPSR。由于用户模式和system特权模式不属于异常模式,它们没有SPSR,当在这两种模式下访问SPSR,结果是未知的
apcs规定:r0-r3一般是传递函数调用第1到第4个参数,需要手动保存,r4-r10一般是保存现场用,系统自动保存
3. 异常向量表
异常程序所放的位置,要方便cpu找到,就需要有张表来一一对应。异常向量表应运而生 因为不知道异常处理程序的大小,所以统一只留四个字节的空间存一条指令,这四个字节中存放的是跳转指令,可以跳转到某个内存中去执行对应的异常处理程序
0x0000 0000地址一般为iROM地址,所以异常向量表一般是通过协处理器映射到其他地址(如DDR地址)中去
4. Undefined异常实现示例
4.1 通过查手册得到负责映射的协处理器的寄存器操作指令
4.2 重映射异常向量表程序
_start:
@重新映射异常向量表
ldr r0, =0x41000000
mcr p15, 0, r0, c12, c0, 0
@打印cpsr低5位信息
ldr r0, =str_svc
mrs r1, cpsr
and r1, r1, $0x1f
mov lr, pc @跳转到printf函数前需要保存pc到lr,以便能够返回
ldr pc, =0x3ff13e54
@发生异常,CPU会自动跳转到0x41000000里面去执行异常处理程序
@模拟未定义指令异常
@1.保存返回地址到lr中
@2.保存cpsr到spsr
@3.修改cpsr为相应异常模式的值
@4.修改pc指向异常向量表
.word 0x77777777
@测试能否返回
ldr r0, =str
mov lr, pc @跳转到printf函数前需要保存pc到lr,以便能够返回
ldr pc, =0x3ff13e54
loop:
b loop
str_svc:
.asciz "hello svc mode cpsr=0x%x\n"
str:
.asciz "i am back\n"
4.3 异常处理程序
.global _start
_start:
@开始地址是0x41000000
b reset
b undef
b swi
b abt_pre
b abt_dat
b reserved
b irq
b fiq
reset:
undef:
ldr sp, =0x42000000 @初始化该模式下专用的sp寄存器
@保存现场
stmfd sp!, {r0-r12,lr}
@打印cpsr信息
ldr r0, =str_undef
mrs r1, cpsr @读cpsr寄存器内容
and r1, r1, #0x1f @取cpsr后五位
mov lr, pc @因为进入异常模式处理程序时已经自动保存返回地址到lr中 这里会覆盖掉lr
ldr pc, =0x3ff13e54
@恢复现场
ldmfd sp!, {r0-r12,lr}
movs pc, lr @+s:表示把spsr恢复到cpsr里面 因为当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复CPSR
swi:
abt_pre:
abt_dat:
reserved:
irq:
fiq:
str_undef:
.asciz "hello undefine mode cpsr=0x%x\n"
4.4 运行
5. swi异常处理实现
用户模式下没有权限修改CPSR,需要通过swi指令进入系统模式,通过swi指令+编号去进行系统调用,编号区分不同的系统调用函数。
5.1 重映射异常向量表程序
_start:
@重新映射异常向量表
ldr r0, =0x41000000
mcr p15, 0, r0, c12, c0, 0
@打印cpsr低5位信息
ldr r0, =str_svc
mrs r1, cpsr
and r1, r1, $0x1f
mov lr, pc @跳转到printf函数前需要保存pc到lr,以便能够返回
ldr pc, =0x3ff13e54
@把cpu的工作模式切换到user模式
mrs r0, cpsr @读cpsr寄存器内容
bic r0, r0, #0x1f
orr r0, r0, #0x10
msr cpsr, r0 @设置cpsr寄存器内容
@给用户模式进入到svc模式的专用指令
@1.保存返回地址到lr中
@2.保存cpsr到spsr
@3.修改cpsr为相应异常模式的值
@4.修改pc指向异常向量表
swi 0x99
@在用户模式 测试能否返回
ldr sp, =0x420000000
ldr r0, =str
mov lr, pc @跳转到printf函数前需要保存pc到lr,以便能够返回
ldr pc, =0x3ff13e54
loop:
b loop
str_svc:
.asciz "hello svc mode cpsr=0x%x\n"
str:
.asciz "in user mode: i am back\n"
5.2 异常处理程序
.global _start
_start:
@开始地址是0x41000000
b reset
b undef
b swi
b abt_pre
b abt_dat
b reserved
b irq
b fiq
reset:
undef:
swi:
@uboot已经初始化好该模式下的sp 所以这里不需要再初始化了
@保存现场
stmfd sp!, {r0-r12,lr}
@打印cpsr信息
ldr r0, =str_swi
mrs r1, cpsr @读cpsr寄存器内容
and r1, r1, #0x1f @取cpsr后五位 放到r1
@把lr地址减4得到swi指令所在地址
sub r3, lr,#4
ldr r2, [r3]
ldr r3, =0xffffff
and r2, r2, r3 @取出指令后面的24位 即0x99 放到r2
mov lr, pc @因为进入异常模式处理程序时已经自动保存返回地址到lr中 这里会覆盖掉lr
ldr pc, =0x3ff13e54
@恢复现场
ldmfd sp!, {r0-r12,lr}
movs pc, lr @+s:表示把spsr恢复到cpsr里面 因为当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复
abt_pre:
abt_dat:
reserved:
irq:
fiq:
str_undef:
.asciz "hello undefine mode cpsr=0x%x\n"
str_swi:
.asciz "hello supervisor mode cpsr=0x%x swi id=0x%x\n"
5.3 运行
|