Allow the Arm MMIO emulator to use a caller-provided register backend.
Realm exits carry GPR state in RecRun, not in guest_cpu_user_regs().

Signed-off-by: Koichiro Den <[email protected]>
---
 xen/arch/arm/include/asm/mmio.h | 11 ++++
 xen/arch/arm/io.c               | 99 +++++++++++++++++++++++++--------
 2 files changed, 88 insertions(+), 22 deletions(-)

diff --git a/xen/arch/arm/include/asm/mmio.h b/xen/arch/arm/include/asm/mmio.h
index b22cfdac5be9..b8a640dc6ee7 100644
--- a/xen/arch/arm/include/asm/mmio.h
+++ b/xen/arch/arm/include/asm/mmio.h
@@ -62,6 +62,14 @@ typedef int (*mmio_read_t)(struct vcpu *v, mmio_info_t *info,
 typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info,
                             register_t r, void *priv);
 
+typedef register_t (*mmio_reg_read_t)(void *ctxt, int reg);
+typedef void (*mmio_reg_write_t)(void *ctxt, int reg, register_t value);
+
+struct mmio_regops {
+    mmio_reg_read_t read;
+    mmio_reg_write_t write;
+};
+
 struct mmio_handler_ops {
     mmio_read_t read;
     mmio_write_t write;
@@ -83,6 +91,9 @@ struct vmmio {
 
 enum io_state try_handle_mmio(struct cpu_user_regs *regs,
                               mmio_info_t *info);
+enum io_state try_handle_mmio_regops(struct vcpu *v, mmio_info_t *info,
+                                     const struct mmio_regops *regops,
+                                     void *ctxt);
 void register_mmio_handler(struct domain *d,
                            const struct mmio_handler_ops *ops,
                            paddr_t addr, paddr_t size, void *priv);
diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
index 9707cadcf80e..9ce9fe1c1528 100644
--- a/xen/arch/arm/io.c
+++ b/xen/arch/arm/io.c
@@ -47,12 +47,36 @@ static const struct mmio_handler unmapped_handler = {
     .ops = &unmapped_ops
 };
 
+struct mmio_guest_regs {
+    struct cpu_user_regs *regs;
+};
+
+static register_t mmio_guest_read_reg(void *ctxt, int reg)
+{
+    struct mmio_guest_regs *guest = ctxt;
+
+    return get_user_reg(guest->regs, reg);
+}
+
+static void mmio_guest_write_reg(void *ctxt, int reg, register_t value)
+{
+    struct mmio_guest_regs *guest = ctxt;
+
+    set_user_reg(guest->regs, reg, value);
+}
+
+static const struct mmio_regops mmio_guest_regops = {
+    .read = mmio_guest_read_reg,
+    .write = mmio_guest_write_reg,
+};
+
 static enum io_state handle_read(const struct mmio_handler *handler,
                                  struct vcpu *v,
-                                 mmio_info_t *info)
+                                 mmio_info_t *info,
+                                 const struct mmio_regops *regops,
+                                 void *ctxt)
 {
     const struct hsr_dabt dabt = info->dabt;
-    struct cpu_user_regs *regs = guest_cpu_user_regs();
     /*
      * Initialize to zero to avoid leaking data if there is an
      * implementation error in the emulation (such as not correctly
@@ -66,22 +90,24 @@ static enum io_state handle_read(const struct mmio_handler 
*handler,
     ASSERT((r & ~GENMASK((1U << info->dabt.size) * 8 - 1, 0)) == 0);
 
     r = sign_extend(dabt, r);
-
-    set_user_reg(regs, dabt.reg, r);
+    regops->write(ctxt, dabt.reg, r);
 
     return IO_HANDLED;
 }
 
 static enum io_state handle_write(const struct mmio_handler *handler,
                                   struct vcpu *v,
-                                  mmio_info_t *info)
+                                  mmio_info_t *info,
+                                  const struct mmio_regops *regops,
+                                  void *ctxt)
 {
     const struct hsr_dabt dabt = info->dabt;
-    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t value;
     int ret;
 
-    ret = handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
-                              handler->priv);
+    value = regops->read(ctxt, dabt.reg);
+    ret = handler->ops->write(v, info, value, handler->priv);
+
     return ret ? IO_HANDLED : IO_ABORT;
 }
 
@@ -183,10 +209,13 @@ void try_decode_instruction(const struct cpu_user_regs 
*regs,
     }
 }
 
-enum io_state try_handle_mmio(struct cpu_user_regs *regs,
-                              mmio_info_t *info)
+static enum io_state __try_handle_mmio(struct vcpu *v,
+                                       struct cpu_user_regs *regs,
+                                       mmio_info_t *info,
+                                       const struct mmio_regops *regops,
+                                       void *ctxt,
+                                       bool allow_ioreq)
 {
-    struct vcpu *v = current;
     const struct mmio_handler *handler = NULL;
     int rc;
 
@@ -202,17 +231,22 @@ enum io_state try_handle_mmio(struct cpu_user_regs *regs,
     if ( !handler )
     {
         bool trap_unmapped = v->domain->options &
-                                         XEN_DOMCTL_CDF_trap_unmapped_accesses;
-        rc = try_fwd_ioserv(regs, v, info);
-        if ( rc == IO_HANDLED )
-            return handle_ioserv(regs, v);
-        else if ( rc == IO_UNHANDLED && !trap_unmapped )
+                             XEN_DOMCTL_CDF_trap_unmapped_accesses;
+
+        if ( allow_ioreq )
         {
-            /* Fallback to the unmapped handler. */
-            handler = &unmapped_handler;
-        } else {
-            return rc;
+            rc = try_fwd_ioserv(regs, v, info);
+            if ( rc == IO_HANDLED )
+                return handle_ioserv(regs, v);
+            else if ( rc != IO_UNHANDLED )
+                return rc;
         }
+
+        if ( trap_unmapped )
+            return IO_UNHANDLED;
+
+        /* Fallback to the unmapped handler. */
+        handler = &unmapped_handler;
     }
 
     /*
@@ -228,9 +262,30 @@ enum io_state try_handle_mmio(struct cpu_user_regs *regs,
      * instruction on the emulated MMIO region.
      */
     if ( info->dabt.write )
-        return handle_write(handler, v, info);
+        return handle_write(handler, v, info, regops, ctxt);
     else
-        return handle_read(handler, v, info);
+        return handle_read(handler, v, info, regops, ctxt);
+}
+
+enum io_state try_handle_mmio(struct cpu_user_regs *regs,
+                              mmio_info_t *info)
+{
+    struct mmio_guest_regs guest = { .regs = regs };
+
+    return __try_handle_mmio(current, regs, info, &mmio_guest_regops,
+                             &guest, true);
+}
+
+enum io_state try_handle_mmio_regops(struct vcpu *v, mmio_info_t *info,
+                                     const struct mmio_regops *regops,
+                                     void *ctxt)
+{
+    ASSERT(v != NULL);
+    ASSERT(regops != NULL);
+    ASSERT(regops->read != NULL);
+    ASSERT(regops->write != NULL);
+
+    return __try_handle_mmio(v, NULL, info, regops, ctxt, false);
 }
 
 void register_mmio_handler(struct domain *d,
-- 
2.51.0


Reply via email to