aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/hvm/emulate.c5
-rw-r--r--xen/arch/x86/hvm/io.c103
-rw-r--r--xen/arch/x86/hvm/svm/svm.c27
-rw-r--r--xen/arch/x86/hvm/vmx/vmx.c34
-rw-r--r--xen/include/asm-x86/hvm/emulate.h4
-rw-r--r--xen/include/asm-x86/hvm/io.h2
-rw-r--r--xen/include/asm-x86/hvm/vcpu.h5
7 files changed, 82 insertions, 98 deletions
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index fe0fe7e108..18748e95eb 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -48,7 +48,7 @@ static void hvmtrace_io_assist(int is_mmio, ioreq_t *p)
trace_var(event, 0/*!cycles*/, size, buffer);
}
-int hvmemul_do_io(
+static int hvmemul_do_io(
int is_mmio, paddr_t addr, unsigned long *reps, int size,
paddr_t ram_gpa, int dir, int df, void *p_data)
{
@@ -142,6 +142,7 @@ int hvmemul_do_io(
curr->arch.hvm_vcpu.io_state =
(p_data == NULL) ? HVMIO_dispatched : HVMIO_awaiting_completion;
+ curr->arch.hvm_vcpu.io_size = size;
p->dir = dir;
p->data_is_ptr = value_is_ptr;
@@ -224,7 +225,7 @@ int hvmemul_do_io(
return X86EMUL_OKAY;
}
-static int hvmemul_do_pio(
+int hvmemul_do_pio(
unsigned long port, unsigned long *reps, int size,
paddr_t ram_gpa, int dir, int df, void *p_data)
{
diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
index f6c7709218..274048d227 100644
--- a/xen/arch/x86/hvm/io.c
+++ b/xen/arch/x86/hvm/io.c
@@ -171,22 +171,10 @@ int handle_mmio(void)
struct hvm_emulate_ctxt ctxt;
struct vcpu *curr = current;
int rc;
- unsigned long data, reps = 1;
- if ( curr->arch.hvm_vcpu.io_size == 0 ) {
- hvm_emulate_prepare(&ctxt, guest_cpu_user_regs());
- rc = hvm_emulate_one(&ctxt);
- } else {
- if ( curr->arch.hvm_vcpu.io_dir == 0 )
- data = guest_cpu_user_regs()->eax;
- rc = hvmemul_do_io(0, curr->arch.hvm_vcpu.io_port, &reps,
- curr->arch.hvm_vcpu.io_size, 0,
- curr->arch.hvm_vcpu.io_dir, 0, &data);
- if ( curr->arch.hvm_vcpu.io_dir == 1 && rc == X86EMUL_OKAY ) {
- memcpy(&(guest_cpu_user_regs()->eax),
- &data, curr->arch.hvm_vcpu.io_size);
- }
- }
+ hvm_emulate_prepare(&ctxt, guest_cpu_user_regs());
+
+ rc = hvm_emulate_one(&ctxt);
if ( curr->arch.hvm_vcpu.io_state == HVMIO_awaiting_completion )
curr->arch.hvm_vcpu.io_state = HVMIO_handle_mmio_awaiting_completion;
@@ -196,21 +184,14 @@ int handle_mmio(void)
switch ( rc )
{
case X86EMUL_UNHANDLEABLE:
- if ( curr->arch.hvm_vcpu.io_size == 0 )
- gdprintk(XENLOG_WARNING,
- "MMIO emulation failed @ %04x:%lx: "
- "%02x %02x %02x %02x %02x %02x\n",
- hvmemul_get_seg_reg(x86_seg_cs, &ctxt)->sel,
- ctxt.insn_buf_eip,
- ctxt.insn_buf[0], ctxt.insn_buf[1],
- ctxt.insn_buf[2], ctxt.insn_buf[3],
- ctxt.insn_buf[4], ctxt.insn_buf[5]);
- else
- gdprintk(XENLOG_WARNING,
- "I/O emulation failed: %s 0x%04x, %i bytes, data=%08lx\n",
- curr->arch.hvm_vcpu.io_dir ? "in" : "out",
- curr->arch.hvm_vcpu.io_port,
- curr->arch.hvm_vcpu.io_size, data);
+ gdprintk(XENLOG_WARNING,
+ "MMIO emulation failed @ %04x:%lx: "
+ "%02x %02x %02x %02x %02x %02x\n",
+ hvmemul_get_seg_reg(x86_seg_cs, &ctxt)->sel,
+ ctxt.insn_buf_eip,
+ ctxt.insn_buf[0], ctxt.insn_buf[1],
+ ctxt.insn_buf[2], ctxt.insn_buf[3],
+ ctxt.insn_buf[4], ctxt.insn_buf[5]);
return 0;
case X86EMUL_EXCEPTION:
if ( ctxt.exn_pending )
@@ -220,15 +201,9 @@ int handle_mmio(void)
break;
}
- if ( curr->arch.hvm_vcpu.io_size == 0 )
- hvm_emulate_writeback(&ctxt);
- else
- curr->arch.hvm_vcpu.io_size = 0;
+ hvm_emulate_writeback(&ctxt);
- if (rc == X86EMUL_RETRY)
- return rc;
- else
- return 1;
+ return 1;
}
int handle_mmio_with_translation(unsigned long gva, unsigned long gpfn)
@@ -238,12 +213,36 @@ int handle_mmio_with_translation(unsigned long gva, unsigned long gpfn)
return handle_mmio();
}
-int handle_mmio_decoded(uint16_t port, int size, int dir)
+int handle_pio(uint16_t port, int size, int dir)
{
- current->arch.hvm_vcpu.io_port = port;
- current->arch.hvm_vcpu.io_size = size;
- current->arch.hvm_vcpu.io_dir = dir;
- return handle_mmio();
+ struct vcpu *curr = current;
+ unsigned long data, reps = 1;
+ int rc;
+
+ if ( dir == IOREQ_WRITE )
+ data = guest_cpu_user_regs()->eax;
+
+ rc = hvmemul_do_pio(port, &reps, size, 0, dir, 0, &data);
+
+ switch ( rc )
+ {
+ case X86EMUL_OKAY:
+ if ( dir == IOREQ_READ )
+ memcpy(&guest_cpu_user_regs()->eax,
+ &data, curr->arch.hvm_vcpu.io_size);
+ break;
+ case X86EMUL_RETRY:
+ if ( curr->arch.hvm_vcpu.io_state != HVMIO_awaiting_completion )
+ return 0;
+ /* Completion in hvm_io_assist() with no re-emulation required. */
+ ASSERT(dir == IOREQ_READ);
+ curr->arch.hvm_vcpu.io_state = HVMIO_handle_pio_awaiting_completion;
+ break;
+ default:
+ BUG();
+ }
+
+ return 1;
}
void hvm_io_assist(void)
@@ -259,13 +258,23 @@ void hvm_io_assist(void)
io_state = curr->arch.hvm_vcpu.io_state;
curr->arch.hvm_vcpu.io_state = HVMIO_none;
- if ( (io_state == HVMIO_awaiting_completion) ||
- (io_state == HVMIO_handle_mmio_awaiting_completion) )
+ switch ( io_state )
{
+ case HVMIO_awaiting_completion:
+ curr->arch.hvm_vcpu.io_state = HVMIO_completed;
+ curr->arch.hvm_vcpu.io_data = p->data;
+ break;
+ case HVMIO_handle_mmio_awaiting_completion:
curr->arch.hvm_vcpu.io_state = HVMIO_completed;
curr->arch.hvm_vcpu.io_data = p->data;
- if ( io_state == HVMIO_handle_mmio_awaiting_completion )
- (void)handle_mmio();
+ (void)handle_mmio();
+ break;
+ case HVMIO_handle_pio_awaiting_completion:
+ memcpy(&guest_cpu_user_regs()->eax,
+ &p->data, curr->arch.hvm_vcpu.io_size);
+ break;
+ default:
+ break;
}
if ( p->state == STATE_IOREQ_NONE )
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index a1b6187cad..45cc2dcff8 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1333,23 +1333,6 @@ static void svm_vmexit_do_invalidate_cache(struct cpu_user_regs *regs)
__update_guest_eip(regs, inst_len);
}
-static int svm_vmexit_do_io(struct vmcb_struct *vmcb,
- struct cpu_user_regs *regs)
-{
- uint16_t port;
- int bytes, dir;
- int rc;
-
- port = (vmcb->exitinfo1 >> 16) & 0xFFFF;
- bytes = ((vmcb->exitinfo1 >> 4) & 0x07);
- dir = (vmcb->exitinfo1 & 1) ? IOREQ_READ : IOREQ_WRITE;
-
- rc = handle_mmio_decoded(port, bytes, dir);
- if ( rc != X86EMUL_RETRY )
- __update_guest_eip(regs, vmcb->exitinfo2 - vmcb->rip);
- return rc;
-}
-
static void svm_invlpg_intercept(unsigned long vaddr)
{
struct vcpu *curr = current;
@@ -1558,9 +1541,13 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
break;
case VMEXIT_IOIO:
- if ( ( vmcb->exitinfo1 & ( 1 << 2 ) ) == 0 ) {
- if ( !svm_vmexit_do_io(vmcb, regs) )
- hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ if ( (vmcb->exitinfo1 & (1u<<2)) == 0 )
+ {
+ uint16_t port = (vmcb->exitinfo1 >> 16) & 0xFFFF;
+ int bytes = ((vmcb->exitinfo1 >> 4) & 0x07);
+ int dir = (vmcb->exitinfo1 & 1) ? IOREQ_READ : IOREQ_WRITE;
+ if ( handle_pio(port, bytes, dir) )
+ __update_guest_eip(regs, vmcb->exitinfo2 - vmcb->rip);
break;
}
/* fallthrough to emulation if a string instruction */
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 8475e8f949..599c5e7bf4 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1700,25 +1700,6 @@ static int vmx_cr_access(unsigned long exit_qualification,
return 1;
}
-static int vmx_io_intercept(unsigned long exit_qualification,
- struct cpu_user_regs *regs)
-{
- uint16_t port;
- int bytes, dir;
- int rc;
- int inst_len;
-
- port = (exit_qualification >> 16) & 0xFFFF;
- bytes = (exit_qualification & 0x07) + 1;
- dir = (exit_qualification & 0x08) ? IOREQ_READ : IOREQ_WRITE;
-
- inst_len = __get_instruction_length();
- rc = handle_mmio_decoded(port, bytes, dir);
- if ( rc != X86EMUL_RETRY)
- __update_guest_eip(inst_len);
- return rc;
-}
-
static const struct lbr_info {
u32 base, count;
} p4_lbr[] = {
@@ -2594,12 +2575,19 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs)
case EXIT_REASON_IO_INSTRUCTION:
exit_qualification = __vmread(EXIT_QUALIFICATION);
- if (exit_qualification & 0x10) {
+ if ( exit_qualification & 0x10 )
+ {
if ( !handle_mmio() )
vmx_inject_hw_exception(TRAP_gp_fault, 0);
- } else {
- if ( !vmx_io_intercept(exit_qualification, regs) )
- vmx_inject_hw_exception(TRAP_gp_fault, 0);
+ }
+ else
+ {
+ uint16_t port = (exit_qualification >> 16) & 0xFFFF;
+ int bytes = (exit_qualification & 0x07) + 1;
+ int dir = (exit_qualification & 0x08) ? IOREQ_READ : IOREQ_WRITE;
+ inst_len = __get_instruction_length();
+ if ( handle_pio(port, bytes, dir) )
+ __update_guest_eip(inst_len);
}
break;
diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h
index 2bb0a98ae9..d579c02ddf 100644
--- a/xen/include/asm-x86/hvm/emulate.h
+++ b/xen/include/asm-x86/hvm/emulate.h
@@ -46,8 +46,8 @@ struct segment_register *hvmemul_get_seg_reg(
enum x86_segment seg,
struct hvm_emulate_ctxt *hvmemul_ctxt);
-int hvmemul_do_io(
- int is_mmio, paddr_t addr, unsigned long *reps, int size,
+int hvmemul_do_pio(
+ paddr_t addr, unsigned long *reps, int size,
paddr_t ram_gpa, int dir, int df, void *p_data);
#endif /* __ASM_X86_HVM_EMULATE_H__ */
diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h
index 4d5e8b1294..c10a0bef2a 100644
--- a/xen/include/asm-x86/hvm/io.h
+++ b/xen/include/asm-x86/hvm/io.h
@@ -100,7 +100,7 @@ void send_timeoffset_req(unsigned long timeoff);
void send_invalidate_req(void);
int handle_mmio(void);
int handle_mmio_with_translation(unsigned long gva, unsigned long gpfn);
-int handle_mmio_decoded(uint16_t port, int size, int dir);
+int handle_pio(uint16_t port, int size, int dir);
void hvm_interrupt_post(struct vcpu *v, int vector, int type);
void hvm_io_assist(void);
void hvm_dpci_eoi(struct domain *d, unsigned int guest_irq,
diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h
index 150b30d32d..52c6c09e55 100644
--- a/xen/include/asm-x86/hvm/vcpu.h
+++ b/xen/include/asm-x86/hvm/vcpu.h
@@ -32,6 +32,7 @@ enum hvm_io_state {
HVMIO_dispatched,
HVMIO_awaiting_completion,
HVMIO_handle_mmio_awaiting_completion,
+ HVMIO_handle_pio_awaiting_completion,
HVMIO_completed
};
@@ -98,6 +99,7 @@ struct hvm_vcpu {
/* I/O request in flight to device model. */
enum hvm_io_state io_state;
unsigned long io_data;
+ int io_size;
/*
* HVM emulation:
@@ -107,9 +109,6 @@ struct hvm_vcpu {
*/
unsigned long mmio_gva;
unsigned long mmio_gpfn;
- uint16_t io_port;
- int io_size;
- unsigned io_dir;
/* Callback into x86_emulate when emulating FPU/MMX/XMM instructions. */
void (*fpu_exception_callback)(void *, struct cpu_user_regs *);