一、undefined异常模式
0. 当执行未定义指令时进入und模式,进入过程:
CPU跳至0x4地址执行代码,自动保存CPSR寄存器值至SPSR寄存器,我们要做的就是在0x4处跳转到另一段代码,用这段代码完成现场保护,以及异常处理,最后退出异常。此处使用NOR启动,并且在0x0处执行reset时已经将NOR中的所有代码重定位至SDRAM中,所以跳转时不能用相对跳转(b和bl),必须使用绝对地址跳转,这样CPU将到SDRAM(0x30000000)中执行代码。
ldr pc, =und /*vector 4*/
und:
/*设置专属sp_und*/
ldr sp,=0x34000000
/*保护现场*/
stmdb sp!, {r0-r12,lr}
/*异常处理*/
bl print2
mrs r0,cpsr
ldr r1,=und_string
bl printException
/*恢复现场*/
ldmia sp!, {r0-r12,pc}^
und_string:
.string "und exception!"
.align(4)
1. 因为und模式有自己的专属sp_und所以第一步设置sp地址
2. CPSR寄存器已经有硬件自动保存,此处只需要保存r0-r12和lr寄存器(lr保存执行未定义指令时的下一条指令的地址),此处我加了打印调试信息的print函数,调试关键点:调试函数不能在进入异常后放在保护现场的代码之前,否则异常的现场被改变,之后程序必然跑飞。
3. 异常处理部分分别用r0和r1传出cpsr的值和字符串"und exception!"的地址,用printException函数打印出。
4. 最后恢复现场,当{ }中有pc时,加^会自动将SPSR的值恢复至CPSR。
5. 未定义指令部分:
ldr pc,=uart
uart:
bl uart0_init
bl print1
und_code:
.word 0xdeadc0de
6. uart是为了初始化串口,以便打印调试信息,und_code是未定义指令,此处有bug,注释掉bl print1时不能发生未定义异常,未debug
输出结果:
cpsr值得M4-M0为11011同下图的数据手册中的值一致
2018.12.3补充,print1处的bug是因为print1改变了cpsr的值使0xdeadc0de成为不可执行指令,debug方法,去掉print1,未定义指令改为0xeeadc0de.
二、svc异常模式
0. 异常的进入与处理与und异常几乎一样,注意点为:
/* 复位之后, cpu处于svc模式
* 现在, 切换到usr模式
*/
mrs r0, cpsr /* 读出cpsr */
bic r0, r0, #0xf /* 修改M4-M0为0b10000, 进入usr模式 */
orr r0, r0, #0x10
msr cpsr, r0
/* 设置 sp_usr */
ldr sp, =0x33f00000
1. 执行swi 0x*** 指令,内核从用户模式切换至svc模式,CPU跳至0x4地址执行代码,之后同und异常流程一样。
ldr pc, =swi /*vector 8*/
swi:
/*设置专属sp_svc*/
ldr sp,=0x33e00000
/*保护现场*/
stmdb sp!, {r0-r12,lr}
/*异常处理*/
mov r4,lr
bl print4
mrs r0,cpsr
ldr r1,=swi_string
bl printException
sub r0, r4, #4
bl printSWIVal
/*恢复现场*/
ldmia sp!, {r0-r12,pc}^
swi_string:
.string "swi exception!"
.align (4)
2. lr 保存了执行的swi 0x*** 指令的下一条指令的地址,将lr-4即可得到swi指令的地址,printSWIVal打印了该处的值。
在将 lr 的值取出至r0前不能做其他操作,例如输出调试信息,否则 之前 lr 的值将被改变
3.输出结果:
cpsr的M4-M0为10011与数据手册一致
SWI val也与进入时的指令相同