在AArch64状态下,SP对应的物理寄存器有如下四个(某一时刻只能对应下面其中一个):
- SP_EL0和SP_EL1
- SP_EL2
- SP_EL3
如何使用呢?
1、如果程序运行在EL0,那么使用的是SP_EL0
2、如果程序运行在其他Exception level下,可以使用SP_EL0和当前Exception level所对应的SP_ELx
3、默认情况下,进入异常后,使用的是当前Exception level对应的SP_ELx。即:发生的进入EL1的异常,那么在跳转到EL1的异常处理入口后,会自动切到SP_EL1,此时SP对应的就是SP_EL1. 当然,可以在异常通过操作PSTATE.SP将SP强制切到SP_EL0
4、即便不是在异常处理程序中,也可以通过操作PSTATE.SP将SP强制切到SP_EL0或者SP_ELx
5、比如程序正运行在EL1,此时使用的SP是SP_EL0,突然发生了一个进入EL1的异常,在跳转到异常处理入口后,SP会自动切到SP_EL1,在异常返回后,SP又会自动切回到原先的SP_EL0
6、后缀t和h:
t 表示使用的是SP_EL0
h 表示使用的是SP_ELx
验证
下面使用DS5仿真的实验,验证一下上面的说法。
系统复位后,默认是在EL3,并且是secure模式。
第73行,将SP切到SP_EL0,然后设置SP的值为0x77,此时的寄存器状态如下:
第77行,将SP切到SP_EL3,然后将SP设置为0x88,此时的寄存器状态如下:
第81行,将SP重新切回SP_EL0,此时的寄存器状态如下:
第83行,访问ICC_SRE_EL2会触发sync异常,因为在secure模式下不存在EL2,触发异常后,会进入EL3的“Current EL with SP0”分支,因为发生异常时使用的是SP_EL0,下面是进入异常处理程序后的寄存器信息:
可以看到,此时SPSel的值是1,Mode的值为EL3h,说明此时SP用的是SP_ELx。此时SPSR_EL3的值是0x3CC,SPSR的含义如下:
M[3:0]的值是0xC,含义如下,表示发生异常前系统的模式和状态:AArch64、EL3、SP_EL0
下面是异常处理函数:
1 // 2 // Current EL with SP0 3 // 4 el3_vectors: 5 c0sync3: 6 mrs x0, elr_el3 7 add x0, x0, #4 8 msr elr_el3, x0 9 10 mov x0, #0x1 11 msr spsel, x0 12 eret
第6到8行的作用是异常返回时跳转到触发异常的指令的下一条指令执行,当第12执行完毕,ELR_EL3的值会设置给PC,SPSR_EL3的值会设置给PSTATE,所以SP会重新切回到SP_EL0:
第85行的作用是将SP切换到SP_EL3,此时的寄存器内容如下:
紧接着第86行,再次触发异常:
此时会跳转到EL3的“Current EL with SPx”分支执行:
1 // 2 // Current EL with SPx 3 // 4 .balign 0x80 5 cxsync3: 6 mrs x0, elr_el3 7 add x0, x0, #4 8 msr elr_el3, x0 9 10 mov x0, #0x0 11 msr spsel, x0 12 eret
第12行,异常返回后,寄存器内容如下:
完。