[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.