Leslie Mann wrote:
I'll prepare the first patch. Can you ensure that your upgraded setup still works kvm-17.It does, as I use it daily in order to run a Win app that I need.
Please test the attached patch, against kvm-17. This is subversion revision 4546 and git commit c01571ed56754dfea458cc37d553c360082411a1.
-- error compiling committee.c: too many arguments to function
diff -ur kvm-17/kernel/include/linux/kvm.h kvm/kernel/include/linux/kvm.h --- kvm-17/kernel/include/linux/kvm.h 2007-03-20 15:12:42.000000000 +0200 +++ kvm/kernel/include/linux/kvm.h 2007-04-04 19:19:44.000000000 +0300 @@ -11,7 +11,7 @@ #include <asm/types.h> #include <linux/ioctl.h> -#define KVM_API_VERSION 4 +#define KVM_API_VERSION 9 /* * Architectural interrupt line count, and the size of the bitmap needed @@ -34,36 +34,33 @@ #define KVM_MEM_LOG_DIRTY_PAGES 1UL -#define KVM_EXIT_TYPE_FAIL_ENTRY 1 -#define KVM_EXIT_TYPE_VM_EXIT 2 - enum kvm_exit_reason { KVM_EXIT_UNKNOWN = 0, KVM_EXIT_EXCEPTION = 1, KVM_EXIT_IO = 2, - KVM_EXIT_CPUID = 3, + KVM_EXIT_HYPERCALL = 3, KVM_EXIT_DEBUG = 4, KVM_EXIT_HLT = 5, KVM_EXIT_MMIO = 6, KVM_EXIT_IRQ_WINDOW_OPEN = 7, KVM_EXIT_SHUTDOWN = 8, + KVM_EXIT_FAIL_ENTRY = 9, + KVM_EXIT_INTR = 10, }; -/* for KVM_RUN */ +/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { /* in */ - __u32 emulated; /* skip current instruction */ - __u32 mmio_completed; /* mmio request completed */ + __u32 io_completed; /* mmio/pio request completed */ __u8 request_interrupt_window; - __u8 padding1[7]; + __u8 padding1[3]; /* out */ - __u32 exit_type; __u32 exit_reason; __u32 instruction_length; __u8 ready_for_interrupt_injection; __u8 if_flag; - __u16 padding2; + __u8 padding2[6]; /* in (pre_kvm_run), out (post_kvm_run) */ __u64 cr8; @@ -72,29 +69,26 @@ union { /* KVM_EXIT_UNKNOWN */ struct { - __u32 hardware_exit_reason; + __u64 hardware_exit_reason; } hw; + /* KVM_EXIT_FAIL_ENTRY */ + struct { + __u64 hardware_entry_failure_reason; + } fail_entry; /* KVM_EXIT_EXCEPTION */ struct { __u32 exception; __u32 error_code; } ex; /* KVM_EXIT_IO */ - struct { + struct kvm_io { #define KVM_EXIT_IO_IN 0 #define KVM_EXIT_IO_OUT 1 __u8 direction; __u8 size; /* bytes */ - __u8 string; - __u8 string_down; - __u8 rep; - __u8 pad; __u16 port; - __u64 count; - union { - __u64 address; - __u32 value; - }; + __u32 count; + __u64 data_offset; /* relative to kvm_run start */ } io; struct { } debug; @@ -105,6 +99,13 @@ __u32 len; __u8 is_write; } mmio; + /* KVM_EXIT_HYPERCALL */ + struct { + __u64 args[6]; + __u64 ret; + __u32 longmode; + __u32 pad; + } hypercall; }; }; @@ -210,39 +211,72 @@ }; }; +struct kvm_cpuid_entry { + __u32 function; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding; +}; + +/* for KVM_SET_CPUID */ +struct kvm_cpuid { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry entries[0]; +}; + +/* for KVM_SET_SIGNAL_MASK */ +struct kvm_signal_mask { + __u32 len; + __u8 sigset[0]; +}; + #define KVMIO 0xAE /* * ioctls for /dev/kvm fds: */ -#define KVM_GET_API_VERSION _IO(KVMIO, 1) -#define KVM_CREATE_VM _IO(KVMIO, 2) /* returns a VM fd */ -#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 15, struct kvm_msr_list) +#define KVM_GET_API_VERSION _IO(KVMIO, 0x00) +#define KVM_CREATE_VM _IO(KVMIO, 0x01) /* returns a VM fd */ +#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list) +/* + * Check if a kvm extension is available. Argument is extension number, + * return is 1 (yes) or 0 (no, sorry). + */ +#define KVM_CHECK_EXTENSION _IO(KVMIO, 0x03) +/* + * Get size for mmap(vcpu_fd) + */ +#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ /* * ioctls for VM fds */ -#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 10, struct kvm_memory_region) +#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) /* * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns * a vcpu fd. */ -#define KVM_CREATE_VCPU _IOW(KVMIO, 11, int) -#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 12, struct kvm_dirty_log) -#define KVM_GET_MEM_MAP _IOW(KVMIO, 16, struct kvm_dirty_log) +#define KVM_CREATE_VCPU _IO(KVMIO, 0x41) +#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) +#define KVM_GET_MEM_MAP _IOW(KVMIO, 0x43, struct kvm_dirty_log) /* * ioctls for vcpu fds */ -#define KVM_RUN _IOWR(KVMIO, 2, struct kvm_run) -#define KVM_GET_REGS _IOR(KVMIO, 3, struct kvm_regs) -#define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs) -#define KVM_GET_SREGS _IOR(KVMIO, 5, struct kvm_sregs) -#define KVM_SET_SREGS _IOW(KVMIO, 6, struct kvm_sregs) -#define KVM_TRANSLATE _IOWR(KVMIO, 7, struct kvm_translation) -#define KVM_INTERRUPT _IOW(KVMIO, 8, struct kvm_interrupt) -#define KVM_DEBUG_GUEST _IOW(KVMIO, 9, struct kvm_debug_guest) -#define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs) -#define KVM_SET_MSRS _IOW(KVMIO, 14, struct kvm_msrs) +#define KVM_RUN _IO(KVMIO, 0x80) +#define KVM_GET_REGS _IOR(KVMIO, 0x81, struct kvm_regs) +#define KVM_SET_REGS _IOW(KVMIO, 0x82, struct kvm_regs) +#define KVM_GET_SREGS _IOR(KVMIO, 0x83, struct kvm_sregs) +#define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs) +#define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation) +#define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt) +#define KVM_DEBUG_GUEST _IOW(KVMIO, 0x87, struct kvm_debug_guest) +#define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs) +#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs) +#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid) +#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask) #endif diff -ur kvm-17/kernel/kvm.h kvm/kernel/kvm.h --- kvm-17/kernel/kvm.h 2007-03-20 15:12:42.000000000 +0200 +++ kvm/kernel/kvm.h 2007-04-04 19:19:44.000000000 +0300 @@ -55,6 +55,7 @@ #define KVM_NUM_MMU_PAGES 256 #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 +#define KVM_MAX_CPUID_ENTRIES 40 #define FX_IMAGE_SIZE 512 #define FX_IMAGE_ALIGN 16 @@ -73,6 +74,8 @@ #define IOPL_SHIFT 12 +#define KVM_PIO_PAGE_OFFSET 1 + /* * Address types: * @@ -219,6 +222,18 @@ VCPU_SREG_LDTR, }; +struct kvm_pio_request { + unsigned long count; + int cur_count; + struct page *guest_pages[2]; + unsigned guest_page_offset; + int in; + int size; + int string; + int down; + int rep; +}; + struct kvm_vcpu { struct kvm *kvm; union { @@ -228,6 +243,7 @@ struct mutex mutex; int cpu; int launched; + struct kvm_run *run; int interrupt_window_open; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) @@ -274,6 +290,11 @@ unsigned char mmio_data[8]; gpa_t mmio_phys_addr; gva_t mmio_fault_cr2; + struct kvm_pio_request pio; + void *pio_data; + + int sigset_active; + sigset_t sigset; struct { int active; @@ -285,6 +306,9 @@ u32 ar; } tr, es, ds, fs, gs; } rmode; + + int cpuid_nent; + struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; }; struct kvm_memory_slot { @@ -413,6 +437,7 @@ #define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva); +struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); void kvm_emulator_want_group7_invlpg(void); @@ -445,6 +470,10 @@ struct x86_emulate_ctxt; +int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int string, int down, + gva_t address, int rep, unsigned port); +void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); int emulate_clts(struct kvm_vcpu *vcpu); int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, diff -ur kvm-17/kernel/kvm_main.c kvm/kernel/kvm_main.c --- kvm-17/kernel/kvm_main.c 2007-03-20 15:12:42.000000000 +0200 +++ kvm/kernel/kvm_main.c 2007-04-04 19:19:44.000000000 +0300 @@ -346,6 +346,17 @@ kvm_free_physmem_slot(&kvm->memslots[i], NULL); } +static void free_pio_guest_pages(struct kvm_vcpu *vcpu) +{ + int i; + + for (i = 0; i < 2; ++i) + if (vcpu->pio.guest_pages[i]) { + __free_page(vcpu->pio.guest_pages[i]); + vcpu->pio.guest_pages[i] = NULL; + } +} + static void kvm_free_vcpu(struct kvm_vcpu *vcpu) { if (!vcpu->vmcs) @@ -355,6 +366,11 @@ kvm_mmu_destroy(vcpu); vcpu_put(vcpu); kvm_arch_ops->vcpu_free(vcpu); + free_page((unsigned long)vcpu->run); + vcpu->run = NULL; + free_page((unsigned long)vcpu->pio_data); + vcpu->pio_data = NULL; + free_pio_guest_pages(vcpu); } static void kvm_free_vcpus(struct kvm *kvm) @@ -1257,7 +1273,16 @@ } switch (nr) { default: - ; + run->hypercall.args[0] = a0; + run->hypercall.args[1] = a1; + run->hypercall.args[2] = a2; + run->hypercall.args[3] = a3; + run->hypercall.args[4] = a4; + run->hypercall.args[5] = a5; + run->hypercall.ret = ret; + run->hypercall.longmode = is_long_mode(vcpu); + kvm_arch_ops->decache_regs(vcpu); + return 0; } vcpu->regs[VCPU_REGS_RAX] = ret; kvm_arch_ops->decache_regs(vcpu); @@ -1558,30 +1583,236 @@ } EXPORT_SYMBOL_GPL(save_msrs); +void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) +{ + int i; + u32 function; + struct kvm_cpuid_entry *e, *best; + + kvm_arch_ops->cache_regs(vcpu); + function = vcpu->regs[VCPU_REGS_RAX]; + vcpu->regs[VCPU_REGS_RAX] = 0; + vcpu->regs[VCPU_REGS_RBX] = 0; + vcpu->regs[VCPU_REGS_RCX] = 0; + vcpu->regs[VCPU_REGS_RDX] = 0; + best = NULL; + for (i = 0; i < vcpu->cpuid_nent; ++i) { + e = &vcpu->cpuid_entries[i]; + if (e->function == function) { + best = e; + break; + } + /* + * Both basic or both extended? + */ + if (((e->function ^ function) & 0x80000000) == 0) + if (!best || e->function > best->function) + best = e; + } + if (best) { + vcpu->regs[VCPU_REGS_RAX] = best->eax; + vcpu->regs[VCPU_REGS_RBX] = best->ebx; + vcpu->regs[VCPU_REGS_RCX] = best->ecx; + vcpu->regs[VCPU_REGS_RDX] = best->edx; + } + kvm_arch_ops->decache_regs(vcpu); + kvm_arch_ops->skip_emulated_instruction(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); + +static int pio_copy_data(struct kvm_vcpu *vcpu) +{ + void *p = vcpu->pio_data; + void *q; + unsigned bytes; + int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; + + kvm_arch_ops->vcpu_put(vcpu); + q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, + PAGE_KERNEL); + if (!q) { + kvm_arch_ops->vcpu_load(vcpu); + return -ENOMEM; + } + q += vcpu->pio.guest_page_offset; + bytes = vcpu->pio.size * vcpu->pio.cur_count; + if (vcpu->pio.in) + memcpy(q, p, bytes); + else + memcpy(p, q, bytes); + q -= vcpu->pio.guest_page_offset; + vunmap(q); + kvm_arch_ops->vcpu_load(vcpu); + return 0; +} + +static int complete_pio(struct kvm_vcpu *vcpu) +{ + struct kvm_pio_request *io = &vcpu->pio; + long delta; + int r; + + kvm_arch_ops->cache_regs(vcpu); + + io->count -= io->cur_count; + if (!io->string) { + if (io->in) + memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data, + io->size); + } else { + if (io->in) { + r = pio_copy_data(vcpu); + if (r) { + kvm_arch_ops->cache_regs(vcpu); + return r; + } + } + + delta = 1; + if (io->rep) { + delta *= io->cur_count; + /* + * The size of the register should really depend on + * current address size. + */ + vcpu->regs[VCPU_REGS_RCX] -= delta; + } + if (io->down) + delta = -delta; + delta *= io->size; + if (io->in) + vcpu->regs[VCPU_REGS_RDI] += delta; + else + vcpu->regs[VCPU_REGS_RSI] += delta; + } + + vcpu->run->io_completed = 0; + + kvm_arch_ops->decache_regs(vcpu); + + if (!io->count) + kvm_arch_ops->skip_emulated_instruction(vcpu); + return 0; +} + +int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int string, int down, + gva_t address, int rep, unsigned port) +{ + unsigned now, in_page; + int i; + int nr_pages = 1; + struct page *page; + + vcpu->run->exit_reason = KVM_EXIT_IO; + vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + vcpu->run->io.size = size; + vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; + vcpu->run->io.count = count; + vcpu->run->io.port = port; + vcpu->pio.count = count; + vcpu->pio.cur_count = count; + vcpu->pio.size = size; + vcpu->pio.in = in; + vcpu->pio.string = string; + vcpu->pio.down = down; + vcpu->pio.guest_page_offset = offset_in_page(address); + vcpu->pio.rep = rep; + + if (!string) { + kvm_arch_ops->cache_regs(vcpu); + memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); + kvm_arch_ops->decache_regs(vcpu); + return 0; + } + + now = min(count, PAGE_SIZE / size); + + if (!down) + in_page = PAGE_SIZE - offset_in_page(address); + else + in_page = offset_in_page(address) + size; + now = min(count, (unsigned long)in_page / size); + if (!now) { + /* + * String I/O straddles page boundary. Pin two guest pages + * so that we satisfy atomicity constraints. Do just one + * transaction to avoid complexity. + */ + nr_pages = 2; + now = 1; + } + if (down) { + /* + * String I/O in reverse. Yuck. Kill the guest, fix later. + */ + printk(KERN_ERR "kvm: guest string pio down\n"); + inject_gp(vcpu); + return 1; + } + vcpu->run->io.count = now; + vcpu->pio.cur_count = now; + + for (i = 0; i < nr_pages; ++i) { + spin_lock(&vcpu->kvm->lock); + page = gva_to_page(vcpu, address + i * PAGE_SIZE); + if (page) + get_page(page); + vcpu->pio.guest_pages[i] = page; + spin_unlock(&vcpu->kvm->lock); + if (!page) { + inject_gp(vcpu); + free_pio_guest_pages(vcpu); + return 1; + } + } + + if (!vcpu->pio.in) + return pio_copy_data(vcpu); + return 0; +} +EXPORT_SYMBOL_GPL(kvm_setup_pio); + static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { int r; + sigset_t sigsaved; vcpu_load(vcpu); + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); + /* re-sync apic's tpr */ vcpu->cr8 = kvm_run->cr8; - if (kvm_run->emulated) { - kvm_arch_ops->skip_emulated_instruction(vcpu); - kvm_run->emulated = 0; - } - - if (kvm_run->mmio_completed) { - memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); - vcpu->mmio_read_completed = 1; - emulate_instruction(vcpu, kvm_run, vcpu->mmio_fault_cr2, 0); + if (kvm_run->io_completed) { + if (vcpu->pio.count) { + r = complete_pio(vcpu); + if (r) + goto out; + } else { + memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); + vcpu->mmio_read_completed = 1; + emulate_instruction(vcpu, kvm_run, + vcpu->mmio_fault_cr2, 0); + } } vcpu->mmio_needed = 0; + if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) { + kvm_arch_ops->cache_regs(vcpu); + vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret; + kvm_arch_ops->decache_regs(vcpu); + } + r = kvm_arch_ops->run(vcpu, kvm_run); +out: + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + vcpu_put(vcpu); return r; } @@ -1944,6 +2175,36 @@ return r; } +static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct kvm_vcpu *vcpu = vma->vm_file->private_data; + unsigned long pgoff; + struct page *page; + + *type = VM_FAULT_MINOR; + pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + if (pgoff == 0) + page = virt_to_page(vcpu->run); + else if (pgoff == KVM_PIO_PAGE_OFFSET) + page = virt_to_page(vcpu->pio_data); + else + return NOPAGE_SIGBUS; + get_page(page); + return page; +} + +static struct vm_operations_struct kvm_vcpu_vm_ops = { + .nopage = kvm_vcpu_nopage, +}; + +static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &kvm_vcpu_vm_ops; + return 0; +} + static int kvm_vcpu_release(struct inode *inode, struct file *filp) { struct kvm_vcpu *vcpu = filp->private_data; @@ -1956,6 +2217,7 @@ .release = kvm_vcpu_release, .unlocked_ioctl = kvm_vcpu_ioctl, .compat_ioctl = kvm_vcpu_ioctl, + .mmap = kvm_vcpu_mmap, }; /* @@ -2004,6 +2266,7 @@ { int r; struct kvm_vcpu *vcpu; + struct page *page; r = -EINVAL; if (!valid_vcpu(n)) @@ -2018,6 +2281,18 @@ return -EEXIST; } + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + r = -ENOMEM; + if (!page) + goto out_unlock; + vcpu->run = page_address(page); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + r = -ENOMEM; + if (!page) + goto out_free_run; + vcpu->pio_data = page_address(page); + vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, FX_IMAGE_ALIGN); vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; @@ -2047,11 +2322,46 @@ out_free_vcpus: kvm_free_vcpu(vcpu); +out_free_run: + free_page((unsigned long)vcpu->run); + vcpu->run = NULL; +out_unlock: mutex_unlock(&vcpu->mutex); out: return r; } +static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, + struct kvm_cpuid *cpuid, + struct kvm_cpuid_entry __user *entries) +{ + int r; + + r = -E2BIG; + if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) + goto out; + r = -EFAULT; + if (copy_from_user(&vcpu->cpuid_entries, entries, + cpuid->nent * sizeof(struct kvm_cpuid_entry))) + goto out; + vcpu->cpuid_nent = cpuid->nent; + return 0; + +out: + return r; +} + +static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) +{ + if (sigset) { + sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + vcpu->sigset_active = 1; + vcpu->sigset = *sigset; + } else + vcpu->sigset_active = 0; + return 0; +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2060,21 +2370,12 @@ int r = -EINVAL; switch (ioctl) { - case KVM_RUN: { - struct kvm_run kvm_run; - - r = -EFAULT; - if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) - goto out; - r = kvm_vcpu_ioctl_run(vcpu, &kvm_run); - if (r < 0 && r != -EINTR) + case KVM_RUN: + r = -EINVAL; + if (arg) goto out; - if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { - r = -EFAULT; - goto out; - } + r = kvm_vcpu_ioctl_run(vcpu, vcpu->run); break; - } case KVM_GET_REGS: { struct kvm_regs kvm_regs; @@ -2170,6 +2471,41 @@ case KVM_SET_MSRS: r = msr_io(vcpu, argp, do_set_msr, 0); break; + case KVM_SET_CPUID: { + struct kvm_cpuid __user *cpuid_arg = argp; + struct kvm_cpuid cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) + goto out; + r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries); + if (r) + goto out; + break; + } + case KVM_SET_SIGNAL_MASK: { + struct kvm_signal_mask __user *sigmask_arg = argp; + struct kvm_signal_mask kvm_sigmask; + sigset_t sigset, *p; + + p = NULL; + if (argp) { + r = -EFAULT; + if (copy_from_user(&kvm_sigmask, argp, + sizeof kvm_sigmask)) + goto out; + r = -EINVAL; + if (kvm_sigmask.len != sizeof sigset) + goto out; + r = -EFAULT; + if (copy_from_user(&sigset, sigmask_arg->sigset, + sizeof sigset)) + goto out; + p = &sigset; + } + r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); + break; + } default: ; } @@ -2316,13 +2652,19 @@ unsigned int ioctl, unsigned long arg) { void __user *argp = (void __user *)arg; - int r = -EINVAL; + long r = -EINVAL; switch (ioctl) { case KVM_GET_API_VERSION: + r = -EINVAL; + if (arg) + goto out; r = KVM_API_VERSION; break; case KVM_CREATE_VM: + r = -EINVAL; + if (arg) + goto out; r = kvm_dev_ioctl_create_vm(); break; case KVM_GET_MSR_INDEX_LIST: { @@ -2352,6 +2694,18 @@ r = 0; break; } + case KVM_CHECK_EXTENSION: + /* + * No extensions defined at present. + */ + r = 0; + break; + case KVM_GET_VCPU_MMAP_SIZE: + r = -EINVAL; + if (arg) + goto out; + r = 2 * PAGE_SIZE; + break; default: ; } diff -ur kvm-17/kernel/mmu.c kvm/kernel/mmu.c --- kvm-17/kernel/mmu.c 2007-03-20 15:12:42.000000000 +0200 +++ kvm/kernel/mmu.c 2007-04-04 19:19:44.000000000 +0300 @@ -735,6 +735,15 @@ return gpa_to_hpa(vcpu, gpa); } +struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) +{ + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); + + if (gpa == UNMAPPED_GVA) + return NULL; + return pfn_to_page(gpa_to_hpa(vcpu, gpa) >> PAGE_SHIFT); +} + static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) { } diff -ur kvm-17/kernel/svm.c kvm/kernel/svm.c --- kvm-17/kernel/svm.c 2007-03-20 15:12:42.000000000 +0200 +++ kvm/kernel/svm.c 2007-04-04 19:19:44.000000000 +0300 @@ -582,6 +582,9 @@ init_vmcb(vcpu->svm->vmcb); fx_init(vcpu); + vcpu->apic_base = 0xfee00000 | + /*for vcpu 0*/ MSR_IA32_APICBASE_BSP | + MSR_IA32_APICBASE_ENABLE; return 0; @@ -981,7 +984,7 @@ return 0; } -static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address) +static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address) { unsigned long addr_mask; unsigned long *reg; @@ -1025,38 +1028,38 @@ static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug? - int _in = io_info & SVM_IOIO_TYPE_MASK; + int size, down, in, string, rep; + unsigned port; + unsigned long count; + gva_t address = 0; ++kvm_stat.io_exits; vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2; - kvm_run->exit_reason = KVM_EXIT_IO; - kvm_run->io.port = io_info >> 16; - kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT); - kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0; - kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0; + in = (io_info & SVM_IOIO_TYPE_MASK) != 0; + port = io_info >> 16; + size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; + string = (io_info & SVM_IOIO_STR_MASK) != 0; + rep = (io_info & SVM_IOIO_REP_MASK) != 0; + count = 1; + down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; - if (kvm_run->io.string) { + if (string) { unsigned addr_mask; - addr_mask = io_adress(vcpu, _in, &kvm_run->io.address); + addr_mask = io_adress(vcpu, in, &address); if (!addr_mask) { printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__); return 1; } - if (kvm_run->io.rep) { - kvm_run->io.count - = vcpu->regs[VCPU_REGS_RCX] & addr_mask; - kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags - & X86_EFLAGS_DF) != 0; - } - } else - kvm_run->io.value = vcpu->svm->vmcb->save.rax; - return 0; + if (rep) + count = vcpu->regs[VCPU_REGS_RCX] & addr_mask; + } + return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, + address, rep, port); } static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -1099,8 +1102,8 @@ static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - kvm_run->exit_reason = KVM_EXIT_CPUID; - return 0; + kvm_emulate_cpuid(vcpu); + return 1; } static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -1296,8 +1299,6 @@ { u32 exit_code = vcpu->svm->vmcb->control.exit_code; - kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; - if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " @@ -1607,8 +1608,9 @@ vcpu->svm->next_rip = 0; if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { - kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; - kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code; + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vcpu->svm->vmcb->control.exit_code; post_kvm_run_save(vcpu, kvm_run); return 0; } @@ -1618,12 +1620,14 @@ if (signal_pending(current)) { ++kvm_stat.signal_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } if (dm_request_for_irq_injection(vcpu, kvm_run)) { ++kvm_stat.request_irq_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } kvm_resched(vcpu); diff -ur kvm-17/kernel/vmx.c kvm/kernel/vmx.c --- kvm-17/kernel/vmx.c 2007-03-20 15:12:42.000000000 +0200 +++ kvm/kernel/vmx.c 2007-04-04 19:19:44.000000000 +0300 @@ -1394,7 +1394,7 @@ return 0; } -static int get_io_count(struct kvm_vcpu *vcpu, u64 *count) +static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count) { u64 inst; gva_t rip; @@ -1439,33 +1439,35 @@ done: countr_size *= 8; *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size)); + //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]); return 1; } static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u64 exit_qualification; + int size, down, in, string, rep; + unsigned port; + unsigned long count; + gva_t address; ++kvm_stat.io_exits; exit_qualification = vmcs_read64(EXIT_QUALIFICATION); - kvm_run->exit_reason = KVM_EXIT_IO; - if (exit_qualification & 8) - kvm_run->io.direction = KVM_EXIT_IO_IN; - else - kvm_run->io.direction = KVM_EXIT_IO_OUT; - kvm_run->io.size = (exit_qualification & 7) + 1; - kvm_run->io.string = (exit_qualification & 16) != 0; - kvm_run->io.string_down - = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; - kvm_run->io.rep = (exit_qualification & 32) != 0; - kvm_run->io.port = exit_qualification >> 16; - if (kvm_run->io.string) { - if (!get_io_count(vcpu, &kvm_run->io.count)) + in = (exit_qualification & 8) != 0; + size = (exit_qualification & 7) + 1; + string = (exit_qualification & 16) != 0; + down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; + count = 1; + rep = (exit_qualification & 32) != 0; + port = exit_qualification >> 16; + address = 0; + if (string) { + if (rep && !get_io_count(vcpu, &count)) return 1; - kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS); - } else - kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */ - return 0; + address = vmcs_readl(GUEST_LINEAR_ADDRESS); + } + return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, + address, rep, port); } static void @@ -1583,8 +1585,8 @@ static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - kvm_run->exit_reason = KVM_EXIT_CPUID; - return 0; + kvm_emulate_cpuid(vcpu); + return 1; } static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -1920,10 +1922,10 @@ asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - kvm_run->exit_type = 0; if (fail) { - kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; - kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR); + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vmcs_read32(VM_INSTRUCTION_ERROR); r = 0; } else { /* @@ -1933,19 +1935,20 @@ profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); vcpu->launched = 1; - kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; r = kvm_handle_exit(kvm_run, vcpu); if (r > 0) { /* Give scheduler a change to reschedule. */ if (signal_pending(current)) { ++kvm_stat.signal_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } if (dm_request_for_irq_injection(vcpu, kvm_run)) { ++kvm_stat.request_irq_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } diff -ur kvm-17/qemu/qemu-kvm.c kvm/qemu/qemu-kvm.c --- kvm-17/qemu/qemu-kvm.c 2007-03-14 19:40:36.000000000 +0200 +++ kvm/qemu/qemu-kvm.c 2007-04-04 19:12:01.000000000 +0300 @@ -449,85 +449,6 @@ return 0; } - -static int kvm_cpuid(void *opaque, uint64_t *rax, uint64_t *rbx, - uint64_t *rcx, uint64_t *rdx) -{ - CPUState **envs = opaque; - CPUState *saved_env; - uint32_t eax = *rax; - - saved_env = env; - env = envs[0]; - - env->regs[R_EAX] = *rax; - env->regs[R_EBX] = *rbx; - env->regs[R_ECX] = *rcx; - env->regs[R_EDX] = *rdx; - helper_cpuid(); - *rdx = env->regs[R_EDX]; - *rcx = env->regs[R_ECX]; - *rbx = env->regs[R_EBX]; - *rax = env->regs[R_EAX]; - // don't report long mode/syscall/nx if no native support - if (eax == 0x80000001) { - unsigned long h_eax = eax, h_edx; - - - // push/pop hack to workaround gcc 3 register pressure trouble - asm ( -#ifdef __x86_64__ - "push %%rbx; push %%rcx; cpuid; pop %%rcx; pop %%rbx" -#else - "push %%ebx; push %%ecx; cpuid; pop %%ecx; pop %%ebx" -#endif - : "+a"(h_eax), "=d"(h_edx)); - - // long mode - if ((h_edx & 0x20000000) == 0) - *rdx &= ~0x20000000ull; - // syscall - if ((h_edx & 0x00000800) == 0) - *rdx &= ~0x00000800ull; - // nx - if ((h_edx & 0x00100000) == 0) - *rdx &= ~0x00100000ull; - } - // sysenter isn't supported on compatibility mode on AMD. and syscall - // isn't supported in compatibility mode on Intel. so advertise the - // actuall cpu, and say goodbye to migration between different vendors - // is you use compatibility mode. - if (eax == 0) { - uint32_t bcd[3]; - asm ( -#ifdef __x86_64__ - "push %%rax; push %%rbx; push %%rcx; push %%rdx \n\t" - "mov $0, %%eax \n\t" - "cpuid \n\t" - "mov (%%rsp), %%rax \n\t" - "mov %%ebx, (%%rax) \n\t" - "mov %%ecx, 4(%%rax) \n\t" - "mov %%edx, 8(%%rax) \n\t" - "pop %%rdx; pop %%rcx; pop %%rbx; pop %%rax" -#else - "push %%eax; push %%ebx; push %%ecx; push %%edx \n\t" - "mov $0, %%eax \n\t" - "cpuid \n\t" - "mov (%%esp), %%eax \n\t" - "mov %%ebx, (%%eax) \n\t" - "mov %%ecx, 4(%%eax) \n\t" - "mov %%edx, 8(%%eax) \n\t" - "pop %%edx; pop %%ecx; pop %%ebx; pop %%eax" -#endif - : : "d"(bcd) : "memory"); - *rbx = bcd[0]; - *rcx = bcd[1]; - *rdx = bcd[2]; - } - env = saved_env; - return 0; -} - static int kvm_debug(void *opaque, int vcpu) { CPUState **envs = opaque; @@ -679,7 +600,6 @@ } static struct kvm_callbacks qemu_kvm_ops = { - .cpuid = kvm_cpuid, .debug = kvm_debug, .inb = kvm_inb, .inw = kvm_inw, @@ -738,6 +658,78 @@ kvm_finalize(kvm_context); } +static void do_cpuid_ent(struct kvm_cpuid_entry *e, uint32_t function) +{ + EAX = function; + helper_cpuid(); + e->function = function; + e->eax = EAX; + e->ebx = EBX; + e->ecx = ECX; + e->edx = EDX; + if (function == 1) + e->edx &= ~(1 << 12); /* disable mtrr support */ + if (function == 0x80000001) { + unsigned long h_eax = function, h_edx; + + + // push/pop hack to workaround gcc 3 register pressure trouble + asm ( +#ifdef __x86_64__ + "push %%rbx; push %%rcx; cpuid; pop %%rcx; pop %%rbx" +#else + "push %%ebx; push %%ecx; cpuid; pop %%ecx; pop %%ebx" +#endif + : "+a"(h_eax), "=d"(h_edx)); + + // long mode + if ((h_edx & 0x20000000) == 0) + e->edx &= ~0x20000000u; + // syscall + if ((h_edx & 0x00000800) == 0) + e->edx &= ~0x00000800u; + // nx + if ((h_edx & 0x00100000) == 0) + e->edx &= ~0x00100000u; + } +} + +int kvm_qemu_init_env(CPUState *cenv) +{ + struct kvm_cpuid_entry cpuid_ent[100]; + int cpuid_nent = 0; + CPUState *oldenv = env; + CPUState copy; + uint32_t i, limit; +#define DECLARE_HOST_REGS +#include "hostregs_helper.h" + +#define SAVE_HOST_REGS +#include "hostregs_helper.h" + + copy = *cenv; + env = cenv; + + EAX = 0; + helper_cpuid(); + limit = EAX; + for (i = 0; i <= limit; ++i) + do_cpuid_ent(&cpuid_ent[cpuid_nent++], i); + EAX = 0x80000000; + helper_cpuid(); + limit = EAX; + for (i = 0x80000000; i <= limit; ++i) + do_cpuid_ent(&cpuid_ent[cpuid_nent++], i); + + kvm_setup_cpuid(kvm_context, 0, cpuid_nent, cpuid_ent); + +#include "hostregs_helper.h" + + env = oldenv; + + return 0; +} + int kvm_update_debugger(CPUState *env) { struct kvm_debug_guest dbg; diff -ur kvm-17/qemu/qemu-kvm.h kvm/qemu/qemu-kvm.h --- kvm-17/qemu/qemu-kvm.h 2007-03-14 16:50:32.000000000 +0200 +++ kvm/qemu/qemu-kvm.h 2007-03-28 11:58:27.000000000 +0200 @@ -10,6 +10,7 @@ void kvm_save_registers(CPUState *env); int kvm_cpu_exec(CPUState *env); int kvm_update_debugger(CPUState *env); +int kvm_qemu_init_env(CPUState *env); int kvm_physical_memory_set_dirty_tracking(int enable); int kvm_update_dirty_pages_log(void); diff -ur kvm-17/qemu/target-i386/helper2.c kvm/qemu/target-i386/helper2.c --- kvm-17/qemu/target-i386/helper2.c 2007-02-11 16:23:08.000000000 +0200 +++ kvm/qemu/target-i386/helper2.c 2007-04-04 19:12:01.000000000 +0300 @@ -144,6 +144,7 @@ kqemu_init(env); #endif #ifdef USE_KVM + kvm_qemu_init_env(env); env->ready_for_interrupt_injection = 1; #endif return env; diff -ur kvm-17/user/kvmctl.c kvm/user/kvmctl.c --- kvm-17/user/kvmctl.c 2007-03-15 16:57:16.000000000 +0200 +++ kvm/user/kvmctl.c 2007-04-04 19:19:41.000000000 +0300 @@ -24,7 +24,7 @@ #include <sys/ioctl.h> #include "kvmctl.h" -#define EXPECTED_KVM_API_VERSION 4 +#define EXPECTED_KVM_API_VERSION 9 #if EXPECTED_KVM_API_VERSION != KVM_API_VERSION #error libkvm: userspace and kernel version mismatch @@ -46,6 +46,7 @@ int fd; int vm_fd; int vcpu_fd[1]; + struct kvm_run *run[1]; /// Callbacks that KVM uses to emulate various unvirtualizable functionality struct kvm_callbacks *callbacks; void *opaque; @@ -228,6 +229,7 @@ { unsigned long dosmem = 0xa0000; unsigned long exmem = 0xc0000; + long mmap_size; int fd = kvm->fd; int zfd; int r; @@ -286,6 +288,17 @@ return -1; } kvm->vcpu_fd[0] = r; + mmap_size = ioctl(kvm->fd, KVM_GET_VCPU_MMAP_SIZE, 0); + if (mmap_size == -1) { + fprintf(stderr, "get vcpu mmap size: %m\n"); + return -1; + } + kvm->run[0] = mmap(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, + kvm->vcpu_fd[0], 0); + if (kvm->run[0] == MAP_FAILED) { + fprintf(stderr, "mmap vcpu area: %m\n"); + return -1; + } return 0; } @@ -374,92 +387,44 @@ #endif /* KVM_GET_MEM_MAP */ } -static int more_io(struct kvm_run *run, int first_time) -{ - if (!run->io.rep) - return first_time; - else - return run->io.count != 0; -} - static int handle_io(kvm_context_t kvm, struct kvm_run *run, int vcpu) { uint16_t addr = run->io.port; - struct kvm_regs regs; - int first_time = 1; - int delta; - struct translation_cache tr; - int _in = (run->io.direction == KVM_EXIT_IO_IN); int r; + int i; + void *p = (void *)run + run->io.data_offset; - translation_cache_init(&tr); - - if (run->io.string || _in) { - r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_REGS, ®s); - if (r == -1) - return -errno; - } - - delta = run->io.string_down ? -run->io.size : run->io.size; - - while (more_io(run, first_time)) { - void *value_addr; - - if (!run->io.string) { - if (_in) - value_addr = ®s.rax; - else - value_addr = &run->io.value; - } else { - r = translate(kvm, vcpu, &tr, run->io.address, - &value_addr); - if (r) { - fprintf(stderr, "failed translating I/O address %llx\n", - run->io.address); - return r; - } - } - + for (i = 0; i < run->io.count; ++i) { switch (run->io.direction) { - case KVM_EXIT_IO_IN: { + case KVM_EXIT_IO_IN: switch (run->io.size) { - case 1: { - uint8_t value; - r = kvm->callbacks->inb(kvm->opaque, addr, &value); - *(uint8_t *)value_addr = value; + case 1: + r = kvm->callbacks->inb(kvm->opaque, addr, p); break; - } - case 2: { - uint16_t value; - r = kvm->callbacks->inw(kvm->opaque, addr, &value); - *(uint16_t *)value_addr = value; + case 2: + r = kvm->callbacks->inw(kvm->opaque, addr, p); break; - } - case 4: { - uint32_t value; - r = kvm->callbacks->inl(kvm->opaque, addr, &value); - *(uint32_t *)value_addr = value; + case 4: + r = kvm->callbacks->inl(kvm->opaque, addr, p); break; - } default: fprintf(stderr, "bad I/O size %d\n", run->io.size); return -EMSGSIZE; } break; - } case KVM_EXIT_IO_OUT: - switch (run->io.size) { + switch (run->io.size) { case 1: r = kvm->callbacks->outb(kvm->opaque, addr, - *(uint8_t *)value_addr); + *(uint8_t *)p); break; case 2: r = kvm->callbacks->outw(kvm->opaque, addr, - *(uint16_t *)value_addr); + *(uint16_t *)p); break; case 4: r = kvm->callbacks->outl(kvm->opaque, addr, - *(uint32_t *)value_addr); + *(uint32_t *)p); break; default: fprintf(stderr, "bad I/O size %d\n", run->io.size); @@ -470,36 +435,11 @@ fprintf(stderr, "bad I/O direction %d\n", run->io.direction); return -EPROTO; } - if (run->io.string) { - run->io.address += delta; - switch (run->io.direction) { - case KVM_EXIT_IO_IN: regs.rdi += delta; break; - case KVM_EXIT_IO_OUT: regs.rsi += delta; break; - } - if (run->io.rep) { - --regs.rcx; - --run->io.count; - } - } - first_time = 0; - if (r) { - int savedret = r; - r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_REGS, ®s); - if (r == -1) - return -errno; - return savedret; - } + p += run->io.size; } - if (run->io.string || _in) { - r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_REGS, ®s); - if (r == -1) - return -errno; - - } - - run->emulated = 1; + run->io_completed = 1; return 0; } @@ -654,31 +594,6 @@ sregs.efer); } -static int handle_cpuid(kvm_context_t kvm, struct kvm_run *run, int vcpu) -{ - struct kvm_regs regs; - uint32_t orig_eax; - uint64_t rax, rbx, rcx, rdx; - int r; - - kvm_get_regs(kvm, vcpu, ®s); - orig_eax = regs.rax; - rax = regs.rax; - rbx = regs.rbx; - rcx = regs.rcx; - rdx = regs.rdx; - r = kvm->callbacks->cpuid(kvm->opaque, &rax, &rbx, &rcx, &rdx); - regs.rax = rax; - regs.rbx = rbx; - regs.rcx = rcx; - regs.rdx = rdx; - if (orig_eax == 1) - regs.rdx &= ~(1ull << 12); /* disable mtrr support */ - kvm_set_regs(kvm, vcpu, ®s); - run->emulated = 1; - return r; -} - static int handle_mmio(kvm_context_t kvm, struct kvm_run *kvm_run) { unsigned long addr = kvm_run->mmio.phys_addr; @@ -715,7 +630,7 @@ r = kvm->callbacks->readq(kvm->opaque, addr, (uint64_t *)data); break; } - kvm_run->mmio_completed = 1; + kvm_run->io_completed = 1; } return r; } @@ -755,71 +670,63 @@ { int r; int fd = kvm->vcpu_fd[vcpu]; - struct kvm_run kvm_run = { - .emulated = 0, - .mmio_completed = 0, - }; + struct kvm_run *run = kvm->run[vcpu]; again: - kvm_run.request_interrupt_window = try_push_interrupts(kvm); - pre_kvm_run(kvm, &kvm_run); - r = ioctl(fd, KVM_RUN, &kvm_run); - post_kvm_run(kvm, &kvm_run); + run->request_interrupt_window = try_push_interrupts(kvm); + pre_kvm_run(kvm, run); + r = ioctl(fd, KVM_RUN, 0); + post_kvm_run(kvm, run); - kvm_run.emulated = 0; - kvm_run.mmio_completed = 0; + run->io_completed = 0; if (r == -1 && errno != EINTR) { r = -errno; printf("kvm_run: %m\n"); return r; } if (r == -1) { - r = handle_io_window(kvm, &kvm_run); + r = handle_io_window(kvm, run); goto more; } - switch (kvm_run.exit_type) { - case KVM_EXIT_TYPE_FAIL_ENTRY: - fprintf(stderr, "kvm_run: failed entry, reason %u\n", - kvm_run.exit_reason & 0xffff); - return -ENOEXEC; - break; - case KVM_EXIT_TYPE_VM_EXIT: - switch (kvm_run.exit_reason) { + if (1) { + switch (run->exit_reason) { case KVM_EXIT_UNKNOWN: fprintf(stderr, "unhandled vm exit: 0x%x\n", - kvm_run.hw.hardware_exit_reason); + (unsigned)run->hw.hardware_exit_reason); kvm_show_regs(kvm, vcpu); abort(); break; + case KVM_EXIT_FAIL_ENTRY: + fprintf(stderr, "kvm_run: failed entry, reason %u\n", + (unsigned)run->fail_entry.hardware_entry_failure_reason & 0xffff); + return -ENOEXEC; + break; case KVM_EXIT_EXCEPTION: fprintf(stderr, "exception %d (%x)\n", - kvm_run.ex.exception, - kvm_run.ex.error_code); + run->ex.exception, + run->ex.error_code); kvm_show_regs(kvm, vcpu); abort(); break; case KVM_EXIT_IO: - r = handle_io(kvm, &kvm_run, vcpu); - break; - case KVM_EXIT_CPUID: - r = handle_cpuid(kvm, &kvm_run, vcpu); + r = handle_io(kvm, run, vcpu); break; case KVM_EXIT_DEBUG: - r = handle_debug(kvm, &kvm_run, vcpu); + r = handle_debug(kvm, run, vcpu); break; case KVM_EXIT_MMIO: - r = handle_mmio(kvm, &kvm_run); + r = handle_mmio(kvm, run); break; case KVM_EXIT_HLT: - r = handle_halt(kvm, &kvm_run, vcpu); + r = handle_halt(kvm, run, vcpu); break; case KVM_EXIT_IRQ_WINDOW_OPEN: break; case KVM_EXIT_SHUTDOWN: - r = handle_shutdown(kvm, &kvm_run, vcpu); + r = handle_shutdown(kvm, run, vcpu); break; default: - fprintf(stderr, "unhandled vm exit: 0x%x\n", kvm_run.exit_reason); + fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason); kvm_show_regs(kvm, vcpu); abort(); break; @@ -843,3 +750,45 @@ { return ioctl(kvm->vcpu_fd[vcpu], KVM_DEBUG_GUEST, dbg); } + +int kvm_setup_cpuid(kvm_context_t kvm, int vcpu, int nent, + struct kvm_cpuid_entry *entries) +{ + struct kvm_cpuid *cpuid; + int r; + + cpuid = malloc(sizeof(*cpuid) + nent * sizeof(*entries)); + if (!cpuid) + return -ENOMEM; + + cpuid->nent = nent; + memcpy(cpuid->entries, entries, nent * sizeof(*entries)); + r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_CPUID, cpuid); + + free(cpuid); + return r; +} + +int kvm_set_signal_mask(kvm_context_t kvm, int vcpu, const sigset_t *sigset) +{ + struct kvm_signal_mask *sigmask; + int r; + + if (!sigset) { + r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_SIGNAL_MASK, NULL); + if (r == -1) + r = -errno; + return r; + } + sigmask = malloc(sizeof(*sigmask) + sizeof(*sigset)); + if (!sigmask) + return -ENOMEM; + + sigmask->len = 8; + memcpy(sigmask->sigset, sigset, sizeof(*sigset)); + r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_SIGNAL_MASK, sigmask); + if (r == -1) + r = -errno; + free(sigmask); + return r; +} diff -ur kvm-17/user/kvmctl.h kvm/user/kvmctl.h --- kvm-17/user/kvmctl.h 2007-03-14 16:45:30.000000000 +0200 +++ kvm/user/kvmctl.h 2007-04-04 19:19:41.000000000 +0300 @@ -8,6 +8,7 @@ #define __user /* temporary, until installed via make headers_install */ #include <linux/kvm.h> #include <stdint.h> +#include <signal.h> struct kvm_context; @@ -21,8 +22,6 @@ * accessing hardware devices via MMIO or regular IO. */ struct kvm_callbacks { - int (*cpuid)(void *opaque, - uint64_t *rax, uint64_t *rbx, uint64_t *rcx, uint64_t *rdx); /// For 8bit IO reads from the guest (Usually when executing 'inb') int (*inb)(void *opaque, uint16_t addr, uint8_t *data); /// For 16bit IO reads from the guest (Usually when executing 'inw') @@ -215,6 +214,35 @@ int kvm_guest_debug(kvm_context_t, int vcpu, struct kvm_debug_guest *dbg); /*! + * \brief Setup a vcpu's cpuid instruction emulation + * + * Set up a table of cpuid function to cpuid outputs.\n + * + * \param kvm Pointer to the current kvm_context + * \param vcpu Which virtual CPU should be initialized + * \param nent number of entries to be installed + * \param entries cpuid function entries table + * \return 0 on success, or -errno on error + */ +int kvm_setup_cpuid(kvm_context_t kvm, int vcpu, int nent, + struct kvm_cpuid_entry *entries); + +/*! + * \brief Set a vcpu's signal mask for guest mode + * + * A vcpu can have different signals blocked in guest mode and user mode. + * This allows guest execution to be interrupted on a signal, without requiring + * that the signal be delivered to a signal handler (the signal can be + * dequeued using sigwait(2). + * + * \param kvm Pointer to the current kvm_context + * \param vcpu Which virtual CPU should be initialized + * \param sigset signal mask for guest mode + * \return 0 on success, or -errno on error + */ +int kvm_set_signal_mask(kvm_context_t kvm, int vcpu, const sigset_t *sigset); + +/*! * \brief Dump all VCPU information * * This dumps \b all the information that KVM has about a virtual CPU, namely: diff -ur kvm-17/user/main.c kvm/user/main.c --- kvm-17/user/main.c 2007-01-29 14:43:53.000000000 +0200 +++ kvm/user/main.c 2007-04-04 19:19:41.000000000 +0300 @@ -23,13 +23,6 @@ kvm_context_t kvm; -static int test_cpuid(void *opaque, uint64_t *rax, uint64_t *rbx, - uint64_t *rcx, uint64_t *rdx) -{ - printf("cpuid 0x%lx\n", (uint32_t)*rax); - return 0; -} - static int test_inb(void *opaque, uint16_t addr, uint8_t *value) { printf("inb 0x%x\n", addr); @@ -112,7 +105,6 @@ } static struct kvm_callbacks test_callbacks = { - .cpuid = test_cpuid, .inb = test_inb, .inw = test_inw, .inl = test_inl,
------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel