diff -r ecb8ff1fcf1f linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c Fri Jul 14 18:53:27 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c Tue Jul 18 13:43:27 2006 +0100 @@ -270,6 +270,7 @@ static int __init privcmd_init(void) set_bit(__HYPERVISOR_sched_op_compat, hypercall_permission_map); set_bit(__HYPERVISOR_event_channel_op_compat, hypercall_permission_map); + set_bit(__HYPERVISOR_hvm_op, hypercall_permission_map); privcmd_intf = create_xen_proc_entry("privcmd", 0400); if (privcmd_intf != NULL) diff -r ecb8ff1fcf1f tools/firmware/hvmloader/hvmloader.c --- a/tools/firmware/hvmloader/hvmloader.c Fri Jul 14 18:53:27 2006 +0100 +++ b/tools/firmware/hvmloader/hvmloader.c Tue Jul 18 13:43:27 2006 +0100 @@ -31,7 +31,7 @@ #define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000 /* invoke SVM's paged realmode support */ -#define SVM_VMMCALL_RESET_TO_REALMODE 0x00000001 +#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001 /* * C runtime start off @@ -133,15 +133,15 @@ cirrus_check(void) return inb(0x3C5) == 0x12; } -int -vmmcall(int edi, int esi, int edx, int ecx, int ebx) +int +vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx) { int eax; __asm__ __volatile__( ".byte 0x0F,0x01,0xD9" : "=a" (eax) - : "a"(0x58454E00), /* XEN\0 key */ + : "a"(function), "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) ); return eax; @@ -200,7 +200,7 @@ main(void) if (check_amd()) { /* AMD implies this is SVM */ puts("SVM go ...\n"); - vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0); + vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0); } else { puts("Loading VMXAssist ...\n"); memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS, diff -r ecb8ff1fcf1f tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Fri Jul 14 18:53:27 2006 +0100 +++ b/tools/ioemu/Makefile.target Tue Jul 18 13:43:27 2006 +0100 @@ -336,6 +336,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o p VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o VL_OBJS+= piix4acpi.o +VL_OBJS+= xen_evtchn.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff -r ecb8ff1fcf1f tools/ioemu/hw/pc.c --- a/tools/ioemu/hw/pc.c Fri Jul 14 18:53:27 2006 +0100 +++ b/tools/ioemu/hw/pc.c Tue Jul 18 13:43:27 2006 +0100 @@ -819,6 +819,9 @@ static void pc_init1(uint64_t ram_size, } #endif /* !CONFIG_DM */ + if (pci_enabled) + pci_xen_evtchn_init(pci_bus); + for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { serial_init(&pic_set_irq_new, isa_pic, diff -r ecb8ff1fcf1f tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Fri Jul 14 18:53:27 2006 +0100 +++ b/tools/ioemu/target-i386-dm/helper2.c Tue Jul 18 13:43:27 2006 +0100 @@ -82,6 +82,10 @@ int xce_handle = -1; /* which vcpu we are serving */ int send_vcpu = 0; +//the evtchn port for polling the notification, +#define NR_CPUS 32 +evtchn_port_t ioreq_local_port[NR_CPUS]; + CPUX86State *cpu_x86_init(void) { CPUX86State *env; @@ -105,15 +109,14 @@ CPUX86State *cpu_x86_init(void) return NULL; } - /* FIXME: how about if we overflow the page here? */ for (i = 0; i < vcpus; i++) { - rc = xc_evtchn_bind_interdomain( - xce_handle, domid, shared_page->vcpu_iodata[i].vp_eport); + rc = xc_evtchn_bind_interdomain(xce_handle, DOMID_XEN, + shared_page->vcpu_iodata[i].vp_xen_port); if (rc == -1) { fprintf(logfile, "bind interdomain ioctl error %d\n", errno); return NULL; } - shared_page->vcpu_iodata[i].dm_eport = rc; + ioreq_local_port[i] = rc; } } @@ -184,10 +187,9 @@ void sp_info() for (i = 0; i < vcpus; i++) { req = &(shared_page->vcpu_iodata[i].vp_ioreq); - term_printf("vcpu %d: event port %d\n", i, - shared_page->vcpu_iodata[i].vp_eport); + term_printf("vcpu %d: event port %d\n", i, ioreq_local_port[i]); term_printf(" req state: %x, pvalid: %x, addr: %"PRIx64", " - "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", + "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", req->state, req->pdata_valid, req->addr, req->u.data, req->count, req->size); term_printf(" IO totally occurred on this vcpu: %"PRIx64"\n", @@ -201,17 +203,12 @@ static ioreq_t *__cpu_get_ioreq(int vcpu ioreq_t *req; req = &(shared_page->vcpu_iodata[vcpu].vp_ioreq); - if (req->state == STATE_IOREQ_READY) { - req->state = STATE_IOREQ_INPROCESS; - return req; - } - - fprintf(logfile, "False I/O request ... in-service already: " - "%x, pvalid: %x, port: %"PRIx64", " - "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", - req->state, req->pdata_valid, req->addr, - req->u.data, req->count, req->size); + req->state = STATE_IOREQ_INPROCESS; + rmb(); + return req; + } + return NULL; } @@ -226,7 +223,7 @@ static ioreq_t *cpu_get_ioreq(void) port = xc_evtchn_pending(xce_handle); if (port != -1) { for ( i = 0; i < vcpus; i++ ) - if ( shared_page->vcpu_iodata[i].dm_eport == port ) + if ( ioreq_local_port[i] == port ) break; if ( i == vcpus ) { @@ -447,8 +444,10 @@ void cpu_handle_ioreq(void *opaque) } /* No state change if state = STATE_IORESP_HOOK */ - if (req->state == STATE_IOREQ_INPROCESS) + if (req->state == STATE_IOREQ_INPROCESS) { + mb(); req->state = STATE_IORESP_READY; + } env->send_event = 1; } } @@ -479,8 +478,7 @@ int main_loop(void) if (env->send_event) { env->send_event = 0; - xc_evtchn_notify(xce_handle, - shared_page->vcpu_iodata[send_vcpu].dm_eport); + (void)xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); } } destroy_hvm_domain(); diff -r ecb8ff1fcf1f tools/libxc/xc_hvm_build.c --- a/tools/libxc/xc_hvm_build.c Fri Jul 14 18:53:27 2006 +0100 +++ b/tools/libxc/xc_hvm_build.c Tue Jul 18 13:43:27 2006 +0100 @@ -6,12 +6,14 @@ #include #include #include "xg_private.h" +#include "xc_private.h" #include "xc_elf.h" #include #include #include #include #include +#include #define HVM_LOADER_ENTR_ADDR 0x00100000 @@ -52,6 +54,30 @@ loadelfimage( char *elfbase, int xch, uint32_t dom, unsigned long *parray, struct domain_setup_info *dsi); +static void xc_set_hvm_param(int handle, + domid_t dom, int param, unsigned long value) +{ + DECLARE_HYPERCALL; + xen_hvm_param_t arg; + int rc; + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_set_param; + hypercall.arg[1] = (unsigned long)&arg; + arg.domid = dom; + arg.index = param; + arg.value = value; + if ( mlock(&arg, sizeof(arg)) != 0 ) + { + PERROR("Could not lock memory for set parameter"); + return; + } + rc = do_xen_hypercall(handle, &hypercall); + safe_munlock(&arg, sizeof(arg)); + if (rc < 0) + PERROR("set HVM parameter failed (%d)", rc); +} + static unsigned char build_e820map(void *e820_page, unsigned long long mem_size) { struct e820entry *e820entry = @@ -162,6 +188,8 @@ static int set_hvm_info(int xc_handle, u set_hvm_info_checksum(va_hvm); munmap(va_map, PAGE_SIZE); + + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_APIC_ENABLED, apic); return 0; } @@ -275,27 +303,17 @@ static int setup_guest(int xc_handle, shared_info->vcpu_info[i].evtchn_upcall_mask = 1; munmap(shared_info, PAGE_SIZE); - /* Populate the event channel port in the shared page */ + /* Paranoia */ shared_page_frame = page_array[(v_end >> PAGE_SHIFT) - 1]; if ( (sp = (shared_iopage_t *) xc_map_foreign_range( xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, shared_page_frame)) == 0 ) goto error_out; memset(sp, 0, PAGE_SIZE); - - /* FIXME: how about if we overflow the page here? */ - for ( i = 0; i < vcpus; i++ ) { - unsigned int vp_eport; - - vp_eport = xc_evtchn_alloc_unbound(xc_handle, dom, 0); - if ( vp_eport < 0 ) { - PERROR("Couldn't get unbound port from VMX guest.\n"); - goto error_out; - } - sp->vcpu_iodata[i].vp_eport = vp_eport; - } - munmap(sp, PAGE_SIZE); + + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, (v_end >> PAGE_SHIFT) - 2); + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn); *store_mfn = page_array[(v_end >> PAGE_SHIFT) - 2]; if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) ) diff -r ecb8ff1fcf1f xen/arch/x86/dom0_ops.c --- a/xen/arch/x86/dom0_ops.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/dom0_ops.c Tue Jul 18 13:43:27 2006 +0100 @@ -429,7 +429,7 @@ long arch_do_dom0_op(struct dom0_op *op, ret = 0; hypercall_page = map_domain_page(mfn); - hypercall_page_initialise(hypercall_page); + hypercall_page_initialise(d, hypercall_page); unmap_domain_page(hypercall_page); put_page_and_type(mfn_to_page(mfn)); diff -r ecb8ff1fcf1f xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/domain.c Tue Jul 18 13:43:27 2006 +0100 @@ -819,7 +819,7 @@ unsigned long hypercall_create_continuat #if defined(__i386__) regs->eax = op; - if ( supervisor_mode_kernel ) + if ( supervisor_mode_kernel || hvm_guest(current) ) regs->eip &= ~31; /* re-execute entire hypercall entry stub */ else regs->eip -= 2; /* re-execute 'int 0x82' */ diff -r ecb8ff1fcf1f xen/arch/x86/domain_build.c --- a/xen/arch/x86/domain_build.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/domain_build.c Tue Jul 18 13:43:27 2006 +0100 @@ -704,7 +704,7 @@ int construct_dom0(struct domain *d, return -1; } - hypercall_page_initialise((void *)hypercall_page); + hypercall_page_initialise(d, (void *)hypercall_page); } /* Copy the initial ramdisk. */ diff -r ecb8ff1fcf1f xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/hvm.c Tue Jul 18 13:43:27 2006 +0100 @@ -45,6 +45,9 @@ #include #include #include +#include +#include +#include int hvm_enabled = 0; @@ -58,6 +61,8 @@ static void hvm_zap_mmio_range( { unsigned long i, val = INVALID_MFN; + ASSERT(d == current->domain); + for ( i = 0; i < nr_pfn; i++ ) { if ( pfn + i >= 0xfffff ) @@ -67,18 +72,27 @@ static void hvm_zap_mmio_range( } } -static void hvm_map_io_shared_page(struct domain *d) +static void e820_zap_iommu_callback(struct domain *d, + struct e820entry *e, + void *ign) +{ + if ( e->type == E820_IO ) + hvm_zap_mmio_range(d, e->addr >> PAGE_SHIFT, e->size >> PAGE_SHIFT); +} + +static void e820_foreach(struct domain *d, + void (*cb)(struct domain *d, + struct e820entry *e, + void *data), + void *data) { int i; unsigned char e820_map_nr; struct e820entry *e820entry; unsigned char *p; unsigned long mfn; - unsigned long gpfn = 0; - - local_flush_tlb_pge(); - - mfn = get_mfn_from_gpfn(E820_MAP_PAGE >> PAGE_SHIFT); + + mfn = gmfn_to_mfn(d, E820_MAP_PAGE >> PAGE_SHIFT); if (mfn == INVALID_MFN) { printk("Can not find E820 memory map page for HVM domain.\n"); domain_crash_synchronous(); @@ -95,26 +109,40 @@ 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); - 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" - " from E820 memory map for HVM domain.\n"); - unmap_domain_page(p); - domain_crash_synchronous(); - } + cb(d, e820entry + i, data); + } + unmap_domain_page(p); - - /* Initialise shared page */ - mfn = get_mfn_from_gpfn(gpfn); - if (mfn == INVALID_MFN) { +} + +static void hvm_zap_iommu_pages(struct domain *d) +{ + e820_foreach(d, e820_zap_iommu_callback, NULL); +} + +static void e820_map_io_shared_callback(struct domain *d, + struct e820entry *e, + void *data) +{ + unsigned long *mfn = data; + if ( e->type == E820_SHARED_PAGE ) { + ASSERT(*mfn == INVALID_MFN); + *mfn = gmfn_to_mfn(d, e->addr >> PAGE_SHIFT); + } +} + +void hvm_map_io_shared_page(struct vcpu *v) +{ + unsigned long mfn = INVALID_MFN; + void *p; + struct domain *d = v->domain; + + if ( d->arch.hvm_domain.shared_page_va ) + return; + + e820_foreach(d, e820_map_io_shared_callback, &mfn); + + if ( mfn == INVALID_MFN ) { printk("Can not find io request shared page for HVM domain.\n"); domain_crash_synchronous(); } @@ -127,59 +155,20 @@ static void hvm_map_io_shared_page(struc d->arch.hvm_domain.shared_page_va = (unsigned long)p; } -static int validate_hvm_info(struct hvm_info_table *t) -{ - char signature[] = "HVM INFO"; - uint8_t *ptr = (uint8_t *)t; - uint8_t sum = 0; - int i; - - /* strncmp(t->signature, "HVM INFO", 8) */ - for ( i = 0; i < 8; i++ ) { - if ( signature[i] != t->signature[i] ) { - printk("Bad hvm info signature\n"); - return 0; - } - } - - for ( i = 0; i < t->length; i++ ) - sum += ptr[i]; - - return (sum == 0); -} - -static void hvm_get_info(struct domain *d) -{ - unsigned char *p; - unsigned long mfn; - struct hvm_info_table *t; - - mfn = get_mfn_from_gpfn(HVM_INFO_PFN); - if ( mfn == INVALID_MFN ) { - printk("Can not get info page mfn for HVM domain.\n"); - domain_crash_synchronous(); - } - - p = map_domain_page(mfn); - if ( p == NULL ) { - printk("Can not map info page for HVM domain.\n"); - domain_crash_synchronous(); - } - - t = (struct hvm_info_table *)(p + HVM_INFO_OFFSET); - - if ( validate_hvm_info(t) ) { - d->arch.hvm_domain.nr_vcpus = t->nr_vcpus; - d->arch.hvm_domain.apic_enabled = t->apic_enabled; - d->arch.hvm_domain.pae_enabled = t->pae_enabled; - } else { - printk("Bad hvm info table\n"); - d->arch.hvm_domain.nr_vcpus = 1; - d->arch.hvm_domain.apic_enabled = 0; - d->arch.hvm_domain.pae_enabled = 0; - } - - unmap_domain_page(p); +static void evtchn_callback_func(void *v) +{ + hvm_assist_complete(v); +} + +void hvm_create_event_channels(struct vcpu *v) +{ + vcpu_iodata_t *p; + p = get_vio(v->domain, v->vcpu_id); + v->arch.hvm_vcpu.xen_port = p->vp_xen_port = + alloc_xen_event_channel(evtchn_callback_func, + v, + dom0); + DPRINTK("Allocated port %d for hvm.\n", v->arch.hvm_vcpu.xen_port); } void hvm_setup_platform(struct domain* d) @@ -196,8 +185,7 @@ void hvm_setup_platform(struct domain* d domain_crash_synchronous(); } - hvm_map_io_shared_page(d); - hvm_get_info(d); + hvm_zap_iommu_pages(d); platform = &d->arch.hvm_domain; pic_init(&platform->vpic, pic_irq_request, &platform->interrupt_request); @@ -329,6 +317,59 @@ void hvm_print_line(struct vcpu *v, cons pbuf[(*index)++] = c; } +void hvm_release_assist_channel(struct vcpu *v) +{ + release_xen_event_channel(v->arch.hvm_vcpu.xen_port); +} + +#if defined(__i386__) +typedef unsigned long hvm_hypercall_handler(unsigned long, unsigned long, + unsigned long, unsigned long, + unsigned long); +#define HYPERCALL(x) [ __HYPERVISOR_ ## x ] = (hvm_hypercall_handler *) do_ ## x +static hvm_hypercall_handler *hvm_hypercall_table[] = { + HYPERCALL(mmu_update), + HYPERCALL(memory_op), + HYPERCALL(multicall), + HYPERCALL(update_va_mapping), + HYPERCALL(event_channel_op_compat), + HYPERCALL(xen_version), + HYPERCALL(grant_table_op), + HYPERCALL(event_channel_op), + HYPERCALL(hvm_op) +}; +#undef HYPERCALL + +void hvm_do_hypercall(struct cpu_user_regs *pregs) +{ + if (pregs->eax > ARRAY_SIZE(hvm_hypercall_table) || + !hvm_hypercall_table[pregs->eax]) { + DPRINTK("HVM vcpu %d:%d did a bad hypercall %d.\n", + current->domain->domain_id, current->vcpu_id, + pregs->eax); + pregs->eax = -ENOSYS; + } else { + pregs->eax = hvm_hypercall_table[pregs->eax](pregs->ebx, pregs->ecx, + pregs->edx, pregs->esi, + pregs->edi); + } +} +#else +void hvm_do_hypercall(struct cpu_user_regs *pregs) +{ + printk("not supported yet!\n"); +} +#endif + +/* Initialise a hypercall transfer page for a VMX domain using + paravirtualised drivers. */ +void hvm_hypercall_page_initialise(struct domain *d, + void *hypercall_page) +{ + hvm_funcs.init_hypercall_page(d, hypercall_page); +} + + /* * only called in HVM domain BSP context * when booting, vcpuid is always equal to apic_id @@ -372,6 +413,57 @@ int hvm_bringup_ap(int vcpuid, int tramp xfree(ctxt); + return rc; +} + +long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) + +{ + long rc = 0; + + switch (op) + { + case HVMOP_set_param: + case HVMOP_get_param: + { + struct xen_hvm_param a; + struct domain *d; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + if ( a.index < 0 || a.index > HVM_NR_PARAMS ) { + return -EINVAL; + } + + if ( a.domid == DOMID_SELF ) { + get_knownalive_domain(current->domain); + d = current->domain; + } else if ( IS_PRIV(current->domain) ) { + d = find_domain_by_id(a.domid); + if ( !d ) { + return -ESRCH; + } + } else { + return -EPERM; + } + + if ( op == HVMOP_set_param ) { + rc = 0; + d->arch.hvm_domain.params[a.index] = a.value; + } else { + rc = d->arch.hvm_domain.params[a.index]; + } + + put_domain(d); + return rc; + } + default: + { + DPRINTK("Bad HVM op %ld.\n", op); + rc = -EINVAL; + } + } return rc; } diff -r ecb8ff1fcf1f xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/intercept.c Tue Jul 18 13:43:27 2006 +0100 @@ -211,7 +211,7 @@ void hlt_timer_fn(void *data) { struct vcpu *v = data; - evtchn_set_pending(v, iopacket_port(v)); + hvm_prod_vcpu(v); } static __inline__ void missed_ticks(struct periodic_time *pt) diff -r ecb8ff1fcf1f xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/io.c Tue Jul 18 13:43:27 2006 +0100 @@ -687,85 +687,18 @@ void hvm_io_assist(struct vcpu *v) p = &vio->vp_ioreq; - /* clear IO wait HVM flag */ - if ( test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) ) { - if ( p->state == STATE_IORESP_READY ) { - p->state = STATE_INVALID; - clear_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags); - - if ( p->type == IOREQ_TYPE_PIO ) - hvm_pio_assist(regs, p, io_opp); - else { - hvm_mmio_assist(regs, p, io_opp); - hvm_load_cpu_guest_regs(v, regs); - } - - /* Copy register changes back into current guest state. */ - memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); - } - /* else an interrupt send event raced us */ - } -} - -/* - * On exit from hvm_wait_io, we're guaranteed not to be waiting on - * I/O response from the device model. - */ -void hvm_wait_io(void) -{ - struct vcpu *v = current; - struct domain *d = v->domain; - int port = iopacket_port(v); - - for ( ; ; ) - { - /* Clear master flag, selector flag, event flag each in turn. */ - v->vcpu_info->evtchn_upcall_pending = 0; - clear_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); - smp_mb__after_clear_bit(); - if ( test_and_clear_bit(port, &d->shared_info->evtchn_pending[0]) ) - hvm_io_assist(v); - - /* Need to wait for I/O responses? */ - if ( !test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) ) - break; - - do_sched_op_compat(SCHEDOP_block, 0); - } - - /* - * Re-set the selector and master flags in case any other notifications - * are pending. - */ - if ( d->shared_info->evtchn_pending[port/BITS_PER_LONG] ) - set_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); - if ( v->vcpu_info->evtchn_pending_sel ) - v->vcpu_info->evtchn_upcall_pending = 1; -} - -void hvm_safe_block(void) -{ - struct vcpu *v = current; - struct domain *d = v->domain; - int port = iopacket_port(v); - - for ( ; ; ) - { - /* Clear master flag & selector flag so we will wake from block. */ - v->vcpu_info->evtchn_upcall_pending = 0; - clear_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); - smp_mb__after_clear_bit(); - - /* Event pending already? */ - if ( test_bit(port, &d->shared_info->evtchn_pending[0]) ) - break; - - do_sched_op_compat(SCHEDOP_block, 0); - } - - /* Reflect pending event in selector and master flags. */ - set_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); - v->vcpu_info->evtchn_upcall_pending = 1; + if (p->state == STATE_IORESP_READY) { + p->state = STATE_INVALID; + if (p->type == IOREQ_TYPE_PIO) + hvm_pio_assist(regs, p, io_opp); + else { + hvm_mmio_assist(regs, p, io_opp); + hvm_load_cpu_guest_regs(v, regs); + } + + /* Copy register changes back into current guest state. */ + memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); + } } /* diff -r ecb8ff1fcf1f xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/platform.c Tue Jul 18 13:43:27 2006 +0100 @@ -669,6 +669,37 @@ int inst_copy_from_guest(unsigned char * return inst_len; } +static void hvm_send_assist_req(struct vcpu *v) +{ + ioreq_t *p; + + ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)); + spin_lock(&v->pause_lock); + if ( v->pause_count++ == 0 ) + set_bit(_VCPUF_paused, &v->vcpu_flags); + spin_unlock(&v->pause_lock); + set_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags); + mb(); + p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; + if (unlikely(p->state != STATE_INVALID)) { + /* This indicates a bug in the device model. Crash the + domain. */ + printf("Device model set bad IO state %d.\n", p->state); + domain_crash(v->domain); + return; + } + vcpu_sleep_nosync(v); + wmb(); + p->state = STATE_IOREQ_READY; + notify_xen_event_channel(v->arch.hvm_vcpu.xen_port); +} + +/* Wake up a vcpu whihc is waiting for interrupts to come in */ +void hvm_prod_vcpu(struct vcpu *v) +{ + vcpu_unblock(v); +} + void send_pio_req(struct cpu_user_regs *regs, unsigned long port, unsigned long count, int size, long value, int dir, int pvalid) { @@ -682,13 +713,11 @@ void send_pio_req(struct cpu_user_regs * domain_crash_synchronous(); } - if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) { - printf("HVM I/O has not yet completed\n"); - domain_crash_synchronous(); - } - set_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags); - p = &vio->vp_ioreq; + if (p->state != STATE_INVALID) { + printf("WARNING: send pio with something already pending (%d)?\n", + p->state); + } p->dir = dir; p->pdata_valid = pvalid; @@ -714,15 +743,11 @@ void send_pio_req(struct cpu_user_regs * return; } - p->state = STATE_IOREQ_READY; - - evtchn_send(iopacket_port(v)); - hvm_wait_io(); -} - -void send_mmio_req( - unsigned char type, unsigned long gpa, - unsigned long count, int size, long value, int dir, int pvalid) + hvm_send_assist_req(v); +} + +static void send_mmio_req(unsigned char type, unsigned long gpa, + unsigned long count, int size, long value, int dir, int pvalid) { struct vcpu *v = current; vcpu_iodata_t *vio; @@ -739,12 +764,10 @@ void send_mmio_req( p = &vio->vp_ioreq; - if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) { - printf("HVM I/O has not yet completed\n"); - domain_crash_synchronous(); - } - - set_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags); + if (p->state != STATE_INVALID) { + printf("WARNING: send pio with something already pending (%d)?\n", + p->state); + } p->dir = dir; p->pdata_valid = pvalid; @@ -770,10 +793,7 @@ void send_mmio_req( return; } - p->state = STATE_IOREQ_READY; - - evtchn_send(iopacket_port(v)); - hvm_wait_io(); + hvm_send_assist_req(v); } static void mmio_operands(int type, unsigned long gpa, struct instruction *inst, @@ -1035,6 +1055,108 @@ void handle_mmio(unsigned long va, unsig } } +void hvm_assist_complete(struct vcpu *v) +{ + ioreq_t *p; + /* The device model just sent an event channel message to us. Either: + + a) It just finished processing a request, or + b) it wants us to send an interrupt into the guest. + + We only need to handle case (b) explicitly if there is no pending + IO request from us to the device model (since if there is, we'll + pick up the interrupt when the request completes). */ + p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; + if (p->state == STATE_IORESP_READY) { + /* There's a race here, in that the device model could set + p->state while we're not looking, but we don't care, since + that would imply that *this* notification is not related to + that state transition, and so there'll be another one along + shortly. */ + if (test_and_clear_bit(ARCH_HVM_IO_WAIT, + &v->arch.hvm_vcpu.ioflags)) { + /* Just completed a wait-for-io, so we can unpause the + vcpu. It'll pick up the response when it returns. */ + vcpu_unpause(v); + return; + } else { + /* Someone got in and processed the response before us. + Just to be on the safe side, treat this as an interrupt + delivery. */ + /* (the other path implicitly does interrupt delivery as + the vcpu returns to the guest) */ + } + } + + /* Evtchn message must have been for interrupt delivery. */ + hvm_prod_vcpu(v); + smp_send_event_check_cpu(v->processor); +} + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +/* Note that copy_{to,from}_user_hvm don't set the A and D bits on + PTEs, and require the PTE to be writable even when they're only + trying to read from it. The guest is expected to deal with + this. */ +unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len) +{ + unsigned long mfn; + unsigned long va; + void *map; + unsigned long off_in_page; + unsigned long chunk_size; + + ASSERT(hvm_guest(current)); + va = (unsigned long)to; + off_in_page = va % PAGE_SIZE; + while (len != 0) { + mfn = gva_to_mfn(va); + if (!mfn) + break; + map = map_domain_page(mfn); + if (!map) + break; + chunk_size = MIN(len, PAGE_SIZE - off_in_page); + memcpy(map + off_in_page, from, chunk_size); + unmap_domain_page(map); + off_in_page = 0; + len -= chunk_size; + from += chunk_size; + va += chunk_size; + } + return len; +} + +unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len) +{ + unsigned long mfn; + unsigned long va; + void *map; + unsigned long off_in_page; + unsigned long chunk_size; + + ASSERT(hvm_guest(current)); + va = (unsigned long)from; + off_in_page = va % PAGE_SIZE; + while (len != 0) { + mfn = gva_to_mfn(va); + if (!mfn) + break; + map = map_domain_page(mfn); + if (!map) + break; + chunk_size = MIN(len, PAGE_SIZE - off_in_page); + memcpy(to, map + off_in_page, chunk_size); + unmap_domain_page(map); + off_in_page = 0; + len -= chunk_size; + to += chunk_size; + va += chunk_size; + } + return len; +} + /* * Local variables: * mode: C diff -r ecb8ff1fcf1f xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Tue Jul 18 13:43:27 2006 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -456,6 +457,28 @@ void svm_init_ap_context(struct vcpu_gue ctxt->flags = VGCF_HVM_GUEST; } +static void svm_init_hypercall_page(struct domain *d, void *hypercall_page) +{ + char *p; + int i; + + memset(hypercall_page, 0, PAGE_SIZE); + + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */ + *(u32 *)(p + 1) = i; + *(u8 *)(p + 5) = 0x0f; /* vmmcall */ + *(u8 *)(p + 6) = 0x01; + *(u8 *)(p + 7) = 0xd9; + *(u8 *)(p + 8) = 0xc3; /* ret */ + } + + /* Don't support HYPERVISOR_iret at the moment */ + *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */ +} + int start_svm(void) { u32 eax, ecx, edx; @@ -503,6 +526,8 @@ int start_svm(void) hvm_funcs.instruction_length = svm_instruction_length; hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg; hvm_funcs.init_ap_context = svm_init_ap_context; + + hvm_funcs.init_hypercall_page = svm_init_hypercall_page; hvm_enabled = 1; @@ -2085,7 +2110,7 @@ static inline void svm_vmexit_do_hlt(str next_wakeup = next_pit; if ( next_wakeup != - 1 ) set_timer(¤t->arch.hvm_svm.hlt_timer, next_wakeup); - hvm_safe_block(); + do_sched_op_compat(SCHEDOP_block, 0); } @@ -2314,33 +2339,39 @@ static int svm_do_vmmcall(struct vcpu *v inst_len = __get_instruction_length(vmcb, INSTR_VMCALL, NULL); ASSERT(inst_len > 0); - /* VMMCALL sanity check */ - if (vmcb->cpl > get_vmmcall_cpl(regs->edi)) - { - printf("VMMCALL CPL check failed\n"); - return -1; - } - - /* handle the request */ - switch (regs->edi) - { - case VMMCALL_RESET_TO_REALMODE: - if (svm_do_vmmcall_reset_to_realmode(v, regs)) - { - printf("svm_do_vmmcall_reset_to_realmode() failed\n"); + if (regs->eax & 0x80000000) { + /* VMMCALL sanity check */ + if (vmcb->cpl > get_vmmcall_cpl(regs->edi)) + { + printf("VMMCALL CPL check failed\n"); return -1; } - - /* since we just reset the VMCB, return without adjusting the eip */ - return 0; - case VMMCALL_DEBUG: - printf("DEBUG features not implemented yet\n"); - break; - default: - break; - } - - hvm_print_line(v, regs->eax); /* provides the current domain */ + + /* handle the request */ + switch (regs->eax) + { + case VMMCALL_RESET_TO_REALMODE: + if (svm_do_vmmcall_reset_to_realmode(v, regs)) + { + printf("svm_do_vmmcall_reset_to_realmode() failed\n"); + return -1; + } + /* since we just reset the VMCB, return without adjusting + * the eip */ + return 0; + + case VMMCALL_DEBUG: + printf("DEBUG features not implemented yet\n"); + break; + default: + break; + } + + hvm_print_line(v, regs->eax); /* provides the current domain */ + } else { + /* It's a hypercall */ + hvm_do_hypercall(regs); + } __update_guest_eip(vmcb, inst_len); return 0; diff -r ecb8ff1fcf1f xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/svm/vmcb.c Tue Jul 18 13:43:27 2006 +0100 @@ -370,18 +370,6 @@ void svm_do_launch(struct vcpu *v) if (v->vcpu_id == 0) hvm_setup_platform(v->domain); - if ( evtchn_bind_vcpu(iopacket_port(v), v->vcpu_id) < 0 ) - { - printk("HVM domain bind port %d to vcpu %d failed!\n", - iopacket_port(v), v->vcpu_id); - domain_crash_synchronous(); - } - - HVM_DBG_LOG(DBG_LEVEL_1, "eport: %x", iopacket_port(v)); - - clear_bit(iopacket_port(v), - &v->domain->shared_info->evtchn_mask[0]); - if (hvm_apic_support(v->domain)) vlapic_init(v); init_timer(&v->arch.hvm_svm.hlt_timer, @@ -455,9 +443,10 @@ void svm_do_resume(struct vcpu *v) pickup_deactive_ticks(pt); } - if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) || - test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) ) - hvm_wait_io(); + if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) { + hvm_io_assist(v); + ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)); + } /* We can't resume the guest if we're waiting on I/O */ ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)); diff -r ecb8ff1fcf1f xen/arch/x86/hvm/vlapic.c --- a/xen/arch/x86/hvm/vlapic.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/vlapic.c Tue Jul 18 13:43:27 2006 +0100 @@ -33,6 +33,7 @@ #include #include #include +#include /* XXX remove this definition after GFW enabled */ #define VLAPIC_NO_BIOS @@ -63,7 +64,7 @@ int vlapic_find_highest_irr(struct vlapi int hvm_apic_support(struct domain *d) { - return d->arch.hvm_domain.apic_enabled; + return d->arch.hvm_domain.params[HVM_PARAM_APIC_ENABLED]; } s_time_t get_apictime_scheduled(struct vcpu *v) @@ -223,7 +224,7 @@ static int vlapic_accept_irq(struct vcpu "level trig mode for vector %d\n", vector); set_bit(vector, &vlapic->tmr[0]); } - evtchn_set_pending(v, iopacket_port(v)); + hvm_prod_vcpu(v); result = 1; break; @@ -367,7 +368,7 @@ int vlapic_check_vector(struct vlapic *v return 1; } -void vlapic_ipi(struct vlapic *vlapic) +static void vlapic_ipi(struct vlapic *vlapic) { unsigned int dest = (vlapic->icr_high >> 24) & 0xff; unsigned int short_hand = (vlapic->icr_low >> 18) & 3; diff -r ecb8ff1fcf1f xen/arch/x86/hvm/vmx/io.c --- a/xen/arch/x86/hvm/vmx/io.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/io.c Tue Jul 18 13:43:27 2006 +0100 @@ -142,6 +142,7 @@ asmlinkage void vmx_intr_assist(void) struct hvm_domain *plat=&v->domain->arch.hvm_domain; struct periodic_time *pt = &plat->pl_time.periodic_tm; struct hvm_virpic *pic= &plat->vpic; + int callback_irq; unsigned int idtv_info_field; unsigned long inst_len; int has_ext_irq; @@ -152,6 +153,15 @@ asmlinkage void vmx_intr_assist(void) if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) { pic_set_irq(pic, pt->irq, 0); pic_set_irq(pic, pt->irq, 1); + } + + callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; + if ( callback_irq != 0 && + local_events_need_delivery() ) { + /*inject para-device call back irq*/ + v->vcpu_info->evtchn_upcall_mask = 1; + pic_set_irq(pic, callback_irq, 0); + pic_set_irq(pic, callback_irq, 1); } has_ext_irq = cpu_has_pending_irq(v); @@ -220,7 +230,7 @@ asmlinkage void vmx_intr_assist(void) void vmx_do_resume(struct vcpu *v) { - struct domain *d = v->domain; + ioreq_t *p; struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm; vmx_stts(); @@ -234,9 +244,13 @@ void vmx_do_resume(struct vcpu *v) pickup_deactive_ticks(pt); } - if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) || - test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) ) - hvm_wait_io(); + p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; + if (p->state == STATE_IORESP_READY) + hvm_io_assist(v); + if (p->state != STATE_INVALID) { + printf("Weird HVM iorequest state %d.\n", p->state); + domain_crash(v->domain); + } /* We can't resume the guest if we're waiting on I/O */ ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)); diff -r ecb8ff1fcf1f xen/arch/x86/hvm/vmx/vmcs.c --- a/xen/arch/x86/hvm/vmx/vmcs.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmcs.c Tue Jul 18 13:43:27 2006 +0100 @@ -245,18 +245,6 @@ static void vmx_do_launch(struct vcpu *v if (v->vcpu_id == 0) hvm_setup_platform(v->domain); - if ( evtchn_bind_vcpu(iopacket_port(v), v->vcpu_id) < 0 ) - { - printk("VMX domain bind port %d to vcpu %d failed!\n", - iopacket_port(v), v->vcpu_id); - domain_crash_synchronous(); - } - - HVM_DBG_LOG(DBG_LEVEL_1, "eport: %x", iopacket_port(v)); - - clear_bit(iopacket_port(v), - &v->domain->shared_info->evtchn_mask[0]); - __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (cr0) : ); error |= __vmwrite(GUEST_CR0, cr0); diff -r ecb8ff1fcf1f xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Tue Jul 18 13:43:27 2006 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,7 @@ static void vmx_relinquish_guest_resourc kill_timer(&VLAPIC(v)->vlapic_timer); xfree(VLAPIC(v)); } + hvm_release_assist_channel(v); } kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer); @@ -669,6 +671,28 @@ static int check_vmx_controls(u32 ctrls, return 1; } +static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page) +{ + char *p; + int i; + + memset(hypercall_page, 0, PAGE_SIZE); + + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */ + *(u32 *)(p + 1) = i; + *(u8 *)(p + 5) = 0x0f; /* vmcall */ + *(u8 *)(p + 6) = 0x01; + *(u8 *)(p + 7) = 0xc1; + *(u8 *)(p + 8) = 0xc3; /* ret */ + } + + /* Don't support HYPERVISOR_iret at the moment */ + *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */ +} + int start_vmx(void) { u32 eax, edx; @@ -748,6 +772,8 @@ int start_vmx(void) hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; hvm_funcs.init_ap_context = vmx_init_ap_context; + + hvm_funcs.init_hypercall_page = vmx_init_hypercall_page; hvm_enabled = 1; @@ -1968,7 +1994,7 @@ void vmx_vmexit_do_hlt(void) next_wakeup = next_pit; if ( next_wakeup != - 1 ) set_timer(¤t->arch.hvm_vmx.hlt_timer, next_wakeup); - hvm_safe_block(); + do_sched_op_compat(SCHEDOP_block, 0); } static inline void vmx_vmexit_do_extint(struct cpu_user_regs *regs) @@ -2138,11 +2164,10 @@ asmlinkage void vmx_vmexit_handler(struc * (1) We can get an exception (e.g. #PG) in the guest, or * (2) NMI */ - int error; unsigned int vector; unsigned long va; - if ((error = __vmread(VM_EXIT_INTR_INFO, &vector)) + if (__vmread(VM_EXIT_INTR_INFO, &vector) || !(vector & INTR_INFO_VALID_MASK)) __hvm_bug(®s); vector &= INTR_INFO_VECTOR_MASK; @@ -2215,7 +2240,7 @@ asmlinkage void vmx_vmexit_handler(struc (unsigned long)regs.ecx, (unsigned long)regs.edx, (unsigned long)regs.esi, (unsigned long)regs.edi); - if (!(error = vmx_do_page_fault(va, ®s))) { + if (!vmx_do_page_fault(va, ®s)) { /* * Inject #PG using Interruption-Information Fields */ @@ -2273,16 +2298,16 @@ asmlinkage void vmx_vmexit_handler(struc __update_guest_eip(inst_len); break; } -#if 0 /* keep this for debugging */ case EXIT_REASON_VMCALL: + { __get_instruction_length(inst_len); __vmread(GUEST_RIP, &eip); __vmread(EXIT_QUALIFICATION, &exit_qualification); - hvm_print_line(v, regs.eax); /* provides the current domain */ + hvm_do_hypercall(®s); __update_guest_eip(inst_len); break; -#endif + } case EXIT_REASON_CR_ACCESS: { __vmread(GUEST_RIP, &eip); @@ -2323,7 +2348,6 @@ asmlinkage void vmx_vmexit_handler(struc case EXIT_REASON_MWAIT_INSTRUCTION: __hvm_bug(®s); break; - case EXIT_REASON_VMCALL: case EXIT_REASON_VMCLEAR: case EXIT_REASON_VMLAUNCH: case EXIT_REASON_VMPTRLD: diff -r ecb8ff1fcf1f xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/mm.c Tue Jul 18 13:43:27 2006 +0100 @@ -2982,7 +2982,12 @@ long arch_memory_op(int op, XEN_GUEST_HA if ( copy_from_guest(&xatp, arg, 1) ) return -EFAULT; - if ( (d = find_domain_by_id(xatp.domid)) == NULL ) + if ( xatp.domid == DOMID_SELF ) { + d = current->domain; + get_knownalive_domain(d); + } else if ( !IS_PRIV(current->domain) ) + return -EPERM; + else if ( (d = find_domain_by_id(xatp.domid)) == NULL ) return -ESRCH; switch ( xatp.space ) diff -r ecb8ff1fcf1f xen/arch/x86/x86_32/entry.S --- a/xen/arch/x86/x86_32/entry.S Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/x86_32/entry.S Tue Jul 18 13:43:27 2006 +0100 @@ -656,6 +656,7 @@ ENTRY(hypercall_table) .long do_xenoprof_op .long do_event_channel_op .long do_physdev_op + .long do_hvm_op /* 34 */ .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -695,6 +696,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_xenoprof_op */ .byte 2 /* do_event_channel_op */ .byte 2 /* do_physdev_op */ + .byte 2 /* do_hvm_op */ /* 34 */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff -r ecb8ff1fcf1f xen/arch/x86/x86_32/traps.c --- a/xen/arch/x86/x86_32/traps.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/arch/x86/x86_32/traps.c Tue Jul 18 13:43:27 2006 +0100 @@ -486,9 +486,11 @@ static void hypercall_page_initialise_ri *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */ } -void hypercall_page_initialise(void *hypercall_page) -{ - if ( supervisor_mode_kernel ) +void hypercall_page_initialise(struct domain *d, void *hypercall_page) +{ + if ( hvm_guest(d->vcpu[0]) ) + hvm_hypercall_page_initialise(d, hypercall_page); + else if ( supervisor_mode_kernel ) hypercall_page_initialise_ring0_kernel(hypercall_page); else hypercall_page_initialise_ring1_kernel(hypercall_page); diff -r ecb8ff1fcf1f xen/common/event_channel.c --- a/xen/common/event_channel.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/common/event_channel.c Tue Jul 18 13:43:27 2006 +0100 @@ -46,6 +46,104 @@ goto out; \ } while ( 0 ) +#define NR_XEN_EVENT_CHANNELS 32 +#define XECS_FREE 0 /* Not in use at all */ +#define XECS_UNBOUND 1 /* Allocated but not bound to */ +#define XECS_BOUND 2 /* Bound to somewhere in domain-space */ +#define XECS_HBOUND 3 /* Half bound: Xen is trying to tear this + down, but a domain is still attached */ +struct xen_evtchn { + int state; + + void (*fire)(void *d); /* called when dom0 tries to send on this + event channel. */ + void *data; + + struct domain *dom; /* Who is allowed to bind/currently bound */ + int dom_port; +}; + +static struct xen_evtchn xen_event_channels[NR_XEN_EVENT_CHANNELS]; +/* Leaf lock protecting the xen_event_channels array. */ +static spinlock_t xen_event_channel_lock = SPIN_LOCK_UNLOCKED; + +int alloc_xen_event_channel(void (*f)(void *d), + void *data, + struct domain *d) +{ + int ind; + + spin_lock(&xen_event_channel_lock); + for (ind = 0; ind < NR_XEN_EVENT_CHANNELS; ind++) + if ( xen_event_channels[ind].state == XECS_FREE ) + break; + if ( ind == NR_XEN_EVENT_CHANNELS ) { + printf("Out of Xen event channels?\n"); + ind = -1; + goto out; + } + xen_event_channels[ind].state = XECS_UNBOUND; + xen_event_channels[ind].fire = f; + xen_event_channels[ind].data = data; + xen_event_channels[ind].dom = d; + out: + spin_unlock(&xen_event_channel_lock); + return ind; +} + +void release_xen_event_channel(int ind) +{ + spin_lock(&xen_event_channel_lock); + switch ( xen_event_channels[ind].state ) { + case XECS_UNBOUND: + xen_event_channels[ind].state = XECS_FREE; + break; + case XECS_BOUND: + xen_event_channels[ind].state = XECS_HBOUND; + break; + case XECS_HBOUND: + panic("Double free of Xen event channel.\n"); + case XECS_FREE: + printf("Attempt to free non-allocated Xen event channel %d?\n", + ind); + default: + BUG(); + } + + spin_unlock(&xen_event_channel_lock); +} + +void notify_xen_event_channel(int port) +{ + struct xen_evtchn *xchn = xen_event_channels + port; + struct domain *d = NULL; + struct evtchn *chn; + + /* We rely on our caller to ensure that nobody's trying to tear + the channel down from inside Xen while it's being signalled on. + That means that the only transition the channel could make is + from BOUND to UNBOUND or vice-versa. Neither of those change + the dom field, so we can read it without taking a lock. This + simplifies the lock ordering a bit. */ + d = xchn->dom; + ASSERT(d); + if ( !get_domain(d) ) + return; + spin_lock(&d->evtchn_lock); + spin_lock(&xen_event_channel_lock); + if ( xchn->state != XECS_UNBOUND ) { + BUG_ON(xchn->state != XECS_BOUND); + BUG_ON(d != xchn->dom); + chn = evtchn_from_port(d, xchn->dom_port); + if ( chn->state == ECS_XEN ) + evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], + xchn->dom_port); + } else + printf("Send on unbound Xen event channel?\n"); + + spin_unlock(&d->evtchn_lock); + spin_unlock(&xen_event_channel_lock); +} static int virq_is_global(int virq) { @@ -134,6 +232,44 @@ static long evtchn_alloc_unbound(evtchn_ } +static long evtchn_bind_xen(struct domain *ld, int xen_port) +{ + long rc = 0; + struct evtchn *lchn; + struct xen_evtchn *rchn; + int lport; + + if ( xen_port < 0 || xen_port >= NR_XEN_EVENT_CHANNELS ) + return -EINVAL; + + spin_lock(&ld->evtchn_lock); + spin_lock(&xen_event_channel_lock); + + rchn = xen_event_channels + xen_port; + if ( rchn->state != XECS_UNBOUND || rchn->dom != ld ) + ERROR_EXIT(-EINVAL); + + if ( (lport = get_free_port(ld)) < 0 ) + ERROR_EXIT(lport); + lchn = evtchn_from_port(ld, lport); + lchn->state = ECS_XEN; + lchn->u.xen_port = xen_port; + + rchn->state = XECS_BOUND; + rchn->dom_port = lport; + + /* Somewhat ugly hack to avoid lost wakeups if we've tried to + notify this port before anyone got around to binding it. */ + evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); + rc = lport; + + out: + spin_unlock(&xen_event_channel_lock); + spin_unlock(&ld->evtchn_lock); + + return rc; +} + static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) { struct evtchn *lchn, *rchn; @@ -147,6 +283,15 @@ static long evtchn_bind_interdomain(evtc if ( rdom == DOMID_SELF ) rdom = current->domain->domain_id; + + if ( rdom == DOMID_XEN ) { + rc = evtchn_bind_xen(ld, rport); + if ( rc >= 0 ) { + bind->local_port = rc; + rc = 0; + } + return rc; + } if ( (rd = find_domain_by_id(rdom)) == NULL ) return -ESRCH; @@ -317,11 +462,12 @@ static long evtchn_bind_pirq(evtchn_bind static long __evtchn_close(struct domain *d1, int port1) { - struct domain *d2 = NULL; - struct vcpu *v; - struct evtchn *chn1, *chn2; - int port2; - long rc = 0; + struct domain *d2 = NULL; + struct vcpu *v; + struct evtchn *chn1, *chn2; + int port2; + long rc = 0; + struct xen_evtchn *xchn; again: spin_lock(&d1->evtchn_lock); @@ -409,6 +555,19 @@ static long __evtchn_close(struct domain chn2->u.unbound.remote_domid = d1->domain_id; break; + case ECS_XEN: + spin_lock(&xen_event_channel_lock); + xchn = xen_event_channels + chn1->u.xen_port; + BUG_ON(xchn->dom != d1); + if ( xchn->state == XECS_HBOUND ) + xchn->state = XECS_FREE; + else if (xchn->state == XECS_BOUND) + xchn->state = XECS_UNBOUND; + else + BUG(); + spin_unlock(&xen_event_channel_lock); + break; + default: BUG(); } @@ -442,6 +601,7 @@ long evtchn_send(unsigned int lport) struct evtchn *lchn, *rchn; struct domain *ld = current->domain, *rd; int rport, ret = 0; + struct xen_evtchn *xchn; spin_lock(&ld->evtchn_lock); @@ -465,6 +625,16 @@ long evtchn_send(unsigned int lport) break; case ECS_UNBOUND: /* silently drop the notification */ + break; + case ECS_XEN: + xchn = xen_event_channels + lchn->u.xen_port; + spin_lock(&xen_event_channel_lock); + if ( xchn->state != XECS_HBOUND ) + { + BUG_ON(xchn->state != XECS_BOUND); + xchn->fire(xchn->data); + } + spin_unlock(&xen_event_channel_lock); break; default: ret = -EINVAL; @@ -596,6 +766,11 @@ static long evtchn_status(evtchn_status_ chn->u.interdomain.remote_dom->domain_id; status->u.interdomain.port = chn->u.interdomain.remote_port; break; + case ECS_XEN: + status->status = EVTCHNSTAT_interdomain; + status->u.interdomain.dom = DOMID_XEN; + status->u.interdomain.port = chn->u.xen_port; + break; case ECS_PIRQ: status->status = EVTCHNSTAT_pirq; status->u.pirq = chn->u.pirq; @@ -649,6 +824,7 @@ long evtchn_bind_vcpu(unsigned int port, case ECS_UNBOUND: case ECS_INTERDOMAIN: case ECS_PIRQ: + case ECS_XEN: chn->notify_vcpu_id = vcpu_id; break; default: diff -r ecb8ff1fcf1f xen/common/memory.c --- a/xen/common/memory.c Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/common/memory.c Tue Jul 18 13:43:27 2006 +0100 @@ -158,6 +158,9 @@ guest_remove_page( } page = mfn_to_page(mfn); + if ( IS_XEN_HEAP_FRAME(page) ) + return 0; + if ( unlikely(!get_page(page, d)) ) { DPRINTK("Bad page free for domain %u\n", d->domain_id); diff -r ecb8ff1fcf1f xen/include/asm-x86/domain.h --- a/xen/include/asm-x86/domain.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/domain.h Tue Jul 18 13:43:27 2006 +0100 @@ -55,7 +55,7 @@ extern void toggle_guest_mode(struct vcp * Initialise a hypercall-transfer page. The given pointer must be mapped * in Xen virtual address space (accesses are not validated or checked). */ -extern void hypercall_page_initialise(void *); +extern void hypercall_page_initialise(struct domain *d, void *); struct arch_domain { diff -r ecb8ff1fcf1f xen/include/asm-x86/guest_access.h --- a/xen/include/asm-x86/guest_access.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/guest_access.h Tue Jul 18 13:43:27 2006 +0100 @@ -8,6 +8,8 @@ #define __ASM_X86_GUEST_ACCESS_H__ #include +#include +#include /* Is the guest handle a NULL reference? */ #define guest_handle_is_null(hnd) ((hnd).p == NULL) @@ -28,6 +30,8 @@ #define copy_to_guest_offset(hnd, off, ptr, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \ copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ }) @@ -38,6 +42,8 @@ #define copy_from_guest_offset(ptr, hnd, off, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_from_user_hvm(_y, _x+(off), sizeof(*_x)*(nr)) :\ copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ }) @@ -45,6 +51,8 @@ #define copy_field_to_guest(hnd, ptr, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x, _y, sizeof(*_x)) : \ copy_to_user(_x, _y, sizeof(*_x)); \ }) @@ -52,6 +60,8 @@ #define copy_field_from_guest(ptr, hnd, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_from_user_hvm(_y, _x, sizeof(*_x)) : \ copy_from_user(_y, _x, sizeof(*_x)); \ }) @@ -60,29 +70,37 @@ * Allows use of faster __copy_* functions. */ #define guest_handle_okay(hnd, nr) \ - array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)) + (hvm_guest(current) || array_access_ok((hnd).p, (nr), sizeof(*(hnd).p))) #define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \ __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ }) #define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_from_user_hvm(_y, _x+(off),sizeof(*_x)*(nr)) : \ __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ }) #define __copy_field_to_guest(hnd, ptr, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x, _y, sizeof(*_x)) : \ __copy_to_user(_x, _y, sizeof(*_x)); \ }) #define __copy_field_from_guest(ptr, hnd, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_from_user_hvm(_x, _y, sizeof(*_x)) : \ __copy_from_user(_y, _x, sizeof(*_x)); \ }) diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/hvm/domain.h Tue Jul 18 13:43:27 2006 +0100 @@ -27,17 +27,15 @@ #include #include #include +#include #define HVM_PBUF_SIZE 80 struct hvm_domain { unsigned long shared_page_va; - unsigned int nr_vcpus; - unsigned int apic_enabled; - unsigned int pae_enabled; s64 tsc_frequency; struct pl_time pl_time; - + struct hvm_virpic vpic; struct hvm_vioapic vioapic; struct hvm_io_handler io_handler; @@ -48,6 +46,8 @@ struct hvm_domain { int pbuf_index; char pbuf[HVM_PBUF_SIZE]; + + unsigned long params[HVM_NR_PARAMS]; }; #endif /* __ASM_X86_HVM_DOMAIN_H__ */ diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/hvm/hvm.h Tue Jul 18 13:43:27 2006 +0100 @@ -61,6 +61,8 @@ struct hvm_function_table { void (*init_ap_context)(struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector); + + void (*init_hypercall_page)(struct domain *d, void *hypercall_page); }; extern struct hvm_function_table hvm_funcs; @@ -75,12 +77,20 @@ hvm_disable(void) hvm_funcs.disable(); } +void hvm_create_event_channels(struct vcpu *v); +void hvm_map_io_shared_page(struct vcpu *v); + static inline int hvm_initialize_guest_resources(struct vcpu *v) { - if ( hvm_funcs.initialize_guest_resources ) - return hvm_funcs.initialize_guest_resources(v); - return 0; + int ret = 1; + if (hvm_funcs.initialize_guest_resources) + ret = hvm_funcs.initialize_guest_resources(v); + if (ret == 1) { + hvm_map_io_shared_page(v); + hvm_create_event_channels(v); + } + return ret; } static inline void @@ -121,6 +131,9 @@ hvm_instruction_length(struct vcpu *v) return hvm_funcs.instruction_length(v); } +void hvm_hypercall_page_initialise(struct domain *d, + void *hypercall_page); + static inline unsigned long hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num) { diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/io.h --- a/xen/include/asm-x86/hvm/io.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/hvm/io.h Tue Jul 18 13:43:27 2006 +0100 @@ -150,14 +150,14 @@ static inline int irq_masked(unsigned lo #endif extern void handle_mmio(unsigned long, unsigned long); -extern void hvm_wait_io(void); -extern void hvm_safe_block(void); extern void hvm_io_assist(struct vcpu *v); extern void pic_irq_request(void *data, int level); extern void hvm_pic_assist(struct vcpu *v); extern int cpu_get_interrupt(struct vcpu *v, int *type); extern int cpu_has_pending_irq(struct vcpu *v); +void hvm_release_assist_channel(struct vcpu *v); + // XXX - think about this, maybe use bit 30 of the mfn to signify an MMIO frame. #define mmio_space(gpa) (!VALID_MFN(get_mfn_from_gpfn((gpa) >> PAGE_SHIFT))) diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/support.h --- a/xen/include/asm-x86/hvm/support.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/hvm/support.h Tue Jul 18 13:43:27 2006 +0100 @@ -42,11 +42,6 @@ static inline vcpu_iodata_t *get_vio(str static inline vcpu_iodata_t *get_vio(struct domain *d, unsigned long cpu) { return &get_sp(d)->vcpu_iodata[cpu]; -} - -static inline int iopacket_port(struct vcpu *v) -{ - return get_vio(v->domain, v->vcpu_id)->vp_eport; } /* XXX these are really VMX specific */ @@ -148,4 +143,9 @@ extern void hvm_print_line(struct vcpu * extern void hvm_print_line(struct vcpu *v, const char c); extern void hlt_timer_fn(void *data); +void hvm_prod_vcpu(struct vcpu *v); +void hvm_assist_complete(struct vcpu *v); + +void hvm_do_hypercall(struct cpu_user_regs *pregs); + #endif /* __ASM_X86_HVM_SUPPORT_H__ */ diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/svm/vmmcall.h --- a/xen/include/asm-x86/hvm/svm/vmmcall.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/hvm/svm/vmmcall.h Tue Jul 18 13:43:27 2006 +0100 @@ -23,11 +23,11 @@ #define __ASM_X86_HVM_SVM_VMMCALL_H__ /* VMMCALL command fields */ -#define VMMCALL_CODE_CPL_MASK 0xC0000000 -#define VMMCALL_CODE_MBZ_MASK 0x3FFF0000 +#define VMMCALL_CODE_CPL_MASK 0x60000000 +#define VMMCALL_CODE_MBZ_MASK 0x1FFF0000 #define VMMCALL_CODE_COMMAND_MASK 0x0000FFFF -#define MAKE_VMMCALL_CODE(cpl,func) ((cpl << 30) | (func)) +#define MAKE_VMMCALL_CODE(cpl,func) ((cpl << 29) | (func) | 0x80000000) /* CPL=0 VMMCALL Requests */ #define VMMCALL_RESET_TO_REALMODE MAKE_VMMCALL_CODE(0,1) @@ -38,7 +38,7 @@ /* return the cpl required for the vmmcall cmd */ static inline int get_vmmcall_cpl(int cmd) { - return (cmd & VMMCALL_CODE_CPL_MASK) >> 30; + return (cmd & VMMCALL_CODE_CPL_MASK) >> 29; } #endif /* __ASM_X86_HVM_SVM_VMMCALL_H__ */ diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/vcpu.h --- a/xen/include/asm-x86/hvm/vcpu.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/hvm/vcpu.h Tue Jul 18 13:43:27 2006 +0100 @@ -38,6 +38,8 @@ struct hvm_vcpu { /* For AP startup */ unsigned long init_sipi_sipi_state; + int xen_port; + /* Flags */ int flag_dr_dirty; diff -r ecb8ff1fcf1f xen/include/asm-x86/shadow.h --- a/xen/include/asm-x86/shadow.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/asm-x86/shadow.h Tue Jul 18 13:43:27 2006 +0100 @@ -1733,6 +1733,32 @@ static inline unsigned long gva_to_gpa(u return l1e_get_paddr(gpte) + (gva & ~PAGE_MASK); } + +static inline unsigned long gva_to_mfn(unsigned long gva) +{ + l1_pgentry_t l1e; + + if (__copy_from_user(&l1e, &shadow_linear_pg_table[l1_linear_offset(gva)], + sizeof(l1e)) || + (l1e_get_flags(l1e) & (_PAGE_PRESENT | _PAGE_RW)) != + (_PAGE_PRESENT | _PAGE_RW) ) { + struct cpu_user_regs cur; + /* Error code -> write */ + cur.error_code = 3; + cur.cs = 0; /* Ring 0 -> hypervisor */ + cur.eflags = 0; + shadow_fault(gva, &cur); + if (__copy_from_user(&l1e, + &shadow_linear_pg_table[l1_linear_offset(gva)], + sizeof(l1e)) || + (l1e_get_flags(l1e) & (_PAGE_PRESENT | _PAGE_RW)) != + (_PAGE_PRESENT | _PAGE_RW) ) { + return 0; + } + } + return l1e_get_pfn(l1e); +} + #endif /************************************************************************/ diff -r ecb8ff1fcf1f xen/include/public/hvm/ioreq.h --- a/xen/include/public/hvm/ioreq.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/public/hvm/ioreq.h Tue Jul 18 13:43:27 2006 +0100 @@ -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 */ @@ -67,10 +66,8 @@ typedef struct global_iodata global_ioda typedef struct global_iodata global_iodata_t; struct vcpu_iodata { - struct ioreq vp_ioreq; - /* Event channel port */ - unsigned int vp_eport; /* VMX vcpu uses this to notify DM */ - unsigned int dm_eport; /* DM uses this to notify VMX vcpu */ + ioreq_t vp_ioreq; + int vp_xen_port; }; typedef struct vcpu_iodata vcpu_iodata_t; diff -r ecb8ff1fcf1f xen/include/public/xen.h --- a/xen/include/public/xen.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/public/xen.h Tue Jul 18 13:43:27 2006 +0100 @@ -66,6 +66,7 @@ #define __HYPERVISOR_xenoprof_op 31 #define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_physdev_op 33 +#define __HYPERVISOR_hvm_op 34 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 diff -r ecb8ff1fcf1f xen/include/xen/event.h --- a/xen/include/xen/event.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/xen/event.h Tue Jul 18 13:43:27 2006 +0100 @@ -44,4 +44,10 @@ extern long evtchn_send(unsigned int lpo /* Bind a local event-channel port to the specified VCPU. */ extern long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); +int alloc_xen_event_channel(void (*f)(void *d), + void *data, + struct domain *d); +void release_xen_event_channel(int ind); +void notify_xen_event_channel(int port); + #endif /* __XEN_EVENT_H__ */ diff -r ecb8ff1fcf1f xen/include/xen/hypercall.h --- a/xen/include/xen/hypercall.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/xen/hypercall.h Tue Jul 18 13:43:27 2006 +0100 @@ -87,4 +87,9 @@ do_nmi_op( unsigned int cmd, XEN_GUEST_HANDLE(void) arg); +extern long +do_hvm_op( + unsigned long op, + XEN_GUEST_HANDLE(void) arg); + #endif /* __XEN_HYPERCALL_H__ */ diff -r ecb8ff1fcf1f xen/include/xen/sched.h --- a/xen/include/xen/sched.h Fri Jul 14 18:53:27 2006 +0100 +++ b/xen/include/xen/sched.h Tue Jul 18 13:43:27 2006 +0100 @@ -36,6 +36,7 @@ struct evtchn #define ECS_PIRQ 4 /* Channel is bound to a physical IRQ line. */ #define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */ #define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */ +#define ECS_XEN 7 /* Channel ends in Xen */ u16 state; /* ECS_* */ u16 notify_vcpu_id; /* VCPU for local delivery notification */ union { @@ -48,6 +49,7 @@ struct evtchn } interdomain; /* state == ECS_INTERDOMAIN */ u16 pirq; /* state == ECS_PIRQ */ u16 virq; /* state == ECS_VIRQ */ + int xen_port; /* state == ECS_XEN */ } u; }; diff -r ecb8ff1fcf1f tools/ioemu/hw/xen_evtchn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_evtchn.c Tue Jul 18 13:43:27 2006 +0100 @@ -0,0 +1,160 @@ +/* + * XEN event channel fake pci devicel + * + * Copyright (c) 2003-2004 Intel Corp. + * Copyright (c) 2006 XenSource + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#include +#include + +extern FILE *logfile; + +extern int domid; +extern int xc_handle; + +static unsigned ioport_base; + +static void evtchn_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + DECLARE_DOM0_OP; + int rc; + + switch (addr - ioport_base) { + case 0: + fprintf(logfile, "Init hypercall page %x, addr %x.\n", val, addr); + op.u.hypercall_init.domain = domid; + op.u.hypercall_init.gmfn = val; + op.cmd = DOM0_HYPERCALL_INIT; + rc = xc_dom0_op(xc_handle, &op); + fprintf(logfile, "result -> %d.\n", rc); + break; + default: + fprintf(logfile, "Write to bad port %x (base %x) on evtchn device.\n", + addr, ioport_base); + break; + } +} + +static uint32_t evtchn_ioport_read(void *opaque, uint32_t addr) +{ + return 0; +} + +static void evtchn_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + ioport_base = addr; + register_ioport_write(addr, 16, 4, evtchn_ioport_write, NULL); + register_ioport_read(addr, 16, 1, evtchn_ioport_read, NULL); +} + +static uint32_t xen_mmio_read(void *opaque, target_phys_addr_t addr) +{ + fprintf(logfile, "Warning: try read from evtchn mmio space\n"); + return 0; +} + +static void xen_mmio_write(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + fprintf(logfile, "Warning: try write to evtchn mmio space\n"); + return; +} + +static CPUReadMemoryFunc *xen_evtchn_mmio_read[3] = { + xen_mmio_read, + xen_mmio_read, + xen_mmio_read, +}; + +static CPUWriteMemoryFunc *xen_evtchn_mmio_write[3] = { + xen_mmio_write, + xen_mmio_write, + xen_mmio_write, +}; + +static void xen_evtchn_pci_mmio_map(PCIDevice *d, int region_num, + uint32_t addr, uint32_t size, int type) +{ + int mmio_io_addr; + + mmio_io_addr = cpu_register_io_memory(0, + xen_evtchn_mmio_read, + xen_evtchn_mmio_write, NULL); + + cpu_register_physical_memory(addr, 0x1000000, mmio_io_addr); +} + +struct pci_config_header { + unsigned short vendor_id; + unsigned short device_id; + unsigned short command; + unsigned short status; + unsigned char revision; + unsigned char api; + unsigned char subclass; + unsigned char class; + unsigned char cache_line_size; /* Units of 32 bit words */ + unsigned char latency_timer; /* In units of bus cycles */ + unsigned char header_type; /* Should be 0 */ + unsigned char bist; /* Built in self test */ + unsigned long base_address_regs[6]; + unsigned long reserved1; + unsigned long reserved2; + unsigned long rom_addr; + unsigned long reserved3; + unsigned long reserved4; + unsigned char interrupt_line; + unsigned char interrupt_pin; + unsigned char min_gnt; + unsigned char max_lat; +}; + +void pci_xen_evtchn_init(PCIBus *bus) +{ + PCIDevice *d; + struct pci_config_header *pch; + + printf("Register xen evtchn.\n"); + d = pci_register_device(bus, "xen-evtchn", sizeof(PCIDevice), -1, NULL, + NULL); + pch = (struct pci_config_header *)d->config; + pch->vendor_id = 0xfffd; + pch->device_id = 0x0101; + pch->command = 3; /* IO and memory access */ + pch->revision = 0; + pch->api = 0; + pch->subclass = 0x80; /* Other */ + pch->class = 0xff; /* Unclassified device class */ + pch->header_type = 0; + pch->interrupt_pin = 1; + + pci_register_io_region(d, 0, 0x100, PCI_ADDRESS_SPACE_IO, evtchn_map); + + /* reserve 16MB mmio address for share memory*/ + pci_register_io_region(d, 1, 0x1000000, PCI_ADDRESS_SPACE_MEM_PREFETCH, + xen_evtchn_pci_mmio_map); + + register_savevm("evtchn", 0, 1, generic_pci_save, generic_pci_load, d); + printf("Done register evtchn.\n"); +} diff -r ecb8ff1fcf1f xen/include/asm-x86/hvm/guest_access.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/hvm/guest_access.h Tue Jul 18 13:43:27 2006 +0100 @@ -0,0 +1,7 @@ +#ifndef __ASM_X86_HVM_GUEST_ACCESS_H__ +#define __ASM_X86_HVM_GUEST_ACCESS_H__ + +unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len); +unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len); + +#endif /* __ASM_X86_HVM_GUEST_ACCESS_H__ */ diff -r ecb8ff1fcf1f xen/include/public/hvm/params.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/hvm/params.h Tue Jul 18 13:43:27 2006 +0100 @@ -0,0 +1,22 @@ +#ifndef PARAMS_H__ +#define PARAMS_H__ + +#define HVM_NR_PARAMS 4 + +#define HVM_PARAM_CALLBACK_IRQ 0 +#define HVM_PARAM_STORE_PFN 1 +#define HVM_PARAM_STORE_EVTCHN 2 +#define HVM_PARAM_APIC_ENABLED 3 + +#define HVMOP_set_param 0 +#define HVMOP_get_param 1 + +struct xen_hvm_param { + domid_t domid; + unsigned index; + unsigned long value; +}; +typedef struct xen_hvm_param xen_hvm_param_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t); + +#endif /* PARAMS_H__ */