[PATCH v2 26/39] xen/riscv: add guest store emulation for trapped MMIO accesses
Oleksii Kurochko <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <230c35550edff0b2b8480b6728614305951fe5cd.1787838835.git.oleksii.kurochko@gmail.com> |
Extend the guest page fault handler with store emulation to support MMIO write accesses. The instruction decode mirrors emulate_load() and, like it, is adapted from Linux's KVM RISC-V implementation. As with the load path, the completion is synchronous through try_handle_mmio() rather than KVM's userspace exit/return split, since Xen's MMIO handlers run in the hypervisor. Faults taken while re-reading the trapped instruction are handled by decode_ldst_insn(), shared with the load path. When a guest store instruction faults, the trapped instruction is decoded using HTINST or, if unavailable, fetched via unprivileged access. At the moment only virtual interrupt controller (vINTC) traps are expected to occur, since it is currently the only backend registered with the MMIO handler dispatch, so in practice the store is emulated via the vINTC backend. Together with load emulation, this completes the basic MMIO handling path needed for virtual interrupt controller support on RISC-V. Signed-off-by: Oleksii Kurochko <[email protected]> --- Changes in v2: - Move the emulation code to the new arch/riscv/emulate.c, leaving traps.c with trap dispatch only. - Split the patch up: the instruction fetch and the mask/match chain now live in "xen/riscv: add helpers for decoding a trapped load or store" (struct decoded_insn, insn_fetch_faulted(), decode_ldst_insn(), guest_gpr(), advance_pc()), so only emulate_store() itself is left here. - Since the decoder is now shared with the load path, reject an encoding which is not a store (!di.is_write) explicitly; in v2 the mask/match chain was store-only and could not match a load. - Recognize the XLEN=64-only encodings by the guest's effective XLEN (guest_xlen()) rather than by Xen's own (CONFIG_RISCV_32). Besides those encodings simply being reserved on RV32, the compressed ones are ambiguous there: C.SD and C.FSW share an encoding, and likewise C.SDSP and C.FSWSP. - Read the source register through guest_gpr() instead of the GET_RS2()/GET_RS2S()/GET_RS2C() macros; which of the three register fields an encoding names is now decided by decode_ldst_insn(). - Take the faulting address from struct guest_fault, filled in by resolve_faulting_gpa(), rather than from the fault_addr parameter. - Drop the description of a fault taken while re-reading the trapped instruction: that code is now in the patch adding the decoding helpers, where a G-stage fault is reported to the guest as CAUSE_FETCH_ACCESS. - Update the commit message accordingly. --- --- xen/arch/riscv/emulate.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/xen/arch/riscv/emulate.c b/xen/arch/riscv/emulate.c index e52f2851800c..1535b843525e 100644 --- a/xen/arch/riscv/emulate.c +++ b/xen/arch/riscv/emulate.c @@ -453,9 +453,28 @@ static int emulate_load(const struct guest_fault *gf) return 0; } -static int emulate_store(struct guest_fault *gf) +static int emulate_store(const struct guest_fault *gf) { - return -EOPNOTSUPP; + struct cpu_user_regs *regs = gf->regs; + mmio_info_t info = { .is_write = true }; + struct decoded_insn di; + int rc; + + if ( insn_fetch_faulted(gf, &di) ) + return 0; + + if ( !decode_ldst_insn(&di, guest_xlen(regs)) || !di.is_write ) + return -EOPNOTSUPP; + + info.data = *guest_gpr(regs, di.reg); + + rc = do_mmio(&info, gf->gpa, di.len); + if ( rc ) + return rc; + + advance_pc(regs, di.insn_len); + + return 0; } static void inject_access_fault(const struct guest_fault *gf) -- 2.55.0