ARMv8的异常处理
一、异常处理过程中的几个基础概念
当发生异常时,当前程序流会被打断,本文将更深入地讨论异常的实际处理方式。
在AArch64的特定术语中,当在谈到异常处理时,需要理解以下几个概念:
-
捕获异常:当处理器(PE)响应异常时,称为“捕获异常”。
-
异常捕获状态:捕获异常前的PE状态称为“异常捕获状态”。
-
异常处理状态:捕获异常后的PE状态称为“异常处理状态”。
-
因此,当处理器在识别异常时所处的状态被称为异常捕获状态,而异常处理后,处理器所处的状态称为异常处理状态。例如,可以从AArch32 EL0捕获异常到AArch64 EL1。在异常处理完成后,系统需要返回到捕获异常之前的状态,这称为“异常返回”,Arm架构提供了触发异常返回的指令:
-
异常返回状态:返回指令执行时PE所处的状态称为“异常返回状态”。
-
返回后状态:异常返回指令执行后PE的状态称为“返回后状态”
二、异常处理
当异常发生时,处理器会保存处理器当前的状态以及异常返回地址,然后进入特定模式处理异常。当前状态的快照从程序状态寄存器(PSTATE)中提取,此快照将被写入到保存程序状态寄存器(SPSR)中,而返回地址则被写入到异常链接寄存器(ELR)。对于同步异常和系统错误(SError),还会更新异常综合寄存器(ESR),该寄存器用于记录触发异常的原因。
当异常被捕获到使用AArch64状态的异常级别(ELx)时,以下操作将会发生:
- 在异常被捕获之前,PSTATE的内容会被写入到SPSR_ELx。
- 首选的异常返回地址会被写入到ELR_ELx。
- 对于同步异常和系统错误(SError)中断,异常综合信息(即异常的原因)会被写入到ESR_ELx寄存器中。
- 对于与地址相关的同步异常,例如MMU故障,会将触发异常的虚拟地址写入故障地址寄存器(FAR_ELx)。
任何给定异常的异常处理都从一个称为异常向量的固定内存地址开始,当发生异常时,处理器(PE)将分支跳转到异常向量表中的某个位置。
备注:在AArch64架构中,向量表与其他许多的处理器架构不同,因为它们包含的是指令而不是地址,每个条目最多包含32条指令,这正好足以执行基本的堆栈操作并调用特定异常的处理代码。
异常向量表的位置通常被配置为包含异常处理的代码,用于执行通用操作并根据异常类型分支跳转到进一步的异常处理代码,如下图所示,这个异常向量代码限制为32个字(words)的代码。异常处理程序包含处理请求操作的代码,并使系统能够从异常状态返回。
每种异常类型都对应一个异常级别(EL),异常被触发时将转向该异常级别。因此处理异常将会路由到不同的EL,这一点对于处理器来说非常重要,因为获得特权的唯一方法是触发异常,而失去或降低特权的唯一方式是执行异常返回。这意味着:
- 在触发异常时,异常级别(EL)可以保持不变或增加。
- 在执行异常返回时,异常级别(EL)可以保持不变或降低。
需要注意的是,触发异常或执行异常返回并不一定意味着EL的变化。异常的目标可以与当前的EL相同,目标EL是根据异常类型隐式定