Verified nested IRQ handling on S32Z280 silicon - #612
Merged
fdesbiens merged 1 commit intoAug 14, 2026
Conversation
eclipse-threadx#611 exercised the nesting routines on the FVP and established what breaks them: the interrupt must be acknowledged before nesting starts, or the still-pending level-asserted timer is retaken the moment IRQ is enabled and recurses until the stacks are gone. entry.S here carries the same ordering for the same reason, and irq_dispatch.c splits the same way, board_irq_service taking an already-acknowledged INTID while board_irq_handler keeps its old shape as the non-nesting entry point. What the model could not answer is whether a real GIC-600 agrees, and two things could have differed. The first is the number of implemented priority bits. Equal priorities do not preempt and it is the low bits that vanish, so if the timer and the SGI collapse to one value after truncation then nesting cannot happen at all -- and the test would fail without saying why. gicv3_priority_bits discovers the count by writing 0xFF to a priority byte and reading back which bits stick, board_init records the two effective values, and check P1 requires the SGI to still outrank the timer. This silicon keeps five bits, the same as the FVP, so 0xA0 and 0x50 stay distinct; that is now measured and reported rather than assumed. The second is whether an SGI raised on real hardware is delivered at all. ICC_SGI1R is a 64-bit AArch32 CP15 register whose encoding does not transcribe from the AArch64 alias, so check N1 raises one from thread context and requires delivery before nesting is involved. It arrives. Verified on S32Z280 silicon: priority bits = 0x00000005 timer effective = 0x000000A0 sgi effective = 0x00000050 P1 SGI outranks timer after truncation PASS N1 SGI delivered and dispatched PASS max depth = 0x00000002 nested SGIs = 0x00000032 depth now = 0x00000000 N2 SGI nested inside another handler PASS N3 nesting unwound to depth zero PASS N4 tick still advancing after nesting PASS N5 lower-priority thread still scheduled PASS N6 no spurious or unexpected interrupts PASS Fifty nested SGIs across fifty ticks, one per tick, and depth never exceeded two. No regression, checked in both configurations on the board. In the nesting build the ThreadX demo still reports 100 ticks with 20 preemptions and the boot image still passes its cache and protection checks. In the default build the image links no nesting symbols at all and the demo is unchanged. Both toolchains compile every file, GNU with no warnings and Arm Toolchain for Embedded 22.1.0 as well. Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
fdesbiens
added a commit
that referenced
this pull request
Aug 14, 2026
…613) _tx_thread_fiq_nesting_start and _tx_thread_fiq_nesting_end complete the set: after #611 and #612 covered IRQ nesting on the model and on silicon, these two were the remaining routines compiled into every build and entered by nothing. demo_fiq.elf enters them. FIQ needs more of the GIC than IRQ does. With a single security state the controller delivers Group 0 as FIQ and Group 1 as IRQ, so an interrupt only arrives as an FIQ if it has been moved into Group 0, the distributor and the CPU interface both have Group 0 enabled, and it is acknowledged through the Group 0 registers. Group 1's acknowledge returns the spurious INTID for a Group 0 interrupt and leaves it pending, which would present as a storm rather than as an error. gicv3.c gains IGRPEN0, BPR0, gicv3_enable_sgi_group0, gicv3_send_sgi_group0 and the Group 0 acknowledge and EOI pair. ICC_SGI0R differs from ICC_SGI1R only in opc1, 2 against 0, and each raises into its own group. entry.S routes the EL1 FIQ vector into _tx_thread_fiq_context_save with the same ordering the IRQ path needed: acknowledge in FIQ mode before nesting starts, then nesting_start, service, nesting_end, and end-of-interrupt last. It also leaves FIQ unmasked on the drop to EL1 when FIQ support is compiled in, because tx_thread_stack_build only clears a thread's F bit in that configuration and nothing else ever clears it, so an FIQ raised before the first thread ran would otherwise be silently ignored. Nesting an FIQ means taking an FIQ while an FIQ handler runs, which one source cannot show, so two Group 0 SGIs are used with the second at a numerically lower priority. The low one's handler raises the high one. One mistake worth recording, because the guard it needed is not obvious. TX_ENABLE_FIQ_SUPPORT is PUBLIC on the threadx target, so it reaches every image as soon as the library is built with FIQ -- including images that link no interrupt controller at all. demo_m2 is one of those: no gicv3.c, no irq_dispatch.c. Referencing gicv3_acknowledge_group0 and board_fiq_service from the FIQ vector broke its link outright. The vector is now gated on TX_R52_USE_THREADX_IRQ as well, which is how the IRQ vector has always been gated, and images without the infrastructure keep the fault reporter. Verified on FVP_BaseR_AEMv8R. F1 covers the whole Group 0 chain on its own -- IGRPEN0, the ICC_SGI0R encoding, IAR0 and EOIR0, the EL1 vector and F being unmasked -- so a failure there points somewhere other than the nesting routines. The demo reports 21 low-priority FIQs, 20 high-priority, 20 of them nested, max depth 2, depth unwound to zero, the IRQ tick undisturbed, threads still scheduled and no unexpected Group 0 INTID. All six images pass in the FIQ configuration, and the default build links no FIQ or Group 0 symbol at all, so the work is absent rather than dormant where it is not wanted. Both toolchains build every file, GNU with no warnings and Arm Toolchain for Embedded 22.1.0 as well. Not done here: the S32Z280 example is untouched, so FIQ on silicon is a separate change, as IRQ nesting was. Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#611 exercised the nesting routines on the FVP and established what breaks them:
the interrupt must be acknowledged before nesting starts, or the still-pending
level-asserted timer is retaken the moment IRQ is enabled and recurses until the
stacks are gone.
entry.Shere carries the same ordering for the same reason, andirq_dispatch.csplits the same way —board_irq_servicetakes analready-acknowledged INTID while
board_irq_handlerkeeps its old shape as thenon-nesting entry point.
What the model could not answer is whether a real GIC-600 agrees. Two things could
have differed, and both are now checked rather than hoped for.
Implemented priority bits. Equal priorities do not preempt, and it is the low
bits that vanish — so if the timer and the SGI collapse to a single value after
truncation, nesting cannot happen at all, and the test would fail without saying
why.
gicv3_priority_bitsdiscovers the count by writing0xFFto a prioritybyte and reading back which bits stick;
board_initrecords the two effectivevalues; check P1 requires the SGI to still outrank the timer. This silicon
keeps five bits, the same as the FVP, so
0xA0and0x50stay distinct. That isnow measured and reported instead of assumed.
SGI delivery on real hardware.
ICC_SGI1Ris a 64-bit AArch32 CP15 registerwhose encoding does not transcribe from the AArch64 alias, so check N1 raises
one from thread context and requires delivery before nesting is involved. It
arrives.
Verified on silicon
Fifty nested SGIs across fifty ticks — one per tick — and depth never exceeded
two.
No regression, checked both ways on the board
and the boot image still passes its cache (C3/C4) and protection (X2/X4) checks.
irq_nestingsymbols, and the demois unchanged. That is the configuration everyone ships, so it is worth showing
the nesting work is genuinely absent from it rather than merely inactive.
Both toolchains compile every file — GNU with no warnings, and Arm Toolchain for
Embedded 22.1.0.