#include "decode.h"
-static int handle_read(const struct mmio_handler *handler, struct vcpu *v,
- mmio_info_t *info)
+static enum io_state handle_read(const struct mmio_handler *handler,
+ struct vcpu *v,
+ mmio_info_t *info)
{
const struct hsr_dabt dabt = info->dabt;
struct cpu_user_regs *regs = guest_cpu_user_regs();
uint8_t size = (1 << dabt.size) * 8;
if ( !handler->ops->read(v, info, &r, handler->priv) )
- return 0;
+ return IO_ABORT;
/*
* Sign extend if required.
set_user_reg(regs, dabt.reg, r);
- return 1;
+ return IO_HANDLED;
}
-static int handle_write(const struct mmio_handler *handler, struct vcpu *v,
- mmio_info_t *info)
+static enum io_state handle_write(const struct mmio_handler *handler,
+ struct vcpu *v,
+ mmio_info_t *info)
{
const struct hsr_dabt dabt = info->dabt;
struct cpu_user_regs *regs = guest_cpu_user_regs();
+ int ret;
- return handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
- handler->priv);
+ ret = handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
+ handler->priv);
+ return ret ? IO_HANDLED : IO_ABORT;
}
/* This function assumes that mmio regions are not overlapped */
return handler;
}
-int try_handle_mmio(struct cpu_user_regs *regs,
- const union hsr hsr,
- paddr_t gpa)
+enum io_state try_handle_mmio(struct cpu_user_regs *regs,
+ const union hsr hsr,
+ paddr_t gpa)
{
struct vcpu *v = current;
const struct mmio_handler *handler = NULL;
handler = find_mmio_handler(v->domain, info.gpa);
if ( !handler )
- return 0;
+ return IO_UNHANDLED;
/* All the instructions used on emulated MMIO region should be valid */
if ( !dabt.valid )
- return 0;
+ return IO_ABORT;
/*
* Erratum 766422: Thumb store translation fault to Hypervisor may
if ( rc )
{
gprintk(XENLOG_DEBUG, "Unable to decode instruction\n");
- return 0;
+ return IO_ABORT;
}
}
*
* Note that emulated region cannot be executed
*/
- if ( is_data && try_handle_mmio(regs, hsr, gpa) )
+ if ( is_data )
{
- advance_pc(regs, hsr);
- return;
+ enum io_state state = try_handle_mmio(regs, hsr, gpa);
+
+ switch ( state )
+ {
+ case IO_ABORT:
+ goto inject_abt;
+ case IO_HANDLED:
+ advance_pc(regs, hsr);
+ return;
+ case IO_UNHANDLED:
+ /* IO unhandled, try another way to handle it. */
+ break;
+ }
}
/*
hsr.bits, xabt.fsc);
}
+inject_abt:
gdprintk(XENLOG_DEBUG, "HSR=0x%x pc=%#"PRIregister" gva=%#"PRIvaddr
" gpa=%#"PRIpaddr"\n", hsr.bits, regs->pc, gva, gpa);
if ( is_data )
paddr_t gpa;
} mmio_info_t;
+enum io_state
+{
+ IO_ABORT, /* The IO was handled by the helper and led to an abort. */
+ IO_HANDLED, /* The IO was successfully handled by the helper. */
+ IO_UNHANDLED, /* The IO was not handled by the helper. */
+};
+
typedef int (*mmio_read_t)(struct vcpu *v, mmio_info_t *info,
register_t *r, void *priv);
typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info,
struct mmio_handler *handlers;
};
-int try_handle_mmio(struct cpu_user_regs *regs,
- const union hsr hsr,
- paddr_t gpa);
+enum io_state try_handle_mmio(struct cpu_user_regs *regs,
+ const union hsr hsr,
+ paddr_t gpa);
void register_mmio_handler(struct domain *d,
const struct mmio_handler_ops *ops,
paddr_t addr, paddr_t size, void *priv);