[PATCH v2 21/39] xen/riscv: resolve the faulting guest physical address
Oleksii Kurochko <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <c7975a131c229c721b2d4fe81c13fecd8deb4329.1787838835.git.oleksii.kurochko@gmail.com> |
Take the guest physical address from htval and stval: on a guest-page fault htval holds it shifted right by 2, so that an address wider than XLEN fits, and stval holds the faulting guest virtual address, whose two least significant bits are those of the guest physical address. The shift is done on paddr_t rather than on the raw register: a guest physical address is 34 bits wide on RV32 with Sv32x4, so shifting an XLEN-wide value would drop its top two bits. Those two low bits come from stval only for a fault on an explicit access. Where one is taken on an implicit access made for VS-stage translation htval holds the address of the VS-stage PTE which could not be read, while stval still holds the guest virtual address which started the walk, and the low bits of the address written to htval are zero instead. htinst tells the two apart, which is what the spec points at it for. stval needs no check against an ISA extension: a guest-page fault writes it with the faulting guest virtual address regardless. Sstvala would not be the right thing to test for either (it covers stval across every trap type which writes it, a wider guarantee than what is needed here). htval does need one. The H extension lets an implementation write it with either the faulting address or zero, so without Shtvala a zero htval cannot be told apart from a genuine fault on guest physical address 0-3, and the address has to be recovered by decoding the access and walking the VS-stage page tables in software instead. That is left as a TODO, and until it is written such hardware panics rather than acting on an address which may not be the one which faulted. Signed-off-by: Oleksii Kurochko <[email protected]> --- Changes in v2: - New patch. --- --- 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 f9da0751049c..ff530ef2df74 100644 --- a/xen/arch/riscv/emulate.c +++ b/xen/arch/riscv/emulate.c @@ -9,6 +9,7 @@ #include <xen/sched.h> #include <xen/types.h> +#include <asm/cpufeature.h> #include <asm/csr.h> #include <asm/current.h> #include <asm/emulate.h> @@ -62,10 +63,28 @@ static bool htinst_is_pseudo(unsigned long htinst) } } -/* Reconstruct the guest physical address of the access which faulted. */ +/* Resolves the guest physical address the access faulted on into @gf->gpa. */ static void resolve_faulting_gpa(struct guest_fault *gf) { - BUG_ON("unimplemented"); + /* + * A zero htval is either a genuine fault on guest physical address 0-3, or + * an implementation which does not report the address at all; only Shtvala + * tells the two apart. + * + * TODO: where it is absent, recover the address in software rather than + * giving up. + */ + if ( !gf->htval && + !riscv_isa_extension_available(NULL, RISCV_ISA_EXT_shtvala) ) + panic("Shtvala isn't supported by h/w; s/w VS-stage walk required\n"); + + /* + * htval does not carry the two low bits of the address: for an explicit + * access they are those of the faulting guest virtual address in stval, + * and for an implicit access made for VS-stage translation they are zero. + */ + gf->gpa = ((paddr_t)gf->htval << 2) | + (htinst_is_pseudo(gf->htinst) ? 0 : (gf->stval & 3)); } static int emulate_load(const struct guest_fault *gf) -- 2.55.0