基本逻辑
SEA (Synchronous External Abort)
- 同步外部中止,由当前指令执行直接触发
- 异常返回地址指向触发异常的指令本身
- 常见原因:内存错误、设备访问错误、页表遍历错误
SEI (SError Interrupt)
- 异步外部中止,与当前指令执行无直接关联
- 异常返回地址指向下一条指令
- 也称为 SError
RAS (Reliability, Availability, Serviceability)
- ARMv8.2-A 引入的 RAS 扩展,提供硬件错误检测和报告机制
- 支持错误记录、错误注入、错误恢复等功能
当SEI/SEA发生的时候,硬件可以通过配置决定是报到EL2还是EL3(固件),通常系统会配置
成报到固件,因为固件是私有的可以查看私有硬件模块的出错信息。固件处理完成后,固件
把需要报给OS的信息放到APEI表里,然后退回OS处理,这里一般是直接退到OS的异常向量
入口。OS里通过读APEI表的信息,得到RAS的更多信息。
硬件通过SCR_EL3配置SEA/SEI报到EL2还是EL3。
1 | SCR_EL3 |
注意,整个硬件系统分很多部件,比如很多L3/内存相关的部件OS里是看不见的,而core上
报SEA/SEI是core和这些OS看不见部件综合作用的结果,这些部件可以有私有的配置,这些
私有的配置甚至可以决定给core是否返回可以触发core SEA/SEI的信号,这些私有配置有些
还可以决定是否这些私有模块发现错误的时候直接报RAS相关的中断上来。
Linux内核处理
1 | // arch/arm64/mm/fault.c |
注意,有的时候,一个RAS错误源头可能触发一个SEA和一个SEI,如果在SEA处理逻辑还没有
关中断的时候,SEI被taken了,那么SEI看到的信息是SEA的栈信息,无法打印出实际触发这个
RAS错误的栈。这个时候可以hack下这里的do_sea,一进来就panic内核,这样可以看到触发
RAS错误的栈。
RAS处理中上下文保存和恢复
EL级别切换示意:
1 | +-------------+ |
逻辑上看,比EL3低的特权级发生SEA时,CPU直接跳到EL3,EL3这时是知道EL0/EL1/EL2的上
下文的。EL3在做完RAS相关处理后,需要把控制转移到EL2异常入口处理,这个转移过程逻辑
上应该模拟EL0/EL1/EL2直接到EL2异常的过程,这样到EL2后,EL2异常处理先保存EL0/EL1/EL2
的上下文,然后进入EL2处理,各种信息不会丢失。理论上看,EL3应该把之前的上下文放到
GPR和EL2相关的寄存器上,SPSR_EL3配置为一个固定PSTATE值,模拟EL0/EL1/EL2异常进入EL2
时EL2 PSTATE的值(这个值是进入EL2时的新PSTATE值,一般是一个固定的值)。
总结下EL3中的配置:
X0-X31 = EL0/EL1/EL2进入EL3的上下文
SPSR_EL2 = EL0/EL1/EL2进入EL3的SPSR_EL3
SPSR_EL3 = 一个固定的PSTATE
…
ERET到EL2
实际上,在RAS处理的流程中,之前EL0/EL1/EL2的PSTATE的值,已经不重要了。所以,直接
把SPSR_EL3配置成一个固定的值就好。