feat(kernel,hal): preemptive kernel-thread scheduling on aarch64 - #144
Merged
Conversation
The timer-IRQ path (#143) delivered interrupts but could not actually preempt: two bugs surfaced when a re-armed timer had to preempt busy kernel threads. 1. GICv3 fresh Group-1 PPI delivery (gic.rs, init_redistributor): the init only enabled PPI 30 (GICR_ISENABLER0); it never assigned the PPI's group, priority, or trigger. Fresh delivery therefore never reached the CPU interface (the earlier 3-tick path only worked off a pre-latched pending IRQ). Program, in the SGI_base frame (GICR_BASE + 0x10000): GICR_IGROUPR0 = 0xFFFF_FFFF (SGIs/PPIs -> Group 1) + GICR_IGRPMODR0 = 0 (NS Group 1); GICR_IPRIORITYR byte for PPI 30 = 0x00 (must be < ICC_PMR_EL1 = 0xFF to pass the priority filter); GICR_ICFGR1 PPI-30 field = level. Written before ISENABLER0. 2. DAIF inheritance across a preemptive switch (main.rs): switch_context swaps GPRs + SP but not PSTATE, so a thread switched-to from inside a timer IRQ inherits DAIF.I = 1 (masked) and can never be preempted again — the demo threads deadlocked in wfi. Each demo thread now unmasks IRQs (msr daifclr) once it starts running under preemption. Adds a preemptive demo: two busy kernel threads (C, D) that NEVER yield; the generic timer alone rotates between them. Verified in QEMU (-M virt,gic-version=3): C and D interleave three times each, then the re-elected boot thread prints 'timer preemption verified', with no faults under 'qemu -d int'. x86_64/riscv64 unaffected.
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.
The timer-IRQ path (#143) delivered interrupts but couldn't actually preempt. Two bugs surfaced when a re-armed timer had to preempt busy kernel threads:
1. GICv3 fresh Group-1 PPI delivery (gic.rs)
init only enabled PPI 30 (
GICR_ISENABLER0) — never set its group/priority/trigger, so fresh delivery never reached the CPU interface (the earlier 3-tick path only worked off a pre-latched pending IRQ). In the SGI_base frame (GICR_BASE + 0x10000):GICR_IGROUPR0 = 0xFFFF_FFFF(+IGRPMODR0 = 0→ NS Group 1),GICR_IPRIORITYR[PPI30] = 0x00 (must be <ICC_PMR_EL1=0xFF),GICR_ICFGR1[PPI30] = level. Written before ISENABLER0.2. DAIF inheritance across a preemptive switch (main.rs)
switch_contextswaps GPRs + SP but not PSTATE, so a thread switched-to from inside a timer IRQ inheritsDAIF.I=1(masked) and can never be preempted again → deadlock in wfi. Each demo thread nowmsr daifclr's once it runs under preemption.Demo
Two busy kernel threads (C, D) that never yield; the generic timer alone rotates between them.
Verified (
-M virt,gic-version=3):No faults under
qemu -d int. GIC fix diagnosed via an opus agent; DAIF fix + demo hand-written & QEMU-verified. x86_64/riscv64 unaffected.