aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/io.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-02-20 14:36:45 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-02-20 14:36:45 +0000
commit3bb4f99d8cec90c3d7731d004333dd03998e2287 (patch)
tree106e622cfc9218e44d1c25a29c3409172a55acb0 /xen/arch/x86/hvm/io.c
parent10d08139c54258700129aebe4193b86efdd94f13 (diff)
downloadxen-3bb4f99d8cec90c3d7731d004333dd03998e2287.tar.gz
xen-3bb4f99d8cec90c3d7731d004333dd03998e2287.tar.bz2
xen-3bb4f99d8cec90c3d7731d004333dd03998e2287.zip
x86 hvm: Replace old MMIO emulator with x86_emulate()-based harness.
Re-factor VMX real-mode emulation to use the same harness. Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/hvm/io.c')
-rw-r--r--xen/arch/x86/hvm/io.c721
1 files changed, 16 insertions, 705 deletions
diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
index 178e6891c8..97ebfd0fff 100644
--- a/xen/arch/x86/hvm/io.c
+++ b/xen/arch/x86/hvm/io.c
@@ -46,379 +46,8 @@
#include <xen/iocap.h>
#include <public/hvm/ioreq.h>
-#if defined (__i386__)
-static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value)
-{
- switch (size) {
- case BYTE:
- switch (index) {
- case 0:
- regs->eax &= 0xFFFFFF00;
- regs->eax |= (value & 0xFF);
- break;
- case 1:
- regs->ecx &= 0xFFFFFF00;
- regs->ecx |= (value & 0xFF);
- break;
- case 2:
- regs->edx &= 0xFFFFFF00;
- regs->edx |= (value & 0xFF);
- break;
- case 3:
- regs->ebx &= 0xFFFFFF00;
- regs->ebx |= (value & 0xFF);
- break;
- case 4:
- regs->eax &= 0xFFFF00FF;
- regs->eax |= ((value & 0xFF) << 8);
- break;
- case 5:
- regs->ecx &= 0xFFFF00FF;
- regs->ecx |= ((value & 0xFF) << 8);
- break;
- case 6:
- regs->edx &= 0xFFFF00FF;
- regs->edx |= ((value & 0xFF) << 8);
- break;
- case 7:
- regs->ebx &= 0xFFFF00FF;
- regs->ebx |= ((value & 0xFF) << 8);
- break;
- default:
- goto crash;
- }
- break;
- case WORD:
- switch (index) {
- case 0:
- regs->eax &= 0xFFFF0000;
- regs->eax |= (value & 0xFFFF);
- break;
- case 1:
- regs->ecx &= 0xFFFF0000;
- regs->ecx |= (value & 0xFFFF);
- break;
- case 2:
- regs->edx &= 0xFFFF0000;
- regs->edx |= (value & 0xFFFF);
- break;
- case 3:
- regs->ebx &= 0xFFFF0000;
- regs->ebx |= (value & 0xFFFF);
- break;
- case 4:
- regs->esp &= 0xFFFF0000;
- regs->esp |= (value & 0xFFFF);
- break;
- case 5:
- regs->ebp &= 0xFFFF0000;
- regs->ebp |= (value & 0xFFFF);
- break;
- case 6:
- regs->esi &= 0xFFFF0000;
- regs->esi |= (value & 0xFFFF);
- break;
- case 7:
- regs->edi &= 0xFFFF0000;
- regs->edi |= (value & 0xFFFF);
- break;
- default:
- goto crash;
- }
- break;
- case LONG:
- switch (index) {
- case 0:
- regs->eax = value;
- break;
- case 1:
- regs->ecx = value;
- break;
- case 2:
- regs->edx = value;
- break;
- case 3:
- regs->ebx = value;
- break;
- case 4:
- regs->esp = value;
- break;
- case 5:
- regs->ebp = value;
- break;
- case 6:
- regs->esi = value;
- break;
- case 7:
- regs->edi = value;
- break;
- default:
- goto crash;
- }
- break;
- default:
- crash:
- gdprintk(XENLOG_ERR, "size:%x, index:%x are invalid!\n", size, index);
- domain_crash_synchronous();
- }
-}
-#else
-static inline void __set_reg_value(unsigned long *reg, int size, long value)
-{
- switch (size) {
- case BYTE_64:
- *reg &= ~0xFF;
- *reg |= (value & 0xFF);
- break;
- case WORD:
- *reg &= ~0xFFFF;
- *reg |= (value & 0xFFFF);
- break;
- case LONG:
- *reg &= ~0xFFFFFFFF;
- *reg |= (value & 0xFFFFFFFF);
- break;
- case QUAD:
- *reg = value;
- break;
- default:
- gdprintk(XENLOG_ERR, "size:%x is invalid\n", size);
- domain_crash_synchronous();
- }
-}
-
-static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value)
-{
- if (size == BYTE) {
- switch (index) {
- case 0:
- regs->rax &= ~0xFF;
- regs->rax |= (value & 0xFF);
- break;
- case 1:
- regs->rcx &= ~0xFF;
- regs->rcx |= (value & 0xFF);
- break;
- case 2:
- regs->rdx &= ~0xFF;
- regs->rdx |= (value & 0xFF);
- break;
- case 3:
- regs->rbx &= ~0xFF;
- regs->rbx |= (value & 0xFF);
- break;
- case 4:
- regs->rax &= 0xFFFFFFFFFFFF00FF;
- regs->rax |= ((value & 0xFF) << 8);
- break;
- case 5:
- regs->rcx &= 0xFFFFFFFFFFFF00FF;
- regs->rcx |= ((value & 0xFF) << 8);
- break;
- case 6:
- regs->rdx &= 0xFFFFFFFFFFFF00FF;
- regs->rdx |= ((value & 0xFF) << 8);
- break;
- case 7:
- regs->rbx &= 0xFFFFFFFFFFFF00FF;
- regs->rbx |= ((value & 0xFF) << 8);
- break;
- default:
- gdprintk(XENLOG_ERR, "size:%x, index:%x are invalid!\n",
- size, index);
- domain_crash_synchronous();
- break;
- }
- return;
- }
-
- switch (index) {
- case 0:
- __set_reg_value(&regs->rax, size, value);
- break;
- case 1:
- __set_reg_value(&regs->rcx, size, value);
- break;
- case 2:
- __set_reg_value(&regs->rdx, size, value);
- break;
- case 3:
- __set_reg_value(&regs->rbx, size, value);
- break;
- case 4:
- __set_reg_value(&regs->rsp, size, value);
- break;
- case 5:
- __set_reg_value(&regs->rbp, size, value);
- break;
- case 6:
- __set_reg_value(&regs->rsi, size, value);
- break;
- case 7:
- __set_reg_value(&regs->rdi, size, value);
- break;
- case 8:
- __set_reg_value(&regs->r8, size, value);
- break;
- case 9:
- __set_reg_value(&regs->r9, size, value);
- break;
- case 10:
- __set_reg_value(&regs->r10, size, value);
- break;
- case 11:
- __set_reg_value(&regs->r11, size, value);
- break;
- case 12:
- __set_reg_value(&regs->r12, size, value);
- break;
- case 13:
- __set_reg_value(&regs->r13, size, value);
- break;
- case 14:
- __set_reg_value(&regs->r14, size, value);
- break;
- case 15:
- __set_reg_value(&regs->r15, size, value);
- break;
- default:
- gdprintk(XENLOG_ERR, "Invalid index\n");
- domain_crash_synchronous();
- }
- return;
-}
-#endif
-
-long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs);
-
-static inline void set_eflags_CF(int size,
- unsigned int instr,
- unsigned long result,
- unsigned long src,
- unsigned long dst,
- struct cpu_user_regs *regs)
-{
- unsigned long mask;
-
- if ( size == BYTE_64 )
- size = BYTE;
- ASSERT((size <= sizeof(mask)) && (size > 0));
-
- mask = ~0UL >> (8 * (sizeof(mask) - size));
-
- if ( instr == INSTR_ADD )
- {
- /* CF=1 <==> result is less than the augend and addend) */
- if ( (result & mask) < (dst & mask) )
- {
- ASSERT((result & mask) < (src & mask));
- regs->eflags |= X86_EFLAGS_CF;
- }
- }
- else
- {
- ASSERT( instr == INSTR_CMP || instr == INSTR_SUB );
- if ( (src & mask) > (dst & mask) )
- regs->eflags |= X86_EFLAGS_CF;
- }
-}
-
-static inline void set_eflags_OF(int size,
- unsigned int instr,
- unsigned long result,
- unsigned long src,
- unsigned long dst,
- struct cpu_user_regs *regs)
-{
- unsigned long mask;
-
- if ( size == BYTE_64 )
- size = BYTE;
- ASSERT((size <= sizeof(mask)) && (size > 0));
-
- mask = 1UL << ((8*size) - 1);
-
- if ( instr == INSTR_ADD )
- {
- if ((src ^ result) & (dst ^ result) & mask);
- regs->eflags |= X86_EFLAGS_OF;
- }
- else
- {
- ASSERT(instr == INSTR_CMP || instr == INSTR_SUB);
- if ((dst ^ src) & (dst ^ result) & mask)
- regs->eflags |= X86_EFLAGS_OF;
- }
-}
-
-static inline void set_eflags_AF(int size,
- unsigned long result,
- unsigned long src,
- unsigned long dst,
- struct cpu_user_regs *regs)
-{
- if ((result ^ src ^ dst) & 0x10)
- regs->eflags |= X86_EFLAGS_AF;
-}
-
-static inline void set_eflags_ZF(int size, unsigned long result,
- struct cpu_user_regs *regs)
-{
- unsigned long mask;
-
- if ( size == BYTE_64 )
- size = BYTE;
- ASSERT((size <= sizeof(mask)) && (size > 0));
-
- mask = ~0UL >> (8 * (sizeof(mask) - size));
-
- if ((result & mask) == 0)
- regs->eflags |= X86_EFLAGS_ZF;
-}
-
-static inline void set_eflags_SF(int size, unsigned long result,
- struct cpu_user_regs *regs)
-{
- unsigned long mask;
-
- if ( size == BYTE_64 )
- size = BYTE;
- ASSERT((size <= sizeof(mask)) && (size > 0));
-
- mask = 1UL << ((8*size) - 1);
-
- if (result & mask)
- regs->eflags |= X86_EFLAGS_SF;
-}
-
-static char parity_table[256] = {
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
- 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
-};
-
-static inline void set_eflags_PF(int size, unsigned long result,
- struct cpu_user_regs *regs)
-{
- if (parity_table[result & 0xFF])
- regs->eflags |= X86_EFLAGS_PF;
-}
-
-static void hvm_pio_assist(struct cpu_user_regs *regs, ioreq_t *p,
- struct hvm_io_op *pio_opp)
+static void hvm_pio_assist(
+ struct cpu_user_regs *regs, ioreq_t *p, struct hvm_io_op *pio_opp)
{
if ( p->data_is_ptr || (pio_opp->flags & OVERLAP) )
{
@@ -472,335 +101,6 @@ static void hvm_pio_assist(struct cpu_user_regs *regs, ioreq_t *p,
}
}
-static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
- struct hvm_io_op *mmio_opp)
-{
- int sign = p->df ? -1 : 1;
- int size = -1, index = -1;
- unsigned long value = 0, result = 0;
- unsigned long src, dst;
-
- src = mmio_opp->operand[0];
- dst = mmio_opp->operand[1];
- size = operand_size(src);
-
- HVMTRACE_1D(MMIO_ASSIST, current, p->data);
-
- switch (mmio_opp->instr) {
- case INSTR_MOV:
- if (dst & REGISTER) {
- index = operand_index(dst);
- set_reg_value(size, index, 0, regs, p->data);
- }
- break;
-
- case INSTR_MOVZX:
- if (dst & REGISTER) {
- switch (size) {
- case BYTE:
- p->data &= 0xFFULL;
- break;
-
- case WORD:
- p->data &= 0xFFFFULL;
- break;
-
- case LONG:
- p->data &= 0xFFFFFFFFULL;
- break;
-
- default:
- printk("Impossible source operand size of movzx instr: %d\n", size);
- domain_crash_synchronous();
- }
- index = operand_index(dst);
- set_reg_value(operand_size(dst), index, 0, regs, p->data);
- }
- break;
-
- case INSTR_MOVSX:
- if (dst & REGISTER) {
- switch (size) {
- case BYTE:
- p->data &= 0xFFULL;
- if ( p->data & 0x80ULL )
- p->data |= 0xFFFFFFFFFFFFFF00ULL;
- break;
-
- case WORD:
- p->data &= 0xFFFFULL;
- if ( p->data & 0x8000ULL )
- p->data |= 0xFFFFFFFFFFFF0000ULL;
- break;
-
- case LONG:
- p->data &= 0xFFFFFFFFULL;
- if ( p->data & 0x80000000ULL )
- p->data |= 0xFFFFFFFF00000000ULL;
- break;
-
- default:
- printk("Impossible source operand size of movsx instr: %d\n", size);
- domain_crash_synchronous();
- }
- index = operand_index(dst);
- set_reg_value(operand_size(dst), index, 0, regs, p->data);
- }
- break;
-
- case INSTR_MOVS:
- sign = p->df ? -1 : 1;
-
- if (mmio_opp->flags & REPZ)
- regs->ecx -= p->count;
-
- if ((mmio_opp->flags & OVERLAP) && p->dir == IOREQ_READ) {
- unsigned long addr = mmio_opp->addr;
-
- if (hvm_paging_enabled(current))
- {
- int rv = hvm_copy_to_guest_virt(addr, &p->data, p->size);
- if ( rv == HVMCOPY_bad_gva_to_gfn )
- return; /* exception already injected */
- }
- else
- (void)hvm_copy_to_guest_phys(addr, &p->data, p->size);
- }
-
- regs->esi += sign * p->count * p->size;
- regs->edi += sign * p->count * p->size;
-
- break;
-
- case INSTR_STOS:
- sign = p->df ? -1 : 1;
- regs->edi += sign * p->count * p->size;
- if (mmio_opp->flags & REPZ)
- regs->ecx -= p->count;
- break;
-
- case INSTR_LODS:
- set_reg_value(size, 0, 0, regs, p->data);
- sign = p->df ? -1 : 1;
- regs->esi += sign * p->count * p->size;
- if (mmio_opp->flags & REPZ)
- regs->ecx -= p->count;
- break;
-
- case INSTR_AND:
- if (src & REGISTER) {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data & value;
- } else if (src & IMMEDIATE) {
- value = mmio_opp->immediate;
- result = (unsigned long) p->data & value;
- } else if (src & MEMORY) {
- index = operand_index(dst);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data & value;
- set_reg_value(size, index, 0, regs, result);
- }
-
- /*
- * The OF and CF flags are cleared; the SF, ZF, and PF
- * flags are set according to the result. The state of
- * the AF flag is undefined.
- */
- regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|
- X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- set_eflags_ZF(size, result, regs);
- set_eflags_SF(size, result, regs);
- set_eflags_PF(size, result, regs);
- break;
-
- case INSTR_ADD:
- if (src & REGISTER) {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data + value;
- } else if (src & IMMEDIATE) {
- value = mmio_opp->immediate;
- result = (unsigned long) p->data + value;
- } else if (src & MEMORY) {
- index = operand_index(dst);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data + value;
- set_reg_value(size, index, 0, regs, result);
- }
-
- /*
- * The CF, OF, SF, ZF, AF, and PF flags are set according
- * to the result
- */
- regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF|
- X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- set_eflags_CF(size, mmio_opp->instr, result, value,
- (unsigned long) p->data, regs);
- set_eflags_OF(size, mmio_opp->instr, result, value,
- (unsigned long) p->data, regs);
- set_eflags_AF(size, result, value, (unsigned long) p->data, regs);
- set_eflags_ZF(size, result, regs);
- set_eflags_SF(size, result, regs);
- set_eflags_PF(size, result, regs);
- break;
-
- case INSTR_OR:
- if (src & REGISTER) {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data | value;
- } else if (src & IMMEDIATE) {
- value = mmio_opp->immediate;
- result = (unsigned long) p->data | value;
- } else if (src & MEMORY) {
- index = operand_index(dst);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data | value;
- set_reg_value(size, index, 0, regs, result);
- }
-
- /*
- * The OF and CF flags are cleared; the SF, ZF, and PF
- * flags are set according to the result. The state of
- * the AF flag is undefined.
- */
- regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|
- X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- set_eflags_ZF(size, result, regs);
- set_eflags_SF(size, result, regs);
- set_eflags_PF(size, result, regs);
- break;
-
- case INSTR_XOR:
- if (src & REGISTER) {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data ^ value;
- } else if (src & IMMEDIATE) {
- value = mmio_opp->immediate;
- result = (unsigned long) p->data ^ value;
- } else if (src & MEMORY) {
- index = operand_index(dst);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data ^ value;
- set_reg_value(size, index, 0, regs, result);
- }
-
- /*
- * The OF and CF flags are cleared; the SF, ZF, and PF
- * flags are set according to the result. The state of
- * the AF flag is undefined.
- */
- regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|
- X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- set_eflags_ZF(size, result, regs);
- set_eflags_SF(size, result, regs);
- set_eflags_PF(size, result, regs);
- break;
-
- case INSTR_CMP:
- case INSTR_SUB:
- if (src & REGISTER) {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- result = (unsigned long) p->data - value;
- } else if (src & IMMEDIATE) {
- value = mmio_opp->immediate;
- result = (unsigned long) p->data - value;
- } else if (src & MEMORY) {
- index = operand_index(dst);
- value = get_reg_value(size, index, 0, regs);
- result = value - (unsigned long) p->data;
- if ( mmio_opp->instr == INSTR_SUB )
- set_reg_value(size, index, 0, regs, result);
- }
-
- /*
- * The CF, OF, SF, ZF, AF, and PF flags are set according
- * to the result
- */
- regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF|
- X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- if ( src & (REGISTER | IMMEDIATE) )
- {
- set_eflags_CF(size, mmio_opp->instr, result, value,
- (unsigned long) p->data, regs);
- set_eflags_OF(size, mmio_opp->instr, result, value,
- (unsigned long) p->data, regs);
- }
- else
- {
- set_eflags_CF(size, mmio_opp->instr, result,
- (unsigned long) p->data, value, regs);
- set_eflags_OF(size, mmio_opp->instr, result,
- (unsigned long) p->data, value, regs);
- }
- set_eflags_AF(size, result, value, (unsigned long) p->data, regs);
- set_eflags_ZF(size, result, regs);
- set_eflags_SF(size, result, regs);
- set_eflags_PF(size, result, regs);
- break;
-
- case INSTR_TEST:
- if (src & REGISTER) {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- } else if (src & IMMEDIATE) {
- value = mmio_opp->immediate;
- } else if (src & MEMORY) {
- index = operand_index(dst);
- value = get_reg_value(size, index, 0, regs);
- }
- result = (unsigned long) p->data & value;
-
- /*
- * Sets the SF, ZF, and PF status flags. CF and OF are set to 0
- */
- regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|
- X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- set_eflags_ZF(size, result, regs);
- set_eflags_SF(size, result, regs);
- set_eflags_PF(size, result, regs);
- break;
-
- case INSTR_BT:
- if ( src & REGISTER )
- {
- index = operand_index(src);
- value = get_reg_value(size, index, 0, regs);
- }
- else if ( src & IMMEDIATE )
- value = mmio_opp->immediate;
- if (p->data & (1 << (value & ((1 << 5) - 1))))
- regs->eflags |= X86_EFLAGS_CF;
- else
- regs->eflags &= ~X86_EFLAGS_CF;
-
- break;
-
- case INSTR_XCHG:
- if (src & REGISTER) {
- index = operand_index(src);
- set_reg_value(size, index, 0, regs, p->data);
- } else {
- index = operand_index(dst);
- set_reg_value(size, index, 0, regs, p->data);
- }
- break;
-
- case INSTR_PUSH:
- mmio_opp->addr += hvm_get_segment_base(current, x86_seg_ss);
- {
- unsigned long addr = mmio_opp->addr;
- int rv = hvm_copy_to_guest_virt(addr, &p->data, size);
- if ( rv == HVMCOPY_bad_gva_to_gfn )
- return; /* exception already injected */
- }
- break;
- }
-}
-
void hvm_io_assist(void)
{
vcpu_iodata_t *vio;
@@ -825,8 +125,18 @@ void hvm_io_assist(void)
p->state = STATE_IOREQ_NONE;
- if ( v->arch.hvm_vcpu.io_complete && v->arch.hvm_vcpu.io_complete() )
+ if ( v->arch.hvm_vcpu.io_in_progress )
+ {
+ v->arch.hvm_vcpu.io_in_progress = 0;
+ if ( p->dir == IOREQ_READ )
+ {
+ v->arch.hvm_vcpu.io_completed = 1;
+ v->arch.hvm_vcpu.io_data = p->data;
+ }
+ if ( v->arch.hvm_vcpu.mmio_in_progress )
+ (void)handle_mmio();
goto out;
+ }
switch ( p->type )
{
@@ -836,8 +146,9 @@ void hvm_io_assist(void)
hvm_pio_assist(regs, p, io_opp);
break;
default:
- hvm_mmio_assist(regs, p, io_opp);
- break;
+ gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state);
+ domain_crash(v->domain);
+ goto out;
}
/* Copy register changes back into current guest state. */