|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH v1 19/26] xen/arm: io: add register-backed MMIO emulation helpers
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 <den@xxxxxxxxxxxxx>
---
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |