异常处理是现代处理器架构的核心功能之一,它使系统能够响应硬件故障、软件错误和外部事件。在ARMv8-A架构的AArch64执行状态下,异常处理机制通过多级异常等级(Exception Levels, EL0-EL3)实现了精细的权限控制和隔离。
AArch64架构将异常分为同步异常和异步异常两大类:
异常优先级决定了当多个异常同时发生时处理顺序。AArch64的异常优先级从高到低依次为:
AArch64架构定义了四个异常等级,形成权限层级:
每个异常等级都有自己的寄存器组和内存映射,确保隔离性。当异常发生时,处理器通常会转移到更高或相同的异常等级进行处理。
当异常发生时,处理器执行以下关键步骤:
这些步骤在伪代码函数AArch64_TakeException中有清晰体现:
c复制func AArch64_TakeException(target_el : bits(2), exception_in : ExceptionRecord,
preferred_exception_return : bits(64), vect_offset_in : integer)
begin
// 验证目标异常等级有效性
assert HaveEL(target_el) && !ELUsingAArch32(target_el)
&& UInt(target_el) >= UInt(PSTATE.EL);
// 上下文同步与屏障操作
SynchronizeContext();
InstructionFetchBarrier();
// 状态保存
var spsr : bits(64) = GetPSRFromPSTATE{}(AArch64_NonDebugState);
SPSR_ELx() = spsr;
ELR_ELx() = preferred_exception_return;
// 更新处理器状态
PSTATE.EL = target_el;
PSTATE.nRW = '0';
PSTATE.SP = '1';
PSTATE.[D,A,I,F] = '1111'; // 屏蔽所有异步异常
// 计算向量表偏移并跳转
let vect_base : bits(64) = VBAR_EL(target_el);
BranchTo{64}(vect_base[63:11]::vect_offset[10:0],
BranchType_EXCEPTION, FALSE);
end
每个异常等级都有自己的向量表基址寄存器(VBAR_ELx),向量表包含16个条目,每个条目对应不同类型的异常。向量偏移量(vect_offset)由以下因素决定:
典型的向量偏移量计算逻辑如下:
c复制if except.exceptype == Exception_TENTER then
vect_offset = if PSTATE.SP == '1' then 0x880 else 0x800;
elsif UInt(target_el) > UInt(PSTATE.EL) then
vect_offset = vect_offset + (if lower_32 then 0x600 else 0x400);
elsif PSTATE.SP == '1' then
vect_offset = vect_offset + 0x200;
end
数据中止通常由内存访问错误引发,如地址转换失败或权限违规。其处理函数AArch64_DataAbort的核心逻辑包括:
AArch64_TakeExceptionc复制func AArch64_DataAbort(fault : FaultRecord)
begin
// 目标异常等级选择
if IsExternalAbort(fault) then
target_el = SyncExternalAbortTarget(fault);
else
let route_to_el2 = (EL2Enabled() && PSTATE.EL IN {EL0, EL1} &&
(HCR_EL2().TGE == '1' || ...));
if PSTATE.EL == EL3 then
target_el = EL3;
elsif PSTATE.EL == EL2 || route_to_el2 then
target_el = EL2;
else
target_el = EL1;
end;
end;
// 异常综合征生成
let except = AArch64_AbortSyndrome(Exception_DataAbort, fault, target_el);
// 触发异常
AArch64_TakeException(target_el, except,
ThisInstrAddr{}(), vect_offset);
end
指令中止发生在指令获取阶段失败时,其处理流程与数据中止类似,但有一些特殊约束:
c复制func AArch64_InstructionAbort(fault : FaultRecord)
begin
// 外部指令中止必须同步处理
if IsFeatureImplemented(FEAT_DoubleFault) then
assert fault.statuscode != Fault_AsyncExternal;
end;
// 目标等级选择逻辑与DataAbort类似
// ...
// 特殊向量偏移处理
if IsExternalAbort(fault) && AArch64_RouteToSErrorOffset(target_el) then
vect_offset = 0x180;
else
vect_offset = 0x0;
end;
AArch64_TakeException(target_el, except,
ThisInstrAddr{}(), vect_offset);
end
SError是异步系统错误,通常由内存子系统或总线错误引发。其处理需要考虑路由配置:
c复制func AArch64_TakePhysicalSErrorException(implicit_esb : boolean)
begin
var (masked, target_el) = PhysicalSErrorTarget();
assert !masked; // 确保SError未被屏蔽
let fault = GetPendingPhysicalSError();
var except = ExceptionSyndrome(Exception_SError);
// 同步错误处理
if IsFeatureImplemented(FEAT_IESB) && sync_errors then
SynchronizeErrors();
end;
AArch64_TakeException(target_el, except,
ThisInstrAddr{}(), 0x180);
end
内存标签扩展为指针和内存添加了4位标签,用于检测内存安全违规。相关异常处理包括:
c复制func AArch64_EffectiveTCF(el : bits(2), read : boolean) => TCFType
begin
// 获取当前执行环境的TCF配置
case TranslationRegime(el) of
when Regime_EL3 => tcf = SCTLR_EL3().TCF;
when Regime_EL2 => tcf = SCTLR_EL2().TCF;
// ...其他等级处理
end;
// 根据配置决定处理方式
case tcf of
when '00' => return TCFType_Ignore; // 忽略标签检查错误
when '01' => return TCFType_Sync; // 同步异常
when '10' => return TCFType_Async; // 异步报告
when '11' => // 混合模式
if read then return TCFType_Sync;
else return TCFType_Async;
end;
end
RME引入了新的安全状态(Realm),相关异常处理需要特殊考虑:
c复制func TakeGPCException(fault : FaultRecord)
begin
assert IsFeatureImplemented(FEAT_RME);
var except = ExceptionRecord;
except.exceptype = Exception_GPC;
// 设置地址空间标识
case fault.ipaddress.paspace of
when PAS_Secure: except.NS = '0';
when PAS_NonSecure: except.NS = '1';
when PAS_Root: except.NS = '0';
when PAS_Realm: except.NS = '1';
end;
AArch64_TakeException(EL3, except,
ThisInstrAddr{}(), vect_offset);
end
异常处理完成后,通过ERET指令返回原执行流。关键恢复步骤包括:
c复制// ERET指令的伪代码示意
func AArch64_ExceptionReturn()
begin
// 从SPSR恢复处理器状态
PSTATE = GetPSTATEFromPSR(SPSR_ELx());
// 安全检查
if IsFeatureImplemented(FEAT_RME) then
ValidateRealmExit();
end;
// 返回到ELR保存的地址
BranchTo(ELR_ELx(), BranchType_EXCEPTION_RETURN, FALSE);
end
AArch64异常处理机制与调试和性能监控系统紧密集成:
c复制func AArch64_BreakpointException(fault : FaultRecord)
begin
let route_to_el2 = (PSTATE.EL IN {EL0, EL1} && EL2Enabled() &&
(HCR_EL2().TGE == '1' || MDCR_EL2().TDE == '1'));
target_el = if (PSTATE.EL == EL2 || route_to_el2) then EL2 else EL1;
let except = AArch64_AbortSyndrome(Exception_Breakpoint, fault, target_el);
AArch64_TakeException(target_el, except,
ThisInstrAddr{}(), 0x0);
end
在异常入口和出口处,处理器会更新性能监控计数器(如PMU),并可能触发性能监控异常。
在虚拟化环境中,EL2处理器的异常路由更为复杂:
c复制func AArch64_TakeVirtualIRQException()
begin
assert PSTATE.EL IN {EL0, EL1} && EL2Enabled();
assert HCR_EL2().TGE == '0' && HCR_EL2().IMO == '1';
let except = ExceptionSyndrome(Exception_IRQ);
AArch64_TakeException(EL1, except,
ThisInstrAddr{}(), 0x80);
end
EL3处理安全状态切换和可信执行环境相关异常:
c复制func AArch64_CallSecureMonitor(immediate : bits(16))
begin
assert HaveEL(EL3) && !ELUsingAArch32(EL3);
let except = ExceptionSyndrome(Exception_MonitorCall);
except.syndrome.iss[15:0] = immediate;
AArch64_TakeException(EL3, except,
NextInstrAddr{}(), 0x0);
end
在实际系统设计中,异常处理性能至关重要。以下是关键优化点:
症状:系统不断触发相同异常
排查步骤:
症状:高优先级异常未被及时处理
解决方法:
症状:合法内存访问触发Data Abort
检查点: