@@ -94,6 +94,26 @@ static const struct hvm_io_handler null_handler = {
.ops = &null_ops
};
+static int ioreq_server_read(const struct hvm_io_handler *io_handler,
+ uint64_t addr,
+ uint32_t size,
+ uint64_t *data)
+{
+ if ( hvm_copy_from_guest_phys(data, addr, size) != HVMCOPY_okay )
+ return X86EMUL_UNHANDLEABLE;
+
+ return X86EMUL_OKAY;
+}
+
+static const struct hvm_io_ops ioreq_server_ops = {
+ .read = ioreq_server_read,
+ .write = null_write
+};
+
+static const struct hvm_io_handler ioreq_server_handler = {
+ .ops = &ioreq_server_ops
+};
+
static int hvmemul_do_io(
bool_t is_mmio, paddr_t addr, unsigned long *reps, unsigned int size,
uint8_t dir, bool_t df, bool_t data_is_addr, uintptr_t data)
@@ -197,6 +217,10 @@ static int hvmemul_do_io(
* - If the IOREQ_MEM_ACCESS_WRITE flag is not set, treat it
* like a normal PIO or MMIO that doesn't have an ioreq
* server (i.e., by ignoring it).
+ *
+ * - If the accesss is a read, this could be part of a
+ * read-modify-write instruction, emulate the read so that we
+ * have it.
*/
struct hvm_ioreq_server *s = NULL;
p2m_type_t p2mt = p2m_invalid;
@@ -226,6 +250,17 @@ static int hvmemul_do_io(
}
/*
+ * This is part of a read-modify-write instruction.
+ * Emulate the read part so we have the value cached.
+ */
+ if ( dir == IOREQ_READ )
+ {
+ rc = hvm_process_io_intercept(&ioreq_server_handler, &p);
+ vio->io_req.state = STATE_IOREQ_NONE;
+ break;
+ }
+
+ /*
* If the IOREQ_MEM_ACCESS_WRITE flag is not set,
* we should set s to NULL, and just ignore such
* access.