在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

ARMv8学习 —— SP_EL0和SP_ELx_寄存器

 验证

下面使用DS5仿真的实验,验证一下上面的说法。

ARMv8学习 —— SP_EL0和SP_ELx_异常处理_02

系统复位后,默认是在EL3,并且是secure模式。

第73行,将SP切到SP_EL0,然后设置SP的值为0x77,此时的寄存器状态如下:

ARMv8学习 —— SP_EL0和SP_ELx_寄存器_03

第77行,将SP切到SP_EL3,然后将SP设置为0x88,此时的寄存器状态如下:

 ARMv8学习 —— SP_EL0和SP_ELx_DS5_04

 

第81行,将SP重新切回SP_EL0,此时的寄存器状态如下:

ARMv8学习 —— SP_EL0和SP_ELx_DS5_05

 

第83行,访问ICC_SRE_EL2会触发sync异常,因为在secure模式下不存在EL2,触发异常后,会进入EL3的“Current EL with SP0”分支,因为发生异常时使用的是SP_EL0,下面是进入异常处理程序后的寄存器信息:

ARMv8学习 —— SP_EL0和SP_ELx_异常处理_06

 

可以看到,此时SPSel的值是1,Mode的值为EL3h,说明此时SP用的是SP_ELx。此时SPSR_EL3的值是0x3CC,SPSR的含义如下:

ARMv8学习 —— SP_EL0和SP_ELx_寄存器_07

M[3:0]的值是0xC,含义如下,表示发生异常前系统的模式和状态:AArch64、EL3、SP_EL0

ARMv8学习 —— SP_EL0和SP_ELx_arm64_08

 

 下面是异常处理函数:

 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:

ARMv8学习 —— SP_EL0和SP_ELx_DS5_09

 

 第85行的作用是将SP切换到SP_EL3,此时的寄存器内容如下:

ARMv8学习 —— SP_EL0和SP_ELx_ARM架构和指令集_10

 

 紧接着第86行,再次触发异常:

ARMv8学习 —— SP_EL0和SP_ELx_寄存器_11

此时会跳转到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行,异常返回后,寄存器内容如下:

ARMv8学习 —— SP_EL0和SP_ELx_异常处理_12

 

完。