[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] merge?
# HG changeset patch # User cl349@xxxxxxxxxxxxxxxxxxxx # Node ID f27205ea60ef4b47734e4a8b8177ca1c2b25fa5d # Parent 5aae0c8158b9782dd0110a97bbe1274da6e83f6d # Parent ce018d2730c037b9d8e1a60c56328aebca5bfc48 merge? diff -r 5aae0c8158b9 -r f27205ea60ef linux-2.6-xen-sparse/mm/memory.c --- a/linux-2.6-xen-sparse/mm/memory.c Sat Sep 3 16:57:54 2005 +++ b/linux-2.6-xen-sparse/mm/memory.c Sat Sep 3 16:58:50 2005 @@ -1367,20 +1367,15 @@ struct page *old_page, *new_page; unsigned long pfn = pte_pfn(pte); pte_t entry; + struct page invalid_page; if (unlikely(!pfn_valid(pfn))) { - /* - * This should really halt the system so it can be debugged or - * at least the kernel stops what it's doing before it corrupts - * data, but for the moment just pretend this is OOM. - */ - pte_unmap(page_table); - printk(KERN_ERR "do_wp_page: bogus page at address %08lx\n", - address); - spin_unlock(&mm->page_table_lock); - return VM_FAULT_OOM; - } - old_page = pfn_to_page(pfn); + /* This can happen with /dev/mem (PROT_WRITE, MAP_PRIVATE). */ + invalid_page.flags = (1<<PG_reserved) | (1<<PG_locked); + old_page = &invalid_page; + } else { + old_page = pfn_to_page(pfn); + } if (!TestSetPageLocked(old_page)) { int reuse = can_share_swap_page(old_page); @@ -1416,7 +1411,13 @@ new_page = alloc_page_vma(GFP_HIGHUSER, vma, address); if (!new_page) goto no_new_page; - copy_user_highpage(new_page, old_page, address); + if (old_page == &invalid_page) { + char *vto = kmap_atomic(new_page, KM_USER1); + copy_page(vto, (void *)(address & PAGE_MASK)); + kunmap_atomic(vto, KM_USER1); + } else { + copy_user_highpage(new_page, old_page, address); + } } /* * Re-check the pte - we dropped the lock diff -r 5aae0c8158b9 -r f27205ea60ef tools/firmware/rombios/rombios.c --- a/tools/firmware/rombios/rombios.c Sat Sep 3 16:57:54 2005 +++ b/tools/firmware/rombios/rombios.c Sat Sep 3 16:58:50 2005 @@ -31,7 +31,7 @@ // Xen full virtualization does not handle unaligned IO with page crossing. // Disable 32-bit PIO as a workaround. -#define NO_PIO32 +#undef NO_PIO32 // ROM BIOS compatability entry points: diff -r 5aae0c8158b9 -r f27205ea60ef tools/firmware/vmxassist/Makefile --- a/tools/firmware/vmxassist/Makefile Sat Sep 3 16:57:54 2005 +++ b/tools/firmware/vmxassist/Makefile Sat Sep 3 16:58:50 2005 @@ -24,7 +24,7 @@ # The emulator code lives in ROM space TEXTADDR=0x000D0000 -DEFINES=-DDEBUG -DENABLE_VME -DTEXTADDR=${TEXTADDR} +DEFINES=-DDEBUG -DTEXTADDR=${TEXTADDR} XENINC=-I$(XEN_ROOT)/xen/include -I$(XEN_ROOT)/tools/libxc #DEFINES=-DDEBUG -DTEST -DTEXTADDR=${TEXTADDR} #XENINC=-I/home/leendert/xen/xeno-unstable.bk/xen/include diff -r 5aae0c8158b9 -r f27205ea60ef tools/firmware/vmxassist/setup.c --- a/tools/firmware/vmxassist/setup.c Sat Sep 3 16:57:54 2005 +++ b/tools/firmware/vmxassist/setup.c Sat Sep 3 16:58:50 2005 @@ -353,7 +353,7 @@ #endif setup_gdt(); setup_idt(); -#ifdef ENABLE_VME +#ifndef TEST set_cr4(get_cr4() | CR4_VME); #endif setup_ctx(); diff -r 5aae0c8158b9 -r f27205ea60ef tools/firmware/vmxassist/vm86.c --- a/tools/firmware/vmxassist/vm86.c Sat Sep 3 16:57:54 2005 +++ b/tools/firmware/vmxassist/vm86.c Sat Sep 3 16:58:50 2005 @@ -465,8 +465,7 @@ * Emulate a segment load in protected mode */ int -load_seg(unsigned long sel, unsigned long *base, unsigned long *limit, - union vmcs_arbytes *arbytes) +load_seg(unsigned long sel, u32 *base, u32 *limit, union vmcs_arbytes *arbytes) { unsigned long long entry; diff -r 5aae0c8158b9 -r f27205ea60ef tools/firmware/vmxassist/vmxloader.c --- a/tools/firmware/vmxassist/vmxloader.c Sat Sep 3 16:57:54 2005 +++ b/tools/firmware/vmxassist/vmxloader.c Sat Sep 3 16:58:50 2005 @@ -110,8 +110,8 @@ } #ifdef _ACPI_ puts("Loading ACPI ...\n"); - if (ACPI_PHYSICAL_ADDRESS+sizeof(acpi) <= 0xF0000 ){ - /* make sure acpi table does not overlap rombios + if (ACPI_PHYSICAL_ADDRESS+sizeof(acpi) <= 0xF0000 ){ + /* make sure acpi table does not overlap rombios * currently acpi less than 8K will be OK. */ memcpy((void *)ACPI_PHYSICAL_ADDRESS, acpi, sizeof(acpi)); @@ -122,5 +122,6 @@ memcpy((void *)TEXTADDR, vmxassist, sizeof(vmxassist)); puts("Go ...\n"); ((void (*)())TEXTADDR)(); + return 0; } diff -r 5aae0c8158b9 -r f27205ea60ef tools/ioemu/exec.c --- a/tools/ioemu/exec.c Sat Sep 3 16:57:54 2005 +++ b/tools/ioemu/exec.c Sat Sep 3 16:58:50 2005 @@ -142,6 +142,10 @@ #else setvbuf(logfile, NULL, _IOLBF, 0); #endif +/* + stdout = logfile; + stderr = logfile; +*/ } } @@ -386,9 +390,6 @@ io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); l = 2; } else { - if (l!=1){ - fprintf(logfile, "ERROR 8 bit mmio\n"); - } /* 8 bit access */ val = ldub_raw(buf); io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); diff -r 5aae0c8158b9 -r f27205ea60ef tools/ioemu/hw/pcnet.c --- a/tools/ioemu/hw/pcnet.c Sat Sep 3 16:57:54 2005 +++ b/tools/ioemu/hw/pcnet.c Sat Sep 3 16:58:50 2005 @@ -569,6 +569,10 @@ cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); s->xmit_pos += 4096 - tmd.tmd1.bcnt; + + tmd.tmd1.own = 0; + TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + #ifdef PCNET_DEBUG printf("pcnet_transmit size=%d\n", s->xmit_pos); #endif @@ -580,10 +584,10 @@ s->csr[0] &= ~0x0008; /* clear TDMD */ s->csr[4] |= 0x0004; /* set TXSTRT */ s->xmit_pos = -1; - } - - tmd.tmd1.own = 0; - TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + } else { + tmd.tmd1.own = 0; + TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + } if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) s->csr[0] |= 0x0200; /* set TINT */ diff -r 5aae0c8158b9 -r f27205ea60ef tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Sat Sep 3 16:57:54 2005 +++ b/tools/ioemu/target-i386-dm/helper2.c Sat Sep 3 16:58:50 2005 @@ -169,133 +169,217 @@ unsigned long do_inp(CPUState *env, unsigned long addr, unsigned long size) { - switch(size) { - case 1: - return cpu_inb(env, addr); - case 2: - return cpu_inw(env, addr); - case 4: - return cpu_inl(env, addr); - default: - fprintf(logfile, "inp: bad size: %lx %lx\n", addr, size); - exit(-1); - } + switch(size) { + case 1: + return cpu_inb(env, addr); + case 2: + return cpu_inw(env, addr); + case 4: + return cpu_inl(env, addr); + default: + fprintf(logfile, "inp: bad size: %lx %lx\n", addr, size); + exit(-1); + } } void do_outp(CPUState *env, unsigned long addr, unsigned long size, unsigned long val) { - switch(size) { - case 1: - return cpu_outb(env, addr, val); - case 2: - return cpu_outw(env, addr, val); - case 4: - return cpu_outl(env, addr, val); - default: - fprintf(logfile, "outp: bad size: %lx %lx\n", addr, size); - exit(-1); - } + switch(size) { + case 1: + return cpu_outb(env, addr, val); + case 2: + return cpu_outw(env, addr, val); + case 4: + return cpu_outl(env, addr, val); + default: + fprintf(logfile, "outp: bad size: %lx %lx\n", addr, size); + exit(-1); + } } extern void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write); static inline void -read_physical(target_phys_addr_t addr, unsigned long size, void *val) -{ - return cpu_physical_memory_rw(addr, val, size, 0); +read_physical(u64 addr, unsigned long size, void *val) +{ + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0); } static inline void -write_physical(target_phys_addr_t addr, unsigned long size, void *val) -{ - return cpu_physical_memory_rw(addr, val, size, 1); -} - -//send the ioreq to device model -void cpu_dispatch_ioreq(CPUState *env, ioreq_t *req) -{ - int i; - int sign; - - sign = (req->df) ? -1 : 1; - - if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) { - if (req->size != 4) { - // Bochs expects higher bits to be 0 - req->u.data &= (1UL << (8 * req->size))-1; - } - } - - if (req->port_mm == 0){//port io - if(req->dir == IOREQ_READ){//read - if (!req->pdata_valid) { - req->u.data = do_inp(env, req->addr, req->size); - } else { - unsigned long tmp; - - for (i = 0; i < req->count; i++) { - tmp = do_inp(env, req->addr, req->size); - write_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), - req->size, &tmp); - } - } - } else if(req->dir == IOREQ_WRITE) { - if (!req->pdata_valid) { - do_outp(env, req->addr, req->size, req->u.data); - } else { - for (i = 0; i < req->count; i++) { - unsigned long tmp; - - read_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), req->size, - &tmp); - do_outp(env, req->addr, req->size, tmp); - } - } - - } - } else if (req->port_mm == 1){//memory map io +write_physical(u64 addr, unsigned long size, void *val) +{ + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1); +} + +void +cpu_ioreq_pio(CPUState *env, ioreq_t *req) +{ + int i, sign; + + sign = req->df ? -1 : 1; + + if (req->dir == IOREQ_READ) { if (!req->pdata_valid) { - //handle stos - if(req->dir == IOREQ_READ) { //read - for (i = 0; i < req->count; i++) { - read_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &req->u.data); - } - } else if(req->dir == IOREQ_WRITE) { //write - for (i = 0; i < req->count; i++) { - write_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &req->u.data); - } - } + req->u.data = do_inp(env, req->addr, req->size); } else { - //handle movs - unsigned long tmp; - if (req->dir == IOREQ_READ) { - for (i = 0; i < req->count; i++) { - read_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &tmp); - write_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), req->size, &tmp); - } - } else if (req->dir == IOREQ_WRITE) { - for (i = 0; i < req->count; i++) { - read_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), req->size, &tmp); - write_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &tmp); - } - } - } - } - /* No state change if state = STATE_IORESP_HOOK */ - if (req->state == STATE_IOREQ_INPROCESS) - req->state = STATE_IORESP_READY; - env->send_event = 1; + unsigned long tmp; + + for (i = 0; i < req->count; i++) { + tmp = do_inp(env, req->addr, req->size); + write_physical((target_phys_addr_t) req->u.pdata + + (sign * i * req->size), + req->size, &tmp); + } + } + } else if (req->dir == IOREQ_WRITE) { + if (!req->pdata_valid) { + do_outp(env, req->addr, req->size, req->u.data); + } else { + for (i = 0; i < req->count; i++) { + unsigned long tmp; + + read_physical((target_phys_addr_t) req->u.pdata + + (sign * i * req->size), + req->size, &tmp); + do_outp(env, req->addr, req->size, tmp); + } + } + } +} + +void +cpu_ioreq_move(CPUState *env, ioreq_t *req) +{ + int i, sign; + + sign = req->df ? -1 : 1; + + if (!req->pdata_valid) { + if (req->dir == IOREQ_READ) { + for (i = 0; i < req->count; i++) { + read_physical(req->addr + + (sign * i * req->size), + req->size, &req->u.data); + } + } else if (req->dir == IOREQ_WRITE) { + for (i = 0; i < req->count; i++) { + write_physical(req->addr + + (sign * i * req->size), + req->size, &req->u.data); + } + } + } else { + unsigned long tmp; + + if (req->dir == IOREQ_READ) { + for (i = 0; i < req->count; i++) { + read_physical(req->addr + + (sign * i * req->size), + req->size, &tmp); + write_physical((target_phys_addr_t )req->u.pdata + + (sign * i * req->size), + req->size, &tmp); + } + } else if (req->dir == IOREQ_WRITE) { + for (i = 0; i < req->count; i++) { + read_physical((target_phys_addr_t) req->u.pdata + + (sign * i * req->size), + req->size, &tmp); + write_physical(req->addr + + (sign * i * req->size), + req->size, &tmp); + } + } + } +} + +void +cpu_ioreq_and(CPUState *env, ioreq_t *req) +{ + unsigned long tmp1, tmp2; + + if (req->pdata_valid != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + if (req->dir == IOREQ_WRITE) { + tmp2 = tmp1 & (unsigned long) req->u.data; + write_physical(req->addr, req->size, &tmp2); + } + req->u.data = tmp1; +} + +void +cpu_ioreq_or(CPUState *env, ioreq_t *req) +{ + unsigned long tmp1, tmp2; + + if (req->pdata_valid != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + if (req->dir == IOREQ_WRITE) { + tmp2 = tmp1 | (unsigned long) req->u.data; + write_physical(req->addr, req->size, &tmp2); + } + req->u.data = tmp1; +} + +void +cpu_ioreq_xor(CPUState *env, ioreq_t *req) +{ + unsigned long tmp1, tmp2; + + if (req->pdata_valid != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + if (req->dir == IOREQ_WRITE) { + tmp2 = tmp1 ^ (unsigned long) req->u.data; + write_physical(req->addr, req->size, &tmp2); + } + req->u.data = tmp1; } void cpu_handle_ioreq(CPUState *env) { ioreq_t *req = cpu_get_ioreq(); - if (req) - cpu_dispatch_ioreq(env, req); + + 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", req->type); + } + + /* No state change if state = STATE_IORESP_HOOK */ + if (req->state == STATE_IOREQ_INPROCESS) + req->state = STATE_IORESP_READY; + env->send_event = 1; + } } void @@ -321,7 +405,7 @@ // Send a message on the event channel. Add the vector to the shared mem // page. - intr = &(shared_page->sp_global.pic_intr[0]); + intr = (unsigned long *) &(shared_page->sp_global.pic_intr[0]); atomic_set_bit(vector, intr); if (loglevel & CPU_LOG_INT) fprintf(logfile, "injecting vector: %x\n", vector); diff -r 5aae0c8158b9 -r f27205ea60ef tools/ioemu/vl.c --- a/tools/ioemu/vl.c Sat Sep 3 16:57:54 2005 +++ b/tools/ioemu/vl.c Sat Sep 3 16:58:50 2005 @@ -413,6 +413,11 @@ fprintf(stderr, "qemu: hardware error: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); + if (logfile) { + fprintf(logfile, "qemu: hardware error: "); + vfprintf(logfile, fmt, ap); + fprintf(logfile, "\n"); + } va_end(ap); abort(); } diff -r 5aae0c8158b9 -r f27205ea60ef tools/libxc/xc_linux_save.c --- a/tools/libxc/xc_linux_save.c Sat Sep 3 16:57:54 2005 +++ b/tools/libxc/xc_linux_save.c Sat Sep 3 16:58:50 2005 @@ -20,6 +20,24 @@ #define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */ #define MAX_MBIT_RATE 500 + + +/* +** Default values for important tuning parameters. Can override by passing +** non-zero replacement values to xc_linux_save(). +** +** XXX SMH: should consider if want to be able to override MAX_MBIT_RATE too. +** +*/ +#define DEF_MAX_ITERS 29 /* limit us to 30 times round loop */ +#define DEF_MAX_FACTOR 3 /* never send more than 3x nr_pfns */ + + + +/* Flags to control behaviour of xc_linux_save */ +#define XCFLAGS_LIVE 1 +#define XCFLAGS_DEBUG 2 + #define DEBUG 0 @@ -320,18 +338,18 @@ xc_dominfo_t *info, vcpu_guest_context_t *ctxt) { - int i=0; + int i = 0; char ans[30]; printf("suspend\n"); fflush(stdout); if (fgets(ans, sizeof(ans), stdin) == NULL) { - ERR("failed reading suspend reply"); - return -1; + ERR("failed reading suspend reply"); + return -1; } if (strncmp(ans, "done\n", 5)) { - ERR("suspend reply incorrect: %s", ans); - return -1; + ERR("suspend reply incorrect: %s", ans); + return -1; } retry: @@ -377,19 +395,16 @@ return -1; } -int xc_linux_save(int xc_handle, int io_fd, u32 dom) +int xc_linux_save(int xc_handle, int io_fd, u32 dom, u32 max_iters, + u32 max_factor, u32 flags) { xc_dominfo_t info; int rc = 1, i, j, k, last_iter, iter = 0; unsigned long mfn; - int live = 0; // (ioctxt->flags & XCFLAGS_LIVE); - int debug = 0; // (ioctxt->flags & XCFLAGS_DEBUG); + int live = (flags & XCFLAGS_LIVE); + int debug = (flags & XCFLAGS_DEBUG); int sent_last_iter, skip_this_iter; - - /* Important tuning parameters */ - int max_iters = 29; /* limit us to 30 times round loop */ - int max_factor = 3; /* never send more than 3x nr_pfns */ /* The new domain's shared-info frame number. */ unsigned long shared_info_frame; @@ -442,8 +457,16 @@ MBIT_RATE = START_MBIT_RATE; - DPRINTF("xc_linux_save start %d\n", dom); - + + /* If no explicit control parameters given, use defaults */ + if(!max_iters) + max_iters = DEF_MAX_ITERS; + if(!max_factor) + max_factor = DEF_MAX_FACTOR; + + + DPRINTF("xc_linux_save start DOM%u live=%s\n", dom, live?"true":"false"); + if (mlock(&ctxt, sizeof(ctxt))) { ERR("Unable to mlock ctxt"); return 1; diff -r 5aae0c8158b9 -r f27205ea60ef tools/libxc/xenguest.h --- a/tools/libxc/xenguest.h Sat Sep 3 16:57:54 2005 +++ b/tools/libxc/xenguest.h Sat Sep 3 16:58:50 2005 @@ -6,13 +6,12 @@ * Copyright (c) 2003-2004, K A Fraser. */ -#ifndef XENBUILD_H -#define XENBUILD_H +#ifndef XENGUEST_H +#define XENGUEST_H -#define XCFLAGS_VERBOSE 1 -#define XCFLAGS_LIVE 2 -#define XCFLAGS_DEBUG 4 -#define XCFLAGS_CONFIGURE 8 +#define XCFLAGS_LIVE 1 +#define XCFLAGS_DEBUG 2 + /** * This function will save a domain running Linux. @@ -22,7 +21,8 @@ * @parm dom the id of the domain * @return 0 on success, -1 on failure */ -int xc_linux_save(int xc_handle, int fd, uint32_t dom); +int xc_linux_save(int xc_handle, int fd, uint32_t dom, uint32_t max_iters, + uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */); /** * This function will restore a saved domain running Linux. @@ -35,8 +35,9 @@ * @parm store_mfn returned with the mfn of the store page * @return 0 on success, -1 on failure */ -int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, unsigned long nr_pfns, - unsigned int store_evtchn, unsigned long *store_mfn); +int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, + unsigned long nr_pfns, unsigned int store_evtchn, + unsigned long *store_mfn); int xc_linux_build(int xc_handle, uint32_t domid, @@ -65,4 +66,4 @@ unsigned int store_evtchn, unsigned long *store_mfn); -#endif +#endif // XENGUEST_H diff -r 5aae0c8158b9 -r f27205ea60ef tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Sat Sep 3 16:57:54 2005 +++ b/tools/python/xen/xend/XendCheckpoint.py Sat Sep 3 16:58:50 2005 @@ -34,7 +34,7 @@ raise XendError(errmsg) return buf -def save(xd, fd, dominfo): +def save(xd, fd, dominfo, live): write_exact(fd, SIGNATURE, "could not write guest state file: signature") config = sxp.to_string(dominfo.sxpr()) @@ -42,8 +42,13 @@ "could not write guest state file: config len") write_exact(fd, config, "could not write guest state file: config") + # xc_save takes three customization parameters: maxit, max_f, and flags + # the last controls whether or not save is 'live', while the first two + # further customize behaviour when 'live' save is enabled. Passing "0" + # simply uses the defaults compiled into libxenguest; see the comments + # and/or code in xc_linux_save() for more information. cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd), - str(dominfo.id)] + str(dominfo.id), "0", "0", str(live) ] log.info("[xc_save] " + join(cmd)) child = xPopen3(cmd, True, -1, [fd, xc.handle()]) diff -r 5aae0c8158b9 -r f27205ea60ef tools/python/xen/xend/XendDomain.py --- a/tools/python/xen/xend/XendDomain.py Sat Sep 3 16:57:54 2005 +++ b/tools/python/xen/xend/XendDomain.py Sat Sep 3 16:58:50 2005 @@ -542,7 +542,7 @@ dominfo.name = "tmp-" + dominfo.name try: - XendCheckpoint.save(self, sock.fileno(), dominfo) + XendCheckpoint.save(self, sock.fileno(), dominfo, live) except: if dst == "localhost": dominfo.name = string.replace(dominfo.name, "tmp-", "", 1) @@ -563,7 +563,8 @@ fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC) - return XendCheckpoint.save(self, fd, dominfo) + # For now we don't support 'live checkpoint' + return XendCheckpoint.save(self, fd, dominfo, False) except OSError, ex: raise XendError("can't write guest state file %s: %s" % diff -r 5aae0c8158b9 -r f27205ea60ef tools/xcutils/xc_save.c --- a/tools/xcutils/xc_save.c Sat Sep 3 16:57:54 2005 +++ b/tools/xcutils/xc_save.c Sat Sep 3 16:58:50 2005 @@ -17,14 +17,17 @@ int main(int argc, char **argv) { - unsigned int xc_fd, io_fd, domid; + unsigned int xc_fd, io_fd, domid, maxit, max_f, flags; - if (argc != 4) - errx(1, "usage: %s xcfd iofd domid", argv[0]); + if (argc != 7) + errx(1, "usage: %s xcfd iofd domid maxit maxf flags", argv[0]); xc_fd = atoi(argv[1]); io_fd = atoi(argv[2]); domid = atoi(argv[3]); + maxit = atoi(argv[4]); + max_f = atoi(argv[5]); + flags = atoi(argv[6]); - return xc_linux_save(xc_fd, io_fd, domid); + return xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags); } diff -r 5aae0c8158b9 -r f27205ea60ef xen/arch/x86/shadow.c --- a/xen/arch/x86/shadow.c Sat Sep 3 16:57:54 2005 +++ b/xen/arch/x86/shadow.c Sat Sep 3 16:58:50 2005 @@ -531,7 +531,7 @@ int i, init_table = 0; __guest_get_l2e(v, va, &gl2e); - ASSERT(l2e_get_flags(gl2e) & _PAGE_PRESENT); + ASSERT(guest_l2e_get_flags(gl2e) & _PAGE_PRESENT); gl1pfn = l2e_get_pfn(gl2e); if ( !(sl1mfn = __shadow_status(d, gl1pfn, PGT_l1_shadow)) ) @@ -1664,7 +1664,7 @@ return 0; } - ASSERT(l1e_get_flags(gpte) & _PAGE_RW); + ASSERT(guest_l1e_get_flags(gpte) & _PAGE_RW); guest_l1e_add_flags(gpte, _PAGE_DIRTY | _PAGE_ACCESSED); spte = l1e_from_pfn(gmfn, guest_l1e_get_flags(gpte) & ~_PAGE_GLOBAL); diff -r 5aae0c8158b9 -r f27205ea60ef xen/arch/x86/vmx.c --- a/xen/arch/x86/vmx.c Sat Sep 3 16:57:54 2005 +++ b/xen/arch/x86/vmx.c Sat Sep 3 16:58:50 2005 @@ -602,15 +602,66 @@ return 0; } +void send_pio_req(struct cpu_user_regs *regs, unsigned long port, + unsigned long count, int size, long value, int dir, int pvalid) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + + vio = get_vio(v->domain, v->vcpu_id); + if (vio == NULL) { + printk("bad shared page: %lx\n", (unsigned long) vio); + domain_crash_synchronous(); + } + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + printf("VMX I/O has not yet completed\n"); + domain_crash_synchronous(); + } + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + + p = &vio->vp_ioreq; + p->dir = dir; + p->pdata_valid = pvalid; + + p->type = IOREQ_TYPE_PIO; + p->size = size; + p->addr = port; + p->count = count; + p->df = regs->eflags & EF_DF ? 1 : 0; + + if (pvalid) { + if (vmx_paging_enabled(current)) + p->u.pdata = (void *) gva_to_gpa(value); + else + p->u.pdata = (void *) value; /* guest VA == guest PA */ + } else + p->u.data = value; + + p->state = STATE_IOREQ_READY; + + if (vmx_portio_intercept(p)) { + /* no blocking & no evtchn notification */ + clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + return; + } + + evtchn_send(iopacket_port(v->domain)); + vmx_wait_io(); +} + static void vmx_io_instruction(struct cpu_user_regs *regs, unsigned long exit_qualification, unsigned long inst_len) { - struct vcpu *d = current; - vcpu_iodata_t *vio; - ioreq_t *p; - unsigned long addr; + struct mi_per_cpu_info *mpcip; unsigned long eip, cs, eflags; + unsigned long port, size, dir; int vm86; + + mpcip = ¤t->domain->arch.vmx_platform.mpci; + mpcip->instr = INSTR_PIO; + mpcip->flags = 0; __vmread(GUEST_RIP, &eip); __vmread(GUEST_CS_SELECTOR, &cs); @@ -623,105 +674,87 @@ vm86, cs, eip, exit_qualification); if (test_bit(6, &exit_qualification)) - addr = (exit_qualification >> 16) & (0xffff); + port = (exit_qualification >> 16) & 0xFFFF; else - addr = regs->edx & 0xffff; - TRACE_VMEXIT (2,addr); - - vio = get_vio(d->domain, d->vcpu_id); - if (vio == 0) { - printk("bad shared page: %lx", (unsigned long) vio); - domain_crash_synchronous(); - } - p = &vio->vp_ioreq; - p->dir = test_bit(3, &exit_qualification); /* direction */ - - p->pdata_valid = 0; - p->count = 1; - p->size = (exit_qualification & 7) + 1; + port = regs->edx & 0xffff; + TRACE_VMEXIT(2, port); + size = (exit_qualification & 7) + 1; + dir = test_bit(3, &exit_qualification); /* direction */ if (test_bit(4, &exit_qualification)) { /* string instruction */ - unsigned long laddr; - - __vmread(GUEST_LINEAR_ADDRESS, &laddr); + unsigned long addr, count = 1; + int sign = regs->eflags & EF_DF ? -1 : 1; + + __vmread(GUEST_LINEAR_ADDRESS, &addr); + /* * In protected mode, guest linear address is invalid if the * selector is null. */ - if (!vm86 && check_for_null_selector(eip)) { - laddr = (p->dir == IOREQ_WRITE) ? regs->esi : regs->edi; - } - p->pdata_valid = 1; - - p->u.data = laddr; - if (vmx_paging_enabled(d)) - p->u.pdata = (void *) gva_to_gpa(p->u.data); - p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0; - - if (test_bit(5, &exit_qualification)) /* "rep" prefix */ - p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx; - - /* - * Split up string I/O operations that cross page boundaries. Don't - * advance %eip so that "rep insb" will restart at the next page. - */ - if ((p->u.data & PAGE_MASK) != - ((p->u.data + p->count * p->size - 1) & PAGE_MASK)) { - VMX_DBG_LOG(DBG_LEVEL_2, - "String I/O crosses page boundary (cs:eip=0x%lx:0x%lx)\n", - cs, eip); - if (p->u.data & (p->size - 1)) { - printf("Unaligned string I/O operation (cs:eip=0x%lx:0x%lx)\n", - cs, eip); - domain_crash_synchronous(); - } - p->count = (PAGE_SIZE - (p->u.data & ~PAGE_MASK)) / p->size; - } else { - __update_guest_eip(inst_len); - } - } else if (p->dir == IOREQ_WRITE) { - p->u.data = regs->eax; + if (!vm86 && check_for_null_selector(eip)) + addr = dir == IOREQ_WRITE ? regs->esi : regs->edi; + + if (test_bit(5, &exit_qualification)) { /* "rep" prefix */ + mpcip->flags |= REPZ; + count = vm86 ? regs->ecx & 0xFFFF : regs->ecx; + } + + /* + * Handle string pio instructions that cross pages or that + * are unaligned. See the comments in vmx_platform.c/handle_mmio() + */ + if ((addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK)) { + unsigned long value = 0; + + mpcip->flags |= OVERLAP; + if (dir == IOREQ_WRITE) + vmx_copy(&value, addr, size, VMX_COPY_IN); + send_pio_req(regs, port, 1, size, value, dir, 0); + } else { + if ((addr & PAGE_MASK) != ((addr + count * size - 1) & PAGE_MASK)) { + if (sign > 0) + count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size; + else + count = (addr & ~PAGE_MASK) / size; + } else + __update_guest_eip(inst_len); + + send_pio_req(regs, port, count, size, addr, dir, 1); + } + } else { __update_guest_eip(inst_len); - } else - __update_guest_eip(inst_len); - - p->addr = addr; - p->port_mm = 0; - - /* Check if the packet needs to be intercepted */ - if (vmx_portio_intercept(p)) - /* no blocking & no evtchn notification */ - return; - - set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags); - p->state = STATE_IOREQ_READY; - evtchn_send(iopacket_port(d->domain)); - vmx_wait_io(); -} - -enum { COPY_IN = 0, COPY_OUT }; - -static inline int + send_pio_req(regs, port, 1, size, regs->eax, dir, 0); + } +} + +int vmx_copy(void *buf, unsigned long laddr, int size, int dir) { + unsigned long mfn; char *addr; - unsigned long mfn; - - if ( (size + (laddr & (PAGE_SIZE - 1))) >= PAGE_SIZE ) - { - printf("vmx_copy exceeds page boundary\n"); - return 0; - } - - mfn = get_mfn_from_pfn(laddr >> PAGE_SHIFT); - addr = (char *)map_domain_page(mfn) + (laddr & ~PAGE_MASK); - - if (dir == COPY_IN) - memcpy(buf, addr, size); - else - memcpy(addr, buf, size); - - unmap_domain_page(addr); + int count; + + while (size > 0) { + count = PAGE_SIZE - (laddr & ~PAGE_MASK); + if (count > size) + count = size; + + mfn = get_mfn_from_pfn(laddr >> PAGE_SHIFT); + /* XXX check whether laddr is valid */ + addr = (char *)map_domain_page(mfn) + (laddr & ~PAGE_MASK); + + if (dir == VMX_COPY_IN) + memcpy(buf, addr, count); + else + memcpy(addr, buf, count); + + unmap_domain_page(addr); + + laddr += count; + buf += count; + size -= count; + } + return 1; } @@ -908,7 +941,7 @@ u32 cp; /* make sure vmxassist exists (this is not an error) */ - if (!vmx_copy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), COPY_IN)) + if (!vmx_copy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), VMX_COPY_IN)) return 0; if (magic != VMXASSIST_MAGIC) return 0; @@ -922,20 +955,20 @@ */ case VMX_ASSIST_INVOKE: /* save the old context */ - if (!vmx_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), COPY_IN)) + if (!vmx_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), VMX_COPY_IN)) goto error; if (cp != 0) { if (!vmx_world_save(d, &c)) goto error; - if (!vmx_copy(&c, cp, sizeof(c), COPY_OUT)) + if (!vmx_copy(&c, cp, sizeof(c), VMX_COPY_OUT)) goto error; } /* restore the new context, this should activate vmxassist */ - if (!vmx_copy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), COPY_IN)) + if (!vmx_copy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), VMX_COPY_IN)) goto error; if (cp != 0) { - if (!vmx_copy(&c, cp, sizeof(c), COPY_IN)) + if (!vmx_copy(&c, cp, sizeof(c), VMX_COPY_IN)) goto error; if (!vmx_world_restore(d, &c)) goto error; @@ -949,10 +982,10 @@ */ case VMX_ASSIST_RESTORE: /* save the old context */ - if (!vmx_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), COPY_IN)) + if (!vmx_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), VMX_COPY_IN)) goto error; if (cp != 0) { - if (!vmx_copy(&c, cp, sizeof(c), COPY_IN)) + if (!vmx_copy(&c, cp, sizeof(c), VMX_COPY_IN)) goto error; if (!vmx_world_restore(d, &c)) goto error; @@ -1554,15 +1587,18 @@ __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field); if (idtv_info_field & INTR_INFO_VALID_MASK) { - if ((idtv_info_field & 0x0700) != 0x400) { /* exclude soft ints */ - __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); - - if (idtv_info_field & 0x800) { /* valid error code */ - unsigned long error_code; - __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code); - __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); - } - } + __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + + __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len); + if (inst_len >= 1 && inst_len <= 15) + __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len); + + if (idtv_info_field & 0x800) { /* valid error code */ + unsigned long error_code; + __vmread(IDT_VECTORING_ERROR_CODE, &error_code); + __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); + } + VMX_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field); } diff -r 5aae0c8158b9 -r f27205ea60ef xen/arch/x86/vmx_intercept.c --- a/xen/arch/x86/vmx_intercept.c Sat Sep 3 16:57:54 2005 +++ b/xen/arch/x86/vmx_intercept.c Sat Sep 3 16:58:50 2005 @@ -172,7 +172,7 @@ if (p->size != 1 || p->pdata_valid || - p->port_mm) + p->type != IOREQ_TYPE_PIO) return 0; if (p->addr == PIT_MODE && @@ -284,7 +284,5 @@ if (!reinit) register_portio_handler(0x40, 4, intercept_pit_io); } - -} - +} #endif /* CONFIG_VMX */ diff -r 5aae0c8158b9 -r f27205ea60ef xen/arch/x86/vmx_io.c --- a/xen/arch/x86/vmx_io.c Sat Sep 3 16:57:54 2005 +++ b/xen/arch/x86/vmx_io.c Sat Sep 3 16:58:50 2005 @@ -33,6 +33,7 @@ #include <asm/vmx_platform.h> #include <asm/vmx_virpit.h> #include <asm/apic.h> +#include <asm/shadow.h> #include <public/io/ioreq.h> #include <public/io/vmx_vlapic.h> @@ -123,7 +124,6 @@ regs->esp &= 0xFFFF0000; regs->esp |= (value & 0xFFFF); break; - case 5: regs->ebp &= 0xFFFF0000; regs->ebp |= (value & 0xFFFF); @@ -207,7 +207,6 @@ *reg &= ~0xFFFF; *reg |= (value & 0xFFFF); break; - case LONG: *reg &= ~0xFFFFFFFF; *reg |= (value & 0xFFFFFFFF); @@ -322,13 +321,319 @@ } #endif +extern long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs); + +static inline void set_eflags_CF(int size, unsigned long v1, + unsigned long v2, struct cpu_user_regs *regs) +{ + unsigned long mask = (1 << (8 * size)) - 1; + + if ((v1 & mask) > (v2 & mask)) + regs->eflags |= X86_EFLAGS_CF; + else + regs->eflags &= ~X86_EFLAGS_CF; +} + +static inline void set_eflags_OF(int size, unsigned long v1, + unsigned long v2, unsigned long v3, struct cpu_user_regs *regs) +{ + if ((v3 ^ v2) & (v3 ^ v1) & (1 << ((8 * size) - 1))) + regs->eflags |= X86_EFLAGS_OF; +} + +static inline void set_eflags_AF(int size, unsigned long v1, + unsigned long v2, unsigned long v3, struct cpu_user_regs *regs) +{ + if ((v1 ^ v2 ^ v3) & 0x10) + regs->eflags |= X86_EFLAGS_AF; +} + +static inline void set_eflags_ZF(int size, unsigned long v1, + struct cpu_user_regs *regs) +{ + unsigned long mask = (1 << (8 * size)) - 1; + + if ((v1 & mask) == 0) + regs->eflags |= X86_EFLAGS_ZF; +} + +static inline void set_eflags_SF(int size, unsigned long v1, + struct cpu_user_regs *regs) +{ + if (v1 & (1 << ((8 * size) - 1))) + regs->eflags |= X86_EFLAGS_SF; +} + +static char parity_table[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + +static inline void set_eflags_PF(int size, unsigned long v1, + struct cpu_user_regs *regs) +{ + if (parity_table[v1 & 0xFF]) + regs->eflags |= X86_EFLAGS_PF; +} + +static void vmx_pio_assist(struct cpu_user_regs *regs, ioreq_t *p, + struct mi_per_cpu_info *mpcip) +{ + unsigned long old_eax; + int sign = p->df ? -1 : 1; + + if (p->dir == IOREQ_WRITE) { + if (p->pdata_valid) { + regs->esi += sign * p->count * p->size; + if (mpcip->flags & REPZ) + regs->ecx -= p->count; + } + } else { + if (mpcip->flags & OVERLAP) { + unsigned long addr; + + regs->edi += sign * p->count * p->size; + if (mpcip->flags & REPZ) + regs->ecx -= p->count; + + addr = regs->edi; + if (sign > 0) + addr -= p->size; + vmx_copy(&p->u.data, addr, p->size, VMX_COPY_OUT); + } else if (p->pdata_valid) { + regs->edi += sign * p->count * p->size; + if (mpcip->flags & REPZ) + regs->ecx -= p->count; + } else { + old_eax = regs->eax; + switch (p->size) { + case 1: + regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff); + break; + case 2: + regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff); + break; + case 4: + regs->eax = (p->u.data & 0xffffffff); + break; + default: + printk("Error: %s unknown port size\n", __FUNCTION__); + domain_crash_synchronous(); + } + } + } +} + +static void vmx_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p, + struct mi_per_cpu_info *mpcip) +{ + int sign = p->df ? -1 : 1; + int size = -1, index = -1; + unsigned long value = 0, diff = 0; + unsigned long src, dst; + + src = mpcip->operand[0]; + dst = mpcip->operand[1]; + size = operand_size(src); + + switch (mpcip->instr) { + case INSTR_MOV: + if (dst & REGISTER) { + index = operand_index(dst); + set_reg_value(size, index, 0, regs, p->u.data); + } + break; + + case INSTR_MOVZ: + if (dst & REGISTER) { + index = operand_index(dst); + switch (size) { + case BYTE: p->u.data = p->u.data & 0xFFULL; break; + case WORD: p->u.data = p->u.data & 0xFFFFULL; break; + case LONG: p->u.data = p->u.data & 0xFFFFFFFFULL; break; + } + set_reg_value(operand_size(dst), index, 0, regs, p->u.data); + } + break; + + case INSTR_MOVS: + sign = p->df ? -1 : 1; + regs->esi += sign * p->count * p->size; + regs->edi += sign * p->count * p->size; + + if ((mpcip->flags & OVERLAP) && p->dir == IOREQ_READ) { + unsigned long addr = regs->edi; + + if (sign > 0) + addr -= p->size; + vmx_copy(&p->u.data, addr, p->size, VMX_COPY_OUT); + } + + if (mpcip->flags & REPZ) + regs->ecx -= p->count; + break; + + case INSTR_STOS: + sign = p->df ? -1 : 1; + regs->edi += sign * p->count * p->size; + if (mpcip->flags & REPZ) + regs->ecx -= p->count; + break; + + case INSTR_AND: + if (src & REGISTER) { + index = operand_index(src); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data & value; + } else if (src & IMMEDIATE) { + value = mpcip->immediate; + diff = (unsigned long) p->u.data & value; + } else if (src & MEMORY) { + index = operand_index(dst); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data & value; + set_reg_value(size, index, 0, regs, diff); + } + + /* + * The OF and CF flags are cleared; the SF, ZF, and PF + * flags are set according to the result. The state of + * the AF flag is undefined. + */ + regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| + X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); + set_eflags_ZF(size, diff, regs); + set_eflags_SF(size, diff, regs); + set_eflags_PF(size, diff, regs); + break; + + case INSTR_OR: + if (src & REGISTER) { + index = operand_index(src); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data | value; + } else if (src & IMMEDIATE) { + value = mpcip->immediate; + diff = (unsigned long) p->u.data | value; + } else if (src & MEMORY) { + index = operand_index(dst); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data | value; + set_reg_value(size, index, 0, regs, diff); + } + + /* + * The OF and CF flags are cleared; the SF, ZF, and PF + * flags are set according to the result. The state of + * the AF flag is undefined. + */ + regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| + X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); + set_eflags_ZF(size, diff, regs); + set_eflags_SF(size, diff, regs); + set_eflags_PF(size, diff, regs); + break; + + case INSTR_XOR: + if (src & REGISTER) { + index = operand_index(src); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data ^ value; + } else if (src & IMMEDIATE) { + value = mpcip->immediate; + diff = (unsigned long) p->u.data ^ value; + } else if (src & MEMORY) { + index = operand_index(dst); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data ^ value; + set_reg_value(size, index, 0, regs, diff); + } + + /* + * The OF and CF flags are cleared; the SF, ZF, and PF + * flags are set according to the result. The state of + * the AF flag is undefined. + */ + regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| + X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); + set_eflags_ZF(size, diff, regs); + set_eflags_SF(size, diff, regs); + set_eflags_PF(size, diff, regs); + break; + + case INSTR_CMP: + if (src & REGISTER) { + index = operand_index(src); + value = get_reg_value(size, index, 0, regs); + diff = (unsigned long) p->u.data - value; + } else if (src & IMMEDIATE) { + value = mpcip->immediate; + diff = (unsigned long) p->u.data - value; + } else if (src & MEMORY) { + index = operand_index(dst); + value = get_reg_value(size, index, 0, regs); + diff = value - (unsigned long) p->u.data; + } + + /* + * The CF, OF, SF, ZF, AF, and PF flags are set according + * to the result + */ + regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF| + X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); + set_eflags_CF(size, value, (unsigned long) p->u.data, regs); + set_eflags_OF(size, diff, value, (unsigned long) p->u.data, regs); + set_eflags_AF(size, diff, value, (unsigned long) p->u.data, regs); + set_eflags_ZF(size, diff, regs); + set_eflags_SF(size, diff, regs); + set_eflags_PF(size, diff, regs); + break; + + case INSTR_TEST: + if (src & REGISTER) { + index = operand_index(src); + value = get_reg_value(size, index, 0, regs); + } else if (src & IMMEDIATE) { + value = mpcip->immediate; + } else if (src & MEMORY) { + index = operand_index(dst); + value = get_reg_value(size, index, 0, regs); + } + diff = (unsigned long) p->u.data & value; + + /* + * Sets the SF, ZF, and PF status flags. CF and OF are set to 0 + */ + regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF| + X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF); + set_eflags_ZF(size, diff, regs); + set_eflags_SF(size, diff, regs); + set_eflags_PF(size, diff, regs); + break; + } + + load_cpu_user_regs(regs); +} + void vmx_io_assist(struct vcpu *v) { vcpu_iodata_t *vio; ioreq_t *p; struct cpu_user_regs *regs = guest_cpu_user_regs(); - unsigned long old_eax; - int sign; struct mi_per_cpu_info *mpci_p; struct cpu_user_regs *inst_decoder_regs; @@ -340,80 +645,26 @@ if (vio == 0) { VMX_DBG_LOG(DBG_LEVEL_1, "bad shared page: %lx", (unsigned long) vio); + printf("bad shared page: %lx\n", (unsigned long) vio); domain_crash_synchronous(); } + p = &vio->vp_ioreq; - - if (p->state == STATE_IORESP_HOOK){ + if (p->state == STATE_IORESP_HOOK) vmx_hooks_assist(v); - } /* clear IO wait VMX flag */ if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { - if (p->state != STATE_IORESP_READY) { - /* An interrupt send event raced us */ - return; - } else { - p->state = STATE_INVALID; - } - clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); - } else { - return; - } - - sign = (p->df) ? -1 : 1; - if (p->port_mm) { - if (p->pdata_valid) { - regs->esi += sign * p->count * p->size; - regs->edi += sign * p->count * p->size; - } else { - if (p->dir == IOREQ_WRITE) { - return; - } - int size = -1, index = -1; - - size = operand_size(v->domain->arch.vmx_platform.mpci.mmio_target); - index = operand_index(v->domain->arch.vmx_platform.mpci.mmio_target); - - if (v->domain->arch.vmx_platform.mpci.mmio_target & WZEROEXTEND) { - p->u.data = p->u.data & 0xffff; - } - set_reg_value(size, index, 0, regs, p->u.data); - - } - load_cpu_user_regs(regs); - return; - } - - if (p->dir == IOREQ_WRITE) { - if (p->pdata_valid) { - regs->esi += sign * p->count * p->size; - regs->ecx -= p->count; - } - return; - } else { - if (p->pdata_valid) { - regs->edi += sign * p->count * p->size; - regs->ecx -= p->count; - return; - } - } - - old_eax = regs->eax; - - switch(p->size) { - case 1: - regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff); - break; - case 2: - regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff); - break; - case 4: - regs->eax = (p->u.data & 0xffffffff); - break; - default: - printk("Error: %s unknwon port size\n", __FUNCTION__); - domain_crash_synchronous(); + if (p->state == STATE_IORESP_READY) { + p->state = STATE_INVALID; + clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + + if (p->type == IOREQ_TYPE_PIO) + vmx_pio_assist(regs, p, mpci_p); + else + vmx_mmio_assist(regs, p, mpci_p); + } + /* else an interrupt send event raced us */ } } @@ -456,8 +707,9 @@ int port = iopacket_port(current->domain); do { - if(!test_bit(port, ¤t->domain->shared_info->evtchn_pending[0])) + if (!test_bit(port, ¤t->domain->shared_info->evtchn_pending[0])) do_block(); + vmx_check_events(current); if (!test_bit(ARCH_VMX_IO_WAIT, ¤t->arch.arch_vmx.flags)) break; diff -r 5aae0c8158b9 -r f27205ea60ef xen/arch/x86/vmx_platform.c --- a/xen/arch/x86/vmx_platform.c Sat Sep 3 16:57:54 2005 +++ b/xen/arch/x86/vmx_platform.c Sat Sep 3 16:58:50 2005 @@ -64,37 +64,37 @@ case QUAD: return (long)(reg); default: - printk("Error: <__get_reg_value>Invalid reg size\n"); + printf("Error: (__get_reg_value) Invalid reg size\n"); domain_crash_synchronous(); } } -static long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs) +long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs) { if (size == BYTE) { switch (index) { - case 0: //%al + case 0: /* %al */ return (char)(regs->rax & 0xFF); - case 1: //%cl + case 1: /* %cl */ return (char)(regs->rcx & 0xFF); - case 2: //%dl + case 2: /* %dl */ return (char)(regs->rdx & 0xFF); - case 3: //%bl + case 3: /* %bl */ return (char)(regs->rbx & 0xFF); - case 4: //%ah + case 4: /* %ah */ return (char)((regs->rax & 0xFF00) >> 8); - case 5: //%ch + case 5: /* %ch */ return (char)((regs->rcx & 0xFF00) >> 8); - case 6: //%dh + case 6: /* %dh */ return (char)((regs->rdx & 0xFF00) >> 8); - case 7: //%bh + case 7: /* %bh */ return (char)((regs->rbx & 0xFF00) >> 8); default: - printk("Error: (get_reg_value)Invalid index value\n"); + printf("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } - - } + } + switch (index) { case 0: return __get_reg_value(regs->rax, size); case 1: return __get_reg_value(regs->rcx, size); @@ -113,7 +113,7 @@ case 14: return __get_reg_value(regs->r14, size); case 15: return __get_reg_value(regs->r15, size); default: - printk("Error: (get_reg_value)Invalid index value\n"); + printf("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } } @@ -129,117 +129,91 @@ __vmread(GUEST_RIP, ®s->eip); } -static long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs) +static inline long __get_reg_value(unsigned long reg, int size) { - /* - * Reference the db_reg[] table - */ - switch (size) { - case BYTE: + switch(size) { + case WORD: + return (short)(reg & 0xFFFF); + case LONG: + return (int)(reg & 0xFFFFFFFF); + default: + printf("Error: (__get_reg_value) Invalid reg size\n"); + domain_crash_synchronous(); + } +} + +long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs) +{ + if (size == BYTE) { switch (index) { - case 0: //%al + case 0: /* %al */ return (char)(regs->eax & 0xFF); - case 1: //%cl + case 1: /* %cl */ return (char)(regs->ecx & 0xFF); - case 2: //%dl + case 2: /* %dl */ return (char)(regs->edx & 0xFF); - case 3: //%bl + case 3: /* %bl */ return (char)(regs->ebx & 0xFF); - case 4: //%ah + case 4: /* %ah */ return (char)((regs->eax & 0xFF00) >> 8); - case 5: //%ch + case 5: /* %ch */ return (char)((regs->ecx & 0xFF00) >> 8); - case 6: //%dh + case 6: /* %dh */ return (char)((regs->edx & 0xFF00) >> 8); - case 7: //%bh + case 7: /* %bh */ return (char)((regs->ebx & 0xFF00) >> 8); default: - printk("Error: (get_reg_value)size case 0 error\n"); + printf("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } - case WORD: + } + switch (index) { - case 0: //%ax - return (short)(regs->eax & 0xFFFF); - case 1: //%cx - return (short)(regs->ecx & 0xFFFF); - case 2: //%dx - return (short)(regs->edx & 0xFFFF); - case 3: //%bx - return (short)(regs->ebx & 0xFFFF); - case 4: //%sp - return (short)(regs->esp & 0xFFFF); - break; - case 5: //%bp - return (short)(regs->ebp & 0xFFFF); - case 6: //%si - return (short)(regs->esi & 0xFFFF); - case 7: //%di - return (short)(regs->edi & 0xFFFF); - default: - printk("Error: (get_reg_value)size case 1 error\n"); - domain_crash_synchronous(); - } - case LONG: - switch (index) { - case 0: //%eax - return regs->eax; - case 1: //%ecx - return regs->ecx; - case 2: //%edx - return regs->edx; - - case 3: //%ebx - return regs->ebx; - case 4: //%esp - return regs->esp; - case 5: //%ebp - return regs->ebp; - case 6: //%esi - return regs->esi; - case 7: //%edi - return regs->edi; - default: - printk("Error: (get_reg_value)size case 2 error\n"); - domain_crash_synchronous(); - } + case 0: return __get_reg_value(regs->eax, size); + case 1: return __get_reg_value(regs->ecx, size); + case 2: return __get_reg_value(regs->edx, size); + case 3: return __get_reg_value(regs->ebx, size); + case 4: return __get_reg_value(regs->esp, size); + case 5: return __get_reg_value(regs->ebp, size); + case 6: return __get_reg_value(regs->esi, size); + case 7: return __get_reg_value(regs->edi, size); default: - printk("Error: (get_reg_value)size case error\n"); + printf("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } } #endif -static inline const unsigned char *check_prefix(const unsigned char *inst, struct instruction *thread_inst, unsigned char *rex_p) +static inline unsigned char *check_prefix(unsigned char *inst, + struct instruction *thread_inst, unsigned char *rex_p) { while (1) { switch (*inst) { - /* rex prefix for em64t instructions*/ + /* rex prefix for em64t instructions */ case 0x40 ... 0x4e: *rex_p = *inst; break; - - case 0xf3: //REPZ + case 0xf3: /* REPZ */ thread_inst->flags = REPZ; - break; - case 0xf2: //REPNZ + break; + case 0xf2: /* REPNZ */ thread_inst->flags = REPNZ; - break; - case 0xf0: //LOCK + break; + case 0xf0: /* LOCK */ break; - case 0x2e: //CS - case 0x36: //SS - case 0x3e: //DS - case 0x26: //ES - case 0x64: //FS - case 0x65: //GS - thread_inst->seg_sel = *inst; + case 0x2e: /* CS */ + case 0x36: /* SS */ + case 0x3e: /* DS */ + case 0x26: /* ES */ + case 0x64: /* FS */ + case 0x65: /* GS */ + thread_inst->seg_sel = *inst; break; - case 0x66: //32bit->16bit + case 0x66: /* 32bit->16bit */ thread_inst->op_size = WORD; break; case 0x67: - printf("Error: Not handling 0x67 (yet)\n"); + printf("Error: Not handling 0x67 (yet)\n"); domain_crash_synchronous(); break; default: @@ -249,7 +223,7 @@ } } -static inline unsigned long get_immediate(int op16, const unsigned char *inst, int op_size) +static inline unsigned long get_immediate(int op16,const unsigned char *inst, int op_size) { int mod, reg, rm; unsigned long val = 0; @@ -317,197 +291,299 @@ static void init_instruction(struct instruction *mmio_inst) { - memset(mmio_inst->i_name, '0', I_NAME_LEN); - mmio_inst->op_size = 0; - mmio_inst->offset = 0; + mmio_inst->instr = 0; + mmio_inst->op_size = 0; mmio_inst->immediate = 0; mmio_inst->seg_sel = 0; - mmio_inst->op_num = 0; mmio_inst->operand[0] = 0; mmio_inst->operand[1] = 0; - mmio_inst->operand[2] = 0; mmio_inst->flags = 0; } #define GET_OP_SIZE_FOR_BYTE(op_size) \ - do {if (rex) op_size = BYTE_64;else op_size = BYTE;} while(0) + do { \ + if (rex) \ + op_size = BYTE_64; \ + else \ + op_size = BYTE; \ + } while(0) #define GET_OP_SIZE_FOR_NONEBYTE(op_size) \ - do {if (rex & 0x8) op_size = QUAD; else if (op_size != WORD) op_size = LONG;} while(0) - -static int vmx_decode(const unsigned char *inst, struct instruction *thread_inst) + do { \ + if (rex & 0x8) \ + op_size = QUAD; \ + else if (op_size != WORD) \ + op_size = LONG; \ + } while(0) + + +/* + * Decode mem,accumulator operands (as in <opcode> m8/m16/m32, al,ax,eax) + */ +static int mem_acc(unsigned char size, struct instruction *instr) +{ + instr->operand[0] = mk_operand(size, 0, 0, MEMORY); + instr->operand[1] = mk_operand(size, 0, 0, REGISTER); + return DECODE_success; +} + +/* + * Decode accumulator,mem operands (as in <opcode> al,ax,eax, m8/m16/m32) + */ +static int acc_mem(unsigned char size, struct instruction *instr) +{ + instr->operand[0] = mk_operand(size, 0, 0, REGISTER); + instr->operand[1] = mk_operand(size, 0, 0, MEMORY); + return DECODE_success; +} + +/* + * Decode mem,reg operands (as in <opcode> r32/16, m32/16) + */ +static int mem_reg(unsigned char size, unsigned char *opcode, + struct instruction *instr, unsigned char rex) +{ + int index = get_index(opcode + 1, rex); + + instr->operand[0] = mk_operand(size, 0, 0, MEMORY); + instr->operand[1] = mk_operand(size, index, 0, REGISTER); + return DECODE_success; +} + +/* + * Decode reg,mem operands (as in <opcode> m32/16, r32/16) + */ +static int reg_mem(unsigned char size, unsigned char *opcode, + struct instruction *instr, unsigned char rex) +{ + int index = get_index(opcode + 1, rex); + + instr->operand[0] = mk_operand(size, index, 0, REGISTER); + instr->operand[1] = mk_operand(size, 0, 0, MEMORY); + return DECODE_success; +} + +static int vmx_decode(unsigned char *opcode, struct instruction *instr) { unsigned long eflags; int index, vm86 = 0; unsigned char rex = 0; unsigned char tmp_size = 0; - - init_instruction(thread_inst); - - inst = check_prefix(inst, thread_inst, &rex); + init_instruction(instr); + + opcode = check_prefix(opcode, instr, &rex); __vmread(GUEST_RFLAGS, &eflags); if (eflags & X86_EFLAGS_VM) vm86 = 1; if (vm86) { /* meaning is reversed */ - if (thread_inst->op_size == WORD) - thread_inst->op_size = LONG; - else if (thread_inst->op_size == LONG) - thread_inst->op_size = WORD; - else if (thread_inst->op_size == 0) - thread_inst->op_size = WORD; - } - - switch(*inst) { - case 0x81: - /* This is only a workaround for cmpl instruction*/ - strcpy((char *)thread_inst->i_name, "cmp"); + if (instr->op_size == WORD) + instr->op_size = LONG; + else if (instr->op_size == LONG) + instr->op_size = WORD; + else if (instr->op_size == 0) + instr->op_size = WORD; + } + + switch (*opcode) { + case 0x0B: /* or m32/16, r32/16 */ + instr->instr = INSTR_OR; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return mem_reg(instr->op_size, opcode, instr, rex); + + case 0x20: /* and r8, m8 */ + instr->instr = INSTR_AND; + GET_OP_SIZE_FOR_BYTE(instr->op_size); + return reg_mem(instr->op_size, opcode, instr, rex); + + case 0x21: /* and r32/16, m32/16 */ + instr->instr = INSTR_AND; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return reg_mem(instr->op_size, opcode, instr, rex); + + case 0x23: /* and m32/16, r32/16 */ + instr->instr = INSTR_AND; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return mem_reg(instr->op_size, opcode, instr, rex); + + case 0x30: /* xor r8, m8 */ + instr->instr = INSTR_XOR; + GET_OP_SIZE_FOR_BYTE(instr->op_size); + return reg_mem(instr->op_size, opcode, instr, rex); + + case 0x31: /* xor r32/16, m32/16 */ + instr->instr = INSTR_XOR; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return reg_mem(instr->op_size, opcode, instr, rex); + + case 0x39: /* cmp r32/16, m32/16 */ + instr->instr = INSTR_CMP; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return reg_mem(instr->op_size, opcode, instr, rex); + + case 0x81: + if (((opcode[1] >> 3) & 7) == 7) { /* cmp $imm, m32/16 */ + instr->instr = INSTR_CMP; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + + instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE); + instr->immediate = get_immediate(vm86, opcode+1, BYTE); + instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY); + return DECODE_success; - - case 0x88: - /* mov r8 to m8 */ - thread_inst->op_size = BYTE; - index = get_index((inst + 1), rex); - GET_OP_SIZE_FOR_BYTE(tmp_size); - thread_inst->operand[0] = mk_operand(tmp_size, index, 0, REGISTER); - - break; - case 0x89: - /* mov r32/16 to m32/16 */ - index = get_index((inst + 1), rex); - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - thread_inst->operand[0] = mk_operand(thread_inst->op_size, index, 0, REGISTER); - - break; - case 0x8a: - /* mov m8 to r8 */ - thread_inst->op_size = BYTE; - index = get_index((inst + 1), rex); - GET_OP_SIZE_FOR_BYTE(tmp_size); - thread_inst->operand[1] = mk_operand(tmp_size, index, 0, REGISTER); - break; - case 0x8b: - /* mov r32/16 to m32/16 */ - index = get_index((inst + 1), rex); - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - thread_inst->operand[1] = mk_operand(thread_inst->op_size, index, 0, REGISTER); - break; - case 0x8c: - case 0x8e: - printk("%x, This opcode hasn't been handled yet!", *inst); - return DECODE_failure; - /* Not handle it yet. */ - case 0xa0: - /* mov byte to al */ - thread_inst->op_size = BYTE; - GET_OP_SIZE_FOR_BYTE(tmp_size); - thread_inst->operand[1] = mk_operand(tmp_size, 0, 0, REGISTER); - break; - case 0xa1: - /* mov word/doubleword to ax/eax */ - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - thread_inst->operand[1] = mk_operand(thread_inst->op_size, 0, 0, REGISTER); - - break; - case 0xa2: - /* mov al to (seg:offset) */ - thread_inst->op_size = BYTE; - GET_OP_SIZE_FOR_BYTE(tmp_size); - thread_inst->operand[0] = mk_operand(tmp_size, 0, 0, REGISTER); - break; - case 0xa3: - /* mov ax/eax to (seg:offset) */ - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - thread_inst->operand[0] = mk_operand(thread_inst->op_size, 0, 0, REGISTER); - break; - case 0xa4: - /* movsb */ - thread_inst->op_size = BYTE; - strcpy((char *)thread_inst->i_name, "movs"); - return DECODE_success; - case 0xa5: - /* movsw/movsl */ - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - strcpy((char *)thread_inst->i_name, "movs"); - return DECODE_success; - case 0xaa: - /* stosb */ - thread_inst->op_size = BYTE; - strcpy((char *)thread_inst->i_name, "stosb"); - return DECODE_success; - case 0xab: - /* stosw/stosl */ - if (thread_inst->op_size == WORD) { - strcpy((char *)thread_inst->i_name, "stosw"); - } else { - thread_inst->op_size = LONG; - strcpy((char *)thread_inst->i_name, "stosl"); - } - return DECODE_success; - case 0xc6: - /* mov imm8 to m8 */ - thread_inst->op_size = BYTE; - thread_inst->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE); - thread_inst->immediate = get_immediate(vm86, - (inst+1), thread_inst->op_size); - break; - case 0xc7: - /* mov imm16/32 to m16/32 */ - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - thread_inst->operand[0] = mk_operand(thread_inst->op_size, 0, 0, IMMEDIATE); - thread_inst->immediate = get_immediate(vm86, (inst+1), thread_inst->op_size); + } else + return DECODE_failure; + + case 0x84: /* test m8, r8 */ + instr->instr = INSTR_TEST; + instr->op_size = BYTE; + GET_OP_SIZE_FOR_BYTE(tmp_size); + return mem_reg(tmp_size, opcode, instr, rex); + + case 0x88: /* mov r8, m8 */ + instr->instr = INSTR_MOV; + instr->op_size = BYTE; + GET_OP_SIZE_FOR_BYTE(tmp_size); + return reg_mem(tmp_size, opcode, instr, rex); + + case 0x89: /* mov r32/16, m32/16 */ + instr->instr = INSTR_MOV; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return reg_mem(instr->op_size, opcode, instr, rex); + + case 0x8A: /* mov m8, r8 */ + instr->instr = INSTR_MOV; + instr->op_size = BYTE; + GET_OP_SIZE_FOR_BYTE(tmp_size); + return mem_reg(tmp_size, opcode, instr, rex); + + case 0x8B: /* mov m32/16, r32/16 */ + instr->instr = INSTR_MOV; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return mem_reg(instr->op_size, opcode, instr, rex); + + case 0xA0: /* mov <addr>, al */ + instr->instr = INSTR_MOV; + instr->op_size = BYTE; + GET_OP_SIZE_FOR_BYTE(tmp_size); + return mem_acc(tmp_size, instr); + + case 0xA1: /* mov <addr>, ax/eax */ + instr->instr = INSTR_MOV; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return mem_acc(instr->op_size, instr); + + case 0xA2: /* mov al, <addr> */ + instr->instr = INSTR_MOV; + instr->op_size = BYTE; + GET_OP_SIZE_FOR_BYTE(tmp_size); + return acc_mem(tmp_size, instr); + + case 0xA3: /* mov ax/eax, <addr> */ + instr->instr = INSTR_MOV; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return acc_mem(instr->op_size, instr); + + case 0xA4: /* movsb */ + instr->instr = INSTR_MOVS; + instr->op_size = BYTE; + return DECODE_success; - break; - case 0x0f: - break; - default: - printk("%x, This opcode hasn't been handled yet!", *inst); - return DECODE_failure; - } + case 0xA5: /* movsw/movsl */ + instr->instr = INSTR_MOVS; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return DECODE_success; - strcpy((char *)thread_inst->i_name, "mov"); - if (*inst != 0x0f) { + case 0xAA: /* stosb */ + instr->instr = INSTR_STOS; + instr->op_size = BYTE; return DECODE_success; - } - - inst++; - switch (*inst) { + + case 0xAB: /* stosw/stosl */ + instr->instr = INSTR_STOS; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + return DECODE_success; - /* movz */ - case 0xb6: - index = get_index((inst + 1), rex); - GET_OP_SIZE_FOR_NONEBYTE(thread_inst->op_size); - thread_inst->operand[1] = mk_operand(thread_inst->op_size, index, 0, REGISTER); - thread_inst->op_size = BYTE; - strcpy((char *)thread_inst->i_name, "movzb"); + case 0xC6: + if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm8, m8 */ + instr->instr = INSTR_MOV; + instr->op_size = BYTE; + + instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE); + instr->immediate = get_immediate(vm86, opcode+1, instr->op_size); + instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY); return DECODE_success; - case 0xb7: - index = get_index((inst + 1), rex); - if (rex & 0x8) { - thread_inst->op_size = LONG; - thread_inst->operand[1] = mk_operand(QUAD, index, 0, REGISTER); - } else { - thread_inst->op_size = WORD; - thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER); - } + } else + return DECODE_failure; - strcpy((char *)thread_inst->i_name, "movzw"); + case 0xC7: + if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm16/32, m16/32 */ + instr->instr = INSTR_MOV; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + + instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE); + instr->immediate = get_immediate(vm86, opcode+1, instr->op_size); + instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY); return DECODE_success; - default: - printk("0f %x, This opcode hasn't been handled yet!", *inst); - return DECODE_failure; - } - - /* will never reach here */ - return DECODE_failure; -} - + } else + return DECODE_failure; + + case 0xF6: + if (((opcode[1] >> 3) & 7) == 0) { /* testb $imm8, m8 */ + instr->instr = INSTR_TEST; + instr->op_size = BYTE; + + instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE); + instr->immediate = get_immediate(vm86, opcode+1, instr->op_size); + instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY); + + return DECODE_success; + } else + return DECODE_failure; + + case 0x0F: + break; + + default: + printf("%x, This opcode isn't handled yet!\n", *opcode); + return DECODE_failure; + } + + switch (*++opcode) { + case 0xB6: /* movz m8, r16/r32 */ + instr->instr = INSTR_MOVZ; + GET_OP_SIZE_FOR_NONEBYTE(instr->op_size); + index = get_index(opcode + 1, rex); + instr->operand[0] = mk_operand(BYTE, 0, 0, MEMORY); + instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER); + return DECODE_success; + + case 0xB7: /* movz m16, r32 */ + instr->instr = INSTR_MOVZ; + index = get_index(opcode + 1, rex); + if (rex & 0x8) { + instr->op_size = LONG; + instr->operand[1] = mk_operand(QUAD, index, 0, REGISTER); + } else { + instr->op_size = WORD; + instr->operand[1] = mk_operand(LONG, index, 0, REGISTER); + } + instr->operand[0] = mk_operand(instr->op_size, 0, 0, MEMORY); + return DECODE_success; + + default: + printf("0f %x, This opcode isn't handled yet\n", *opcode); + return DECODE_failure; + } +} + +/* XXX use vmx_copy instead */ int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip, int inst_len) { unsigned long gpa; @@ -552,40 +628,27 @@ return inst_len+remaining; } -static int read_from_mmio(struct instruction *inst_p) -{ - // Only for mov instruction now!!! - if (inst_p->operand[1] & REGISTER) - return 1; - - return 0; -} - -// dir: 1 read from mmio -// 0 write to mmio -static void send_mmio_req(unsigned long gpa, - struct instruction *inst_p, long value, int dir, int pvalid) +void send_mmio_req(unsigned char type, unsigned long gpa, + unsigned long count, int size, long value, int dir, int pvalid) { struct vcpu *d = current; vcpu_iodata_t *vio; ioreq_t *p; int vm86; - struct mi_per_cpu_info *mpci_p; - struct cpu_user_regs *inst_decoder_regs; + struct cpu_user_regs *regs; extern long evtchn_send(int lport); - mpci_p = ¤t->domain->arch.vmx_platform.mpci; - inst_decoder_regs = mpci_p->inst_decoder_regs; + regs = current->domain->arch.vmx_platform.mpci.inst_decoder_regs; vio = get_vio(d->domain, d->vcpu_id); - if (vio == NULL) { - printk("bad shared page\n"); + printf("bad shared page\n"); domain_crash_synchronous(); } + p = &vio->vp_ioreq; - vm86 = inst_decoder_regs->eflags & X86_EFLAGS_VM; + vm86 = regs->eflags & X86_EFLAGS_VM; if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) { printf("VMX I/O has not yet completed\n"); @@ -596,24 +659,21 @@ p->dir = dir; p->pdata_valid = pvalid; - p->port_mm = 1; - p->size = inst_p->op_size; + p->type = type; + p->size = size; p->addr = gpa; - p->u.data = value; + p->count = count; + p->df = regs->eflags & EF_DF ? 1 : 0; + + if (pvalid) { + if (vmx_paging_enabled(current)) + p->u.pdata = (void *) gva_to_gpa(value); + else + p->u.pdata = (void *) value; /* guest VA == guest PA */ + } else + p->u.data = value; p->state = STATE_IOREQ_READY; - - if (inst_p->flags & REPZ) { - if (vm86) - p->count = inst_decoder_regs->ecx & 0xFFFF; - else - p->count = inst_decoder_regs->ecx; - p->df = (inst_decoder_regs->eflags & EF_DF) ? 1 : 0; - } else - p->count = 1; - - if ((pvalid) && vmx_paging_enabled(current)) - p->u.pdata = (void *) gva_to_gpa(p->u.data); if (vmx_mmio_intercept(p)){ p->state = STATE_IORESP_READY; @@ -625,18 +685,50 @@ vmx_wait_io(); } +static void mmio_operands(int type, unsigned long gpa, struct instruction *inst, + struct mi_per_cpu_info *mpcip, struct cpu_user_regs *regs) +{ + unsigned long value = 0; + int index, size; + + size = operand_size(inst->operand[0]); + + mpcip->flags = inst->flags; + mpcip->instr = inst->instr; + mpcip->operand[0] = inst->operand[0]; /* source */ + mpcip->operand[1] = inst->operand[1]; /* destination */ + + if (inst->operand[0] & REGISTER) { /* dest is memory */ + index = operand_index(inst->operand[0]); + value = get_reg_value(size, index, 0, regs); + send_mmio_req(type, gpa, 1, size, value, IOREQ_WRITE, 0); + } else if (inst->operand[0] & IMMEDIATE) { /* dest is memory */ + value = inst->immediate; + send_mmio_req(type, gpa, 1, size, value, IOREQ_WRITE, 0); + } else if (inst->operand[0] & MEMORY) { /* dest is register */ + /* send the request and wait for the value */ + send_mmio_req(type, gpa, 1, size, 0, IOREQ_READ, 0); + } else { + printf("mmio_operands: invalid operand\n"); + domain_crash_synchronous(); + } +} + +#define GET_REPEAT_COUNT() \ + (mmio_inst.flags & REPZ ? (vm86 ? regs->ecx & 0xFFFF : regs->ecx) : 1) + void handle_mmio(unsigned long va, unsigned long gpa) { unsigned long eip, eflags, cs; unsigned long inst_len, inst_addr; - struct mi_per_cpu_info *mpci_p; - struct cpu_user_regs *inst_decoder_regs; + struct mi_per_cpu_info *mpcip; + struct cpu_user_regs *regs; struct instruction mmio_inst; unsigned char inst[MAX_INST_LEN]; - int vm86, ret; + int i, vm86, ret; - mpci_p = ¤t->domain->arch.vmx_platform.mpci; - inst_decoder_regs = mpci_p->inst_decoder_regs; + mpcip = ¤t->domain->arch.vmx_platform.mpci; + regs = mpcip->inst_decoder_regs; __vmread(GUEST_RIP, &eip); __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len); @@ -647,108 +739,142 @@ __vmread(GUEST_CS_SELECTOR, &cs); inst_addr = (cs << 4) + eip; } else - inst_addr = eip; /* XXX should really look at GDT[cs].base too */ - - memset(inst, '0', MAX_INST_LEN); + inst_addr = eip; + + memset(inst, 0, MAX_INST_LEN); ret = inst_copy_from_guest(inst, inst_addr, inst_len); if (ret != inst_len) { - printk("handle_mmio - EXIT: get guest instruction fault\n"); + printf("handle_mmio - EXIT: get guest instruction fault\n"); domain_crash_synchronous(); } - init_instruction(&mmio_inst); if (vmx_decode(inst, &mmio_inst) == DECODE_failure) { - printk("vmx decode failure: eip=%lx, va=%lx\n %x %x %x %x\n", eip, va, - inst[0], inst[1], inst[2], inst[3]); + printf("mmio opcode: va 0x%lx, gpa 0x%lx, len %ld:", + va, gpa, inst_len); + for (i = 0; i < inst_len; i++) + printf(" %02x", inst[i] & 0xFF); + printf("\n"); domain_crash_synchronous(); } - __vmwrite(GUEST_RIP, eip + inst_len); - store_cpu_user_regs(inst_decoder_regs); - - // Only handle "mov" and "movs" instructions! - if (!strncmp((char *)mmio_inst.i_name, "movz", 4)) { - if (read_from_mmio(&mmio_inst)) { - // Send the request and waiting for return value. - mpci_p->mmio_target = mmio_inst.operand[1] | WZEROEXTEND; - send_mmio_req(gpa, &mmio_inst, 0, IOREQ_READ, 0); - return ; - } else { - printk("handle_mmio - EXIT: movz error!\n"); - domain_crash_synchronous(); - } - } - - if (!strncmp((char *)mmio_inst.i_name, "movs", 4)) { + store_cpu_user_regs(regs); + regs->eip += inst_len; /* advance %eip */ + + switch (mmio_inst.instr) { + case INSTR_MOV: + mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mpcip, regs); + break; + + case INSTR_MOVS: + { + unsigned long count = GET_REPEAT_COUNT(); + unsigned long size = mmio_inst.op_size; + int sign = regs->eflags & EF_DF ? -1 : 1; unsigned long addr = 0; int dir; + /* determine non-MMIO address */ if (vm86) { unsigned long seg; __vmread(GUEST_ES_SELECTOR, &seg); - if (((seg << 4) + (inst_decoder_regs->edi & 0xFFFF)) == va) { + if (((seg << 4) + (regs->edi & 0xFFFF)) == va) { dir = IOREQ_WRITE; __vmread(GUEST_DS_SELECTOR, &seg); - addr = (seg << 4) + (inst_decoder_regs->esi & 0xFFFF); + addr = (seg << 4) + (regs->esi & 0xFFFF); } else { dir = IOREQ_READ; - addr = (seg << 4) + (inst_decoder_regs->edi & 0xFFFF); + addr = (seg << 4) + (regs->edi & 0xFFFF); } - } else { /* XXX should really look at GDT[ds/es].base too */ - if (va == inst_decoder_regs->edi) { + } else { + if (va == regs->edi) { dir = IOREQ_WRITE; - addr = inst_decoder_regs->esi; + addr = regs->esi; } else { dir = IOREQ_READ; - addr = inst_decoder_regs->edi; + addr = regs->edi; } } - send_mmio_req(gpa, &mmio_inst, addr, dir, 1); - return; - } - - if (!strncmp((char *)mmio_inst.i_name, "mov", 3)) { - long value = 0; - int size, index; - - if (read_from_mmio(&mmio_inst)) { - // Send the request and waiting for return value. - mpci_p->mmio_target = mmio_inst.operand[1]; - send_mmio_req(gpa, &mmio_inst, value, IOREQ_READ, 0); - return; - } else { - // Write to MMIO - if (mmio_inst.operand[0] & IMMEDIATE) { - value = mmio_inst.immediate; - } else if (mmio_inst.operand[0] & REGISTER) { - size = operand_size(mmio_inst.operand[0]); - index = operand_index(mmio_inst.operand[0]); - value = get_reg_value(size, index, 0, inst_decoder_regs); - } else { - domain_crash_synchronous(); - } - send_mmio_req(gpa, &mmio_inst, value, IOREQ_WRITE, 0); - return; - } - } - - if (!strncmp((char *)mmio_inst.i_name, "stos", 4)) { - send_mmio_req(gpa, &mmio_inst, - inst_decoder_regs->eax, IOREQ_WRITE, 0); - return; - } - /* Workaround for cmp instruction */ - if (!strncmp((char *)mmio_inst.i_name, "cmp", 3)) { - inst_decoder_regs->eflags &= ~X86_EFLAGS_ZF; - __vmwrite(GUEST_RFLAGS, inst_decoder_regs->eflags); - return; - } - - domain_crash_synchronous(); + mpcip->flags = mmio_inst.flags; + mpcip->instr = mmio_inst.instr; + + /* + * In case of a movs spanning multiple pages, we break the accesses + * up into multiple pages (the device model works with non-continguous + * physical guest pages). To copy just one page, we adjust %ecx and + * do not advance %eip so that the next "rep movs" copies the next page. + * Unaligned accesses, for example movsl starting at PGSZ-2, are + * turned into a single copy where we handle the overlapping memory + * copy ourself. After this copy succeeds, "rep movs" is executed + * again. + */ + if ((addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK)) { + unsigned long value = 0; + + mpcip->flags |= OVERLAP; + + regs->eip -= inst_len; /* do not advance %eip */ + + if (dir == IOREQ_WRITE) + vmx_copy(&value, addr, size, VMX_COPY_IN); + send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, size, value, dir, 0); + } else { + if ((addr & PAGE_MASK) != ((addr + count * size - 1) & PAGE_MASK)) { + regs->eip -= inst_len; /* do not advance %eip */ + + if (sign > 0) + count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size; + else + count = (addr & ~PAGE_MASK) / size; + } + + send_mmio_req(IOREQ_TYPE_COPY, gpa, count, size, addr, dir, 1); + } + break; + } + + case INSTR_MOVZ: + mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mpcip, regs); + break; + + case INSTR_STOS: + /* + * Since the destination is always in (contiguous) mmio space we don't + * need to break it up into pages. + */ + mpcip->flags = mmio_inst.flags; + mpcip->instr = mmio_inst.instr; + send_mmio_req(IOREQ_TYPE_COPY, gpa, + GET_REPEAT_COUNT(), mmio_inst.op_size, regs->eax, IOREQ_WRITE, 0); + break; + + case INSTR_OR: + mmio_operands(IOREQ_TYPE_OR, gpa, &mmio_inst, mpcip, regs); + break; + + case INSTR_AND: + mmio_operands(IOREQ_TYPE_AND, gpa, &mmio_inst, mpcip, regs); + break; + + case INSTR_XOR: + mmio_operands(IOREQ_TYPE_XOR, gpa, &mmio_inst, mpcip, regs); + break; + + case INSTR_CMP: + mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mpcip, regs); + break; + + case INSTR_TEST: + mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mpcip, regs); + break; + + default: + printf("Unhandled MMIO instruction\n"); + domain_crash_synchronous(); + } } #endif /* CONFIG_VMX */ diff -r 5aae0c8158b9 -r f27205ea60ef xen/common/memory.c --- a/xen/common/memory.c Sat Sep 3 16:57:54 2005 +++ b/xen/common/memory.c Sat Sep 3 16:58:50 2005 @@ -25,7 +25,8 @@ unsigned long *extent_list, unsigned int nr_extents, unsigned int extent_order, - unsigned int flags) + unsigned int flags, + int *preempted) { struct pfn_info *page; unsigned long i; @@ -43,7 +44,10 @@ for ( i = 0; i < nr_extents; i++ ) { if ( hypercall_preempt_check() ) - return i; + { + *preempted = 1; + return i; + } if ( unlikely((page = alloc_domheap_pages( d, extent_order, flags)) == NULL) ) @@ -67,7 +71,8 @@ unsigned long *extent_list, unsigned int nr_extents, unsigned int extent_order, - unsigned int flags) + unsigned int flags, + int *preempted) { struct pfn_info *page; unsigned long i, j, mpfn; @@ -78,7 +83,10 @@ for ( i = 0; i < nr_extents; i++ ) { if ( hypercall_preempt_check() ) - return i; + { + *preempted = 1; + return i; + } if ( unlikely(__get_user(mpfn, &extent_list[i]) != 0) ) return i; @@ -124,7 +132,7 @@ long do_memory_op(int cmd, void *arg) { struct domain *d; - int rc, start_extent, op, flags = 0; + int rc, start_extent, op, flags = 0, preempted = 0; struct xen_memory_reservation reservation; op = cmd & ((1 << START_EXTENT_SHIFT) - 1); @@ -165,19 +173,18 @@ reservation.extent_start, reservation.nr_extents, reservation.extent_order, - flags); + flags, + &preempted); if ( unlikely(reservation.domid != DOMID_SELF) ) put_domain(d); rc += start_extent; - if ( (rc != reservation.nr_extents) && hypercall_preempt_check() ) + if ( preempted ) return hypercall2_create_continuation( - __HYPERVISOR_memory_op, - op | (rc << START_EXTENT_SHIFT), - arg); - + __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg); + break; case XENMEM_maximum_ram_page: diff -r 5aae0c8158b9 -r f27205ea60ef xen/include/asm-x86/vmx.h --- a/xen/include/asm-x86/vmx.h Sat Sep 3 16:57:54 2005 +++ b/xen/include/asm-x86/vmx.h Sat Sep 3 16:58:50 2005 @@ -471,4 +471,7 @@ void load_cpu_user_regs(struct cpu_user_regs *regs); void store_cpu_user_regs(struct cpu_user_regs *regs); +enum { VMX_COPY_IN = 0, VMX_COPY_OUT }; +int vmx_copy(void *buf, unsigned long laddr, int size, int dir); + #endif /* __ASM_X86_VMX_H__ */ diff -r 5aae0c8158b9 -r f27205ea60ef xen/include/asm-x86/vmx_platform.h --- a/xen/include/asm-x86/vmx_platform.h Sat Sep 3 16:57:54 2005 +++ b/xen/include/asm-x86/vmx_platform.h Sat Sep 3 16:58:50 2005 @@ -24,8 +24,7 @@ #include <asm/vmx_virpit.h> #include <asm/vmx_intercept.h> -#define MAX_OPERAND_NUM 3 -#define I_NAME_LEN 16 +#define MAX_OPERAND_NUM 2 #define mk_operand(size, index, seg, flag) \ (((size) << 24) | ((index) << 16) | ((seg) << 8) | (flag)) @@ -35,54 +34,60 @@ #define operand_index(operand) \ ((operand >> 16) & 0xFF) - //For instruction.operand[].size + +/* for instruction.operand[].size */ #define BYTE 1 #define WORD 2 #define LONG 4 #define QUAD 8 #define BYTE_64 16 - //For instruction.operand[].flag +/* for instruction.operand[].flag */ #define REGISTER 0x1 #define MEMORY 0x2 #define IMMEDIATE 0x4 -#define WZEROEXTEND 0x8 - //For instruction.flags +/* for instruction.flags */ #define REPZ 0x1 #define REPNZ 0x2 +#define OVERLAP 0x4 + +#define INSTR_PIO 1 +#define INSTR_OR 2 +#define INSTR_AND 3 +#define INSTR_XOR 4 +#define INSTR_CMP 5 +#define INSTR_MOV 6 +#define INSTR_MOVS 7 +#define INSTR_MOVZ 8 +#define INSTR_STOS 9 +#define INSTR_TEST 10 struct instruction { - __s8 i_name[I_NAME_LEN]; //Instruction's name - __s16 op_size; //The operand's bit size, e.g. 16-bit or 32-bit. - - __u64 offset; //The effective address - //offset = Base + (Index * Scale) + Displacement - + __s8 instr; /* instruction type */ + __s16 op_size; /* the operand's bit size, e.g. 16-bit or 32-bit */ __u64 immediate; - - __u16 seg_sel; //Segmentation selector - - __u32 operand[MAX_OPERAND_NUM]; //The order of operand is from AT&T Assembly - __s16 op_num; //The operand numbers - - __u32 flags; // + __u16 seg_sel; /* segmentation selector */ + __u32 operand[MAX_OPERAND_NUM]; /* order is AT&T assembly */ + __u32 flags; }; #define MAX_INST_LEN 32 -struct mi_per_cpu_info -{ - unsigned long mmio_target; - struct cpu_user_regs *inst_decoder_regs; +struct mi_per_cpu_info { + int flags; + int instr; /* instruction */ + unsigned long operand[2]; /* operands */ + unsigned long immediate; /* immediate portion */ + struct cpu_user_regs *inst_decoder_regs; /* current context */ }; struct virtual_platform_def { - unsigned long *real_mode_data; /* E820, etc. */ + unsigned long *real_mode_data; /* E820, etc. */ unsigned long shared_page_va; struct vmx_virpit_t vmx_pit; struct vmx_handler_t vmx_handler; - struct mi_per_cpu_info mpci; /* MMIO */ + struct mi_per_cpu_info mpci; /* MMIO */ }; extern void handle_mmio(unsigned long, unsigned long); diff -r 5aae0c8158b9 -r f27205ea60ef xen/include/public/io/ioreq.h --- a/xen/include/public/io/ioreq.h Sat Sep 3 16:57:54 2005 +++ b/xen/include/public/io/ioreq.h Sat Sep 3 16:58:50 2005 @@ -29,9 +29,17 @@ #define STATE_IORESP_READY 3 #define STATE_IORESP_HOOK 4 -/* VMExit dispatcher should cooperate with instruction decoder to - prepare this structure and notify service OS and DM by sending - virq */ +#define IOREQ_TYPE_PIO 0 /* pio */ +#define IOREQ_TYPE_COPY 1 /* mmio ops */ +#define IOREQ_TYPE_AND 2 +#define IOREQ_TYPE_OR 3 +#define IOREQ_TYPE_XOR 4 + +/* + * VMExit dispatcher should cooperate with instruction decoder to + * prepare this structure and notify service OS and DM by sending + * virq + */ typedef struct { u64 addr; /* physical address */ u64 size; /* size in bytes */ @@ -43,8 +51,8 @@ u8 state:4; u8 pdata_valid:1; /* if 1, use pdata above */ u8 dir:1; /* 1=read, 0=write */ - u8 port_mm:1; /* 0=portio, 1=mmio */ u8 df:1; + u8 type; /* I/O type */ } ioreq_t; #define MAX_VECTOR 256 diff -r 5aae0c8158b9 -r f27205ea60ef tools/firmware/vmxassist/TODO --- a/tools/firmware/vmxassist/TODO Sat Sep 3 16:57:54 2005 +++ /dev/null Sat Sep 3 16:58:50 2005 @@ -1,8 +0,0 @@ - -- Use the VME extensions (interrupt handling) - -- Use E820 map in vmxassist instead of cmos hack - -- Add ACPI support (Nitin's patch) - - _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |