diff -r aa1ab056bfbf tools/libxc/xc_hvm_build.c --- a/tools/libxc/xc_hvm_build.c Wed Aug 02 17:42:38 2006 +0100 +++ b/tools/libxc/xc_hvm_build.c Thu Aug 03 10:39:16 2006 +0800 @@ -24,6 +24,7 @@ #define E820_IO 16 #define E820_SHARED_PAGE 17 #define E820_XENSTORE 18 +#define E820_BUFFERED_IO 19 #define E820_MAP_PAGE 0x00090000 #define E820_MAP_NR_OFFSET 0x000001E8 @@ -70,7 +71,13 @@ static void build_e820map(void *e820_pag e820entry[nr_map].type = E820_RESERVED; nr_map++; -#define STATIC_PAGES 2 /* for ioreq_t and store_mfn */ +#define STATIC_PAGES 3 + /* Totally 3 static pages. + * The 1st one for ioreq buffer. + * The 2nd one for xenstore + * The 3rd one for shared_page. + */ + /* Most of the ram goes here */ e820entry[nr_map].addr = 0x100000; e820entry[nr_map].size = mem_size - 0x100000 - STATIC_PAGES * PAGE_SIZE; @@ -78,6 +85,12 @@ static void build_e820map(void *e820_pag nr_map++; /* Statically allocated special pages */ + + /* For buffered IO requests */ + e820entry[nr_map].addr = mem_size - 3 * PAGE_SIZE; + e820entry[nr_map].size = PAGE_SIZE; + e820entry[nr_map].type = E820_BUFFERED_IO; + nr_map++; /* For xenstore */ e820entry[nr_map].addr = mem_size - 2 * PAGE_SIZE; @@ -184,6 +197,9 @@ static int setup_guest(int xc_handle, unsigned long shared_page_frame = 0; shared_iopage_t *sp; + unsigned long ioreq_buffer_frame = 0; + void *ioreq_buffer_page; + memset(&dsi, 0, sizeof(struct domain_setup_info)); if ( (parseelfimage(image, image_size, &dsi)) != 0 ) @@ -286,6 +302,18 @@ static int setup_guest(int xc_handle, } munmap(sp, PAGE_SIZE); + + /* clean the buffered IO requests page */ + ioreq_buffer_frame = page_array[(v_end >> PAGE_SHIFT) - 3]; + ioreq_buffer_page = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ | PROT_WRITE, ioreq_buffer_frame); + + if ( ioreq_buffer_page == NULL ) + goto error_out; + + memset(ioreq_buffer_page, 0, PAGE_SIZE); + + munmap(ioreq_buffer_page, PAGE_SIZE); *store_mfn = page_array[(v_end >> PAGE_SHIFT) - 2]; if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) ) diff -r aa1ab056bfbf xen/arch/ia64/vmx/vmx_support.c --- a/xen/arch/ia64/vmx/vmx_support.c Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/arch/ia64/vmx/vmx_support.c Thu Aug 03 10:39:16 2006 +0800 @@ -83,9 +83,6 @@ void vmx_io_assist(struct vcpu *v) p = &vio->vp_ioreq; - if (p->state == STATE_IORESP_HOOK) - panic_domain(vcpu_regs(v),"Not supported: No hook available for DM request\n"); - if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { if (p->state != STATE_IORESP_READY) { /* Can't block here, for the same reason as other places to diff -r aa1ab056bfbf xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/arch/x86/hvm/hvm.c Thu Aug 03 10:39:16 2006 +0800 @@ -68,14 +68,14 @@ static void hvm_zap_mmio_range( } } -static void hvm_map_io_shared_page(struct domain *d) +static void hvm_map_io_shared_pages(struct domain *d) { int i; unsigned char e820_map_nr; struct e820entry *e820entry; - unsigned char *p; + unsigned char *p, *buffered_io_p; unsigned long mfn; - unsigned long gpfn = 0; + unsigned long gpfn_ioreq = 0, gpfn_buffered_io = 0; local_flush_tlb_pge(); @@ -97,35 +97,59 @@ static void hvm_map_io_shared_page(struc for ( i = 0; i < e820_map_nr; i++ ) { if ( e820entry[i].type == E820_SHARED_PAGE ) - gpfn = (e820entry[i].addr >> PAGE_SHIFT); + gpfn_ioreq = e820entry[i].addr >> PAGE_SHIFT; + if ( e820entry[i].type == E820_BUFFERED_IO ) + gpfn_buffered_io = e820entry[i].addr >> PAGE_SHIFT; if ( e820entry[i].type == E820_IO ) - hvm_zap_mmio_range( - d, - e820entry[i].addr >> PAGE_SHIFT, - e820entry[i].size >> PAGE_SHIFT); - } - - if ( gpfn == 0 ) { - printk("Can not get io request shared page" + hvm_zap_mmio_range(d, + e820entry[i].addr >> PAGE_SHIFT, + e820entry[i].size >> PAGE_SHIFT); + } + + unmap_domain_page(p); + + if ( gpfn_ioreq == 0 ) { + printk("Can not get IO request shared page" " from E820 memory map for HVM domain.\n"); - unmap_domain_page(p); - domain_crash_synchronous(); - } - unmap_domain_page(p); - - /* Initialise shared page */ - mfn = get_mfn_from_gpfn(gpfn); - if (mfn == INVALID_MFN) { - printk("Can not find io request shared page for HVM domain.\n"); + domain_crash_synchronous(); + } + + if ( gpfn_buffered_io == 0 ) { + printk("Can not get IO request buffer page" + " from E820 memory map for HVM domain.\n"); + domain_crash_synchronous(); + } + + /* Initialise ioreq page */ + mfn = get_mfn_from_gpfn(gpfn_ioreq); + if ( mfn == INVALID_MFN ) { + printk("Can not find IO request shared page for HVM domain.\n"); domain_crash_synchronous(); } p = map_domain_page_global(mfn); - if (p == NULL) { - printk("Can not map io request shared page for HVM domain.\n"); - domain_crash_synchronous(); - } + if ( p == NULL ) { + printk("Can not map IO request shared page for HVM domain.\n"); + domain_crash_synchronous(); + } + + /* Initialise ioreq buffer page*/ + mfn = get_mfn_from_gpfn(gpfn_buffered_io); + if ( mfn == INVALID_MFN ) { + printk("can not find buffered IO request page for HVM domain.\n"); + unmap_domain_page_global(p); + domain_crash_synchronous(); + } + + buffered_io_p = map_domain_page_global(mfn); + if ( buffered_io_p == NULL ) { + printk("can not map IO request buffer page for HVM domain.\n"); + unmap_domain_page_global(p); + domain_crash_synchronous(); + } + d->arch.hvm_domain.shared_page_va = (unsigned long)p; + d->arch.hvm_domain.buffered_io_va = (unsigned long)buffered_io_p; } static int validate_hvm_info(struct hvm_info_table *t) @@ -197,7 +221,7 @@ void hvm_setup_platform(struct domain* d domain_crash_synchronous(); } - hvm_map_io_shared_page(d); + hvm_map_io_shared_pages(d); hvm_get_info(d); platform = &d->arch.hvm_domain; @@ -209,6 +233,7 @@ void hvm_setup_platform(struct domain* d spin_lock_init(&d->arch.hvm_domain.round_robin_lock); hvm_vioapic_init(d); } + spin_lock_init(&d->arch.hvm_domain.buffered_io_lock); init_timer(&platform->pl_time.periodic_tm.timer, pt_timer_fn, v, v->processor); pit_init(v, cpu_khz); diff -r aa1ab056bfbf xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/arch/x86/hvm/intercept.c Thu Aug 03 10:39:16 2006 +0800 @@ -36,10 +36,24 @@ extern struct hvm_mmio_handler vioapic_m #define HVM_MMIO_HANDLER_NR 2 -struct hvm_mmio_handler *hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] = +static struct hvm_mmio_handler *hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] = { &vlapic_mmio_handler, &vioapic_mmio_handler +}; + +struct hvm_buffered_io_range { + unsigned long start_addr; + unsigned long length; +}; + +#define HVM_BUFFERED_IO_RANGE_NR 1 + +static struct hvm_buffered_io_range buffered_stdvga_range = {0xA0000, 0x20000}; +static struct hvm_buffered_io_range +*hvm_buffered_io_ranges[HVM_BUFFERED_IO_RANGE_NR] = +{ + &buffered_stdvga_range }; static inline void hvm_mmio_access(struct vcpu *v, @@ -140,6 +154,56 @@ static inline void hvm_mmio_access(struc } } +int hvm_buffered_io_intercept(ioreq_t *p) +{ + struct vcpu *v = current; + spinlock_t *buffered_io_lock; + buffered_iopage_t *buffered_iopage = + (buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va); + unsigned long tmp_write_pointer = 0; + int i; + + /* ignore READ ioreq_t! */ + if ( p->dir == IOREQ_READ ) + return 0; + + for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) { + if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr && + p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr + + hvm_buffered_io_ranges[i]->length ) + break; + } + + if ( i == HVM_BUFFERED_IO_RANGE_NR ) + return 0; + + buffered_io_lock = &v->domain->arch.hvm_domain.buffered_io_lock; + spin_lock(buffered_io_lock); + + if ( buffered_iopage->write_pointer - buffered_iopage->read_pointer == + (unsigned long)IOREQ_BUFFER_SLOT_NUM ) { + /* the queue is full. + * send the iopacket through the normal path. + * NOTE: The arithimetic operation could handle the situation for + * write_pointer overflow. + */ + spin_unlock(buffered_io_lock); + return 0; + } + + tmp_write_pointer = buffered_iopage->write_pointer % IOREQ_BUFFER_SLOT_NUM; + + memcpy(&buffered_iopage->ioreq[tmp_write_pointer], p, sizeof(ioreq_t)); + + /*make the ioreq_t visible before write_pointer*/ + wmb(); + buffered_iopage->write_pointer++; + + spin_unlock(buffered_io_lock); + + return 1; +} + int hvm_mmio_intercept(ioreq_t *p) { struct vcpu *v = current; diff -r aa1ab056bfbf xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/arch/x86/hvm/platform.c Thu Aug 03 10:39:16 2006 +0800 @@ -764,7 +764,7 @@ void send_mmio_req( } else p->u.data = value; - if (hvm_mmio_intercept(p)){ + if ( hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p) ) { p->state = STATE_IORESP_READY; hvm_io_assist(v); return; diff -r aa1ab056bfbf xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Thu Aug 03 10:39:16 2006 +0800 @@ -808,6 +808,10 @@ static void svm_relinquish_guest_resourc if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( (void *)d->arch.hvm_domain.shared_page_va); + + if ( d->arch.hvm_domain.buffered_io_va ) + unmap_domain_page_global( + (void *)d->arch.hvm_domain.buffered_io_va); shadow_direct_map_clean(d); } diff -r aa1ab056bfbf xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu Aug 03 10:39:16 2006 +0800 @@ -147,7 +147,11 @@ static void vmx_relinquish_guest_resourc if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( - (void *)d->arch.hvm_domain.shared_page_va); + (void *)d->arch.hvm_domain.shared_page_va); + + if ( d->arch.hvm_domain.buffered_io_va ) + unmap_domain_page_global( + (void *)d->arch.hvm_domain.buffered_io_va); shadow_direct_map_clean(d); } @@ -602,8 +606,8 @@ static int vmx_instruction_length(struct { unsigned long inst_len; - if (__vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len)) - return 0; + if ( __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len) ) + return 0; return inst_len; } @@ -1090,7 +1094,7 @@ static int check_for_null_selector(unsig extern void send_pio_req(struct cpu_user_regs *regs, unsigned long port, unsigned long count, int size, long value, - int dir, int pvalid); + int dir, int pvalid); static void vmx_io_instruction(unsigned long exit_qualification, unsigned long inst_len) diff -r aa1ab056bfbf xen/include/asm-x86/e820.h --- a/xen/include/asm-x86/e820.h Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/include/asm-x86/e820.h Thu Aug 03 10:39:16 2006 +0800 @@ -12,6 +12,7 @@ #define E820_IO 16 #define E820_SHARED_PAGE 17 #define E820_XENSTORE 18 +#define E820_BUFFERED_IO 19 #define E820_MAP_PAGE 0x00090000 #define E820_MAP_NR_OFFSET 0x000001E8 diff -r aa1ab056bfbf xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/include/asm-x86/hvm/domain.h Thu Aug 03 10:39:16 2006 +0800 @@ -32,6 +32,8 @@ struct hvm_domain { unsigned long shared_page_va; + unsigned long buffered_io_va; + spinlock_t buffered_io_lock; unsigned int nr_vcpus; unsigned int apic_enabled; unsigned int pae_enabled; diff -r aa1ab056bfbf xen/include/asm-x86/hvm/support.h --- a/xen/include/asm-x86/hvm/support.h Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/include/asm-x86/hvm/support.h Thu Aug 03 10:39:16 2006 +0800 @@ -144,6 +144,7 @@ extern void hvm_setup_platform(struct do extern void hvm_setup_platform(struct domain* d); extern int hvm_mmio_intercept(ioreq_t *p); extern int hvm_io_intercept(ioreq_t *p, int type); +extern int hvm_buffered_io_intercept(ioreq_t *p); extern void hvm_hooks_assist(struct vcpu *v); extern void hvm_print_line(struct vcpu *v, const char c); extern void hlt_timer_fn(void *data); diff -r aa1ab056bfbf xen/include/public/hvm/ioreq.h --- a/xen/include/public/hvm/ioreq.h Wed Aug 02 17:42:38 2006 +0100 +++ b/xen/include/public/hvm/ioreq.h Thu Aug 03 10:39:16 2006 +0800 @@ -27,7 +27,6 @@ #define STATE_IOREQ_READY 1 #define STATE_IOREQ_INPROCESS 2 #define STATE_IORESP_READY 3 -#define STATE_IORESP_HOOK 4 #define IOREQ_TYPE_PIO 0 /* pio */ #define IOREQ_TYPE_COPY 1 /* mmio ops */