From: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
To: Leslie Mann <lmann-7al4MSP+J8o@public.gmane.org>
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: Re: kvm-18 breaks Cisco VPN on WinXP SP1
Date: Wed, 04 Apr 2007 19:28:48 +0300 [thread overview]
Message-ID: <4613D240.2000003@qumranet.com> (raw)
In-Reply-To: <loom.20070402T151656-719-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 411 bytes --]
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
[-- Attachment #2: kvm-17-4546-c01571ed56754dfea458cc37d553c360082411a1.patch --]
[-- Type: text/x-patch, Size: 44930 bytes --]
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,
[-- Attachment #3: Type: text/plain, Size: 345 bytes --]
-------------------------------------------------------------------------
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
[-- Attachment #4: Type: text/plain, Size: 186 bytes --]
_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel
next prev parent reply other threads:[~2007-04-04 16:28 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-27 2:47 kvm-18 breaks Cisco VPN on WinXP SP1 Leslie Mann
[not found] ` <460885B2.7080907-7al4MSP+J8o@public.gmane.org>
2007-03-27 7:11 ` Avi Kivity
2007-03-28 0:55 ` Leslie Mann
[not found] ` <loom.20070328T025020-733-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-03-28 7:12 ` Avi Kivity
2007-03-29 3:02 ` Leslie Mann
[not found] ` <loom.20070329T043939-431-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-03-29 6:59 ` Avi Kivity
2007-03-30 1:12 ` Leslie Mann
[not found] ` <loom.20070330T030834-700-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-03-30 6:48 ` Avi Kivity
2007-03-30 9:16 ` Uri Lublin
2007-04-01 18:43 ` Leslie Mann
[not found] ` <loom.20070401T202531-319-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-04-02 8:51 ` Avi Kivity
2007-04-02 13:44 ` Leslie Mann
[not found] ` <loom.20070402T151656-719-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-04-04 16:28 ` Avi Kivity [this message]
2007-04-05 8:57 ` Leslie Mann
2007-04-09 23:04 ` Leslie Mann
[not found] ` <loom.20070410T003525-72-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-04-10 6:37 ` Avi Kivity
2007-04-11 3:48 ` Leslie Mann
2007-04-15 12:42 ` Avi Kivity
2007-04-16 4:28 ` Leslie Mann
[not found] ` <loom.20070405T104629-941-eS7Uydv5nfjZ+VzJOa5vwg@public.gmane.org>
2007-04-12 8:37 ` Avi Kivity
[not found] ` <461DEFBA.8080907-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-04-13 6:55 ` Carsten Emde
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4613D240.2000003@qumranet.com \
--to=avi-atkuwr5tajbwk0htik3j/w@public.gmane.org \
--cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
--cc=lmann-7al4MSP+J8o@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.