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
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel