Hi,
Recently I am working on porting our Cortex A7 code that used to run in secure world to non-secure world for some reason. I got a problem when it came to GIC initialization.
I noticed that in order to manipulate a certain interrupt settings in non-secure world, I need to set that interrupt to Group 1 before I jump to non-secure. Besides that, everything else should be just identical to what should be done in secure world. Even the GICC and GICD control registers banked for non-secure world changed the enable bit for Group 1 to bit 0 so it can be enabled with the same bit mask I used for secure world. I also noticed the difference in priority settings, however, since all my interrupts have the same priority, I didn't make any change to priority settings either.
However, the CPU is not seeing any interrupts that could be seen before, PPI or SPI. Did I miss something here?
BTW, one reason I need to make this work is because I need to jump to non-secure Linux at some point, so need to make sure the GIC is initialized properly for non-secure operations. It would be great if somebody could point me at something explains how to prepare the processor before jumping to a NS linux.
Thanks,
Zizhu
This could be a priority issue.
From the GICv2 Architecture Reference Manual (ARM IHI 0048B) §4.4.2 "Interrupt Priority Mask Register, GICC_PMR":
If a Secure write has programmed the GICC_PMR with a value that corresponds to a value in the upper half of the priority range then:Any Non-secure read of the GICC_PMR returns 0x00, regardless of the value held in the registerAny Non-secure write to the GICC_PMR is ignored.
If a Secure write has programmed the GICC_PMR with a value that corresponds to a value in the upper half of the priority range then:
Note: Higher priority corresponds to a lower Priority field value.
A similar effect occurs when programming the GICD_IPRIORITYR Priority field of an interrupt. From §3.5.1 "Software views of interrupt priority in a GIC that includes the Security Extensions":
The Non-secure view of a priority value does not show how the value is stored in the Distributor. Taking the value from a Non-secure write to a priority field, before storing the value:• The value is right-shifted by one bit• Bit [7] of the value is set to 1.
The Non-secure view of a priority value does not show how the value is stored in the Distributor. Taking the value from a Non-secure write to a priority field, before storing the value:
• The value is right-shifted by one bit
• Bit [7] of the value is set to 1.
In other words the Non-secure world can only program interrupts to have a priority in the bottom half of the priority range (0x80-0xFF), and similarly can only program GICC_PMR if the Secure world has already written a value to it in the range [0x80..0xFF] inclusive.
The end result of this is that if you haven't programmed GICC_PMR to a low enough priority value while still in the Secure world, the Non-secure world cannot program interrupts to have a higher priority than GICC_PMR, which means all of your interrupts will be masked out i.e. they will not be signalled to the processor.
As a simple test, before leaving the Secure world please can you try writing 0xFF to GICC_PMR on each CPU that will be attempting to handle interrupts in the Non-secure world and see if that works?
Hope that helps,
Ash.