目录
Aarch64中异常的基本概念
在aarch64中,将中断、系统调用、数据指令异常等等情况统称为异常。异常会中断当前cpu执行流,转而执行具有更高权限的代码,即exception handler。当异常处理完毕后cpu会再次返回到之前的被中断的代码流继续执行。
常见的异常有中断、系统调用、数据指令失效访问等等。虽然异常类型各种各样,但aarch64将异常分为同步异常(synchronous exception)和异步异常(asynchronous exception)两类。
- asynchronous exception的特点:
1异常发生的时机无法预料,与CPU执行的指令无关;
2异常处理的返回地址并非是产生异常时的那一条指令。
IRQ、FIQ和SError interrupt属于asynchronous exception。
- synchronous exception的特点:
1 异常的产生是和CPU执行的指令或者试图执行的指令有关;
2 异常处理的返回地址就是产生异常的那一条指令所在的地址。
异常发生时硬件做了哪些事情?
- 异常返回地址保存到ELR_ELn寄存器中
PE会根据异常的类型选择一个合适返回地址保存到ELR_ELn中,n的含义和签名SPSR_ELn类似。等到异常处理完毕、软件主动调用ERET指令,这个指令会将ELR_ELn的内容更新到PC指针,实现异常的返回跳转。
- 将当前PE状态保存到SPSR_ELn寄存器中
其中n表示target exception level。例如,在linux中用户态任务(EL0)执行时触发一个数据访问异常,此时target exception level就是EL1。
待异常处理完毕后,软件会主动调用ERET指令,这个指令的一个功能就是将SPSR_ELn恢复到PSATE寄存器中(严格来说PSTATE不是一个寄存器,是一组表示PE状态寄存器的组合)。
- 更新PE状态寄存器进入目标EL
发生异常,PE进入要给全新的执行状态,因而PSATE寄存器的各个状态域也会随之更新。
其中DAIF域的各个位都会被mask,从而禁止在此cpu上这些异常事件的发生;因而异常处理过程中除非软件显示的unmask DAIF中的bit位,否则这些异常一直处于禁止状态,知道ERET指令执行时DAIF的值从SPSR_ELn寄存器恢复到异常前的状态。
- 堆栈指针SP_ELn的切换
程序运行在EL0时使用的是SP_EL0;其他Exception level下,可以使用SP_EL0或者当前Exception level所对应的SP_ELn寄存器;具体使用SP_EL0还是SP_EL1是由PSTATE.SP决定,对应的寄存器是Spsel。若Spsel==0,那么强制使用SP_EL0,否则使用用SP_ELn。在linux中Spsel默认位1。因而异常发生时,默认会切换到SP_ELn。
- 视情况更新ESR_ELn寄存器
如果发生的是同步异常或者SError异常,则将异常原因信息更新到ESR_ELn寄存器中。其他FIQ、IRQ异常则不会更新此寄存器。
- 视情况更新FAR_ELn寄存器
FAR_ELn寄存器全称叫Fault Address Registe。在指令或者数据 Aborts异常、非对齐异常时,这个寄存器保存引发异常的地址。
异常的处理
根据发生在内核态还是用户态,中断还是异常, cpu会自动跳转到异常向量表中的el1_sync,el1_irq,el0_sync,el0_irq处;
异常处理完毕后软件通过执行ERET指令返回异常,这条指令完成:将SPSR_ELn寄存器的值恢复到PSTATE中;
如图所示(下图来自):
参考:
https://static.docs.arm.com/100933/0100/aarch64_exception_and_interrupt_handling_100933_0100_en.pdf
《ARM® Cortex®-A Series Programmer’s Guide for ARMv8-A》