Hi Julius,

 

In the Arm Architecture, all asynchronous exceptions (IRQ, FIQ, SError) target EL1 by default, unless specifically overridden to be routed EL2 by HCR_EL2.{IMO, FMO, AMO} or overridden to be routed to EL3 by SCR_EL3.{IRQ, FIQ, EA}; if both EL2 and EL3 try to route a particular type of asynchronous exception to their respective EL – for example HCR_EL2.AMO == SCR_EL3.EA == 1, then EL3 “wins” as it’s more privileged and the exception will be routed to EL3.

 

Separately, the PSTATE.{A, I, F} fields control whether the corresponding type of asynchronous exception is taken in the current EL, but does not prevent an exception from being routed to a higher EL.

 

So for example, you may have SCR_EL3.FIQ == 1, meaning FIQs are routed to EL3. If you’re currently executing at EL1 and an FIQ is asserted to the core, then the value of PSTATE.F is ignored and the exception is taken to EL3. This is by design, otherwise less privileged software could for example DoS the more privileged software if that FIQ corresponded to a timer tick / maintenance interrupt.

 

Another nuance here is that an asynchronous exception being asserted which targets a lower exception level than we’re currently executing in will be pended until we return back to either that level (or an even lower level).

 

For example, if we have HCR_EL2.EA == SCR_EL3.EA == 0, meaning SErrors are targeting the default EL1, and an SError is asserted to the core while executing in EL3, then we will not take the SError exception and it will instead become pending until we return back to EL1/EL0, at which point we’ll take the SError exception – if not masked by PSTATE.A.

 

The final bit of nuance here is around the NMEA and TMEA bits.

 

The NMEA bit basically says “If we’re executing at the current EL and an SError is asserted that would have been masked by PSTATE.A, take the SError anyway” – with some rules around when this is possible so as to prevent us from e.g. taking an SError in the middle of stacking off context at the entrypoint of some other exception handler.

 

And the TMEA bit basically says “Route an SError / Synchronous External Abort to me, but only if it’s not been handled by a lower EL”. As an example, if we have something like SCR_EL3.TMEA == HCR_EL2.AMO == PSTATE.A == 1, then we could imagine two scenarios:

 

1) We’re executing in EL1 and an SError is asserted PSTATE.A is ignored the SError is routed to EL2.

 

2) We’re executing in EL2 and an SError is asserted PSTATE.A masks the SError the SError is trapped to EL3 since it wasn’t handled by a lower EL (or more accurately, it was masked by all lower ELs).

 

Hope that helps to clarify :-)

 

Cheers,

Ash.