* [PATCH v4 00/42] [RISC-V] virtual interrupt controller (vAPLIC/vIMSIC) support
@ 2026-11-13 15:48 Oleksii Kurochko
0 siblings, 0 replies; only message in thread
From: Oleksii Kurochko @ 2026-11-13 15:48 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini,
Baptiste Le Duc
Hi all,
This series adds the initial virtual interrupt controller (vINTC) support
for RISC-V guests in Xen, based on the Advanced Interrupt Architecture
(AIA): a virtual APLIC (vAPLIC) in MSI mode backed by a virtual IMSIC
(vIMSIC) using hardware guest interrupt files.
Rather than emulating APLIC in direct-delivery mode (which requires
trap-and-emulate for every interrupt and is costly), the series targets
IMSIC from the start. AIA lets a hart implement several "guest interrupt
files" (up to GEILEN), so external interrupts can be delivered to a vCPU
directly by hardware via the VGEIN field of hstatus, without a hypervisor
round-trip. Xen only has to emulate the APLIC MMIO programming interface
and route the guest's intent onto the physical MSI topology; interrupt
delivery itself stays in hardware. Interrupts of devices emulated by Xen
itself (virtual sources) are supported as well: vAPLIC keeps their state
and Xen injects their MSIs into the vCPU's guest interrupt file.
The work breaks down into a few logical blocks:
Self-contained preparatory patches (patches 1-6)
- A helper to test for APLIC MSI mode.
- Make csr_write64() take the CSR name without the CSR_ prefix
(MISRA C Rule 20.12), and add csr_volatile_read64() as its
counterpart, used for CSR_TIME so that get_cycles() no longer
truncates the time counter on RV32.
- Define the IPRIO field of the APLIC target register, and build the
physical APLIC's target hart index with aplic_hart_index(), dropping
the last in-tree duplicate of the AIA hart index formula.
- CPU_NONE as an explicit "no pCPU" marker instead of NR_CPUS.
None of these depends on the rest of the series, so they can go in
ahead of it.
MMIO emulation and vAPLIC (patches 7-10)
- A per-domain MMIO handler table modelled on Arm's framework, so
emulated devices self-register their GPA ranges and the fault path
stays agnostic via a single try_handle_mmio() entry point.
- Tell h/w vINTC sources (a physical IRQ is routed to them) from
virtual ones (driven by a device emulator in Xen) with a new
hw_irqs bitmap.
- vAPLIC MMIO read/write emulation for the h/w sources of the domain.
Writes are limited to the sources the domain owns, and target[]
writes are translated from virtual to physical hart/guest-file
indices. Only MSI delivery mode is emulated, and delegation
(sourcecfg.D) is not supported.
- Leave the h/w source of an IRQ routed to a guest Inactive, as the
guest configures it itself.
vCPU context switching (patches 11-13)
- context_switch() and the helpers it needs: save/restore of H/VS CSRs,
the virtual timer and P2M context, and __context_switch() in assembly.
The VMID is claimed in p2m_ctxt_switch_to() rather than at the next
guest entry.
- Save and restore the AIA CSRs a guest can change (vsiselect and
hviprio{1,2}), gated by hstateen0 where Smstateen is implemented.
- vintc_ctxt_switch_{from,to}() wrappers over new ctxt_switch_{from,to}
hooks in struct vintc_ops, called from the context switch path.
Trap and instruction emulation infrastructure (patches 14-22)
- Extend the exception-table format with type/data fields and add
EX_TYPE_TRAP_INFO so fixups can capture sepc/scause/stval.
- A guest page-fault handler, and trap_redirect() to forward a
synchronous trap back into the guest's VS-mode handler for the faults
which can never become an emulated access.
- Resolve the faulting guest physical address from htval and stval,
which first needs Shtvala to be detected.
- read_guest() (HLV/HLVX) to read guest memory and instructions
safely, the decoding helpers shared by both access types, and the load
and store emulation which dispatches the access through
try_handle_mmio().
vCPU bring-up (patches 23-29)
- Program hstatus.VSXL explicitly, as decoding a trapped instruction
depends on the effective XLEN of the guest.
- continue_new_vcpu(): switch to the idle vCPU's own stack for the idle
vCPU, and enter the guest through the new return_to_new_vcpu() path in
entry.S for a guest one.
- Per-pCPU VGEIN (guest interrupt file) allocator: a bitmap of the files
a hart implements (up to GEILEN) with helpers to assign and release
one, and an owners[] map so a file reported pending in HGEIP can be
traced back to the vCPU it belongs to.
- Stage-2 map a vCPU's physical guest interrupt file to the fixed
per-vCPU GPA page the guest expects, and vaplic_reconfigure_target()
to retarget the domain's h/w sources at a new file.
- imsic_vsfile_attach(), called once the pCPU a vCPU will run on is
known: it assigns a VGEIN, clears and maps the guest interrupt file
and records the IMSIC state as a consistent unit.
- Watch a descheduled vCPU's guest interrupt file through HGEIE, so that
a guest blocked on an external interrupt is woken up instead of
waiting for an unrelated event to schedule it again.
vCPU migration between pCPUs (patches 30-35)
- An APLIC-IMSIC-hart sync barrier, using an interrupt identity
reserved for Xen.
- The move of a vCPU's IMSIC guest interrupt file, following the
sequence the AIA spec prescribes: take, zero and G-stage map the new
file, retarget the domain's APLIC interrupts at it and fence off
straggler MSIs with the barrier, save and clear the old file (in a
single IPI to the pCPU owning it), then restore that state into the
new file and update the vCPU's hstatus.VGEIN.
- The move is done by the vCPU itself on its way back to the guest,
from check_for_pcpu_work() through a new vintc_ops.enter_guest hook,
rather than from arch_move_irqs() (see "Changes in v4" below).
Virtual interrupt sources (patches 36-42)
- vcpu_imsic_inject() to make an identity pending in a vCPU's guest
interrupt file from any pCPU, through its SETIPNUM_LE register, and
the synchronisation of such injections with a migration of the file.
- Emulate genmsi.
- Keep the guest's view of sourcecfg[], setie[]/clrie[] and
domaincfg.IE, which can now be cleared, for both kinds of source.
- Emulate target[], the pending bits and the MSIs of virtual sources,
and vintc_set_irq_level(), through which a device emulator drives
the line of its virtual source.
CI tests: https://gitlab.com/xen-project/people/olkur/xen/-/pipelines/3063920059
---
Changes in v4:
- Add support for virtual interrupts, i.e. interrupts of devices
emulated by Xen (patches 36-42). Could go separately as we don't really use
now virtual interrupts. It was tested based on Denis M's vuart framework +
some extra patch to make it work for RISC-V.
- Fix a race between the vCPU migration and the vCPU entering the guest
with a stale hstatus.VGEIN: the vCPU's guest interrupt file is now
moved by the vCPU itself right before entering the guest, rather than
from arch_move_irqs(). See "xen/riscv: move a vCPU's guest interrupt
file on its way to the guest" for details.
- Reorder the series: self-contained patches are moved to the beginning
(patches 1-6) to make them easier to merge, and vCPU bring-up now
comes before vCPU migration.
- Drop the patches which are already in staging.
- Address the comments from ML.
- The remaining changes are described in the per-patch changelogs.
---
Changes in v3:
- Address the comments from ML.
- New patches: "drop INSN_{16,32}BIT_MASK and report unknown instruction
lengths", "set the domain type for 64-bit kernel images" and
"introduce CPU_NONE" (used instead of NR_CPUS as "no CPU" marker).
- Drop patch series dependecny as it was merged to upstream/staging.
---
Changes in v2:
- The series has grown from 17 to 39 patches. vCPU context switching, vCPU
migration between pCPUs and the vCPU bring-up path (continue_new_vcpu(),
attaching an IMSIC h/w interrupt file) are now part of it to have better
context of how things are using, together with the trap-side pieces the
MMIO emulation depends on (faulting GPA resolution, Shtvala detection,
instruction decoding).
- vintc_state_{save,restore}() became vintc_ctxt_switch_{from,to}() and
vcpu_aia_init() became imsic_vsfile_attach(); "xen/riscv: manage
IRQ_DISABLED flag in APLIC irq enable/disable callbacks" is no longer part
of this series. The remaining changes are described in the per-patch
changelogs.
---
Oleksii Kurochko (42):
xen/riscv: add helper to check APLIC MSI mode
xen/riscv: address violation of MISRA C Rule 20.12 in csr_write64()
xen/riscv: introduce csr_volatile_read64()
xen/riscv: define the IPRIO field of the APLIC target register
xen/riscv: build the target hart index via aplic_hart_index()
xen/riscv: introduce CPU_NONE
xen/riscv: introduce device-agnostic MMIO emulation dispatch
xen/riscv: distinguish h/w and virtual vINTC sources
xen/riscv: implement virtual APLIC MMIO emulation
xen/riscv: leave the h/w source of an IRQ routed to a guest inactive
xen/riscv: implement vCPU context switching
xen/riscv: save and restore vsiselect on vCPU context switch
xen/riscv: introduce vintc_ctxt_switch_{from,to}()
xen/riscv: extend exception tables with type and data fields
xen/riscv: add guest page fault handling stub
xen/riscv: implement trap redirection to a guest
xen/riscv: detect Shtvala
xen/riscv: resolve the faulting guest physical address
xen/riscv: add guest memory read helper
xen/riscv: add helpers for decoding a trapped load or store
xen/riscv: add guest load emulation for trapped MMIO accesses
xen/riscv: add guest store emulation for trapped MMIO accesses
xen/riscv: set the guest's XLEN explicitly in hstatus.VSXL
xen/riscv: implement continue_new_vcpu()
xen/riscv: add basic VGEIN management for AIA guests
xen/riscv: map IMSIC interrupt file for vCPUs
xen/riscv: introduce vaplic_reconfigure_target()
xen/riscv: introduce IMSIC h/w interrupt file attaching to vcpu
xen/riscv: wake up a descheduled vCPU on a guest external interrupt
xen/riscv: implement APLIC-IMSIC-hart sync barrier for vCPU migration
xen/riscv: introduce imsic_migrate_vcpu()
xen/riscv: remap interrupts to new IMSIC VS-file
xen/riscv: save and clear the old IMSIC VS-file on vCPU migration
xen/riscv: restore register state in the new IMSIC VS-file
xen/riscv: move a vCPU's guest interrupt file on its way to the guest
xen/riscv: send MSIs to a vCPU's guest interrupt file
xen/riscv: sync with IMSIC VS-file injections on vCPU migration
xen/riscv: emulate the vAPLIC genmsi register
xen/riscv: emulate vAPLIC sourcecfg[], setie[] and domaincfg.IE
xen/riscv: emulate target[] of virtual vAPLIC sources
xen/riscv: emulate the pending bits and MSIs of virtual vAPLIC sources
xen/riscv: drive the line of a virtual vAPLIC source
docs/misc/riscv/booting.txt | 11 +
xen/arch/riscv/Makefile | 2 +
xen/arch/riscv/aia.c | 180 +++
xen/arch/riscv/aplic-priv.h | 2 +
xen/arch/riscv/aplic.c | 243 +++-
xen/arch/riscv/cpufeature.c | 1 +
xen/arch/riscv/device.c | 17 +-
xen/arch/riscv/domain-build.c | 8 +
xen/arch/riscv/domain.c | 341 +++++-
xen/arch/riscv/emulate.c | 582 +++++++++
xen/arch/riscv/entry.S | 87 ++
xen/arch/riscv/extable.c | 48 +-
xen/arch/riscv/guestcopy.c | 68 ++
xen/arch/riscv/imsic.c | 900 +++++++++++++-
xen/arch/riscv/include/asm/aia.h | 7 +
xen/arch/riscv/include/asm/aplic.h | 47 +-
xen/arch/riscv/include/asm/config.h | 3 +
xen/arch/riscv/include/asm/cpufeature.h | 1 +
xen/arch/riscv/include/asm/csr.h | 47 +-
xen/arch/riscv/include/asm/current.h | 6 +
xen/arch/riscv/include/asm/domain.h | 22 +-
xen/arch/riscv/include/asm/emulate.h | 10 +
xen/arch/riscv/include/asm/extable.h | 61 +-
xen/arch/riscv/include/asm/gpr-num.h | 53 +
xen/arch/riscv/include/asm/guest_access.h | 28 +
xen/arch/riscv/include/asm/imsic.h | 58 +-
xen/arch/riscv/include/asm/intc.h | 34 +-
xen/arch/riscv/include/asm/irq.h | 5 +-
xen/arch/riscv/include/asm/mmio.h | 48 +
xen/arch/riscv/include/asm/p2m.h | 1 -
xen/arch/riscv/include/asm/processor.h | 14 +-
xen/arch/riscv/include/asm/regs.h | 23 +-
xen/arch/riscv/include/asm/riscv_encoding.h | 28 +-
xen/arch/riscv/include/asm/setup.h | 2 +
xen/arch/riscv/include/asm/smp.h | 2 +-
xen/arch/riscv/include/asm/system.h | 3 +
xen/arch/riscv/include/asm/time.h | 4 +-
xen/arch/riscv/include/asm/traps.h | 9 +
xen/arch/riscv/include/asm/vaplic.h | 66 +
xen/arch/riscv/intc.c | 76 +-
xen/arch/riscv/irq.c | 2 +-
xen/arch/riscv/mmio.c | 205 ++++
xen/arch/riscv/p2m.c | 157 ++-
xen/arch/riscv/riscv64/asm-offsets.c | 19 +-
xen/arch/riscv/setup.c | 2 +
xen/arch/riscv/smp.c | 4 +-
xen/arch/riscv/stubs.c | 5 -
xen/arch/riscv/time.c | 4 +-
xen/arch/riscv/traps.c | 91 +-
xen/arch/riscv/vaplic.c | 1201 ++++++++++++++++++-
50 files changed, 4659 insertions(+), 179 deletions(-)
create mode 100644 xen/arch/riscv/emulate.c
create mode 100644 xen/arch/riscv/include/asm/emulate.h
create mode 100644 xen/arch/riscv/include/asm/gpr-num.h
create mode 100644 xen/arch/riscv/include/asm/mmio.h
create mode 100644 xen/arch/riscv/mmio.c
--
2.56.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-11-13 15:49 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-13 15:48 [PATCH v4 00/42] [RISC-V] virtual interrupt controller (vAPLIC/vIMSIC) support Oleksii Kurochko
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.