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
