diff -r 8c35da364ab3 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Thu Dec 18 17:18:28 2008 +0000 +++ b/xen/arch/x86/hvm/hvm.c Fri Dec 19 09:33:23 2008 +0800 @@ -169,7 +169,6 @@ void hvm_do_resume(struct vcpu *v) void hvm_do_resume(struct vcpu *v) { ioreq_t *p; - pt_restore_timer(v); /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ @@ -179,7 +178,16 @@ void hvm_do_resume(struct vcpu *v) switch ( p->state ) { case STATE_IORESP_READY: /* IORESP_READY -> NONE */ - hvm_io_assist(); + if ( p->type==IOREQ_TYPE_PIO && + p->subtype==IOREQ_SUBTYPE_NOSTRING && + !(v->arch.hvm_vmx.vmx_realmode) ) + { + struct cpu_user_regs *regs = guest_cpu_user_regs(); + p->subtype=IOREQ_SUBTYPE_NULL; + hvm_pio_assist(regs); + } + else + hvm_io_assist(); break; case STATE_IOREQ_READY: /* IOREQ_{READY,INPROCESS} -> IORESP_READY */ case STATE_IOREQ_INPROCESS: diff -r 8c35da364ab3 xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Thu Dec 18 17:18:28 2008 +0000 +++ b/xen/arch/x86/hvm/intercept.c Fri Dec 19 09:33:23 2008 +0800 @@ -171,7 +171,7 @@ static int process_portio_intercept(port /* * Check if the request is handled inside xen - * return value: 0 --not handled; 1 --handled + * return value: X86EMUL_OKAY --handled; Others -- not handled */ int hvm_io_intercept(ioreq_t *p, int type) { diff -r 8c35da364ab3 xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Thu Dec 18 17:18:28 2008 +0000 +++ b/xen/arch/x86/hvm/io.c Fri Dec 19 09:33:23 2008 +0800 @@ -218,6 +218,98 @@ int handle_mmio_with_translation(unsigne return handle_mmio(); } +void hvm_pio_quickpath(struct cpu_user_regs *regs, + unsigned long port, + unsigned int size, + int dir, int df) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + + if ( size == 0 ) { + printk("null pio request? port %lx, " + "size %d, value %"PRIpaddr", dir %d.\n", + port, size, regs->eax, dir); + } + + vio = get_ioreq(v); + if ( vio == NULL ) { + printk("bad shared page: %lx\n", (unsigned long) vio); + domain_crash_synchronous(); + } + + p = &vio->vp_ioreq; + if ( p->state != STATE_IOREQ_NONE ) + printk("WARNING: send pio with something already pending (%d)?\n", + p->state); + + p->dir = dir; + p->data_is_ptr = 0; + + p->type = IOREQ_TYPE_PIO; + p->subtype = IOREQ_SUBTYPE_NOSTRING; + p->size = size; + p->addr = port; + p->count = 1; + p->df = df; + p->io_count++; + + p->data = regs->eax; + + if ( !hvm_portio_intercept(p) ) + { + p->state = STATE_IORESP_READY; + hvm_pio_assist(regs); + return; + } + hvm_send_assist_req(v); +} + +void hvm_pio_assist(struct cpu_user_regs *regs) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio = get_ioreq(v); + ioreq_t *p; + + p = &vio->vp_ioreq; + if ( p->state != STATE_IORESP_READY ) + { + gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state); + domain_crash(v->domain); + goto out; + } + + rmb(); + + p->state = STATE_IOREQ_NONE; + + if ( p->dir == IOREQ_READ ) + { + unsigned long old_eax = regs->eax; + + switch ( p->size ) + { + case 1: + regs->eax = (old_eax & ~0xff) | (p->data & 0xff); + break; + case 2: + regs->eax = (old_eax & ~0xffff) | (p->data & 0xffff); + break; + case 4: + regs->eax = (p->data & 0xffffffff); + break; + default: + printk("Error: %s unknown port size\n", __FUNCTION__); + domain_crash_synchronous(); + } + } + + out: + vcpu_end_shutdown_deferral(v); + +} + void hvm_io_assist(void) { struct vcpu *curr = current; diff -r 8c35da364ab3 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Thu Dec 18 17:18:28 2008 +0000 +++ b/xen/arch/x86/hvm/vmx/vmx.c Fri Dec 19 09:33:23 2008 +0800 @@ -2496,6 +2496,25 @@ asmlinkage void vmx_vmexit_handler(struc break; case EXIT_REASON_IO_INSTRUCTION: + exit_qualification = __vmread(EXIT_QUALIFICATION); + /* quick path for no string port IO */ + if ( !test_bit(4, &exit_qualification) ) + { + unsigned long port; + int df = regs->eflags & X86_EFLAGS_DF ? 1 : 0; + unsigned int size = (exit_qualification & 7) + 1; + int dir = test_bit(3, &exit_qualification); /* direction */ + if ( test_bit(6, &exit_qualification) ) + port = (exit_qualification >> 16) & 0xFFFF; + else + port = regs->edx & 0xffff; + + inst_len = __get_instruction_length(); + __update_guest_eip(inst_len); + hvm_pio_quickpath(regs, port, size, dir, df); + + break; + } case EXIT_REASON_APIC_ACCESS: if ( !handle_mmio() ) vmx_inject_hw_exception(TRAP_gp_fault, 0); diff -r 8c35da364ab3 xen/include/asm-x86/hvm/io.h --- a/xen/include/asm-x86/hvm/io.h Thu Dec 18 17:18:28 2008 +0000 +++ b/xen/include/asm-x86/hvm/io.h Fri Dec 19 09:33:23 2008 +0800 @@ -101,6 +101,9 @@ int handle_mmio(void); int handle_mmio(void); int handle_mmio_with_translation(unsigned long gva, unsigned long gpfn); void hvm_interrupt_post(struct vcpu *v, int vector, int type); +void hvm_pio_assist(struct cpu_user_regs *regs); +void hvm_pio_quickpath(struct cpu_user_regs *regs, unsigned long port, + unsigned int size, int dir, int df); void hvm_io_assist(void); void hvm_dpci_eoi(struct domain *d, unsigned int guest_irq, union vioapic_redir_entry *ent); diff -r 8c35da364ab3 xen/include/public/hvm/ioreq.h --- a/xen/include/public/hvm/ioreq.h Thu Dec 18 17:18:28 2008 +0000 +++ b/xen/include/public/hvm/ioreq.h Fri Dec 19 09:33:23 2008 +0800 @@ -37,6 +37,8 @@ #define IOREQ_TYPE_TIMEOFFSET 7 #define IOREQ_TYPE_INVALIDATE 8 /* mapcache */ +#define IOREQ_SUBTYPE_NULL 0 +#define IOREQ_SUBTYPE_NOSTRING 1 /* * VMExit dispatcher should cooperate with instruction decoder to * prepare this structure and notify service OS and DM by sending @@ -54,7 +56,8 @@ struct ioreq { uint8_t df:1; uint8_t pad:1; uint8_t type; /* I/O type */ - uint8_t _pad0[6]; + uint8_t subtype; /* I/O subtype for none string optimization */ + uint8_t _pad0[5]; uint64_t io_count; /* How many IO done on a vcpu */ }; typedef struct ioreq ioreq_t;