Hello everyone,
I am working on a hypervisor running in EL2N (aarch64). I try to use the physical EL2 timer (CNTHP_*_EL2) to signal an interrupt to the hypervisor. I configured the counter and write to the timer value register. After the time has passed, the ISTATUS bit in CNTHP_CTL_EL2 is correctly set to 1, the IMASK bit is 0 all the time.
As detailed in "AArch64 Programmer's Guides Generic Timer" I configure INTID 26. It is set as a Group 1 NS interrupt, which I enable and set the priority to 0xa0. After the timer condition is met, the INTID shows up in ICC_HPPIR1_EL1 and reading GICR_ICPENDR0 also show that INTID 26 is pending.
Further checks I did to ensure the interrupt is enabled:
ICC_GRPEN1_EL1 is set to one, showing that group 1 interrupts are enabled for the current security state (non-secure)
ICC_GRPEN1_EL3 also shows that Group 1 NS interrupts are enabled
GICD_CTLR Affinity Routing is enabled and Group1NS Interrrupts are enabled
From my understanding the interrupt is configured correctly and should interrupt the execution on the PE (I only use 1 PE). However, this does not happen.
Can anyone help me in understanding why this is the case or which configuration I might have missed?
Any help is appreciated!
With kind regards
Martin S.
Hi Martin.S
The fact that you're seeing the INTID reported in ICC_HPPIR1_EL1 is good. It means the interrupt reached the GIC and forwarded it to the CPU IF.
As to what is going wrong, two things spring to mind:
To work out which is happening, read ISR_EL1. This register reports the state of the interrupt inputs to the PE (so, effectively the output of the GIC CPU IF).
If ISR_EL1.{I,F} are both 0, that means the CPU IF isn't asserting an interrupt to the PE. Mostly likely reasons are the Priority Mask (ICC_PMR_EL1) or Running Priority (ICC_RPR_EL1). These set the minimum priority the current HPPI (highest priority pending interrupt) has to have in order to be signalled to the PE. The Priority Mask is set manually by software, the Running Priority floats up and down as you acknowledge and EOI interrupts.
https://developer.arm.com/documentation/198123/0302/Handling-interrupts
Note: ICC_PMR_EL1 resets of 0x00, which means "mask ALL interrupt priorities". If you're running in Non-secure state, then software in Secure state will have to initialised the register before you switched Security state.
If ISR_EL1.{I,F} show that the interrupt is being signalled by the GIC, then you're getting PE level masking. Most obvious candidate is PSTATE.I. But interrupts can also be implicitly masked by the routing controls in HCR_EL2 and SCR_EL3. Any interrupted routed to an EL lower than the current EL is implicitly masked. For example, if HCR_EL2 and SCR_EL3 collectively route IRQs to EL1 then IRQs are implicitly masked at EL2 and EL3.
Learn the architecture - AArch64 Exception Model (arm.com)
Martin.W
Hello Martin,
thank you for the detailed and helpful answer! ISR_EL1.I showed the interrupt is signalled and since PSTATE.I also did not mask exceptions I found the reason for my problem in HCR_EL2.IMO I thought it was only relevant for interrupts from lower ELs but apparently it is relevant for interrupts at any EL, good to know.
Know the interrupt handler is triggered as soon as the timer condition is met which is the expected result.
Thank you very much!
Greetings
Martin