3.3 KiB
AArch64 GICv3 Distributor Virtualization (vGICD)
Goal: Trap guest accesses to the GIC distributor (GICD @ 0x08000000) and emulate a per-vCPU virtual distributor, so a guest (today the C payload; eventually Linux) programs its own interrupt controller without touching the physical GICD. This is the next Linux-boot step after PL011 trap-emulate.
Why now: Today the whole low 4 GiB is mapped device at stage-2, so the guest sees the real GICD. A Linux guest would reprogram the physical distributor and fight the HV. GICv3's hardware virtualizes the CPU interface (ICV_* via ICH_*), but NOT the distributor — that must be emulated in software (KVM vgic-v3, Xen vgic, Bao vgicd).
Scope (bounded, MVP):
- Stage-2: leave a trap hole over the GICD 64 KiB window (same mechanism as the existing PL011 hole in
s2_fill_l2). - New
kernel/src/arch/aarch64/vgicd.{cpp,h}: per-vCPU GICD shadow state + read/write emulation for the registers a GICv3 driver touches at probe/bring-up:- ID/config (read-only): GICD_CTLR, GICD_TYPER, GICD_IIDR
- per-IRQ: IGROUPRn, ISENABLERn/ICENABLERn, ISPENDRn/ICPENDRn, ISACTIVERn/ICACTIVERn, IPRIORITYRn, ICFGRn, IROUTERn
- Wire ISENABLER writes into the existing
aarch64_vcpu_irq_enable()bitmap (already consulted byel2_guest_irq_handlerfor physical→virtual routing). - Extend
el2_guest.cppEC_DATA_ABORT_LELpath: dispatch GICD-window faults tovgicd_emulate()(alongside the existing PL011 path). - Guest payload: add a probe sequence that reads GICD_TYPER/IIDR, writes GICD_CTLR, enables a PPI via the virtual ISENABLER0-equivalent on the distributor, and reads it back — printing the values so the verify script can confirm the shadow round-trips.
Out of scope (deferred): GICR virtualization (GICv3 uses ICC/ICV sysregs, hardware-virtualized), ITS/LPI, full SPI routing to other vCPUs, priority-based preemption between virtual IRQs, GICD_CTLR.ARE/DIS security semantics.
Files:
- Modify:
kernel/src/arch/aarch64/stage2.cpp— secondleave_*_holefor the GICD window. - Create:
kernel/src/arch/aarch64/vgicd.h— vGICD state struct + emulate() decl. - Create:
kernel/src/arch/aarch64/vgicd.cpp— shadow + read/write emulation. - Modify:
kernel/src/arch/aarch64/el2_guest.cpp— dispatch GICD faults to vgicd_emulate. - Modify:
kernel/src/arch/aarch64/objects.mk— add vgicd.o. - Modify:
kernel/src/arch/aarch64/guest_payload/guest_main.c— GICD probe sequence. - Modify:
kernel/src/arch/aarch64/vcpu.h— add a vgicd state pointer/field to aarch64_vcpu (or keep a single global vgicd for the one-vCPU MVP).
Verification (ad-hoc):
make ARCH=aarch64 PLATFORM=qemu-aarch64-virtclean.-smp 4boot UART shows the guest reading back the exact TYPER/IIDR/CTLR values it expects, and the ISENABLER write round-tripping — proving the trap-emulate shadow works and the guest no longer touches the physical GICD.- ARMv7 build clean.
Risks: GICD_IROUTERn are 64-bit registers the guest may access with a single 64-bit store (SAS=3) or two 32-bit stores — handle both. GICD access decode (ISS_ISV) must be valid; if a guest uses an addressing mode without syndrome, we log + inject vSError (already plumbed). Linux also reads GICR_TYPER via sysreg-free MMIO on some paths — out of scope; if a future guest faults on GICR we'll add it then.