diff -r bbabdebc54ad tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Wed Jul 19 21:13:36 2006 +0100 +++ b/tools/ioemu/target-i386-dm/helper2.c Thu Jul 27 10:24:07 2006 +0800 @@ -74,7 +74,9 @@ int vcpus = 1; int xc_handle; +buffered_iopage_t *buffered_io_page; shared_iopage_t *shared_page = NULL; +extern void handle_buffered_io(void *opaque); /* the evtchn fd for polling */ int xce_handle = -1; @@ -415,38 +417,63 @@ void cpu_ioreq_xor(CPUState *env, ioreq_ req->u.data = tmp1; } +void __handle_ioreq(CPUState *env, ioreq_t *req) +{ + if ( !req->pdata_valid && (req->dir == IOREQ_WRITE)) { + if (req->size != 4) + req->u.data &= (1UL << (8 * req->size))-1; + } + + switch (req->type) { + case IOREQ_TYPE_PIO: + cpu_ioreq_pio(env, req); + break; + case IOREQ_TYPE_COPY: + cpu_ioreq_move(env, req); + break; + case IOREQ_TYPE_AND: + cpu_ioreq_and(env, req); + break; + case IOREQ_TYPE_OR: + cpu_ioreq_or(env, req); + break; + case IOREQ_TYPE_XOR: + cpu_ioreq_xor(env, req); + break; + default: + hw_error("Invalid ioreq type 0x%x\n", req->type); + } +} + +void __handle_buffered_iopage(CPUState *env) +{ + ioreq_t *req = NULL; + + if ( !buffered_io_page ) + return; + + while ( buffered_io_page->read_pointer != + buffered_io_page->write_pointer ) { + unsigned long tmp_read_pointer; + tmp_read_pointer = buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM; + req = &buffered_io_page->ioreq[tmp_read_pointer]; + + __handle_ioreq (env, req); + + mb(); + buffered_io_page->read_pointer++; + } +} + void cpu_handle_ioreq(void *opaque) { CPUState *env = opaque; ioreq_t *req = cpu_get_ioreq(); + handle_buffered_io(env); if (req) { - if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) { - if (req->size != 4) - req->u.data &= (1UL << (8 * req->size))-1; - } - - switch (req->type) { - case IOREQ_TYPE_PIO: - cpu_ioreq_pio(env, req); - break; - case IOREQ_TYPE_COPY: - cpu_ioreq_move(env, req); - break; - case IOREQ_TYPE_AND: - cpu_ioreq_and(env, req); - break; - case IOREQ_TYPE_OR: - cpu_ioreq_or(env, req); - break; - case IOREQ_TYPE_XOR: - cpu_ioreq_xor(env, req); - break; - default: - hw_error("Invalid ioreq type 0x%x\n", req->type); - } - - /* No state change if state = STATE_IORESP_HOOK */ + __handle_ioreq (env, req); + if (req->state == STATE_IOREQ_INPROCESS) req->state = STATE_IORESP_READY; env->send_event = 1; diff -r bbabdebc54ad tools/ioemu/vl.c --- a/tools/ioemu/vl.c Wed Jul 19 21:13:36 2006 +0100 +++ b/tools/ioemu/vl.c Thu Jul 27 10:24:07 2006 +0800 @@ -107,6 +107,7 @@ #endif /* in ms */ #define GUI_REFRESH_INTERVAL 30 +#define BUFFER_IO_MAX_DELAY 100 /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 @@ -130,6 +131,7 @@ int nb_nics; int nb_nics; NICInfo nd_table[MAX_NICS]; QEMUTimer *gui_timer; +QEMUTimer *buffered_io_timer; int vm_running; int rtc_utc = 1; int cirrus_vga_enabled = 1; @@ -4382,6 +4384,15 @@ void gui_update(void *opaque) qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); } +void handle_buffered_io(void *opaque) +{ + CPUState *env = opaque; + extern void __handle_buffered_iopage(CPUState *env); + + __handle_buffered_iopage(env); + qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY + qemu_get_clock(rt_clock)); +} + struct vm_change_state_entry { VMChangeStateHandler *cb; void *opaque; @@ -5274,6 +5285,7 @@ int main(int argc, char **argv) unsigned long nr_pages; xen_pfn_t *page_array; extern void *shared_page; + extern void *buffered_io_page; char qemu_dm_logfilename[64]; @@ -5761,11 +5773,16 @@ int main(int argc, char **argv) phys_ram_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE, page_array, - nr_pages - 1); + nr_pages - 3); if (phys_ram_base == 0) { fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); exit(-1); } + + /* not yet add for IA64 */ + buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + page_array[nr_pages - 3]); shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ|PROT_WRITE, @@ -5988,6 +6005,8 @@ int main(int argc, char **argv) gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); } + buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io, cpu_single_env); + qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock)); #ifdef CONFIG_GDBSTUB if (use_gdbstub) { diff -r bbabdebc54ad tools/libxc/xc_hvm_build.c --- a/tools/libxc/xc_hvm_build.c Wed Jul 19 21:13:36 2006 +0100 +++ b/tools/libxc/xc_hvm_build.c Thu Jul 27 10:24:07 2006 +0800 @@ -30,6 +30,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 @@ -79,7 +80,13 @@ static unsigned char build_e820map(void 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; @@ -87,6 +94,12 @@ static unsigned char build_e820map(void 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; @@ -194,6 +207,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 ) @@ -296,6 +312,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 == 0 ) + 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 bbabdebc54ad xen/arch/ia64/vmx/vmx_support.c --- a/xen/arch/ia64/vmx/vmx_support.c Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/arch/ia64/vmx/vmx_support.c Thu Jul 27 10:24:07 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 bbabdebc54ad xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/arch/x86/hvm/hvm.c Thu Jul 27 10:24:07 2006 +0800 @@ -67,14 +67,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(); @@ -96,35 +96,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) @@ -196,7 +220,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; @@ -208,6 +232,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 bbabdebc54ad xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/arch/x86/hvm/intercept.c Thu Jul 27 10:24:07 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 end_addr; +}; + +#define HVM_BUFFERED_IO_RANGE_NR 1 + +static struct hvm_buffered_io_range buffered_stdvga_range = {0xA0000, 0xC0000}; +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,55 @@ 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 < hvm_buffered_io_ranges[i]->end_addr ) + 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 bbabdebc54ad xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/arch/x86/hvm/platform.c Thu Jul 27 10:24:07 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 bbabdebc54ad xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Thu Jul 27 10:24:07 2006 +0800 @@ -784,6 +784,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 bbabdebc54ad xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu Jul 27 10:24:07 2006 +0800 @@ -146,6 +146,10 @@ 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); + + 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 bbabdebc54ad xen/include/asm-x86/e820.h --- a/xen/include/asm-x86/e820.h Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/include/asm-x86/e820.h Thu Jul 27 10:24:07 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 bbabdebc54ad xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/include/asm-x86/hvm/domain.h Thu Jul 27 10:24:07 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 bbabdebc54ad xen/include/asm-x86/hvm/support.h --- a/xen/include/asm-x86/hvm/support.h Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/include/asm-x86/hvm/support.h Thu Jul 27 10:24:07 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 bbabdebc54ad xen/include/public/hvm/ioreq.h --- a/xen/include/public/hvm/ioreq.h Wed Jul 19 21:13:36 2006 +0100 +++ b/xen/include/public/hvm/ioreq.h Thu Jul 27 10:24:07 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 */ @@ -80,6 +79,14 @@ struct shared_iopage { }; typedef struct shared_iopage shared_iopage_t; +#define IOREQ_BUFFER_SLOT_NUM 80 +struct buffered_iopage { + unsigned long read_pointer; + unsigned long write_pointer; + ioreq_t ioreq[IOREQ_BUFFER_SLOT_NUM]; +}; /* sizeof this structure must be in one page */ +typedef struct buffered_iopage buffered_iopage_t; + #endif /* _IOREQ_H_ */ /*