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, &regs);
-		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 = &regs.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, &regs);
-			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, &regs);
-		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, &regs);
-	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, &regs);
-	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

Reply via email to