diff options
-rw-r--r-- | xen/arch/x86/hvm/emulate.c | 5 | ||||
-rw-r--r-- | xen/arch/x86/hvm/io.c | 103 | ||||
-rw-r--r-- | xen/arch/x86/hvm/svm/svm.c | 27 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmx.c | 34 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/emulate.h | 4 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/io.h | 2 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vcpu.h | 5 |
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 *); |