public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/3] Split kvmctl for architectures
@ 2007-10-18 20:10 Jerone Young
  2007-10-18 20:28 ` Anthony Liguori
  2007-10-18 20:47 ` Izik Eidus
  0 siblings, 2 replies; 7+ messages in thread
From: Jerone Young @ 2007-10-18 20:10 UTC (permalink / raw)
  To: kvm-devel; +Cc: kvm-ppc-devel

This patch splits kvmctl architecture specific declarations &
implementations into their own files & headers. Common interfaces are
kept in kvmctl.h, as well as the arch specific headers are included from
within kvmctl.h. This may or may not want to be changed.

 Also includes the having different main.c files for different
architectures (otherwise it's a lot of ifdefs). 

Signed-off-by: Christian Ehrhardt <ehrhardt-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>


diff --git a/user/kvmctl-powerpc.c b/user/kvmctl-powerpc.c
new file mode 100644
--- /dev/null
+++ b/user/kvmctl-powerpc.c
@@ -0,0 +1,351 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Christian Ehrhardt <ehrhardt-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
+*/
+
+#ifndef __user
+#define __user /* temporary, until installed via make headers_install */
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "kvmctl.h"
+
+/*!
+ * \brief The KVM context
+ *
+ * The verbose KVM context to pass our states 
+ * between different calls if needed
+ */
+struct kvm_context {
+	// Filedescriptor to /dev/kvm
+	int fd;
+	/* 
+	 * this represents our kvm_run for ppc e.g. 
+	 * in drivers/kvm/powerpc/kvm.h while the 
+	 *
+	 * original represents what comes from <linux/kvm.h>
+	 */
+	struct kvm_run run; /* we are not multi cpu so one 
+                               struct in userspace should be enough */
+	/// Callbacks that KVM uses to emulate various unvirtualizable functionality
+	struct kvm_callbacks *callbacks;
+	void *opaque;	
+};
+
+kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
+		       void *opaque){
+	kvm_context_t kvm;
+	int fd;
+	int r;
+
+	fd = open("/dev/kvm", O_RDWR);
+	if (fd == -1) {
+		char *errstr;
+		r = errno;
+		errstr = strerror(errno);
+                printf("open /dev/kvm: %s\n", errstr);
+		return NULL;
+	}
+
+	kvm = malloc(sizeof(*kvm));
+	kvm->fd = fd;
+	kvm->callbacks = callbacks;
+	kvm->opaque = opaque;
+	return kvm;
+}
+
+void kvm_finalize(kvm_context_t kvm)
+{
+	close(kvm->fd);
+	free(kvm);
+}
+
+int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, void **vm_mem)
+{
+	struct create {
+		uint32_t guest_ram;
+		uint32_t guest_size;
+	} create;
+	int r;
+
+        *vm_mem = mmap(NULL, phys_mem_bytes, PROT_EXEC|PROT_READ|PROT_WRITE,
+                         MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, -1, 0);
+        if (*vm_mem == (void *)-1) {
+                perror("mmap");
+                return 2;
+        }
+	create.guest_ram = (uint32_t)(*vm_mem);
+	create.guest_size = phys_mem_bytes;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_CREATE, &create);
+	printf("create ioctl returned %d (errno %d)\n", r, errno);
+	return 0;
+}
+
+int kvm_create_vcpu(kvm_context_t kvm, int slot)
+{
+	/* atm we do all (1vcpu) in create and have no smp, ... */
+	return 0;
+}
+
+int kvm_set_pc(kvm_context_t kvm, uint32_t pc)
+{
+	struct kvm_regs regs;
+	int r;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_GETREGS, &regs);
+	if (r)
+		return r;
+
+	regs.pc = pc;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_SETREGS, &regs);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+int emulate_dcr(kvm_context_t kvm, struct kvm_run *run)
+{
+	int r;
+ 
+	if (run->dcr.is_write)
+		r = kvm->callbacks->ppc_dcr_write(kvm,
+			run->dcr.dcrn,run->dcr.data);
+	else
+		r = kvm->callbacks->ppc_dcr_read(kvm,
+			run->dcr.dcrn,&(run->dcr.data));
+
+#ifdef DEBUG_KVMPPC
+	if (r)
+		fprintf(stderr,"%s:%d - failed write '%d' dcrn '0x%08X' "
+			"data '%d' retval '%d'\n",
+			__FILE__,__LINE__,
+			run->dcr.is_write,run->dcr.dcrn,run->dcr.data,r);
+	else
+		fprintf(stderr,"%s:%d - wrote '%d' dcrn '0x%08X' "
+			"data '%d' retval '%d'\n",
+			__FILE__,__LINE__,
+			run->dcr.is_write,run->dcr.dcrn,run->dcr.data,r);
+#endif
+
+	/* currently we live with nop for unimplemented dcr registers */
+	return 0;
+}
+
+int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
+{
+	int r = 0;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_GETREGS, regs);
+	if (r) {
+		fprintf(stderr,"%s - KVM_PPC_IOCTL_GETREGS failed (r='%d')\n",
+								__func__,r);
+	}
+
+	return r;
+}
+
+int kvm_set_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
+{
+	int r = 0;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_SETREGS, regs);
+	if (r) {
+		fprintf(stderr,"%s - KVM_PPC_IOCTL_SETREGS failed (r='%d')\n",
+								__func__,r);
+	}
+
+	return r;
+}
+
+int kvm_get_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *sregs)
+{
+	fprintf(stderr,"%s - not implemented \n",__func__);
+	return -ENOTSUP;
+}
+
+int kvm_set_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *sregs)
+{
+	fprintf(stderr,"%s - not implemented \n",__func__);
+	return -ENOTSUP;
+}
+
+int kvm_get_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu)
+{
+	fprintf(stderr,"%s - not implemented \n",__func__);
+	return -ENOTSUP;
+}
+
+int kvm_set_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu)
+{
+	fprintf(stderr,"%s - not implemented \n",__func__);
+	return -ENOTSUP;
+}
+
+int kvm_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_debug_guest *dbg)
+{
+	fprintf(stderr,"%s - not implemented \n",__func__);
+	return -ENOTSUP;
+}
+
+int kvm_get_tlb(kvm_context_t kvm, struct kvm_tlb *tlb)
+{
+	int r = 0;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_GETTLB, tlb);
+	if (r) {
+		fprintf(stderr,"%s - KVM_PPC_IOCTL_GETTLB failed (r='%d')\n",
+								__func__,r);
+	}
+
+	return r;
+}
+
+int kvm_set_tlb(kvm_context_t kvm, struct kvm_tlb *tlb)
+{
+	int r = 0;
+
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_SETTLB, tlb);
+	if (r) {
+		fprintf(stderr,"%s - KVM_PPC_IOCTL_SETTLB failed (r='%d')\n",
+								__func__,r);
+	}
+
+	return r;
+}
+
+int kvm_dump_vcpu(kvm_context_t kvm, int vcpu)
+{
+	int i;
+	struct kvm_regs regs;
+
+	kvm_get_regs(kvm,-1,&regs);
+
+	fprintf(stderr,"Guest vcpu\n");
+	fprintf(stderr,"pc:   %08x msr:  %08x\n", regs.pc, regs.msr);
+	fprintf(stderr,"lr:   %08x ctr:  %08x\n", regs.lr, regs.ctr);
+	fprintf(stderr,"srr0: %08x srr1: %08x\n", regs.srr0, regs.srr1);
+	for (i = 0; i < 32; i += 4) {
+		fprintf(stderr,"gpr%02d: %08x %08x %08x %08x\n", i,
+			regs.gpr[i],
+			regs.gpr[i+1],
+			regs.gpr[i+2],
+			regs.gpr[i+3]);
+	}
+	fflush(stdout);
+	return 0;
+}
+
+void kvm_show_regs(kvm_context_t kvm, int vcpu) {
+	struct kvm_regs regs;
+	int i;
+
+	kvm_get_regs(kvm,-1,&regs);
+
+	for (i = 0; i < 32; i += 4) {
+		fprintf(stderr,"gpr%02d: %08x %08x %08x %08x\n", i,
+			regs.gpr[i],
+			regs.gpr[i+1],
+			regs.gpr[i+2],
+			regs.gpr[i+3]);
+	}
+	fflush(stdout);
+
+}
+
+static void print_tlb(struct tlbe tlb[PPC44x_TLB_SIZE], char* name, char* flag)
+{
+	int i;
+
+	fprintf(stderr,"%s:\n",name);
+	fprintf(stderr,"| %2s | %8s | %8s | %8s | %8s |\n","nr","mmucr",
+						"word0","word1","word2");
+	for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+		if (tlb[i].word0 & PPC44x_TLB_VALID)
+			fprintf(stderr,"%s%2d | %08X | %08X | %08X | %08X |\n",
+				flag,i,
+				tlb[i].mmucr,
+				tlb[i].word0,
+				tlb[i].word1,
+				tlb[i].word2);
+	}
+	fflush(stdout);
+}
+
+static void kvm_dump_tlb(kvm_context_t kvm)
+{
+	struct kvm_tlb tlb;
+
+	kvm_get_tlb(kvm,&tlb);
+
+	print_tlb(tlb.guest_tlb,"Guest TLB","G");
+	print_tlb(tlb.shadow_tlb,"Shadow TLB","S");
+}
+
+int kvm_run(kvm_context_t kvm, int vcpu)
+{
+	int r=0;
+	struct kvm_run *run = &(kvm->run);
+again:
+	r = ioctl(kvm->fd, KVM_PPC_IOCTL_RUN, run);
+
+	if (r == -1 && errno != EINTR) {
+		r = -errno;
+		printf("kvm_run: %m\n");
+		return r;
+	}
+	if (1) {
+		switch (kvm->run.exit_reason) {
+		case KVM_EXIT_MMIO:
+			kvm->callbacks->cpu_physical_memory_rw(run->mmio.phys_addr, 
+					run->mmio.data,
+					run->mmio.len,
+					run->mmio.is_write);
+			break;
+		case KVM_EXIT_DCR:
+			r = emulate_dcr(kvm,run);
+			break;
+
+		case KVM_EXIT_SHUTDOWN:
+			printf("guest exited\n");
+			r = 1;
+			break;
+		default:
+			fprintf(stderr, "unhandled vm exit_reason: 0x%x\n", 
+							  run->exit_reason);
+			kvm_dump_vcpu(kvm,-1);
+			kvm_dump_tlb(kvm);
+			r=-EINVAL;
+			break;
+		}
+	}
+
+	if (!r)
+		goto again;
+	return r;
+
+}
diff --git a/user/kvmctl-powerpc.h b/user/kvmctl-powerpc.h
new file mode 100644
--- /dev/null
+++ b/user/kvmctl-powerpc.h
@@ -0,0 +1,152 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Christian Ehrhardt <ehrhardt-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
+*/
+
+#ifndef KVMCTL_PPC_H
+#define KVMCTL_PPC_H
+
+/* 
+ * TODO discuss
+ * we have create the linux header representation of Hollis kvm.h 
+ * in include/linux/ to make it available for userspace inclusion.
+ * atm I just added kvm_run there
+*/
+#include <inttypes.h>
+#include <asm/types.h>
+#include <stdint.h>
+#include <signal.h>
+
+/* duplicate structs and defines from kernel as needed */ 			
+#define KVM_PPC_IOCTL_CREATE 1
+#define KVM_PPC_IOCTL_RUN 2
+#define KVM_PPC_IOCTL_GETREGS 3
+#define KVM_PPC_IOCTL_SETREGS 4
+#define KVM_PPC_IOCTL_GETTLB 5
+#define KVM_PPC_IOCTL_SETTLB 6
+
+#define PPC44x_TLB_SIZE		64
+#define PPC44x_TLB_VALID	0x00000200
+
+enum kvm_exit_reason {
+	KVM_EXIT_UNKNOWN          = 0,
+	KVM_EXIT_EXCEPTION        = 1,
+	KVM_EXIT_IO               = 2,
+	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,
+	KVM_EXIT_DCR              = 11,
+};
+
+/*!
+ * \brief KVM callbacks structure
+ *
+ * This structure holds pointers to various functions that KVM will call
+ * when it encounters something that cannot be virtualized, such as
+ * accessing hardware devices via MMIO or regular IO.
+ */
+struct kvm_callbacks {
+    /* callbacks needed for powerpc support */
+    void (*cpu_physical_memory_rw)(uint64_t addr, uint8_t *data,
+					int len, int is_write);
+    int (*ppc_dcr_read)(kvm_context_t kvm, int dcrn, uint32_t *valp);
+    int (*ppc_dcr_write)(kvm_context_t kvm, int dcrn, uint32_t val);
+    void *CPUState_env;
+};
+
+
+/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
+struct kvm_run {
+        __u32 exit_reason;
+
+        union {
+                /* KVM_EXIT_MMIO */
+                struct {
+                        __u64 phys_addr;
+                        __u8  data[8];
+                        __u32 len;
+                        __u8  is_write;
+                } mmio;
+		/* KVM_EXIT_DCR */
+		struct {
+			__u32 dcrn;
+			__u32 data;
+			__u8  is_write;
+		} dcr;
+                /* Fix the size of the union. */
+                __u32 padding[256];
+        };
+};
+
+struct tlbe {
+	__u32 mmucr;
+	__u32 word0;
+	__u32 word1;
+	__u32 word2;
+};
+
+struct kvm_regs {
+	__u32 pc;
+	__u32 cr;
+	__u32 ctr;
+	__u32 lr;
+	__u32 xer;
+
+	__u32 msr;
+
+	__u32 srr0;
+	__u32 srr1;
+
+	__u32 sprg0;
+	__u32 sprg1;
+	__u32 sprg2;
+	__u32 sprg3;
+	__u32 sprg4;
+	__u32 sprg5;
+	__u32 sprg6;
+	__u32 sprg7;
+
+	__u64 fpr[32];
+	__u32 gpr[32];
+};
+
+/* atm we don't support regs/sregs differentiation -> empty struct*/
+struct kvm_sregs {
+};
+
+/* atm we don't support fpu -> empty struct */
+struct kvm_fpu {
+};
+
+/* atm we don't support debug -> empty struct */
+struct kvm_debug_guest {
+};
+
+struct kvm_tlb {
+	struct tlbe guest_tlb[PPC44x_TLB_SIZE];
+	struct tlbe shadow_tlb[PPC44x_TLB_SIZE];
+};
+
+int kvm_set_pc(kvm_context_t kvm, uint32_t pc);
+
+#endif
diff --git a/user/kvmctl-x86.c b/user/kvmctl-x86.c
new file mode 100644
--- /dev/null
+++ b/user/kvmctl-x86.c
@@ -0,0 +1,1437 @@
+/*
+ * Kernel-based Virtual Machine control library
+ *
+ * This library provides an API to control the kvm hardware virtualization
+ * module.
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ * Authors:
+ *
+ *  Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
+ *  Yaniv Kamay <yaniv-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef __user
+#define __user /* temporary, until installed via make headers_install */
+#endif
+
+#include <linux/kvm.h>
+
+#define EXPECTED_KVM_API_VERSION 12
+
+#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
+#error libkvm: userspace and kernel version mismatch
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include "kvmctl.h"
+#include "kvm-abi-10.h"
+
+static int kvm_abi = EXPECTED_KVM_API_VERSION;
+
+#define PAGE_SIZE 4096ul
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+/* FIXME: share this number with kvm */
+/* FIXME: or dynamically alloc/realloc regions */
+#define KVM_MAX_NUM_MEM_REGIONS 8u
+#define MAX_VCPUS 4
+
+/**
+ * \brief The KVM context
+ *
+ * The verbose KVM context
+ */
+struct kvm_context {
+	/// Filedescriptor to /dev/kvm
+	int fd;
+	int vm_fd;
+	int vcpu_fd[MAX_VCPUS];
+	struct kvm_run *run[MAX_VCPUS];
+	/// Callbacks that KVM uses to emulate various unvirtualizable functionality
+	struct kvm_callbacks *callbacks;
+	void *opaque;
+	/// A pointer to the memory used as the physical memory for the guest
+	void *physical_memory;
+	/// is dirty pages logging enabled for all regions or not
+	int dirty_pages_log_all;
+	/// memory regions parameters
+	struct kvm_memory_region mem_regions[KVM_MAX_NUM_MEM_REGIONS];
+	/// do not create in-kernel irqchip if set
+	int no_irqchip_creation;
+	/// in-kernel irqchip status
+	int irqchip_in_kernel;
+};
+
+/*
+ * memory regions parameters
+ */
+static void kvm_memory_region_save_params(kvm_context_t kvm, 
+					 struct kvm_memory_region *mem)
+{
+	if (!mem || (mem->slot >= KVM_MAX_NUM_MEM_REGIONS)) {
+		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
+		return;
+	}
+	kvm->mem_regions[mem->slot] = *mem;
+}
+
+#ifdef KVM_CAP_USER_MEMORY
+
+static void kvm_userspace_memory_region_save_params(kvm_context_t kvm,
+					struct kvm_userspace_memory_region *mem)
+{
+	struct kvm_memory_region kvm_mem;
+
+	kvm_mem.slot = mem->slot;
+	kvm_mem.memory_size = mem->memory_size;
+	kvm_mem.guest_phys_addr = mem->guest_phys_addr;
+
+	kvm_memory_region_save_params(kvm, &kvm_mem);
+}
+
+#endif
+
+static void kvm_memory_region_clear_params(kvm_context_t kvm, int regnum)
+{
+	if (regnum >= KVM_MAX_NUM_MEM_REGIONS) {
+		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
+		return;
+	}
+	kvm->mem_regions[regnum].memory_size = 0;
+}
+
+/* 
+ * dirty pages logging control 
+ */
+static int kvm_dirty_pages_log_change(kvm_context_t kvm, int regnum, __u32 flag)
+{
+	int r;
+	struct kvm_memory_region *mem;
+
+	if (regnum >= KVM_MAX_NUM_MEM_REGIONS) {
+		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
+		return 1;
+	}
+	mem = &kvm->mem_regions[regnum];
+	if (mem->memory_size == 0) /* not used */
+		return 0;
+	if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) /* log already enabled */
+		return 0;
+	mem->flags |= flag;  /* temporary turn on flag */
+	r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, mem);
+	mem->flags &= ~flag; /* back to previous value */
+	if (r == -1) {
+		fprintf(stderr, "%s: %m\n", __FUNCTION__);
+	}
+	return r;
+}
+
+static int kvm_dirty_pages_log_change_all(kvm_context_t kvm, __u32 flag)
+{
+	int i, r;
+
+	for (i=r=0; i<KVM_MAX_NUM_MEM_REGIONS && r==0; i++) {
+		r = kvm_dirty_pages_log_change(kvm, i, flag);
+	}
+	return r;
+}
+
+/**
+ * Enable dirty page logging for all memory regions
+ */
+int kvm_dirty_pages_log_enable_all(kvm_context_t kvm)
+{
+	if (kvm->dirty_pages_log_all)
+		return 0;
+	kvm->dirty_pages_log_all = 1;
+	return kvm_dirty_pages_log_change_all(kvm, KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+/**
+ * Enable dirty page logging only for memory regions that were created with
+ *     dirty logging enabled (disable for all other memory regions).
+ */
+int kvm_dirty_pages_log_reset(kvm_context_t kvm)
+{
+	if (!kvm->dirty_pages_log_all)
+		return 0;
+	kvm->dirty_pages_log_all = 0;
+	return kvm_dirty_pages_log_change_all(kvm, 0);
+}
+
+
+kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
+		       void *opaque)
+{
+	int fd;
+	kvm_context_t kvm;
+	int r;
+
+	fd = open("/dev/kvm", O_RDWR);
+	if (fd == -1) {
+		perror("open /dev/kvm");
+		return NULL;
+	}
+	r = ioctl(fd, KVM_GET_API_VERSION, 0);
+	if (r == -1) {
+	    fprintf(stderr, "kvm kernel version too old: "
+		    "KVM_GET_API_VERSION ioctl not supported\n");
+	    goto out_close;
+	}
+	if (r < EXPECTED_KVM_API_VERSION && r != 10) {
+		fprintf(stderr, "kvm kernel version too old: "
+			"We expect API version %d or newer, but got "
+			"version %d\n",
+			EXPECTED_KVM_API_VERSION, r);
+	    goto out_close;
+	}
+	if (r > EXPECTED_KVM_API_VERSION) {
+	    fprintf(stderr, "kvm userspace version too old\n");
+	    goto out_close;
+	}
+	kvm_abi = r;
+	kvm = malloc(sizeof(*kvm));
+	kvm->fd = fd;
+	kvm->vm_fd = -1;
+	kvm->callbacks = callbacks;
+	kvm->opaque = opaque;
+	kvm->dirty_pages_log_all = 0;
+	kvm->no_irqchip_creation = 0;
+	memset(&kvm->mem_regions, 0, sizeof(kvm->mem_regions));
+
+	return kvm;
+ out_close:
+	close(fd);
+	return NULL;
+}
+
+void kvm_finalize(kvm_context_t kvm)
+{
+    	if (kvm->vcpu_fd[0] != -1)
+		close(kvm->vcpu_fd[0]);
+    	if (kvm->vm_fd != -1)
+		close(kvm->vm_fd);
+	close(kvm->fd);
+	free(kvm);
+}
+
+void kvm_disable_irqchip_creation(kvm_context_t kvm)
+{
+	kvm->no_irqchip_creation = 1;
+}
+
+int kvm_create_vcpu(kvm_context_t kvm, int slot)
+{
+	long mmap_size;
+	int r;
+
+	r = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, slot);
+	if (r == -1) {
+		r = -errno;
+		fprintf(stderr, "kvm_create_vcpu: %m\n");
+		return r;
+	}
+	kvm->vcpu_fd[slot] = r;
+	mmap_size = ioctl(kvm->fd, KVM_GET_VCPU_MMAP_SIZE, 0);
+	if (mmap_size == -1) {
+		r = -errno;
+		fprintf(stderr, "get vcpu mmap size: %m\n");
+		return r;
+	}
+	kvm->run[slot] = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+			      kvm->vcpu_fd[slot], 0);
+	if (kvm->run[slot] == MAP_FAILED) {
+		r = -errno;
+		fprintf(stderr, "mmap vcpu area: %m\n");
+		return r;
+	}
+	return 0;
+}
+
+int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages)
+{
+#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
+	int r;
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
+		  KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
+	if (r > 0) {
+		r = ioctl(kvm->vm_fd, KVM_SET_NR_MMU_PAGES, nrshadow_pages);
+		if (r == -1) {
+			fprintf(stderr, "kvm_set_shadow_pages: %m\n");
+			return -errno;
+		}
+		return 0;
+	}
+#endif
+	return -1;
+}
+
+int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages)
+{
+#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
+	int r;
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
+		  KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
+	if (r > 0) {
+		*nrshadow_pages = ioctl(kvm->vm_fd, KVM_GET_NR_MMU_PAGES);
+		return 0;
+	}
+#endif
+	return -1;
+}
+
+int kvm_alloc_kernel_memory(kvm_context_t kvm, unsigned long memory,
+								void **vm_mem)
+{
+	unsigned long dosmem = 0xa0000;
+	unsigned long exmem = 0xc0000;
+	unsigned long pcimem = 0xf0000000;
+	int r;
+	struct kvm_memory_region low_memory = {
+		.slot = 3,
+		.memory_size = memory  < dosmem ? memory : dosmem,
+		.guest_phys_addr = 0,
+	};
+	struct kvm_memory_region extended_memory = {
+		.slot = 0,
+		.memory_size = memory < exmem ? 0 : memory - exmem,
+		.guest_phys_addr = exmem,
+	};
+	struct kvm_memory_region above_4g_memory = {
+		.slot = 4,
+		.memory_size = memory < pcimem ? 0 : memory - pcimem,
+		.guest_phys_addr = 0x100000000,
+	};
+
+	if (memory >= pcimem)
+		extended_memory.memory_size = pcimem - exmem;
+
+	/* 640K should be enough. */
+	r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &low_memory);
+	if (r == -1) {
+		fprintf(stderr, "kvm_create_memory_region: %m\n");
+		return -1;
+	}
+	if (extended_memory.memory_size) {
+		r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &extended_memory);
+		if (r == -1) {
+			fprintf(stderr, "kvm_create_memory_region: %m\n");
+			return -1;
+		}
+	}
+
+	if (above_4g_memory.memory_size) {
+		r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &above_4g_memory);
+		if (r == -1) {
+			fprintf(stderr, "kvm_create_memory_region: %m\n");
+			return -1;
+		}
+	}
+
+	kvm_memory_region_save_params(kvm, &low_memory);
+	kvm_memory_region_save_params(kvm, &extended_memory);
+	kvm_memory_region_save_params(kvm, &above_4g_memory);
+
+	*vm_mem = mmap(NULL, memory, PROT_READ|PROT_WRITE, MAP_SHARED, kvm->vm_fd, 0);
+
+	return 0;
+}
+
+#ifdef KVM_CAP_USER_MEMORY
+
+int kvm_alloc_userspace_memory(kvm_context_t kvm, unsigned long memory,
+								void **vm_mem)
+{
+	unsigned long dosmem = 0xa0000;
+	unsigned long exmem = 0xc0000;
+	unsigned long pcimem = 0xf0000000;
+	int r;
+	struct kvm_userspace_memory_region low_memory = {
+		.slot = 3,
+		.memory_size = memory  < dosmem ? memory : dosmem,
+		.guest_phys_addr = 0,
+	};
+	struct kvm_userspace_memory_region extended_memory = {
+		.slot = 0,
+		.memory_size = memory < exmem ? 0 : memory - exmem,
+		.guest_phys_addr = exmem,
+	};
+	struct kvm_userspace_memory_region above_4g_memory = {
+		.slot = 4,
+		.memory_size = memory < pcimem ? 0 : memory - pcimem,
+		.guest_phys_addr = 0x100000000,
+	};
+
+	if (memory >= pcimem) {
+		extended_memory.memory_size = pcimem - exmem;
+		*vm_mem = mmap(NULL, memory + 0x100000000 - pcimem,
+				PROT_READ|PROT_WRITE, MAP_ANONYMOUS |
+							MAP_SHARED, -1, 0);
+	}
+	else
+		*vm_mem = mmap(NULL, memory, PROT_READ|PROT_WRITE, MAP_ANONYMOUS
+							| MAP_SHARED, -1, 0);
+	if (*vm_mem == MAP_FAILED) {
+		fprintf(stderr, "kvm_alloc_userspace_memory: %s", strerror(errno));
+		return -1;
+	}
+
+
+	low_memory.userspace_addr = (unsigned long)*vm_mem;
+	memset((unsigned long *)low_memory.userspace_addr, 0, low_memory.memory_size);
+	/* 640K should be enough. */
+	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &low_memory);
+	if (r == -1) {
+		fprintf(stderr, "kvm_create_memory_region: %m\n");
+		return -1;
+	}
+	if (extended_memory.memory_size) {
+		r = munmap(*vm_mem + dosmem, exmem - dosmem);
+		if (r == -1) {
+			fprintf(stderr, "kvm_alloc_userspace_memory: %s",
+							strerror(errno));
+			return -1;
+		}
+		extended_memory.userspace_addr = (unsigned long)(*vm_mem + exmem);
+		memset((unsigned long *)extended_memory.userspace_addr, 0, extended_memory.memory_size);
+		r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &extended_memory);
+		if (r == -1) {
+			fprintf(stderr, "kvm_create_memory_region: %m\n");
+			return -1;
+		}
+	}
+
+	if (above_4g_memory.memory_size) {
+		r = munmap(*vm_mem + pcimem, 0x100000000 - pcimem);
+		if (r == -1) {
+			fprintf(stderr, "kvm_alloc_userspace_memory: %s",
+							strerror(errno));
+			return -1;
+		}
+		above_4g_memory.userspace_addr = (unsigned long)(*vm_mem + 0x100000000);
+		memset((unsigned long *)above_4g_memory.userspace_addr, 0, above_4g_memory.memory_size);
+		r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &above_4g_memory);
+		if (r == -1) {
+			fprintf(stderr, "kvm_create_memory_region: %m\n");
+			return -1;
+		}
+	}
+
+	kvm_userspace_memory_region_save_params(kvm, &low_memory);
+	kvm_userspace_memory_region_save_params(kvm, &extended_memory);
+	kvm_userspace_memory_region_save_params(kvm, &above_4g_memory);
+
+	return 0;
+}
+
+#endif
+
+int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, void **vm_mem)
+{
+	unsigned long memory = (phys_mem_bytes + PAGE_SIZE - 1) & PAGE_MASK;
+	int fd = kvm->fd;
+	int zfd;
+	int r;
+
+	kvm->vcpu_fd[0] = -1;
+
+	fd = ioctl(fd, KVM_CREATE_VM, 0);
+	if (fd == -1) {
+		fprintf(stderr, "kvm_create_vm: %m\n");
+		return -1;
+	}
+	kvm->vm_fd = fd;
+
+#ifdef KVM_CAP_USER_MEMORY
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
+	if (r > 0)
+		r = kvm_alloc_userspace_memory(kvm, memory, vm_mem);
+	else
+#endif
+		r = kvm_alloc_kernel_memory(kvm, memory, vm_mem);
+	if (r < 0)
+		return r;
+
+        zfd = open("/dev/zero", O_RDONLY);
+        mmap(*vm_mem + 0xa8000, 0x8000, PROT_READ|PROT_WRITE,
+             MAP_PRIVATE|MAP_FIXED, zfd, 0);
+        close(zfd);
+
+	kvm->physical_memory = *vm_mem;
+
+	kvm->irqchip_in_kernel = 0;
+#ifdef KVM_CAP_IRQCHIP
+	if (!kvm->no_irqchip_creation) {
+		r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP);
+		if (r > 0) {	/* kernel irqchip supported */
+			r = ioctl(fd, KVM_CREATE_IRQCHIP);
+			if (r >= 0)
+				kvm->irqchip_in_kernel = 1;
+			else
+				printf("Create kernel PIC irqchip failed\n");
+		}
+	}
+#endif
+	r = kvm_create_vcpu(kvm, 0);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+void *kvm_create_kernel_phys_mem(kvm_context_t kvm, unsigned long phys_start,
+			unsigned long len, int slot, int log, int writable)
+{
+	int r;
+	int prot = PROT_READ;
+	void *ptr;
+	struct kvm_memory_region memory = {
+		.slot = slot,
+		.memory_size = len,
+		.guest_phys_addr = phys_start,
+		.flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
+	};
+
+	r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &memory);
+	if (r == -1) {
+		fprintf(stderr, "create_kernel_phys_mem: %s", strerror(errno));
+		return 0;
+	}
+	kvm_memory_region_save_params(kvm, &memory);
+
+	if (writable)
+		prot |= PROT_WRITE;
+
+	ptr = mmap(NULL, len, prot, MAP_SHARED, kvm->vm_fd, phys_start);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "create_kernel_phys_mem: %s", strerror(errno));
+		return 0;
+	}
+
+	return ptr;
+}
+
+#ifdef KVM_CAP_USER_MEMORY
+
+void *kvm_create_userspace_phys_mem(kvm_context_t kvm, unsigned long phys_start,
+			unsigned long len, int slot, int log, int writable)
+{
+	int r;
+	int prot = PROT_READ;
+	void *ptr;
+	struct kvm_userspace_memory_region memory = {
+		.slot = slot,
+		.memory_size = len,
+		.guest_phys_addr = phys_start,
+		.flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
+	};
+
+	if (writable)
+		prot |= PROT_WRITE;
+
+	ptr = mmap(NULL, len, prot, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "create_userspace_phys_mem: %s", strerror(errno));
+		return 0;
+	}
+
+	memset(ptr, 0, len);
+
+	memory.userspace_addr = (unsigned long)ptr;
+	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &memory);
+	if (r == -1) {
+		fprintf(stderr, "create_userspace_phys_mem: %s", strerror(errno));
+		return 0;
+	}
+
+	kvm_userspace_memory_region_save_params(kvm, &memory);
+
+        return ptr;
+}
+
+#endif
+
+void *kvm_create_phys_mem(kvm_context_t kvm, unsigned long phys_start,
+			  unsigned long len, int slot, int log, int writable)
+{
+#ifdef KVM_CAP_USER_MEMORY
+	int r;
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
+	if (r > 0)
+		return kvm_create_userspace_phys_mem(kvm, phys_start, len, slot,
+								log, writable);
+	else
+#endif
+		return kvm_create_kernel_phys_mem(kvm, phys_start, len, slot,
+								log, writable);
+}
+
+/* destroy/free a whole slot.
+ * phys_start, len and slot are the params passed to kvm_create_phys_mem()
+ */
+void kvm_destroy_phys_mem(kvm_context_t kvm, unsigned long phys_start, 
+			  unsigned long len, int slot)
+{
+	struct kvm_memory_region *mem;
+
+	if (slot >= KVM_MAX_NUM_MEM_REGIONS) {
+		fprintf(stderr, "BUG: %s: invalid parameters (slot=%d)\n",
+			__FUNCTION__, slot);
+		return;
+	}
+	mem = &kvm->mem_regions[slot];
+	if (phys_start != mem->guest_phys_addr) {
+		fprintf(stderr,
+			"WARNING: %s: phys_start is 0x%lx expecting 0x%llx\n",
+			__FUNCTION__, phys_start, mem->guest_phys_addr);
+		phys_start = mem->guest_phys_addr;
+	}
+	kvm_create_phys_mem(kvm, phys_start, 0, slot, 0, 0);
+}
+
+int kvm_create_memory_alias(kvm_context_t kvm,
+			    int slot,
+			    uint64_t phys_start,
+			    uint64_t len,
+			    uint64_t target_phys)
+{
+	struct kvm_memory_alias alias = {
+		.slot = slot,
+		.flags = 0,
+		.guest_phys_addr = phys_start,
+		.memory_size = len,
+		.target_phys_addr = target_phys,
+	};
+	int fd = kvm->vm_fd;
+	int r;
+
+	r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias);
+	if (r == -1)
+	    return -errno;
+
+	return 0;
+}
+
+int kvm_destroy_memory_alias(kvm_context_t kvm, int slot)
+{
+	return kvm_create_memory_alias(kvm, slot, 0, 0, 0);
+}
+
+static int kvm_get_map(kvm_context_t kvm, int ioctl_num, int slot, void *buf)
+{
+	int r;
+	struct kvm_dirty_log log = {
+		.slot = slot,
+	};
+
+	log.dirty_bitmap = buf;
+
+	r = ioctl(kvm->vm_fd, ioctl_num, &log);
+	if (r == -1)
+		return -errno;
+	return 0;
+}
+
+int kvm_get_dirty_pages(kvm_context_t kvm, int slot, void *buf)
+{
+	return kvm_get_map(kvm, KVM_GET_DIRTY_LOG, slot, buf);
+}
+
+int kvm_get_mem_map(kvm_context_t kvm, int slot, void *buf)
+{
+#ifdef KVM_GET_MEM_MAP
+	return kvm_get_map(kvm, KVM_GET_MEM_MAP, slot, buf);
+#else /* not KVM_GET_MEM_MAP ==> fake it: all pages exist */
+	unsigned long i, n, m, npages;
+	unsigned char v;
+
+	if (slot >= KVM_MAX_NUM_MEM_REGIONS) {
+		errno = -EINVAL;
+		return -1;
+	}
+	npages = kvm->mem_regions[slot].memory_size / PAGE_SIZE;
+	n = npages / 8;
+	m = npages % 8;
+	memset(buf, 0xff, n); /* all pages exist */
+	v = 0;
+	for (i=0; i<=m; i++) /* last byte may not be "aligned" */
+		v |= 1<<(7-i);
+	if (v)
+		*(unsigned char*)(buf+n) = v;
+	return 0;
+#endif /* KVM_GET_MEM_MAP */
+}
+
+#ifdef KVM_CAP_IRQCHIP
+
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level)
+{
+	struct kvm_irq_level event;
+	int r;
+
+	if (!kvm->irqchip_in_kernel)
+		return 0;
+	event.level = level;
+	event.irq = irq;
+	r = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &event);
+	if (r == -1)
+		perror("kvm_set_irq_level");
+	return 1;
+}
+
+int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
+{
+	int r;
+
+	if (!kvm->irqchip_in_kernel)
+		return 0;
+	r = ioctl(kvm->vm_fd, KVM_GET_IRQCHIP, chip);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_get_irqchip\n");
+	}
+	return r;
+}
+
+int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
+{
+	int r;
+
+	if (!kvm->irqchip_in_kernel)
+		return 0;
+	r = ioctl(kvm->vm_fd, KVM_SET_IRQCHIP, chip);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_set_irqchip\n");
+	}
+	return r;
+}
+
+int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s)
+{
+	int r;
+	if (!kvm->irqchip_in_kernel)
+		return 0;
+	r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_LAPIC, s);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_get_lapic");
+	}
+	return r;
+}
+
+int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s)
+{
+	int r;
+	if (!kvm->irqchip_in_kernel)
+		return 0;
+	r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_LAPIC, s);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_set_lapic");
+	}
+	return r;
+}
+
+#endif
+
+static int handle_io_abi10(kvm_context_t kvm, struct kvm_run_abi10 *run,
+			   int vcpu)
+{
+	uint16_t addr = run->io.port;
+	int r;
+	int i;
+	void *p = (void *)run + run->io.data_offset;
+
+	for (i = 0; i < run->io.count; ++i) {
+		switch (run->io.direction) {
+		case KVM_EXIT_IO_IN:
+			switch (run->io.size) {
+			case 1:
+				r = kvm->callbacks->inb(kvm->opaque, addr, p);
+				break;
+			case 2:
+				r = kvm->callbacks->inw(kvm->opaque, addr, p);
+				break;
+			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) {
+			case 1:
+				r = kvm->callbacks->outb(kvm->opaque, addr,
+						     *(uint8_t *)p);
+				break;
+			case 2:
+				r = kvm->callbacks->outw(kvm->opaque, addr,
+						     *(uint16_t *)p);
+				break;
+			case 4:
+				r = kvm->callbacks->outl(kvm->opaque, addr,
+						     *(uint32_t *)p);
+				break;
+			default:
+				fprintf(stderr, "bad I/O size %d\n", run->io.size);
+				return -EMSGSIZE;
+			}
+			break;
+		default:
+			fprintf(stderr, "bad I/O direction %d\n", run->io.direction);
+			return -EPROTO;
+		}
+
+		p += run->io.size;
+	}
+	run->io_completed = 1;
+
+	return 0;
+}
+
+static int handle_io(kvm_context_t kvm, struct kvm_run *run, int vcpu)
+{
+	uint16_t addr = run->io.port;
+	int r;
+	int i;
+	void *p = (void *)run + run->io.data_offset;
+
+	for (i = 0; i < run->io.count; ++i) {
+		switch (run->io.direction) {
+		case KVM_EXIT_IO_IN:
+			switch (run->io.size) {
+			case 1:
+				r = kvm->callbacks->inb(kvm->opaque, addr, p);
+				break;
+			case 2:
+				r = kvm->callbacks->inw(kvm->opaque, addr, p);
+				break;
+			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) {
+			case 1:
+				r = kvm->callbacks->outb(kvm->opaque, addr,
+						     *(uint8_t *)p);
+				break;
+			case 2:
+				r = kvm->callbacks->outw(kvm->opaque, addr,
+						     *(uint16_t *)p);
+				break;
+			case 4:
+				r = kvm->callbacks->outl(kvm->opaque, addr,
+						     *(uint32_t *)p);
+				break;
+			default:
+				fprintf(stderr, "bad I/O size %d\n", run->io.size);
+				return -EMSGSIZE;
+			}
+			break;
+		default:
+			fprintf(stderr, "bad I/O direction %d\n", run->io.direction);
+			return -EPROTO;
+		}
+
+		p += run->io.size;
+	}
+
+	return 0;
+}
+
+static int handle_debug(kvm_context_t kvm, int vcpu)
+{
+	return kvm->callbacks->debug(kvm->opaque, vcpu);
+}
+
+int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
+{
+    return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_REGS, regs);
+}
+
+int kvm_set_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
+{
+    return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_REGS, regs);
+}
+
+int kvm_get_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu)
+{
+    return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_FPU, fpu);
+}
+
+int kvm_set_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu)
+{
+    return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_FPU, fpu);
+}
+
+int kvm_get_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *sregs)
+{
+    return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_SREGS, sregs);
+}
+
+int kvm_set_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *sregs)
+{
+    return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_SREGS, sregs);
+}
+
+/*
+ * Returns available msr list.  User must free.
+ */
+struct kvm_msr_list *kvm_get_msr_list(kvm_context_t kvm)
+{
+	struct kvm_msr_list sizer, *msrs;
+	int r, e;
+
+	sizer.nmsrs = 0;
+	r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, &sizer);
+	if (r == -1 && errno != E2BIG)
+		return NULL;
+	msrs = malloc(sizeof *msrs + sizer.nmsrs * sizeof *msrs->indices);
+	if (!msrs) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	msrs->nmsrs = sizer.nmsrs;
+	r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, msrs);
+	if (r == -1) {
+		e = errno;
+		free(msrs);
+		errno = e;
+		return NULL;
+	}
+	return msrs;
+}
+
+int kvm_get_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
+		 int n)
+{
+    struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r, e;
+
+    if (!kmsrs) {
+	errno = ENOMEM;
+	return -1;
+    }
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_MSRS, kmsrs);
+    e = errno;
+    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
+    free(kmsrs);
+    errno = e;
+    return r;
+}
+
+int kvm_set_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
+		 int n)
+{
+    struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r, e;
+
+    if (!kmsrs) {
+	errno = ENOMEM;
+	return -1;
+    }
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_MSRS, kmsrs);
+    e = errno;
+    free(kmsrs);
+    errno = e;
+    return r;
+}
+
+static void print_seg(FILE *file, const char *name, struct kvm_segment *seg)
+{
+    	fprintf(stderr,
+		"%s %04x (%08llx/%08x p %d dpl %d db %d s %d type %x l %d"
+		" g %d avl %d)\n",
+		name, seg->selector, seg->base, seg->limit, seg->present,
+		seg->dpl, seg->db, seg->s, seg->type, seg->l, seg->g,
+		seg->avl);
+}
+
+static void print_dt(FILE *file, const char *name, struct kvm_dtable *dt)
+{
+    	fprintf(stderr, "%s %llx/%x\n", name, dt->base, dt->limit);
+}
+
+void kvm_show_regs(kvm_context_t kvm, int vcpu)
+{
+	int fd = kvm->vcpu_fd[vcpu];
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int r;
+
+	r = ioctl(fd, KVM_GET_REGS, &regs);
+	if (r == -1) {
+		perror("KVM_GET_REGS");
+		return;
+	}
+	fprintf(stderr,
+		"rax %016llx rbx %016llx rcx %016llx rdx %016llx\n"
+		"rsi %016llx rdi %016llx rsp %016llx rbp %016llx\n"
+		"r8  %016llx r9  %016llx r10 %016llx r11 %016llx\n"
+		"r12 %016llx r13 %016llx r14 %016llx r15 %016llx\n"
+		"rip %016llx rflags %08llx\n",
+		regs.rax, regs.rbx, regs.rcx, regs.rdx,
+		regs.rsi, regs.rdi, regs.rsp, regs.rbp,
+		regs.r8,  regs.r9,  regs.r10, regs.r11,
+		regs.r12, regs.r13, regs.r14, regs.r15,
+		regs.rip, regs.rflags);
+	r = ioctl(fd, KVM_GET_SREGS, &sregs);
+	if (r == -1) {
+		perror("KVM_GET_SREGS");
+		return;
+	}
+	print_seg(stderr, "cs", &sregs.cs);
+	print_seg(stderr, "ds", &sregs.ds);
+	print_seg(stderr, "es", &sregs.es);
+	print_seg(stderr, "ss", &sregs.ss);
+	print_seg(stderr, "fs", &sregs.fs);
+	print_seg(stderr, "gs", &sregs.gs);
+	print_seg(stderr, "tr", &sregs.tr);
+	print_seg(stderr, "ldt", &sregs.ldt);
+	print_dt(stderr, "gdt", &sregs.gdt);
+	print_dt(stderr, "idt", &sregs.idt);
+	fprintf(stderr, "cr0 %llx cr2 %llx cr3 %llx cr4 %llx cr8 %llx"
+		" efer %llx\n",
+		sregs.cr0, sregs.cr2, sregs.cr3, sregs.cr4, sregs.cr8,
+		sregs.efer);
+}
+
+static void kvm_show_code(kvm_context_t kvm, int vcpu)
+{
+#define CR0_PE_MASK	(1ULL<<0)
+	int fd = kvm->vcpu_fd[vcpu];
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int r;
+	unsigned char code[50];
+	int back_offset;
+	char code_str[sizeof(code) * 3 + 1];
+	unsigned long rip;
+
+	r = ioctl(fd, KVM_GET_SREGS, &sregs);
+	if (r == -1) {
+		perror("KVM_GET_SREGS");
+		return;
+	}
+	if (sregs.cr0 & CR0_PE_MASK)
+		return;
+
+	r = ioctl(fd, KVM_GET_REGS, &regs);
+	if (r == -1) {
+		perror("KVM_GET_REGS");
+		return;
+	}
+	rip = sregs.cs.base + regs.rip;
+	back_offset = regs.rip;
+	if (back_offset > 20)
+	    back_offset = 20;
+	memcpy(code, kvm->physical_memory + rip - back_offset, sizeof code);
+	*code_str = 0;
+	for (r = 0; r < sizeof code; ++r) {
+	    	if (r == back_offset)
+			strcat(code_str, " -->");
+		sprintf(code_str + strlen(code_str), " %02x", code[r]);
+	}
+	fprintf(stderr, "code:%s\n", code_str);
+}
+
+static int handle_mmio_abi10(kvm_context_t kvm, struct kvm_run_abi10 *kvm_run)
+{
+	unsigned long addr = kvm_run->mmio.phys_addr;
+	void *data = kvm_run->mmio.data;
+	int r = -1;
+
+	if (kvm_run->mmio.is_write) {
+		switch (kvm_run->mmio.len) {
+		case 1:
+			r = kvm->callbacks->writeb(kvm->opaque, addr, *(uint8_t *)data);
+			break;
+		case 2:
+			r = kvm->callbacks->writew(kvm->opaque, addr, *(uint16_t *)data);
+			break;
+		case 4:
+			r = kvm->callbacks->writel(kvm->opaque, addr, *(uint32_t *)data);
+			break;
+		case 8:
+			r = kvm->callbacks->writeq(kvm->opaque, addr, *(uint64_t *)data);
+			break;
+		}
+	} else {
+		switch (kvm_run->mmio.len) {
+		case 1:
+			r = kvm->callbacks->readb(kvm->opaque, addr, (uint8_t *)data);
+			break;
+		case 2:
+			r = kvm->callbacks->readw(kvm->opaque, addr, (uint16_t *)data);
+			break;
+		case 4:
+			r = kvm->callbacks->readl(kvm->opaque, addr, (uint32_t *)data);
+			break;
+		case 8:
+			r = kvm->callbacks->readq(kvm->opaque, addr, (uint64_t *)data);
+			break;
+		}
+		kvm_run->io_completed = 1;
+	}
+	return r;
+}
+
+static int handle_mmio(kvm_context_t kvm, struct kvm_run *kvm_run)
+{
+	unsigned long addr = kvm_run->mmio.phys_addr;
+	void *data = kvm_run->mmio.data;
+	int r = -1;
+
+	/* hack: Red Hat 7.1 generates these wierd accesses. */
+	if (addr == 0xa0000 && kvm_run->mmio.len == 3)
+	    return 0;
+
+	if (kvm_run->mmio.is_write) {
+		switch (kvm_run->mmio.len) {
+		case 1:
+			r = kvm->callbacks->writeb(kvm->opaque, addr, *(uint8_t *)data);
+			break;
+		case 2:
+			r = kvm->callbacks->writew(kvm->opaque, addr, *(uint16_t *)data);
+			break;
+		case 4:
+			r = kvm->callbacks->writel(kvm->opaque, addr, *(uint32_t *)data);
+			break;
+		case 8:
+			r = kvm->callbacks->writeq(kvm->opaque, addr, *(uint64_t *)data);
+			break;
+		}
+	} else {
+		switch (kvm_run->mmio.len) {
+		case 1:
+			r = kvm->callbacks->readb(kvm->opaque, addr, (uint8_t *)data);
+			break;
+		case 2:
+			r = kvm->callbacks->readw(kvm->opaque, addr, (uint16_t *)data);
+			break;
+		case 4:
+			r = kvm->callbacks->readl(kvm->opaque, addr, (uint32_t *)data);
+			break;
+		case 8:
+			r = kvm->callbacks->readq(kvm->opaque, addr, (uint64_t *)data);
+			break;
+		}
+	}
+	return r;
+}
+
+static int handle_io_window(kvm_context_t kvm)
+{
+	return kvm->callbacks->io_window(kvm->opaque);
+}
+
+static int handle_halt(kvm_context_t kvm, int vcpu)
+{
+	return kvm->callbacks->halt(kvm->opaque, vcpu);
+}
+
+static int handle_shutdown(kvm_context_t kvm, int vcpu)
+{
+	return kvm->callbacks->shutdown(kvm->opaque, vcpu);
+}
+
+int try_push_interrupts(kvm_context_t kvm)
+{
+	return kvm->callbacks->try_push_interrupts(kvm->opaque);
+}
+
+static void post_kvm_run(kvm_context_t kvm, int vcpu)
+{
+	kvm->callbacks->post_kvm_run(kvm->opaque, vcpu);
+}
+
+static int pre_kvm_run(kvm_context_t kvm, int vcpu)
+{
+	return kvm->callbacks->pre_kvm_run(kvm->opaque, vcpu);
+}
+
+int kvm_get_interrupt_flag(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	if (kvm_abi == 10)
+		return ((struct kvm_run_abi10 *)run)->if_flag;
+	return run->if_flag;
+}
+
+uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	if (kvm_abi == 10)
+		return ((struct kvm_run_abi10 *)run)->apic_base;
+	return run->apic_base;
+}
+
+int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	if (kvm_abi == 10)
+		return ((struct kvm_run_abi10 *)run)->ready_for_interrupt_injection;
+	return run->ready_for_interrupt_injection;
+}
+
+void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	if (kvm_abi == 10) {
+		((struct kvm_run_abi10 *)run)->cr8 = cr8;
+		return;
+	}
+	run->cr8 = cr8;
+}
+
+__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu)
+{
+	return kvm->run[vcpu]->cr8;
+}
+
+static int kvm_run_abi10(kvm_context_t kvm, int vcpu)
+{
+	int r;
+	int fd = kvm->vcpu_fd[vcpu];
+	struct kvm_run_abi10 *run = (struct kvm_run_abi10 *)kvm->run[vcpu];
+
+again:
+	run->request_interrupt_window = try_push_interrupts(kvm);
+	r = pre_kvm_run(kvm, vcpu);
+	if (r)
+	    return r;
+	r = ioctl(fd, KVM_RUN, 0);
+	post_kvm_run(kvm, vcpu);
+
+	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);
+		goto more;
+	}
+	if (1) {
+		switch (run->exit_reason) {
+		case KVM_EXIT_UNKNOWN:
+			fprintf(stderr, "unhandled vm exit: 0x%x vcpu_id %d\n",
+				(unsigned)run->hw.hardware_exit_reason, vcpu);
+			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", 
+			       run->ex.exception,
+			       run->ex.error_code);
+			kvm_show_regs(kvm, vcpu);
+			kvm_show_code(kvm, vcpu);
+			abort();
+			break;
+		case KVM_EXIT_IO:
+			r = handle_io_abi10(kvm, run, vcpu);
+			break;
+		case KVM_EXIT_DEBUG:
+			r = handle_debug(kvm, vcpu);
+			break;
+		case KVM_EXIT_MMIO:
+			r = handle_mmio_abi10(kvm, run);
+			break;
+		case KVM_EXIT_HLT:
+			r = handle_halt(kvm, vcpu);
+			break;
+		case KVM_EXIT_IRQ_WINDOW_OPEN:
+			break;
+		case KVM_EXIT_SHUTDOWN:
+			r = handle_shutdown(kvm, vcpu);
+			break;
+		default:
+			fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason);
+			kvm_show_regs(kvm, vcpu);
+			abort();
+			break;
+		}
+	}
+more:
+	if (!r)
+		goto again;
+	return r;
+}
+
+int kvm_run(kvm_context_t kvm, int vcpu)
+{
+	int r;
+	int fd = kvm->vcpu_fd[vcpu];
+	struct kvm_run *run = kvm->run[vcpu];
+
+	if (kvm_abi == 10)
+		return kvm_run_abi10(kvm, vcpu);
+
+again:
+	if (!kvm->irqchip_in_kernel)
+		run->request_interrupt_window = try_push_interrupts(kvm);
+	r = pre_kvm_run(kvm, vcpu);
+	if (r)
+	    return r;
+	r = ioctl(fd, KVM_RUN, 0);
+	post_kvm_run(kvm, vcpu);
+
+	if (r == -1 && errno != EINTR && errno != EAGAIN) {
+		r = -errno;
+		printf("kvm_run: %m\n");
+		return r;
+	}
+	if (r == -1) {
+		r = handle_io_window(kvm);
+		goto more;
+	}
+	if (1) {
+		switch (run->exit_reason) {
+		case KVM_EXIT_UNKNOWN:
+			fprintf(stderr, "unhandled vm exit: 0x%x vcpu_id %d\n",
+				(unsigned)run->hw.hardware_exit_reason, vcpu);
+			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", 
+			       run->ex.exception,
+			       run->ex.error_code);
+			kvm_show_regs(kvm, vcpu);
+			kvm_show_code(kvm, vcpu);
+			abort();
+			break;
+		case KVM_EXIT_IO:
+			r = handle_io(kvm, run, vcpu);
+			break;
+		case KVM_EXIT_DEBUG:
+			r = handle_debug(kvm, vcpu);
+			break;
+		case KVM_EXIT_MMIO:
+			r = handle_mmio(kvm, run);
+			break;
+		case KVM_EXIT_HLT:
+			r = handle_halt(kvm, vcpu);
+			break;
+		case KVM_EXIT_IRQ_WINDOW_OPEN:
+			break;
+		case KVM_EXIT_SHUTDOWN:
+			r = handle_shutdown(kvm, vcpu);
+			break;
+#ifdef KVM_EXIT_SET_TPR
+		case KVM_EXIT_SET_TPR:
+			break;
+#endif
+		default:
+			fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason);
+			kvm_show_regs(kvm, vcpu);
+			abort();
+			break;
+		}
+	}
+more:
+	if (!r)
+		goto again;
+	return r;
+}
+
+int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq)
+{
+	struct kvm_interrupt intr;
+
+	intr.irq = irq;
+	return ioctl(kvm->vcpu_fd[vcpu], KVM_INTERRUPT, &intr);
+}
+
+int kvm_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_debug_guest *dbg)
+{
+	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;
+}
+
+int kvm_irqchip_in_kernel(kvm_context_t kvm)
+{
+    return kvm->irqchip_in_kernel;
+}
diff --git a/user/kvmctl-x86.h b/user/kvmctl-x86.h
new file mode 100644
--- /dev/null
+++ b/user/kvmctl-x86.h
@@ -0,0 +1,292 @@
+/** \file kvmctl.h
+ * libkvm API
+ */
+
+#ifndef KVMCTL_X86_H
+#define KVMCTL_X86_H
+
+#ifndef __user
+#define __user /* temporary, until installed via make headers_install */
+#endif
+
+#include <linux/kvm.h>
+#define u32 uint32_t  /* older kvm_para.h had a u32 exposed */
+#define u64 uint32_t  /* older kvm_para.h had a u32 exposed */
+#define PAGE_SIZE 4096
+#include <linux/kvm_para.h>
+#undef u32
+#undef u64
+#undef PAGE_SIZE
+
+
+#include <stdint.h>
+#include <signal.h>
+
+
+/*!
+ * \brief KVM callbacks structure
+ *
+ * This structure holds pointers to various functions that KVM will call
+ * when it encounters something that cannot be virtualized, such as
+ * accessing hardware devices via MMIO or regular IO.
+ */
+struct kvm_callbacks {
+	/// 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')
+    int (*inw)(void *opaque, uint16_t addr, uint16_t *data);
+	/// For 32bit IO reads from the guest (Usually when executing 'inl')
+    int (*inl)(void *opaque, uint16_t addr, uint32_t *data);
+	/// For 8bit IO writes from the guest (Usually when executing 'outb')
+    int (*outb)(void *opaque, uint16_t addr, uint8_t data);
+	/// For 16bit IO writes from the guest (Usually when executing 'outw')
+    int (*outw)(void *opaque, uint16_t addr, uint16_t data);
+	/// For 32bit IO writes from the guest (Usually when executing 'outl')
+    int (*outl)(void *opaque, uint16_t addr, uint32_t data);
+	/// For 8bit memory reads from unmapped memory (For MMIO devices)
+    int (*readb)(void *opaque, uint64_t addr, uint8_t *data);
+	/// For 16bit memory reads from unmapped memory (For MMIO devices)
+    int (*readw)(void *opaque, uint64_t addr, uint16_t *data);
+	/// For 32bit memory reads from unmapped memory (For MMIO devices)
+    int (*readl)(void *opaque, uint64_t addr, uint32_t *data);
+	/// For 64bit memory reads from unmapped memory (For MMIO devices)
+    int (*readq)(void *opaque, uint64_t addr, uint64_t *data);
+	/// For 8bit memory writes to unmapped memory (For MMIO devices)
+    int (*writeb)(void *opaque, uint64_t addr, uint8_t data);
+	/// For 16bit memory writes to unmapped memory (For MMIO devices)
+    int (*writew)(void *opaque, uint64_t addr, uint16_t data);
+	/// For 32bit memory writes to unmapped memory (For MMIO devices)
+    int (*writel)(void *opaque, uint64_t addr, uint32_t data);
+	/// For 64bit memory writes to unmapped memory (For MMIO devices)
+    int (*writeq)(void *opaque, uint64_t addr, uint64_t data);
+    int (*debug)(void *opaque, int vcpu);
+	/*!
+	 * \brief Called when the VCPU issues an 'hlt' instruction.
+	 *
+	 * Typically, you should yeild here to prevent 100% CPU utilization
+	 * on the host CPU.
+	 */
+    int (*halt)(void *opaque, int vcpu);
+    int (*shutdown)(void *opaque, int vcpu);
+    int (*io_window)(void *opaque);
+    int (*try_push_interrupts)(void *opaque);
+    void (*post_kvm_run)(void *opaque, int vcpu);
+    int (*pre_kvm_run)(void *opaque, int vcpu);
+};
+
+
+/*!
+ * \brief Disable the in-kernel IRQCHIP creation
+ *
+ * In-kernel irqchip is enabled by default. If userspace irqchip is to be used,
+ * this should be called prior to kvm_create().
+ *
+ * \param kvm Pointer to the kvm_context
+ */
+void kvm_disable_irqchip_creation(kvm_context_t kvm);
+
+/*!
+ * \brief Get interrupt flag from on last exit to userspace
+ *
+ * This gets the CPU interrupt flag as it was on the last exit to userspace.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return interrupt flag value (0 or 1)
+ */
+int kvm_get_interrupt_flag(kvm_context_t kvm, int vcpu);
+
+/*!
+ * \brief Get the value of the APIC_BASE msr as of last exit to userspace
+ *
+ * This gets the APIC_BASE msr as it was on the last exit to userspace.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return APIC_BASE msr contents
+ */
+uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu);
+
+/*!
+ * \brief Check if a vcpu is ready for interrupt injection
+ *
+ * This checks if vcpu interrupts are not masked by mov ss or sti.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return boolean indicating interrupt injection readiness
+ */
+int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu);
+
+/*!
+ * \brief Simulate an external vectored interrupt
+ *
+ * This allows you to simulate an external vectored interrupt.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param irq Vector number
+ * \return 0 on success
+ */
+int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq);
+
+/*!
+ * \brief Set up cr8 for next time the vcpu is executed
+ *
+ * This is a fast setter for cr8, which will be applied when the
+ * vcpu next enters guest mode.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param cr8 next cr8 value
+ */
+void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8);
+
+/*!
+ * \brief Get cr8 for sync tpr in qemu apic emulation
+ *
+ * This is a getter for cr8, which used to sync with the tpr in qemu
+ * apic emualtion.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ */
+__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu);
+
+struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
+int kvm_get_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
+int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
+
+/*!
+ * \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);
+
+void *kvm_create_phys_mem(kvm_context_t, unsigned long phys_start, 
+			  unsigned long len, int slot, int log, int writable);
+void kvm_destroy_phys_mem(kvm_context_t, unsigned long phys_start, 
+			  unsigned long len, int slot);
+int kvm_get_dirty_pages(kvm_context_t, int slot, void *buf);
+
+/*!
+ * \brief Create a memory alias
+ *
+ * Aliases a portion of physical memory to another portion.  If the guest
+ * accesses the alias region, it will behave exactly as if it accessed
+ * the target memory.
+ */
+int kvm_create_memory_alias(kvm_context_t, int slot,
+			    uint64_t phys_start, uint64_t len,
+			    uint64_t target_phys);
+
+/*!
+ * \brief Destroy a memory alias
+ *
+ * Removes an alias created with kvm_create_memory_alias().
+ */
+int kvm_destroy_memory_alias(kvm_context_t, int slot);
+
+/*!
+ * \brief Get a bitmap of guest ram pages which are allocated to the guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param slot Memory slot number
+ * \param bitmap Long aligned address of a big enough bitmap (one bit per page)
+ */
+int kvm_get_mem_map(kvm_context_t kvm, int slot, void *bitmap);
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level);
+
+/*!
+ * \brief Enable dirty-pages-logging for all memory regions
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_dirty_pages_log_enable_all(kvm_context_t kvm);
+
+/*!
+ * \brief Disable dirty-page-logging for some memory regions
+ *
+ * Disable dirty-pages-logging for those memory regions that were
+ * created with dirty-page-logging disabled.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_dirty_pages_log_reset(kvm_context_t kvm);
+
+/*!
+ * \brief Query whether in kernel irqchip is used
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_irqchip_in_kernel(kvm_context_t kvm);
+
+/*!
+ * \brief Dump in kernel IRQCHIP contents
+ *
+ * Dump one of the in kernel irq chip devices, including PIC (master/slave)
+ * and IOAPIC into a kvm_irqchip structure
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param chip The irq chip device to be dumped
+ */
+int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
+
+/*!
+ * \brief Set in kernel IRQCHIP contents
+ *
+ * Write one of the in kernel irq chip devices, including PIC (master/slave)
+ * and IOAPIC
+ *
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param chip THe irq chip device to be written
+ */
+int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
+
+/*!
+ * \brief Get in kernel local APIC for vcpu
+ *
+ * Save the local apic state including the timer of a virtual CPU
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should be accessed
+ * \param s Local apic state of the specific virtual CPU
+ */
+int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
+
+/*!
+ * \brief Set in kernel local APIC for vcpu
+ *
+ * Restore the local apic state including the timer of a virtual CPU
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should be accessed
+ * \param s Local apic state of the specific virtual CPU
+ */
+int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
+
+#endif
diff --git a/user/kvmctl.c b/user/kvmctl.c
deleted file mode 100644
--- a/user/kvmctl.c
+++ /dev/null
@@ -1,1437 +0,0 @@
-/*
- * Kernel-based Virtual Machine control library
- *
- * This library provides an API to control the kvm hardware virtualization
- * module.
- *
- * Copyright (C) 2006 Qumranet
- *
- * Authors:
- *
- *  Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
- *  Yaniv Kamay <yaniv-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
- *
- * This work is licensed under the GNU LGPL license, version 2.
- */
-
-#ifndef __user
-#define __user /* temporary, until installed via make headers_install */
-#endif
-
-#include <linux/kvm.h>
-
-#define EXPECTED_KVM_API_VERSION 12
-
-#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
-#error libkvm: userspace and kernel version mismatch
-#endif
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include "kvmctl.h"
-#include "kvm-abi-10.h"
-
-static int kvm_abi = EXPECTED_KVM_API_VERSION;
-
-#define PAGE_SIZE 4096ul
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-
-/* FIXME: share this number with kvm */
-/* FIXME: or dynamically alloc/realloc regions */
-#define KVM_MAX_NUM_MEM_REGIONS 8u
-#define MAX_VCPUS 4
-
-/**
- * \brief The KVM context
- *
- * The verbose KVM context
- */
-struct kvm_context {
-	/// Filedescriptor to /dev/kvm
-	int fd;
-	int vm_fd;
-	int vcpu_fd[MAX_VCPUS];
-	struct kvm_run *run[MAX_VCPUS];
-	/// Callbacks that KVM uses to emulate various unvirtualizable functionality
-	struct kvm_callbacks *callbacks;
-	void *opaque;
-	/// A pointer to the memory used as the physical memory for the guest
-	void *physical_memory;
-	/// is dirty pages logging enabled for all regions or not
-	int dirty_pages_log_all;
-	/// memory regions parameters
-	struct kvm_memory_region mem_regions[KVM_MAX_NUM_MEM_REGIONS];
-	/// do not create in-kernel irqchip if set
-	int no_irqchip_creation;
-	/// in-kernel irqchip status
-	int irqchip_in_kernel;
-};
-
-/*
- * memory regions parameters
- */
-static void kvm_memory_region_save_params(kvm_context_t kvm, 
-					 struct kvm_memory_region *mem)
-{
-	if (!mem || (mem->slot >= KVM_MAX_NUM_MEM_REGIONS)) {
-		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
-		return;
-	}
-	kvm->mem_regions[mem->slot] = *mem;
-}
-
-#ifdef KVM_CAP_USER_MEMORY
-
-static void kvm_userspace_memory_region_save_params(kvm_context_t kvm,
-					struct kvm_userspace_memory_region *mem)
-{
-	struct kvm_memory_region kvm_mem;
-
-	kvm_mem.slot = mem->slot;
-	kvm_mem.memory_size = mem->memory_size;
-	kvm_mem.guest_phys_addr = mem->guest_phys_addr;
-
-	kvm_memory_region_save_params(kvm, &kvm_mem);
-}
-
-#endif
-
-static void kvm_memory_region_clear_params(kvm_context_t kvm, int regnum)
-{
-	if (regnum >= KVM_MAX_NUM_MEM_REGIONS) {
-		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
-		return;
-	}
-	kvm->mem_regions[regnum].memory_size = 0;
-}
-
-/* 
- * dirty pages logging control 
- */
-static int kvm_dirty_pages_log_change(kvm_context_t kvm, int regnum, __u32 flag)
-{
-	int r;
-	struct kvm_memory_region *mem;
-
-	if (regnum >= KVM_MAX_NUM_MEM_REGIONS) {
-		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
-		return 1;
-	}
-	mem = &kvm->mem_regions[regnum];
-	if (mem->memory_size == 0) /* not used */
-		return 0;
-	if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) /* log already enabled */
-		return 0;
-	mem->flags |= flag;  /* temporary turn on flag */
-	r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, mem);
-	mem->flags &= ~flag; /* back to previous value */
-	if (r == -1) {
-		fprintf(stderr, "%s: %m\n", __FUNCTION__);
-	}
-	return r;
-}
-
-static int kvm_dirty_pages_log_change_all(kvm_context_t kvm, __u32 flag)
-{
-	int i, r;
-
-	for (i=r=0; i<KVM_MAX_NUM_MEM_REGIONS && r==0; i++) {
-		r = kvm_dirty_pages_log_change(kvm, i, flag);
-	}
-	return r;
-}
-
-/**
- * Enable dirty page logging for all memory regions
- */
-int kvm_dirty_pages_log_enable_all(kvm_context_t kvm)
-{
-	if (kvm->dirty_pages_log_all)
-		return 0;
-	kvm->dirty_pages_log_all = 1;
-	return kvm_dirty_pages_log_change_all(kvm, KVM_MEM_LOG_DIRTY_PAGES);
-}
-
-/**
- * Enable dirty page logging only for memory regions that were created with
- *     dirty logging enabled (disable for all other memory regions).
- */
-int kvm_dirty_pages_log_reset(kvm_context_t kvm)
-{
-	if (!kvm->dirty_pages_log_all)
-		return 0;
-	kvm->dirty_pages_log_all = 0;
-	return kvm_dirty_pages_log_change_all(kvm, 0);
-}
-
-
-kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
-		       void *opaque)
-{
-	int fd;
-	kvm_context_t kvm;
-	int r;
-
-	fd = open("/dev/kvm", O_RDWR);
-	if (fd == -1) {
-		perror("open /dev/kvm");
-		return NULL;
-	}
-	r = ioctl(fd, KVM_GET_API_VERSION, 0);
-	if (r == -1) {
-	    fprintf(stderr, "kvm kernel version too old: "
-		    "KVM_GET_API_VERSION ioctl not supported\n");
-	    goto out_close;
-	}
-	if (r < EXPECTED_KVM_API_VERSION && r != 10) {
-		fprintf(stderr, "kvm kernel version too old: "
-			"We expect API version %d or newer, but got "
-			"version %d\n",
-			EXPECTED_KVM_API_VERSION, r);
-	    goto out_close;
-	}
-	if (r > EXPECTED_KVM_API_VERSION) {
-	    fprintf(stderr, "kvm userspace version too old\n");
-	    goto out_close;
-	}
-	kvm_abi = r;
-	kvm = malloc(sizeof(*kvm));
-	kvm->fd = fd;
-	kvm->vm_fd = -1;
-	kvm->callbacks = callbacks;
-	kvm->opaque = opaque;
-	kvm->dirty_pages_log_all = 0;
-	kvm->no_irqchip_creation = 0;
-	memset(&kvm->mem_regions, 0, sizeof(kvm->mem_regions));
-
-	return kvm;
- out_close:
-	close(fd);
-	return NULL;
-}
-
-void kvm_finalize(kvm_context_t kvm)
-{
-    	if (kvm->vcpu_fd[0] != -1)
-		close(kvm->vcpu_fd[0]);
-    	if (kvm->vm_fd != -1)
-		close(kvm->vm_fd);
-	close(kvm->fd);
-	free(kvm);
-}
-
-void kvm_disable_irqchip_creation(kvm_context_t kvm)
-{
-	kvm->no_irqchip_creation = 1;
-}
-
-int kvm_create_vcpu(kvm_context_t kvm, int slot)
-{
-	long mmap_size;
-	int r;
-
-	r = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, slot);
-	if (r == -1) {
-		r = -errno;
-		fprintf(stderr, "kvm_create_vcpu: %m\n");
-		return r;
-	}
-	kvm->vcpu_fd[slot] = r;
-	mmap_size = ioctl(kvm->fd, KVM_GET_VCPU_MMAP_SIZE, 0);
-	if (mmap_size == -1) {
-		r = -errno;
-		fprintf(stderr, "get vcpu mmap size: %m\n");
-		return r;
-	}
-	kvm->run[slot] = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED,
-			      kvm->vcpu_fd[slot], 0);
-	if (kvm->run[slot] == MAP_FAILED) {
-		r = -errno;
-		fprintf(stderr, "mmap vcpu area: %m\n");
-		return r;
-	}
-	return 0;
-}
-
-int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages)
-{
-#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
-	int r;
-
-	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
-		  KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
-	if (r > 0) {
-		r = ioctl(kvm->vm_fd, KVM_SET_NR_MMU_PAGES, nrshadow_pages);
-		if (r == -1) {
-			fprintf(stderr, "kvm_set_shadow_pages: %m\n");
-			return -errno;
-		}
-		return 0;
-	}
-#endif
-	return -1;
-}
-
-int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages)
-{
-#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
-	int r;
-
-	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
-		  KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
-	if (r > 0) {
-		*nrshadow_pages = ioctl(kvm->vm_fd, KVM_GET_NR_MMU_PAGES);
-		return 0;
-	}
-#endif
-	return -1;
-}
-
-int kvm_alloc_kernel_memory(kvm_context_t kvm, unsigned long memory,
-								void **vm_mem)
-{
-	unsigned long dosmem = 0xa0000;
-	unsigned long exmem = 0xc0000;
-	unsigned long pcimem = 0xf0000000;
-	int r;
-	struct kvm_memory_region low_memory = {
-		.slot = 3,
-		.memory_size = memory  < dosmem ? memory : dosmem,
-		.guest_phys_addr = 0,
-	};
-	struct kvm_memory_region extended_memory = {
-		.slot = 0,
-		.memory_size = memory < exmem ? 0 : memory - exmem,
-		.guest_phys_addr = exmem,
-	};
-	struct kvm_memory_region above_4g_memory = {
-		.slot = 4,
-		.memory_size = memory < pcimem ? 0 : memory - pcimem,
-		.guest_phys_addr = 0x100000000,
-	};
-
-	if (memory >= pcimem)
-		extended_memory.memory_size = pcimem - exmem;
-
-	/* 640K should be enough. */
-	r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &low_memory);
-	if (r == -1) {
-		fprintf(stderr, "kvm_create_memory_region: %m\n");
-		return -1;
-	}
-	if (extended_memory.memory_size) {
-		r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &extended_memory);
-		if (r == -1) {
-			fprintf(stderr, "kvm_create_memory_region: %m\n");
-			return -1;
-		}
-	}
-
-	if (above_4g_memory.memory_size) {
-		r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &above_4g_memory);
-		if (r == -1) {
-			fprintf(stderr, "kvm_create_memory_region: %m\n");
-			return -1;
-		}
-	}
-
-	kvm_memory_region_save_params(kvm, &low_memory);
-	kvm_memory_region_save_params(kvm, &extended_memory);
-	kvm_memory_region_save_params(kvm, &above_4g_memory);
-
-	*vm_mem = mmap(NULL, memory, PROT_READ|PROT_WRITE, MAP_SHARED, kvm->vm_fd, 0);
-
-	return 0;
-}
-
-#ifdef KVM_CAP_USER_MEMORY
-
-int kvm_alloc_userspace_memory(kvm_context_t kvm, unsigned long memory,
-								void **vm_mem)
-{
-	unsigned long dosmem = 0xa0000;
-	unsigned long exmem = 0xc0000;
-	unsigned long pcimem = 0xf0000000;
-	int r;
-	struct kvm_userspace_memory_region low_memory = {
-		.slot = 3,
-		.memory_size = memory  < dosmem ? memory : dosmem,
-		.guest_phys_addr = 0,
-	};
-	struct kvm_userspace_memory_region extended_memory = {
-		.slot = 0,
-		.memory_size = memory < exmem ? 0 : memory - exmem,
-		.guest_phys_addr = exmem,
-	};
-	struct kvm_userspace_memory_region above_4g_memory = {
-		.slot = 4,
-		.memory_size = memory < pcimem ? 0 : memory - pcimem,
-		.guest_phys_addr = 0x100000000,
-	};
-
-	if (memory >= pcimem) {
-		extended_memory.memory_size = pcimem - exmem;
-		*vm_mem = mmap(NULL, memory + 0x100000000 - pcimem,
-				PROT_READ|PROT_WRITE, MAP_ANONYMOUS |
-							MAP_SHARED, -1, 0);
-	}
-	else
-		*vm_mem = mmap(NULL, memory, PROT_READ|PROT_WRITE, MAP_ANONYMOUS
-							| MAP_SHARED, -1, 0);
-	if (*vm_mem == MAP_FAILED) {
-		fprintf(stderr, "kvm_alloc_userspace_memory: %s", strerror(errno));
-		return -1;
-	}
-
-
-	low_memory.userspace_addr = (unsigned long)*vm_mem;
-	memset((unsigned long *)low_memory.userspace_addr, 0, low_memory.memory_size);
-	/* 640K should be enough. */
-	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &low_memory);
-	if (r == -1) {
-		fprintf(stderr, "kvm_create_memory_region: %m\n");
-		return -1;
-	}
-	if (extended_memory.memory_size) {
-		r = munmap(*vm_mem + dosmem, exmem - dosmem);
-		if (r == -1) {
-			fprintf(stderr, "kvm_alloc_userspace_memory: %s",
-							strerror(errno));
-			return -1;
-		}
-		extended_memory.userspace_addr = (unsigned long)(*vm_mem + exmem);
-		memset((unsigned long *)extended_memory.userspace_addr, 0, extended_memory.memory_size);
-		r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &extended_memory);
-		if (r == -1) {
-			fprintf(stderr, "kvm_create_memory_region: %m\n");
-			return -1;
-		}
-	}
-
-	if (above_4g_memory.memory_size) {
-		r = munmap(*vm_mem + pcimem, 0x100000000 - pcimem);
-		if (r == -1) {
-			fprintf(stderr, "kvm_alloc_userspace_memory: %s",
-							strerror(errno));
-			return -1;
-		}
-		above_4g_memory.userspace_addr = (unsigned long)(*vm_mem + 0x100000000);
-		memset((unsigned long *)above_4g_memory.userspace_addr, 0, above_4g_memory.memory_size);
-		r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &above_4g_memory);
-		if (r == -1) {
-			fprintf(stderr, "kvm_create_memory_region: %m\n");
-			return -1;
-		}
-	}
-
-	kvm_userspace_memory_region_save_params(kvm, &low_memory);
-	kvm_userspace_memory_region_save_params(kvm, &extended_memory);
-	kvm_userspace_memory_region_save_params(kvm, &above_4g_memory);
-
-	return 0;
-}
-
-#endif
-
-int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, void **vm_mem)
-{
-	unsigned long memory = (phys_mem_bytes + PAGE_SIZE - 1) & PAGE_MASK;
-	int fd = kvm->fd;
-	int zfd;
-	int r;
-
-	kvm->vcpu_fd[0] = -1;
-
-	fd = ioctl(fd, KVM_CREATE_VM, 0);
-	if (fd == -1) {
-		fprintf(stderr, "kvm_create_vm: %m\n");
-		return -1;
-	}
-	kvm->vm_fd = fd;
-
-#ifdef KVM_CAP_USER_MEMORY
-	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
-	if (r > 0)
-		r = kvm_alloc_userspace_memory(kvm, memory, vm_mem);
-	else
-#endif
-		r = kvm_alloc_kernel_memory(kvm, memory, vm_mem);
-	if (r < 0)
-		return r;
-
-        zfd = open("/dev/zero", O_RDONLY);
-        mmap(*vm_mem + 0xa8000, 0x8000, PROT_READ|PROT_WRITE,
-             MAP_PRIVATE|MAP_FIXED, zfd, 0);
-        close(zfd);
-
-	kvm->physical_memory = *vm_mem;
-
-	kvm->irqchip_in_kernel = 0;
-#ifdef KVM_CAP_IRQCHIP
-	if (!kvm->no_irqchip_creation) {
-		r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP);
-		if (r > 0) {	/* kernel irqchip supported */
-			r = ioctl(fd, KVM_CREATE_IRQCHIP);
-			if (r >= 0)
-				kvm->irqchip_in_kernel = 1;
-			else
-				printf("Create kernel PIC irqchip failed\n");
-		}
-	}
-#endif
-	r = kvm_create_vcpu(kvm, 0);
-	if (r < 0)
-		return r;
-
-	return 0;
-}
-
-void *kvm_create_kernel_phys_mem(kvm_context_t kvm, unsigned long phys_start,
-			unsigned long len, int slot, int log, int writable)
-{
-	int r;
-	int prot = PROT_READ;
-	void *ptr;
-	struct kvm_memory_region memory = {
-		.slot = slot,
-		.memory_size = len,
-		.guest_phys_addr = phys_start,
-		.flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
-	};
-
-	r = ioctl(kvm->vm_fd, KVM_SET_MEMORY_REGION, &memory);
-	if (r == -1) {
-		fprintf(stderr, "create_kernel_phys_mem: %s", strerror(errno));
-		return 0;
-	}
-	kvm_memory_region_save_params(kvm, &memory);
-
-	if (writable)
-		prot |= PROT_WRITE;
-
-	ptr = mmap(NULL, len, prot, MAP_SHARED, kvm->vm_fd, phys_start);
-	if (ptr == MAP_FAILED) {
-		fprintf(stderr, "create_kernel_phys_mem: %s", strerror(errno));
-		return 0;
-	}
-
-	return ptr;
-}
-
-#ifdef KVM_CAP_USER_MEMORY
-
-void *kvm_create_userspace_phys_mem(kvm_context_t kvm, unsigned long phys_start,
-			unsigned long len, int slot, int log, int writable)
-{
-	int r;
-	int prot = PROT_READ;
-	void *ptr;
-	struct kvm_userspace_memory_region memory = {
-		.slot = slot,
-		.memory_size = len,
-		.guest_phys_addr = phys_start,
-		.flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
-	};
-
-	if (writable)
-		prot |= PROT_WRITE;
-
-	ptr = mmap(NULL, len, prot, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
-	if (ptr == MAP_FAILED) {
-		fprintf(stderr, "create_userspace_phys_mem: %s", strerror(errno));
-		return 0;
-	}
-
-	memset(ptr, 0, len);
-
-	memory.userspace_addr = (unsigned long)ptr;
-	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &memory);
-	if (r == -1) {
-		fprintf(stderr, "create_userspace_phys_mem: %s", strerror(errno));
-		return 0;
-	}
-
-	kvm_userspace_memory_region_save_params(kvm, &memory);
-
-        return ptr;
-}
-
-#endif
-
-void *kvm_create_phys_mem(kvm_context_t kvm, unsigned long phys_start,
-			  unsigned long len, int slot, int log, int writable)
-{
-#ifdef KVM_CAP_USER_MEMORY
-	int r;
-
-	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
-	if (r > 0)
-		return kvm_create_userspace_phys_mem(kvm, phys_start, len, slot,
-								log, writable);
-	else
-#endif
-		return kvm_create_kernel_phys_mem(kvm, phys_start, len, slot,
-								log, writable);
-}
-
-/* destroy/free a whole slot.
- * phys_start, len and slot are the params passed to kvm_create_phys_mem()
- */
-void kvm_destroy_phys_mem(kvm_context_t kvm, unsigned long phys_start, 
-			  unsigned long len, int slot)
-{
-	struct kvm_memory_region *mem;
-
-	if (slot >= KVM_MAX_NUM_MEM_REGIONS) {
-		fprintf(stderr, "BUG: %s: invalid parameters (slot=%d)\n",
-			__FUNCTION__, slot);
-		return;
-	}
-	mem = &kvm->mem_regions[slot];
-	if (phys_start != mem->guest_phys_addr) {
-		fprintf(stderr,
-			"WARNING: %s: phys_start is 0x%lx expecting 0x%llx\n",
-			__FUNCTION__, phys_start, mem->guest_phys_addr);
-		phys_start = mem->guest_phys_addr;
-	}
-	kvm_create_phys_mem(kvm, phys_start, 0, slot, 0, 0);
-}
-
-int kvm_create_memory_alias(kvm_context_t kvm,
-			    int slot,
-			    uint64_t phys_start,
-			    uint64_t len,
-			    uint64_t target_phys)
-{
-	struct kvm_memory_alias alias = {
-		.slot = slot,
-		.flags = 0,
-		.guest_phys_addr = phys_start,
-		.memory_size = len,
-		.target_phys_addr = target_phys,
-	};
-	int fd = kvm->vm_fd;
-	int r;
-
-	r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias);
-	if (r == -1)
-	    return -errno;
-
-	return 0;
-}
-
-int kvm_destroy_memory_alias(kvm_context_t kvm, int slot)
-{
-	return kvm_create_memory_alias(kvm, slot, 0, 0, 0);
-}
-
-static int kvm_get_map(kvm_context_t kvm, int ioctl_num, int slot, void *buf)
-{
-	int r;
-	struct kvm_dirty_log log = {
-		.slot = slot,
-	};
-
-	log.dirty_bitmap = buf;
-
-	r = ioctl(kvm->vm_fd, ioctl_num, &log);
-	if (r == -1)
-		return -errno;
-	return 0;
-}
-
-int kvm_get_dirty_pages(kvm_context_t kvm, int slot, void *buf)
-{
-	return kvm_get_map(kvm, KVM_GET_DIRTY_LOG, slot, buf);
-}
-
-int kvm_get_mem_map(kvm_context_t kvm, int slot, void *buf)
-{
-#ifdef KVM_GET_MEM_MAP
-	return kvm_get_map(kvm, KVM_GET_MEM_MAP, slot, buf);
-#else /* not KVM_GET_MEM_MAP ==> fake it: all pages exist */
-	unsigned long i, n, m, npages;
-	unsigned char v;
-
-	if (slot >= KVM_MAX_NUM_MEM_REGIONS) {
-		errno = -EINVAL;
-		return -1;
-	}
-	npages = kvm->mem_regions[slot].memory_size / PAGE_SIZE;
-	n = npages / 8;
-	m = npages % 8;
-	memset(buf, 0xff, n); /* all pages exist */
-	v = 0;
-	for (i=0; i<=m; i++) /* last byte may not be "aligned" */
-		v |= 1<<(7-i);
-	if (v)
-		*(unsigned char*)(buf+n) = v;
-	return 0;
-#endif /* KVM_GET_MEM_MAP */
-}
-
-#ifdef KVM_CAP_IRQCHIP
-
-int kvm_set_irq_level(kvm_context_t kvm, int irq, int level)
-{
-	struct kvm_irq_level event;
-	int r;
-
-	if (!kvm->irqchip_in_kernel)
-		return 0;
-	event.level = level;
-	event.irq = irq;
-	r = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &event);
-	if (r == -1)
-		perror("kvm_set_irq_level");
-	return 1;
-}
-
-int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
-{
-	int r;
-
-	if (!kvm->irqchip_in_kernel)
-		return 0;
-	r = ioctl(kvm->vm_fd, KVM_GET_IRQCHIP, chip);
-	if (r == -1) {
-		r = -errno;
-		perror("kvm_get_irqchip\n");
-	}
-	return r;
-}
-
-int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
-{
-	int r;
-
-	if (!kvm->irqchip_in_kernel)
-		return 0;
-	r = ioctl(kvm->vm_fd, KVM_SET_IRQCHIP, chip);
-	if (r == -1) {
-		r = -errno;
-		perror("kvm_set_irqchip\n");
-	}
-	return r;
-}
-
-int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s)
-{
-	int r;
-	if (!kvm->irqchip_in_kernel)
-		return 0;
-	r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_LAPIC, s);
-	if (r == -1) {
-		r = -errno;
-		perror("kvm_get_lapic");
-	}
-	return r;
-}
-
-int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s)
-{
-	int r;
-	if (!kvm->irqchip_in_kernel)
-		return 0;
-	r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_LAPIC, s);
-	if (r == -1) {
-		r = -errno;
-		perror("kvm_set_lapic");
-	}
-	return r;
-}
-
-#endif
-
-static int handle_io_abi10(kvm_context_t kvm, struct kvm_run_abi10 *run,
-			   int vcpu)
-{
-	uint16_t addr = run->io.port;
-	int r;
-	int i;
-	void *p = (void *)run + run->io.data_offset;
-
-	for (i = 0; i < run->io.count; ++i) {
-		switch (run->io.direction) {
-		case KVM_EXIT_IO_IN:
-			switch (run->io.size) {
-			case 1:
-				r = kvm->callbacks->inb(kvm->opaque, addr, p);
-				break;
-			case 2:
-				r = kvm->callbacks->inw(kvm->opaque, addr, p);
-				break;
-			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) {
-			case 1:
-				r = kvm->callbacks->outb(kvm->opaque, addr,
-						     *(uint8_t *)p);
-				break;
-			case 2:
-				r = kvm->callbacks->outw(kvm->opaque, addr,
-						     *(uint16_t *)p);
-				break;
-			case 4:
-				r = kvm->callbacks->outl(kvm->opaque, addr,
-						     *(uint32_t *)p);
-				break;
-			default:
-				fprintf(stderr, "bad I/O size %d\n", run->io.size);
-				return -EMSGSIZE;
-			}
-			break;
-		default:
-			fprintf(stderr, "bad I/O direction %d\n", run->io.direction);
-			return -EPROTO;
-		}
-
-		p += run->io.size;
-	}
-	run->io_completed = 1;
-
-	return 0;
-}
-
-static int handle_io(kvm_context_t kvm, struct kvm_run *run, int vcpu)
-{
-	uint16_t addr = run->io.port;
-	int r;
-	int i;
-	void *p = (void *)run + run->io.data_offset;
-
-	for (i = 0; i < run->io.count; ++i) {
-		switch (run->io.direction) {
-		case KVM_EXIT_IO_IN:
-			switch (run->io.size) {
-			case 1:
-				r = kvm->callbacks->inb(kvm->opaque, addr, p);
-				break;
-			case 2:
-				r = kvm->callbacks->inw(kvm->opaque, addr, p);
-				break;
-			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) {
-			case 1:
-				r = kvm->callbacks->outb(kvm->opaque, addr,
-						     *(uint8_t *)p);
-				break;
-			case 2:
-				r = kvm->callbacks->outw(kvm->opaque, addr,
-						     *(uint16_t *)p);
-				break;
-			case 4:
-				r = kvm->callbacks->outl(kvm->opaque, addr,
-						     *(uint32_t *)p);
-				break;
-			default:
-				fprintf(stderr, "bad I/O size %d\n", run->io.size);
-				return -EMSGSIZE;
-			}
-			break;
-		default:
-			fprintf(stderr, "bad I/O direction %d\n", run->io.direction);
-			return -EPROTO;
-		}
-
-		p += run->io.size;
-	}
-
-	return 0;
-}
-
-static int handle_debug(kvm_context_t kvm, int vcpu)
-{
-	return kvm->callbacks->debug(kvm->opaque, vcpu);
-}
-
-int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
-{
-    return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_REGS, regs);
-}
-
-int kvm_set_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
-{
-    return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_REGS, regs);
-}
-
-int kvm_get_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu)
-{
-    return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_FPU, fpu);
-}
-
-int kvm_set_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu)
-{
-    return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_FPU, fpu);
-}
-
-int kvm_get_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *sregs)
-{
-    return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_SREGS, sregs);
-}
-
-int kvm_set_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *sregs)
-{
-    return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_SREGS, sregs);
-}
-
-/*
- * Returns available msr list.  User must free.
- */
-struct kvm_msr_list *kvm_get_msr_list(kvm_context_t kvm)
-{
-	struct kvm_msr_list sizer, *msrs;
-	int r, e;
-
-	sizer.nmsrs = 0;
-	r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, &sizer);
-	if (r == -1 && errno != E2BIG)
-		return NULL;
-	msrs = malloc(sizeof *msrs + sizer.nmsrs * sizeof *msrs->indices);
-	if (!msrs) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	msrs->nmsrs = sizer.nmsrs;
-	r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, msrs);
-	if (r == -1) {
-		e = errno;
-		free(msrs);
-		errno = e;
-		return NULL;
-	}
-	return msrs;
-}
-
-int kvm_get_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
-		 int n)
-{
-    struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs);
-    int r, e;
-
-    if (!kmsrs) {
-	errno = ENOMEM;
-	return -1;
-    }
-    kmsrs->nmsrs = n;
-    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
-    r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_MSRS, kmsrs);
-    e = errno;
-    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
-    free(kmsrs);
-    errno = e;
-    return r;
-}
-
-int kvm_set_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
-		 int n)
-{
-    struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs);
-    int r, e;
-
-    if (!kmsrs) {
-	errno = ENOMEM;
-	return -1;
-    }
-    kmsrs->nmsrs = n;
-    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
-    r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_MSRS, kmsrs);
-    e = errno;
-    free(kmsrs);
-    errno = e;
-    return r;
-}
-
-static void print_seg(FILE *file, const char *name, struct kvm_segment *seg)
-{
-    	fprintf(stderr,
-		"%s %04x (%08llx/%08x p %d dpl %d db %d s %d type %x l %d"
-		" g %d avl %d)\n",
-		name, seg->selector, seg->base, seg->limit, seg->present,
-		seg->dpl, seg->db, seg->s, seg->type, seg->l, seg->g,
-		seg->avl);
-}
-
-static void print_dt(FILE *file, const char *name, struct kvm_dtable *dt)
-{
-    	fprintf(stderr, "%s %llx/%x\n", name, dt->base, dt->limit);
-}
-
-void kvm_show_regs(kvm_context_t kvm, int vcpu)
-{
-	int fd = kvm->vcpu_fd[vcpu];
-	struct kvm_regs regs;
-	struct kvm_sregs sregs;
-	int r;
-
-	r = ioctl(fd, KVM_GET_REGS, &regs);
-	if (r == -1) {
-		perror("KVM_GET_REGS");
-		return;
-	}
-	fprintf(stderr,
-		"rax %016llx rbx %016llx rcx %016llx rdx %016llx\n"
-		"rsi %016llx rdi %016llx rsp %016llx rbp %016llx\n"
-		"r8  %016llx r9  %016llx r10 %016llx r11 %016llx\n"
-		"r12 %016llx r13 %016llx r14 %016llx r15 %016llx\n"
-		"rip %016llx rflags %08llx\n",
-		regs.rax, regs.rbx, regs.rcx, regs.rdx,
-		regs.rsi, regs.rdi, regs.rsp, regs.rbp,
-		regs.r8,  regs.r9,  regs.r10, regs.r11,
-		regs.r12, regs.r13, regs.r14, regs.r15,
-		regs.rip, regs.rflags);
-	r = ioctl(fd, KVM_GET_SREGS, &sregs);
-	if (r == -1) {
-		perror("KVM_GET_SREGS");
-		return;
-	}
-	print_seg(stderr, "cs", &sregs.cs);
-	print_seg(stderr, "ds", &sregs.ds);
-	print_seg(stderr, "es", &sregs.es);
-	print_seg(stderr, "ss", &sregs.ss);
-	print_seg(stderr, "fs", &sregs.fs);
-	print_seg(stderr, "gs", &sregs.gs);
-	print_seg(stderr, "tr", &sregs.tr);
-	print_seg(stderr, "ldt", &sregs.ldt);
-	print_dt(stderr, "gdt", &sregs.gdt);
-	print_dt(stderr, "idt", &sregs.idt);
-	fprintf(stderr, "cr0 %llx cr2 %llx cr3 %llx cr4 %llx cr8 %llx"
-		" efer %llx\n",
-		sregs.cr0, sregs.cr2, sregs.cr3, sregs.cr4, sregs.cr8,
-		sregs.efer);
-}
-
-static void kvm_show_code(kvm_context_t kvm, int vcpu)
-{
-#define CR0_PE_MASK	(1ULL<<0)
-	int fd = kvm->vcpu_fd[vcpu];
-	struct kvm_regs regs;
-	struct kvm_sregs sregs;
-	int r;
-	unsigned char code[50];
-	int back_offset;
-	char code_str[sizeof(code) * 3 + 1];
-	unsigned long rip;
-
-	r = ioctl(fd, KVM_GET_SREGS, &sregs);
-	if (r == -1) {
-		perror("KVM_GET_SREGS");
-		return;
-	}
-	if (sregs.cr0 & CR0_PE_MASK)
-		return;
-
-	r = ioctl(fd, KVM_GET_REGS, &regs);
-	if (r == -1) {
-		perror("KVM_GET_REGS");
-		return;
-	}
-	rip = sregs.cs.base + regs.rip;
-	back_offset = regs.rip;
-	if (back_offset > 20)
-	    back_offset = 20;
-	memcpy(code, kvm->physical_memory + rip - back_offset, sizeof code);
-	*code_str = 0;
-	for (r = 0; r < sizeof code; ++r) {
-	    	if (r == back_offset)
-			strcat(code_str, " -->");
-		sprintf(code_str + strlen(code_str), " %02x", code[r]);
-	}
-	fprintf(stderr, "code:%s\n", code_str);
-}
-
-static int handle_mmio_abi10(kvm_context_t kvm, struct kvm_run_abi10 *kvm_run)
-{
-	unsigned long addr = kvm_run->mmio.phys_addr;
-	void *data = kvm_run->mmio.data;
-	int r = -1;
-
-	if (kvm_run->mmio.is_write) {
-		switch (kvm_run->mmio.len) {
-		case 1:
-			r = kvm->callbacks->writeb(kvm->opaque, addr, *(uint8_t *)data);
-			break;
-		case 2:
-			r = kvm->callbacks->writew(kvm->opaque, addr, *(uint16_t *)data);
-			break;
-		case 4:
-			r = kvm->callbacks->writel(kvm->opaque, addr, *(uint32_t *)data);
-			break;
-		case 8:
-			r = kvm->callbacks->writeq(kvm->opaque, addr, *(uint64_t *)data);
-			break;
-		}
-	} else {
-		switch (kvm_run->mmio.len) {
-		case 1:
-			r = kvm->callbacks->readb(kvm->opaque, addr, (uint8_t *)data);
-			break;
-		case 2:
-			r = kvm->callbacks->readw(kvm->opaque, addr, (uint16_t *)data);
-			break;
-		case 4:
-			r = kvm->callbacks->readl(kvm->opaque, addr, (uint32_t *)data);
-			break;
-		case 8:
-			r = kvm->callbacks->readq(kvm->opaque, addr, (uint64_t *)data);
-			break;
-		}
-		kvm_run->io_completed = 1;
-	}
-	return r;
-}
-
-static int handle_mmio(kvm_context_t kvm, struct kvm_run *kvm_run)
-{
-	unsigned long addr = kvm_run->mmio.phys_addr;
-	void *data = kvm_run->mmio.data;
-	int r = -1;
-
-	/* hack: Red Hat 7.1 generates these wierd accesses. */
-	if (addr == 0xa0000 && kvm_run->mmio.len == 3)
-	    return 0;
-
-	if (kvm_run->mmio.is_write) {
-		switch (kvm_run->mmio.len) {
-		case 1:
-			r = kvm->callbacks->writeb(kvm->opaque, addr, *(uint8_t *)data);
-			break;
-		case 2:
-			r = kvm->callbacks->writew(kvm->opaque, addr, *(uint16_t *)data);
-			break;
-		case 4:
-			r = kvm->callbacks->writel(kvm->opaque, addr, *(uint32_t *)data);
-			break;
-		case 8:
-			r = kvm->callbacks->writeq(kvm->opaque, addr, *(uint64_t *)data);
-			break;
-		}
-	} else {
-		switch (kvm_run->mmio.len) {
-		case 1:
-			r = kvm->callbacks->readb(kvm->opaque, addr, (uint8_t *)data);
-			break;
-		case 2:
-			r = kvm->callbacks->readw(kvm->opaque, addr, (uint16_t *)data);
-			break;
-		case 4:
-			r = kvm->callbacks->readl(kvm->opaque, addr, (uint32_t *)data);
-			break;
-		case 8:
-			r = kvm->callbacks->readq(kvm->opaque, addr, (uint64_t *)data);
-			break;
-		}
-	}
-	return r;
-}
-
-static int handle_io_window(kvm_context_t kvm)
-{
-	return kvm->callbacks->io_window(kvm->opaque);
-}
-
-static int handle_halt(kvm_context_t kvm, int vcpu)
-{
-	return kvm->callbacks->halt(kvm->opaque, vcpu);
-}
-
-static int handle_shutdown(kvm_context_t kvm, int vcpu)
-{
-	return kvm->callbacks->shutdown(kvm->opaque, vcpu);
-}
-
-int try_push_interrupts(kvm_context_t kvm)
-{
-	return kvm->callbacks->try_push_interrupts(kvm->opaque);
-}
-
-static void post_kvm_run(kvm_context_t kvm, int vcpu)
-{
-	kvm->callbacks->post_kvm_run(kvm->opaque, vcpu);
-}
-
-static int pre_kvm_run(kvm_context_t kvm, int vcpu)
-{
-	return kvm->callbacks->pre_kvm_run(kvm->opaque, vcpu);
-}
-
-int kvm_get_interrupt_flag(kvm_context_t kvm, int vcpu)
-{
-	struct kvm_run *run = kvm->run[vcpu];
-
-	if (kvm_abi == 10)
-		return ((struct kvm_run_abi10 *)run)->if_flag;
-	return run->if_flag;
-}
-
-uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu)
-{
-	struct kvm_run *run = kvm->run[vcpu];
-
-	if (kvm_abi == 10)
-		return ((struct kvm_run_abi10 *)run)->apic_base;
-	return run->apic_base;
-}
-
-int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu)
-{
-	struct kvm_run *run = kvm->run[vcpu];
-
-	if (kvm_abi == 10)
-		return ((struct kvm_run_abi10 *)run)->ready_for_interrupt_injection;
-	return run->ready_for_interrupt_injection;
-}
-
-void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8)
-{
-	struct kvm_run *run = kvm->run[vcpu];
-
-	if (kvm_abi == 10) {
-		((struct kvm_run_abi10 *)run)->cr8 = cr8;
-		return;
-	}
-	run->cr8 = cr8;
-}
-
-__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu)
-{
-	return kvm->run[vcpu]->cr8;
-}
-
-static int kvm_run_abi10(kvm_context_t kvm, int vcpu)
-{
-	int r;
-	int fd = kvm->vcpu_fd[vcpu];
-	struct kvm_run_abi10 *run = (struct kvm_run_abi10 *)kvm->run[vcpu];
-
-again:
-	run->request_interrupt_window = try_push_interrupts(kvm);
-	r = pre_kvm_run(kvm, vcpu);
-	if (r)
-	    return r;
-	r = ioctl(fd, KVM_RUN, 0);
-	post_kvm_run(kvm, vcpu);
-
-	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);
-		goto more;
-	}
-	if (1) {
-		switch (run->exit_reason) {
-		case KVM_EXIT_UNKNOWN:
-			fprintf(stderr, "unhandled vm exit: 0x%x vcpu_id %d\n",
-				(unsigned)run->hw.hardware_exit_reason, vcpu);
-			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", 
-			       run->ex.exception,
-			       run->ex.error_code);
-			kvm_show_regs(kvm, vcpu);
-			kvm_show_code(kvm, vcpu);
-			abort();
-			break;
-		case KVM_EXIT_IO:
-			r = handle_io_abi10(kvm, run, vcpu);
-			break;
-		case KVM_EXIT_DEBUG:
-			r = handle_debug(kvm, vcpu);
-			break;
-		case KVM_EXIT_MMIO:
-			r = handle_mmio_abi10(kvm, run);
-			break;
-		case KVM_EXIT_HLT:
-			r = handle_halt(kvm, vcpu);
-			break;
-		case KVM_EXIT_IRQ_WINDOW_OPEN:
-			break;
-		case KVM_EXIT_SHUTDOWN:
-			r = handle_shutdown(kvm, vcpu);
-			break;
-		default:
-			fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason);
-			kvm_show_regs(kvm, vcpu);
-			abort();
-			break;
-		}
-	}
-more:
-	if (!r)
-		goto again;
-	return r;
-}
-
-int kvm_run(kvm_context_t kvm, int vcpu)
-{
-	int r;
-	int fd = kvm->vcpu_fd[vcpu];
-	struct kvm_run *run = kvm->run[vcpu];
-
-	if (kvm_abi == 10)
-		return kvm_run_abi10(kvm, vcpu);
-
-again:
-	if (!kvm->irqchip_in_kernel)
-		run->request_interrupt_window = try_push_interrupts(kvm);
-	r = pre_kvm_run(kvm, vcpu);
-	if (r)
-	    return r;
-	r = ioctl(fd, KVM_RUN, 0);
-	post_kvm_run(kvm, vcpu);
-
-	if (r == -1 && errno != EINTR && errno != EAGAIN) {
-		r = -errno;
-		printf("kvm_run: %m\n");
-		return r;
-	}
-	if (r == -1) {
-		r = handle_io_window(kvm);
-		goto more;
-	}
-	if (1) {
-		switch (run->exit_reason) {
-		case KVM_EXIT_UNKNOWN:
-			fprintf(stderr, "unhandled vm exit: 0x%x vcpu_id %d\n",
-				(unsigned)run->hw.hardware_exit_reason, vcpu);
-			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", 
-			       run->ex.exception,
-			       run->ex.error_code);
-			kvm_show_regs(kvm, vcpu);
-			kvm_show_code(kvm, vcpu);
-			abort();
-			break;
-		case KVM_EXIT_IO:
-			r = handle_io(kvm, run, vcpu);
-			break;
-		case KVM_EXIT_DEBUG:
-			r = handle_debug(kvm, vcpu);
-			break;
-		case KVM_EXIT_MMIO:
-			r = handle_mmio(kvm, run);
-			break;
-		case KVM_EXIT_HLT:
-			r = handle_halt(kvm, vcpu);
-			break;
-		case KVM_EXIT_IRQ_WINDOW_OPEN:
-			break;
-		case KVM_EXIT_SHUTDOWN:
-			r = handle_shutdown(kvm, vcpu);
-			break;
-#ifdef KVM_EXIT_SET_TPR
-		case KVM_EXIT_SET_TPR:
-			break;
-#endif
-		default:
-			fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason);
-			kvm_show_regs(kvm, vcpu);
-			abort();
-			break;
-		}
-	}
-more:
-	if (!r)
-		goto again;
-	return r;
-}
-
-int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq)
-{
-	struct kvm_interrupt intr;
-
-	intr.irq = irq;
-	return ioctl(kvm->vcpu_fd[vcpu], KVM_INTERRUPT, &intr);
-}
-
-int kvm_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_debug_guest *dbg)
-{
-	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;
-}
-
-int kvm_irqchip_in_kernel(kvm_context_t kvm)
-{
-    return kvm->irqchip_in_kernel;
-}
diff --git a/user/kvmctl.h b/user/kvmctl.h
--- a/user/kvmctl.h
+++ b/user/kvmctl.h
@@ -11,73 +11,22 @@
 #define __user /* temporary, until installed via make headers_install */
 #endif
 
-#include <linux/kvm.h>
-
-#define u32 uint32_t  /* older kvm_para.h had a u32 exposed */
-#define u64 uint32_t  /* older kvm_para.h had a u32 exposed */
-#define PAGE_SIZE 4096
-#include <linux/kvm_para.h>
-#undef u32
-#undef u64
-#undef PAGE_SIZE
-
+#include <stdint.h>
 #include <signal.h>
 
+#include <signal.h>
+
 struct kvm_context;
+struct kvm_callbacks;
 
 typedef struct kvm_context *kvm_context_t;
 
-/*!
- * \brief KVM callbacks structure
- *
- * This structure holds pointers to various functions that KVM will call
- * when it encounters something that cannot be virtualized, such as
- * accessing hardware devices via MMIO or regular IO.
- */
-struct kvm_callbacks {
-	/// 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')
-    int (*inw)(void *opaque, uint16_t addr, uint16_t *data);
-	/// For 32bit IO reads from the guest (Usually when executing 'inl')
-    int (*inl)(void *opaque, uint16_t addr, uint32_t *data);
-	/// For 8bit IO writes from the guest (Usually when executing 'outb')
-    int (*outb)(void *opaque, uint16_t addr, uint8_t data);
-	/// For 16bit IO writes from the guest (Usually when executing 'outw')
-    int (*outw)(void *opaque, uint16_t addr, uint16_t data);
-	/// For 32bit IO writes from the guest (Usually when executing 'outl')
-    int (*outl)(void *opaque, uint16_t addr, uint32_t data);
-	/// For 8bit memory reads from unmapped memory (For MMIO devices)
-    int (*readb)(void *opaque, uint64_t addr, uint8_t *data);
-	/// For 16bit memory reads from unmapped memory (For MMIO devices)
-    int (*readw)(void *opaque, uint64_t addr, uint16_t *data);
-	/// For 32bit memory reads from unmapped memory (For MMIO devices)
-    int (*readl)(void *opaque, uint64_t addr, uint32_t *data);
-	/// For 64bit memory reads from unmapped memory (For MMIO devices)
-    int (*readq)(void *opaque, uint64_t addr, uint64_t *data);
-	/// For 8bit memory writes to unmapped memory (For MMIO devices)
-    int (*writeb)(void *opaque, uint64_t addr, uint8_t data);
-	/// For 16bit memory writes to unmapped memory (For MMIO devices)
-    int (*writew)(void *opaque, uint64_t addr, uint16_t data);
-	/// For 32bit memory writes to unmapped memory (For MMIO devices)
-    int (*writel)(void *opaque, uint64_t addr, uint32_t data);
-	/// For 64bit memory writes to unmapped memory (For MMIO devices)
-    int (*writeq)(void *opaque, uint64_t addr, uint64_t data);
-    int (*debug)(void *opaque, int vcpu);
-	/*!
-	 * \brief Called when the VCPU issues an 'hlt' instruction.
-	 *
-	 * Typically, you should yeild here to prevent 100% CPU utilization
-	 * on the host CPU.
-	 */
-    int (*halt)(void *opaque, int vcpu);
-    int (*shutdown)(void *opaque, int vcpu);
-    int (*io_window)(void *opaque);
-    int (*try_push_interrupts)(void *opaque);
-    void (*post_kvm_run)(void *opaque, int vcpu);
-    int (*pre_kvm_run)(void *opaque, int vcpu);
-};
-
+/* structures defined by arch headers */
+struct kvm_regs;
+struct kvm_sregs;
+struct kvm_fpu;
+struct kvm_debug_guest;
+ 
 /*!
  * \brief Create new KVM context
  *
@@ -102,16 +51,6 @@ kvm_context_t kvm_init(struct kvm_callba
  * \param kvm Pointer to the kvm_context that is to be freed
  */
 void kvm_finalize(kvm_context_t kvm);
-
-/*!
- * \brief Disable the in-kernel IRQCHIP creation
- *
- * In-kernel irqchip is enabled by default. If userspace irqchip is to be used,
- * this should be called prior to kvm_create().
- *
- * \param kvm Pointer to the kvm_context
- */
-void kvm_disable_irqchip_creation(kvm_context_t kvm);
 
 /*!
  * \brief Setting the number of shadow pages to be allocated to the vm
@@ -182,62 +121,6 @@ int kvm_run(kvm_context_t kvm, int vcpu)
 int kvm_run(kvm_context_t kvm, int vcpu);
 
 /*!
- * \brief Get interrupt flag from on last exit to userspace
- *
- * This gets the CPU interrupt flag as it was on the last exit to userspace.
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should get dumped
- * \return interrupt flag value (0 or 1)
- */
-int kvm_get_interrupt_flag(kvm_context_t kvm, int vcpu);
-
-/*!
- * \brief Get the value of the APIC_BASE msr as of last exit to userspace
- *
- * This gets the APIC_BASE msr as it was on the last exit to userspace.
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should get dumped
- * \return APIC_BASE msr contents
- */
-uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu);
-
-/*!
- * \brief Check if a vcpu is ready for interrupt injection
- *
- * This checks if vcpu interrupts are not masked by mov ss or sti.
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should get dumped
- * \return boolean indicating interrupt injection readiness
- */
-int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu);
-
-/*!
- * \brief Set up cr8 for next time the vcpu is executed
- *
- * This is a fast setter for cr8, which will be applied when the
- * vcpu next enters guest mode.
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should get dumped
- * \param cr8 next cr8 value
- */
-void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8);
-
-/*!
- * \brief Get cr8 for sync tpr in qemu apic emulation
- *
- * This is a getter for cr8, which used to sync with the tpr in qemu
- * apic emualtion.
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should get dumped
- */
-__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu);
-
-/*!
  * \brief Read VCPU registers
  *
  * This gets the GP registers from the VCPU and outputs them
@@ -332,52 +215,7 @@ int kvm_get_sregs(kvm_context_t kvm, int
  */
 int kvm_set_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *regs);
 
-struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
-int kvm_get_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
-int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
-
-/*!
- * \brief Simulate an external vectored interrupt
- *
- * This allows you to simulate an external vectored interrupt.
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should get dumped
- * \param irq Vector number
- * \return 0 on success
- */
-int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq);
-
 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
@@ -409,111 +247,11 @@ int kvm_dump_vcpu(kvm_context_t kvm, int
  */
 void kvm_show_regs(kvm_context_t kvm, int vcpu);
 
-void *kvm_create_phys_mem(kvm_context_t, unsigned long phys_start, 
-			  unsigned long len, int slot, int log, int writable);
-void kvm_destroy_phys_mem(kvm_context_t, unsigned long phys_start, 
-			  unsigned long len, int slot);
-int kvm_get_dirty_pages(kvm_context_t, int slot, void *buf);
-
-
-/*!
- * \brief Create a memory alias
- *
- * Aliases a portion of physical memory to another portion.  If the guest
- * accesses the alias region, it will behave exactly as if it accessed
- * the target memory.
- */
-int kvm_create_memory_alias(kvm_context_t, int slot,
-			    uint64_t phys_start, uint64_t len,
-			    uint64_t target_phys);
-
-/*!
- * \brief Destroy a memory alias
- *
- * Removes an alias created with kvm_create_memory_alias().
- */
-int kvm_destroy_memory_alias(kvm_context_t, int slot);
-
-/*!
- * \brief Get a bitmap of guest ram pages which are allocated to the guest.
- *
- * \param kvm Pointer to the current kvm_context
- * \param slot Memory slot number
- * \param bitmap Long aligned address of a big enough bitmap (one bit per page)
- */
-int kvm_get_mem_map(kvm_context_t kvm, int slot, void *bitmap);
-int kvm_set_irq_level(kvm_context_t kvm, int irq, int level);
-
-/*!
- * \brief Enable dirty-pages-logging for all memory regions
- *
- * \param kvm Pointer to the current kvm_context
- */
-int kvm_dirty_pages_log_enable_all(kvm_context_t kvm);
-
-/*!
- * \brief Disable dirty-page-logging for some memory regions
- *
- * Disable dirty-pages-logging for those memory regions that were
- * created with dirty-page-logging disabled.
- *
- * \param kvm Pointer to the current kvm_context
- */
-int kvm_dirty_pages_log_reset(kvm_context_t kvm);
-
-/*!
- * \brief Query whether in kernel irqchip is used
- *
- * \param kvm Pointer to the current kvm_context
- */
-int kvm_irqchip_in_kernel(kvm_context_t kvm);
-
-#ifdef KVM_CAP_IRQCHIP
-/*!
- * \brief Dump in kernel IRQCHIP contents
- *
- * Dump one of the in kernel irq chip devices, including PIC (master/slave)
- * and IOAPIC into a kvm_irqchip structure
- *
- * \param kvm Pointer to the current kvm_context
- * \param chip The irq chip device to be dumped
- */
-int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
-
-/*!
- * \brief Set in kernel IRQCHIP contents
- *
- * Write one of the in kernel irq chip devices, including PIC (master/slave)
- * and IOAPIC
- *
- *
- * \param kvm Pointer to the current kvm_context
- * \param chip THe irq chip device to be written
- */
-int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
-
-/*!
- * \brief Get in kernel local APIC for vcpu
- *
- * Save the local apic state including the timer of a virtual CPU
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should be accessed
- * \param s Local apic state of the specific virtual CPU
- */
-int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
-
-/*!
- * \brief Set in kernel local APIC for vcpu
- *
- * Restore the local apic state including the timer of a virtual CPU
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should be accessed
- * \param s Local apic state of the specific virtual CPU
- */
-int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
-
-#endif
-
-#endif
+#if defined(__x86_64__) || defined(__i386__)
+#include "kvmctl-x86.h"
+#endif
+#if defined(__powerpc__)
+#include "kvmctl-powerpc.h"
+#endif
+
+#endif
diff --git a/user/main-powerpc.c b/user/main-powerpc.c
new file mode 100644
--- /dev/null
+++ b/user/main-powerpc.c
@@ -0,0 +1,298 @@
+/*
+ * Kernel-based Virtual Machine test driver
+ *
+ * This test driver provides a simple way of testing kvm, without a full
+ * device model.
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ * Authors:
+ *
+ *  Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
+ *  Yaniv Kamay <yaniv-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
+ *  Christian Ehrhardt <ehrhardt-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
+ *  Jerone Young <jyoung5-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#define _GNU_SOURCE
+
+#include "kvmctl.h"
+#include "test/apic.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/syscall.h>
+#include <linux/unistd.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#define MEMSIZE 32
+
+static int gettid(void)
+{
+	return syscall(__NR_gettid);
+}
+
+kvm_context_t kvm;
+
+#define MAX_VCPUS 4
+
+#define IPI_SIGNAL (SIGRTMIN + 4)
+
+#define MAX_IO_TABLE	50
+
+typedef int (io_table_handler_t)(void *, int, int, uint64_t, uint64_t *);
+
+struct io_table_entry
+{
+	uint64_t start;
+	uint64_t end;
+	io_table_handler_t *handler;
+	void *opaque;
+};
+
+struct io_table
+{
+	int nr_entries;
+	struct io_table_entry entries[MAX_IO_TABLE];
+};
+
+static int ncpus = 1;
+static sem_t init_sem;
+static __thread int vcpu;
+static sigset_t kernel_sigmask;
+static sigset_t ipi_sigmask;
+static uint64_t memory_size = 128 * 1024 * 1024;
+
+struct vcpu_info {
+	pid_t tid;
+	sem_t sipi_sem;
+};
+
+struct vcpu_info *vcpus;
+
+void test_cpu_physical_memory_rw(uint64_t addr, uint8_t *data,
+                            int len, int is_write)
+{
+    uint32_t val = *(uint32_t *)data;
+    static int scratch;
+
+    printf("%s: addr %lx data %lx len %d write %d\n", __func__,
+           (long)addr, (long)val, len, is_write);
+
+    if (addr == 0xf0000000) {
+        if (is_write) 
+                scratch = val;
+        else 
+            *(uint32_t *)data = scratch;
+    }
+
+}
+
+int test_ppc_dcr_read(kvm_context_t kvm, int dcrn, uint32_t *valp)
+{
+    printf("%s: dcrn %d (unhandled)\n", __func__,dcrn);
+    return 0;
+
+}
+
+int test_ppc_dcr_write(kvm_context_t kvm, int dcrn, uint32_t val)
+{
+    printf("%s: dcrn %d data %d (unhandled)\n", __func__,dcrn,val);
+    return 0;
+}
+
+static struct kvm_callbacks test_callbacks = {
+    .cpu_physical_memory_rw = test_cpu_physical_memory_rw,
+    .ppc_dcr_read = test_ppc_dcr_read,
+    .ppc_dcr_write = test_ppc_dcr_write,
+};
+ 
+
+static void load_file(void *mem, const char *fname)
+{
+	int r;
+	int fd;
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1) {
+		perror("open");
+		exit(1);
+	}
+	while ((r = read(fd, mem, 4096)) != -1 && r != 0)
+		mem += r;
+	if (r == -1) {
+		perror("read");
+		exit(1);
+	}
+}
+
+static void init_vcpu(int n)
+{
+	sigemptyset(&ipi_sigmask);
+	sigaddset(&ipi_sigmask, IPI_SIGNAL);
+	sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL);
+	sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask);
+	vcpus[n].tid = gettid();
+	vcpu = n;
+	sem_post(&init_sem);
+}
+
+static void *do_create_vcpu(void *_n)
+{
+	int n = (long)_n;
+
+	kvm_create_vcpu(kvm, n);
+	init_vcpu(n);
+	sem_wait(&vcpus[n].sipi_sem);
+	kvm_run(kvm, n);
+	return NULL;
+}
+
+static void start_vcpu(int n)
+{
+	pthread_t thread;
+
+	sem_init(&vcpus[n].sipi_sem, 0, 0);
+	pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n);
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr,
+"Usage: %s [OPTIONS] [bootstrap] flatfile\n"
+"KVM test harness.\n"
+"\n"
+"  -s, --smp=NUM          create a VM with NUM virtual CPUs\n"
+"  -p, --protected-mode   start VM in protected mode\n"
+"  -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine.  A suffix\n"
+"                         can be used to change the unit (default: `M')\n"
+"  -h, --help             display this help screen and exit\n"
+"\n"
+"Report bugs to <kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>.\n"
+		, progname);
+}
+
+static void sig_ignore(int sig)
+{
+	write(1, "boo\n", 4);
+}
+
+int main(int argc, char **argv)
+{
+	void *vm_mem;
+	int i;
+	const char *sopts = "s:phm:";
+	struct option lopts[] = {
+		{ "smp", 1, 0, 's' },
+		{ "protected-mode", 0, 0, 'p' },
+		{ "memory", 1, 0, 'm' },
+		{ "help", 0, 0, 'h' },
+		{ 0 },
+	};
+	int opt_ind, ch;
+	bool enter_protected_mode = false;
+	int nb_args;
+	char *endptr;
+
+	while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
+		switch (ch) {
+		case 's':
+			ncpus = atoi(optarg);
+			break;
+		case 'p':
+			enter_protected_mode = true;
+			break;
+		case 'm':
+			memory_size = strtoull(optarg, &endptr, 0);
+			switch (*endptr) {
+			case 'G': case 'g':
+				memory_size <<= 30;
+				break;
+			case '\0':
+			case 'M': case 'm':
+				memory_size <<= 20;
+				break;
+			case 'K': case 'k':
+				memory_size <<= 10;
+				break;
+			default:
+				fprintf(stderr,
+					"Unrecongized memory suffix: %c\n",
+					*endptr);
+				exit(1);
+			}
+			if (memory_size == 0) {
+				fprintf(stderr,
+					"Invalid memory size: 0\n");
+				exit(1);
+			}
+			break;
+		case 'h':
+			usage(argv[0]);
+			exit(0);
+		case '?':
+		default:
+			fprintf(stderr,
+				"Try `%s --help' for more information.\n",
+				argv[0]);
+			exit(1);
+		}
+	}
+
+	nb_args = argc - optind;
+	if (nb_args < 1 || nb_args > 2) {
+		fprintf(stderr,
+			"Incorrect number of arguments.\n"
+			"Try `%s --help' for more information.\n",
+			argv[0]);
+		exit(1);
+	}
+
+	signal(IPI_SIGNAL, sig_ignore);
+
+	vcpus = calloc(ncpus, sizeof *vcpus);
+	if (!vcpus) {
+		fprintf(stderr, "calloc failed\n");
+		return 1;
+	}
+
+	kvm = kvm_init(&test_callbacks, 0);
+	if (!kvm) {
+		fprintf(stderr, "kvm_init failed\n");
+		return 1;
+	}
+	if (kvm_create(kvm, memory_size, &vm_mem) < 0) {
+		kvm_finalize(kvm);
+		fprintf(stderr, "kvm_create failed\n");
+		return 1;
+	}
+
+	if (enter_protected_mode)
+		fprintf(stderr, "enter_protected_mode not supported for ppc\n");
+	else
+		load_file(vm_mem, argv[optind]);
+ 
+
+	sem_init(&init_sem, 0, 0);
+	init_vcpu(0);
+	for (i = 1; i < ncpus; ++i)
+		start_vcpu(i);
+	for (i = 0; i < ncpus; ++i)
+		sem_wait(&init_sem);
+
+	kvm_run(kvm, 0);
+
+	return 0;
+}
diff --git a/user/main-x86.c b/user/main-x86.c
new file mode 100644
--- /dev/null
+++ b/user/main-x86.c
@@ -0,0 +1,590 @@
+/*
+ * Kernel-based Virtual Machine test driver
+ *
+ * This test driver provides a simple way of testing kvm, without a full
+ * device model.
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ * Authors:
+ *
+ *  Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
+ *  Yaniv Kamay <yaniv-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#define _GNU_SOURCE
+
+#include "kvmctl.h"
+#include "test/apic.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/syscall.h>
+#include <linux/unistd.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+static int gettid(void)
+{
+	return syscall(__NR_gettid);
+}
+
+static int tkill(int pid, int sig)
+{
+	return syscall(__NR_tkill, pid, sig);
+}
+
+kvm_context_t kvm;
+
+#define MAX_VCPUS 4
+
+#define IPI_SIGNAL (SIGRTMIN + 4)
+
+#define MAX_IO_TABLE	50
+
+typedef int (io_table_handler_t)(void *, int, int, uint64_t, uint64_t *);
+
+struct io_table_entry
+{
+	uint64_t start;
+	uint64_t end;
+	io_table_handler_t *handler;
+	void *opaque;
+};
+
+struct io_table
+{
+	int nr_entries;
+	struct io_table_entry entries[MAX_IO_TABLE];
+};
+
+static int ncpus = 1;
+static sem_t init_sem;
+static __thread int vcpu;
+static int apic_ipi_vector = 0xff;
+static sigset_t kernel_sigmask;
+static sigset_t ipi_sigmask;
+static uint64_t memory_size = 128 * 1024 * 1024;
+
+static struct io_table pio_table;
+
+struct vcpu_info {
+	pid_t tid;
+	sem_t sipi_sem;
+};
+
+struct vcpu_info *vcpus;
+
+static uint32_t apic_sipi_addr;
+
+struct io_table_entry *io_table_lookup(struct io_table *io_table, uint64_t addr)
+{
+	int i;
+
+	for (i = 0; i < io_table->nr_entries; i++) {
+		if (io_table->entries[i].start <= addr &&
+		    addr < io_table->entries[i].end)
+			return &io_table->entries[i];
+	}
+
+	return NULL;
+}
+
+int io_table_register(struct io_table *io_table, uint64_t start, uint64_t size,
+		      io_table_handler_t *handler, void *opaque)
+{
+	struct io_table_entry *entry;
+
+	if (io_table->nr_entries == MAX_IO_TABLE)
+		return -ENOSPC;
+
+	entry = &io_table->entries[io_table->nr_entries];
+	io_table->nr_entries++;
+
+	entry->start = start;
+	entry->end = start + size;
+	entry->handler = handler;
+	entry->opaque = opaque;
+
+	return 0;
+}
+
+static void apic_send_sipi(int vcpu)
+{
+	sem_post(&vcpus[vcpu].sipi_sem);
+}
+
+static void apic_send_ipi(int vcpu)
+{
+	struct vcpu_info *v;
+
+	if (vcpu < 0 || vcpu >= ncpus)
+		return;
+	v = &vcpus[vcpu];
+	tkill(v->tid, IPI_SIGNAL);
+}
+
+static int apic_io(void *opaque, int size, int is_write,
+		   uint64_t addr, uint64_t *value)
+{
+	if (!is_write)
+		*value = -1u;
+
+	switch (addr - APIC_BASE) {
+	case APIC_REG_NCPU:
+		if (!is_write)
+			*value = ncpus;
+		break;
+	case APIC_REG_ID:
+		if (!is_write)
+			*value = vcpu;
+		break;
+	case APIC_REG_SIPI_ADDR:
+		if (!is_write)
+			*value = apic_sipi_addr;
+		else
+			apic_sipi_addr = *value;
+		break;
+	case APIC_REG_SEND_SIPI:
+		if (is_write)
+			apic_send_sipi(*value);
+		break;
+	case APIC_REG_IPI_VECTOR:
+		if (!is_write)
+			*value = apic_ipi_vector;
+		else
+			apic_ipi_vector = *value;
+		break;
+	case APIC_REG_SEND_IPI:
+		if (is_write)
+			apic_send_ipi(*value);
+		break;
+	}
+
+	return 0;
+}
+
+static int apic_init(void)
+{
+	return io_table_register(&pio_table, APIC_BASE,
+				 APIC_SIZE, apic_io, NULL);
+}
+
+static int misc_io(void *opaque, int size, int is_write,
+		   uint64_t addr, uint64_t *value)
+{
+	static int newline = 1;
+
+	if (!is_write)
+		*value = -1;
+
+	switch (addr) {
+	case 0xff: // irq injector
+		if (is_write) {
+			printf("injecting interrupt 0x%x\n", (uint8_t)*value);
+			kvm_inject_irq(kvm, 0, *value);
+		}
+		break;
+	case 0xf1: // serial
+		if (is_write) {
+			if (newline)
+				fputs("GUEST: ", stdout);
+			putchar(*value);
+			newline = *value == '\n';
+		}
+		break;
+	case 0xd1:
+		if (!is_write)
+			*value = memory_size;
+		break;
+	}
+
+	return 0;
+}
+
+static int misc_init(void)
+{
+	int err;
+
+	err = io_table_register(&pio_table, 0xff, 1, misc_io, NULL);
+	if (err < 0)
+		return err;
+
+	err = io_table_register(&pio_table, 0xf1, 1, misc_io, NULL);
+	if (err < 0)
+		return err;
+
+	return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL);
+}
+
+static int test_inb(void *opaque, uint16_t addr, uint8_t *value)
+{
+	struct io_table_entry *entry;
+
+	entry = io_table_lookup(&pio_table, addr);
+	if (entry) {
+		uint64_t val;
+		entry->handler(entry->opaque, 1, 0, addr, &val);
+		*value = val;
+	} else {
+		*value = -1;
+		printf("inb 0x%x\n", addr);
+	}
+
+	return 0;
+}
+
+static int test_inw(void *opaque, uint16_t addr, uint16_t *value)
+{
+	struct io_table_entry *entry;
+
+	entry = io_table_lookup(&pio_table, addr);
+	if (entry) {
+		uint64_t val;
+		entry->handler(entry->opaque, 2, 0, addr, &val);
+		*value = val;
+	} else {
+		*value = -1;
+		printf("inw 0x%x\n", addr);
+	}
+
+	return 0;
+}
+
+static int test_inl(void *opaque, uint16_t addr, uint32_t *value)
+{
+	struct io_table_entry *entry;
+
+	entry = io_table_lookup(&pio_table, addr);
+	if (entry) {
+		uint64_t val;
+		entry->handler(entry->opaque, 4, 0, addr, &val);
+		*value = val;
+	} else {
+		*value = -1;
+		printf("inl 0x%x\n", addr);
+	}
+
+	return 0;
+}
+
+static int test_outb(void *opaque, uint16_t addr, uint8_t value)
+{
+	struct io_table_entry *entry;
+
+	entry = io_table_lookup(&pio_table, addr);
+	if (entry) {
+		uint64_t val = value;
+		entry->handler(entry->opaque, 1, 1, addr, &val);
+	} else
+		printf("outb $0x%x, 0x%x\n", value, addr);
+
+	return 0;
+}
+
+static int test_outw(void *opaque, uint16_t addr, uint16_t value)
+{
+	struct io_table_entry *entry;
+
+	entry = io_table_lookup(&pio_table, addr);
+	if (entry) {
+		uint64_t val = value;
+		entry->handler(entry->opaque, 2, 1, addr, &val);
+	} else
+		printf("outw $0x%x, 0x%x\n", value, addr);
+
+	return 0;
+}
+
+static int test_outl(void *opaque, uint16_t addr, uint32_t value)
+{
+	struct io_table_entry *entry;
+
+	entry = io_table_lookup(&pio_table, addr);
+	if (entry) {
+		uint64_t val = value;
+		entry->handler(entry->opaque, 4, 1, addr, &val);
+	} else
+		printf("outl $0x%x, 0x%x\n", value, addr);
+
+	return 0;
+}
+
+static int test_debug(void *opaque, int vcpu)
+{
+	printf("test_debug\n");
+	return 0;
+}
+
+static int test_halt(void *opaque, int vcpu)
+{
+	int n;
+
+	sigwait(&ipi_sigmask, &n);
+	kvm_inject_irq(kvm, vcpu, apic_ipi_vector);
+	return 0;
+}
+
+static int test_io_window(void *opaque)
+{
+	return 0;
+}
+
+static int test_try_push_interrupts(void *opaque)
+{
+	return 0;
+}
+
+static void test_post_kvm_run(void *opaque, int vcpu)
+{
+}
+
+static int test_pre_kvm_run(void *opaque, int vcpu)
+{
+	return 0;
+}
+
+static struct kvm_callbacks test_callbacks = {
+	.inb         = test_inb,
+	.inw         = test_inw,
+	.inl         = test_inl,
+	.outb        = test_outb,
+	.outw        = test_outw,
+	.outl        = test_outl,
+	.debug       = test_debug,
+	.halt        = test_halt,
+	.io_window = test_io_window,
+	.try_push_interrupts = test_try_push_interrupts,
+	.post_kvm_run = test_post_kvm_run,
+	.pre_kvm_run = test_pre_kvm_run,
+};
+ 
+
+static void load_file(void *mem, const char *fname)
+{
+	int r;
+	int fd;
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1) {
+		perror("open");
+		exit(1);
+	}
+	while ((r = read(fd, mem, 4096)) != -1 && r != 0)
+		mem += r;
+	if (r == -1) {
+		perror("read");
+		exit(1);
+	}
+}
+
+static void enter_32(kvm_context_t kvm)
+{
+	struct kvm_regs regs = {
+		.rsp = 0x80000,  /* 512KB */
+		.rip = 0x100000, /* 1MB */
+		.rflags = 2,
+	};
+	struct kvm_sregs sregs = {
+		.cs = { 0, -1u,  8, 11, 1, 0, 1, 1, 0, 1, 0, 0 },
+		.ds = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
+		.es = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
+		.fs = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
+		.gs = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
+		.ss = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
+
+		.tr = { 0, 10000, 24, 11, 1, 0, 0, 0, 0, 0, 0, 0 },
+		.ldt = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+		.gdt = { 0, 0 },
+		.idt = { 0, 0 },
+		.cr0 = 0x37,
+		.cr3 = 0,
+		.cr4 = 0,
+		.efer = 0,
+		.apic_base = 0,
+		.interrupt_bitmap = { 0 },
+	};
+
+	kvm_set_regs(kvm, 0, &regs);
+	kvm_set_sregs(kvm, 0, &sregs);
+}
+
+static void init_vcpu(int n)
+{
+	sigemptyset(&ipi_sigmask);
+	sigaddset(&ipi_sigmask, IPI_SIGNAL);
+	sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL);
+	sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask);
+	vcpus[n].tid = gettid();
+	vcpu = n;
+	kvm_set_signal_mask(kvm, n, &kernel_sigmask);
+	sem_post(&init_sem);
+}
+
+static void *do_create_vcpu(void *_n)
+{
+	int n = (long)_n;
+	struct kvm_regs regs;
+
+	kvm_create_vcpu(kvm, n);
+	init_vcpu(n);
+	sem_wait(&vcpus[n].sipi_sem);
+	kvm_get_regs(kvm, n, &regs);
+	regs.rip = apic_sipi_addr;
+	kvm_set_regs(kvm, n, &regs);
+	kvm_run(kvm, n);
+	return NULL;
+}
+
+static void start_vcpu(int n)
+{
+	pthread_t thread;
+
+	sem_init(&vcpus[n].sipi_sem, 0, 0);
+	pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n);
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr,
+"Usage: %s [OPTIONS] [bootstrap] flatfile\n"
+"KVM test harness.\n"
+"\n"
+"  -s, --smp=NUM          create a VM with NUM virtual CPUs\n"
+"  -p, --protected-mode   start VM in protected mode\n"
+"  -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine.  A suffix\n"
+"                         can be used to change the unit (default: `M')\n"
+"  -h, --help             display this help screen and exit\n"
+"\n"
+"Report bugs to <kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>.\n"
+		, progname);
+}
+
+static void sig_ignore(int sig)
+{
+	write(1, "boo\n", 4);
+}
+
+int main(int argc, char **argv)
+{
+	void *vm_mem;
+	int i;
+	const char *sopts = "s:phm:";
+	struct option lopts[] = {
+		{ "smp", 1, 0, 's' },
+		{ "protected-mode", 0, 0, 'p' },
+		{ "memory", 1, 0, 'm' },
+		{ "help", 0, 0, 'h' },
+		{ 0 },
+	};
+	int opt_ind, ch;
+	bool enter_protected_mode = false;
+	int nb_args;
+	char *endptr;
+
+	while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
+		switch (ch) {
+		case 's':
+			ncpus = atoi(optarg);
+			break;
+		case 'p':
+			enter_protected_mode = true;
+			break;
+		case 'm':
+			memory_size = strtoull(optarg, &endptr, 0);
+			switch (*endptr) {
+			case 'G': case 'g':
+				memory_size <<= 30;
+				break;
+			case '\0':
+			case 'M': case 'm':
+				memory_size <<= 20;
+				break;
+			case 'K': case 'k':
+				memory_size <<= 10;
+				break;
+			default:
+				fprintf(stderr,
+					"Unrecongized memory suffix: %c\n",
+					*endptr);
+				exit(1);
+			}
+			if (memory_size == 0) {
+				fprintf(stderr,
+					"Invalid memory size: 0\n");
+				exit(1);
+			}
+			break;
+		case 'h':
+			usage(argv[0]);
+			exit(0);
+		case '?':
+		default:
+			fprintf(stderr,
+				"Try `%s --help' for more information.\n",
+				argv[0]);
+			exit(1);
+		}
+	}
+
+	nb_args = argc - optind;
+	if (nb_args < 1 || nb_args > 2) {
+		fprintf(stderr,
+			"Incorrect number of arguments.\n"
+			"Try `%s --help' for more information.\n",
+			argv[0]);
+		exit(1);
+	}
+
+	signal(IPI_SIGNAL, sig_ignore);
+
+	vcpus = calloc(ncpus, sizeof *vcpus);
+	if (!vcpus) {
+		fprintf(stderr, "calloc failed\n");
+		return 1;
+	}
+
+	kvm = kvm_init(&test_callbacks, 0);
+	if (!kvm) {
+		fprintf(stderr, "kvm_init failed\n");
+		return 1;
+	}
+	if (kvm_create(kvm, memory_size, &vm_mem) < 0) {
+		kvm_finalize(kvm);
+		fprintf(stderr, "kvm_create failed\n");
+		return 1;
+	}
+
+	if (enter_protected_mode)
+		enter_32(kvm);
+	else
+		load_file(vm_mem + 0xf0000, argv[optind]);
+
+	if (nb_args > 1)
+		load_file(vm_mem + 0x100000, argv[optind + 1]);
+
+	apic_init();
+	misc_init();
+
+	sem_init(&init_sem, 0, 0);
+	init_vcpu(0);
+	for (i = 1; i < ncpus; ++i)
+		start_vcpu(i);
+	for (i = 0; i < ncpus; ++i)
+		sem_wait(&init_sem);
+
+	kvm_run(kvm, 0);
+
+	return 0;
+}
diff --git a/user/main.c b/user/main.c
deleted file mode 100644
--- a/user/main.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Kernel-based Virtual Machine test driver
- *
- * This test driver provides a simple way of testing kvm, without a full
- * device model.
- *
- * Copyright (C) 2006 Qumranet
- *
- * Authors:
- *
- *  Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
- *  Yaniv Kamay <yaniv-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
- *
- * This work is licensed under the GNU LGPL license, version 2.
- */
-
-#define _GNU_SOURCE
-
-#include "kvmctl.h"
-#include "test/apic.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <semaphore.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <pthread.h>
-#include <sys/syscall.h>
-#include <linux/unistd.h>
-#include <getopt.h>
-#include <stdbool.h>
-
-static int gettid(void)
-{
-	return syscall(__NR_gettid);
-}
-
-static int tkill(int pid, int sig)
-{
-	return syscall(__NR_tkill, pid, sig);
-}
-
-kvm_context_t kvm;
-
-#define MAX_VCPUS 4
-
-#define IPI_SIGNAL (SIGRTMIN + 4)
-
-#define MAX_IO_TABLE	50
-
-typedef int (io_table_handler_t)(void *, int, int, uint64_t, uint64_t *);
-
-struct io_table_entry
-{
-	uint64_t start;
-	uint64_t end;
-	io_table_handler_t *handler;
-	void *opaque;
-};
-
-struct io_table
-{
-	int nr_entries;
-	struct io_table_entry entries[MAX_IO_TABLE];
-};
-
-static int ncpus = 1;
-static sem_t init_sem;
-static __thread int vcpu;
-static int apic_ipi_vector = 0xff;
-static sigset_t kernel_sigmask;
-static sigset_t ipi_sigmask;
-static uint64_t memory_size = 128 * 1024 * 1024;
-
-static struct io_table pio_table;
-
-struct vcpu_info {
-	pid_t tid;
-	sem_t sipi_sem;
-};
-
-struct vcpu_info *vcpus;
-
-static uint32_t apic_sipi_addr;
-
-struct io_table_entry *io_table_lookup(struct io_table *io_table, uint64_t addr)
-{
-	int i;
-
-	for (i = 0; i < io_table->nr_entries; i++) {
-		if (io_table->entries[i].start <= addr &&
-		    addr < io_table->entries[i].end)
-			return &io_table->entries[i];
-	}
-
-	return NULL;
-}
-
-int io_table_register(struct io_table *io_table, uint64_t start, uint64_t size,
-		      io_table_handler_t *handler, void *opaque)
-{
-	struct io_table_entry *entry;
-
-	if (io_table->nr_entries == MAX_IO_TABLE)
-		return -ENOSPC;
-
-	entry = &io_table->entries[io_table->nr_entries];
-	io_table->nr_entries++;
-
-	entry->start = start;
-	entry->end = start + size;
-	entry->handler = handler;
-	entry->opaque = opaque;
-
-	return 0;
-}
-
-static void apic_send_sipi(int vcpu)
-{
-	sem_post(&vcpus[vcpu].sipi_sem);
-}
-
-static void apic_send_ipi(int vcpu)
-{
-	struct vcpu_info *v;
-
-	if (vcpu < 0 || vcpu >= ncpus)
-		return;
-	v = &vcpus[vcpu];
-	tkill(v->tid, IPI_SIGNAL);
-}
-
-static int apic_io(void *opaque, int size, int is_write,
-		   uint64_t addr, uint64_t *value)
-{
-	if (!is_write)
-		*value = -1u;
-
-	switch (addr - APIC_BASE) {
-	case APIC_REG_NCPU:
-		if (!is_write)
-			*value = ncpus;
-		break;
-	case APIC_REG_ID:
-		if (!is_write)
-			*value = vcpu;
-		break;
-	case APIC_REG_SIPI_ADDR:
-		if (!is_write)
-			*value = apic_sipi_addr;
-		else
-			apic_sipi_addr = *value;
-		break;
-	case APIC_REG_SEND_SIPI:
-		if (is_write)
-			apic_send_sipi(*value);
-		break;
-	case APIC_REG_IPI_VECTOR:
-		if (!is_write)
-			*value = apic_ipi_vector;
-		else
-			apic_ipi_vector = *value;
-		break;
-	case APIC_REG_SEND_IPI:
-		if (is_write)
-			apic_send_ipi(*value);
-		break;
-	}
-
-	return 0;
-}
-
-static int apic_init(void)
-{
-	return io_table_register(&pio_table, APIC_BASE,
-				 APIC_SIZE, apic_io, NULL);
-}
-
-static int misc_io(void *opaque, int size, int is_write,
-		   uint64_t addr, uint64_t *value)
-{
-	static int newline = 1;
-
-	if (!is_write)
-		*value = -1;
-
-	switch (addr) {
-	case 0xff: // irq injector
-		if (is_write) {
-			printf("injecting interrupt 0x%x\n", (uint8_t)*value);
-			kvm_inject_irq(kvm, 0, *value);
-		}
-		break;
-	case 0xf1: // serial
-		if (is_write) {
-			if (newline)
-				fputs("GUEST: ", stdout);
-			putchar(*value);
-			newline = *value == '\n';
-		}
-		break;
-	case 0xd1:
-		if (!is_write)
-			*value = memory_size;
-		break;
-	}
-
-	return 0;
-}
-
-static int misc_init(void)
-{
-	int err;
-
-	err = io_table_register(&pio_table, 0xff, 1, misc_io, NULL);
-	if (err < 0)
-		return err;
-
-	err = io_table_register(&pio_table, 0xf1, 1, misc_io, NULL);
-	if (err < 0)
-		return err;
-
-	return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL);
-}
-
-static int test_inb(void *opaque, uint16_t addr, uint8_t *value)
-{
-	struct io_table_entry *entry;
-
-	entry = io_table_lookup(&pio_table, addr);
-	if (entry) {
-		uint64_t val;
-		entry->handler(entry->opaque, 1, 0, addr, &val);
-		*value = val;
-	} else {
-		*value = -1;
-		printf("inb 0x%x\n", addr);
-	}
-
-	return 0;
-}
-
-static int test_inw(void *opaque, uint16_t addr, uint16_t *value)
-{
-	struct io_table_entry *entry;
-
-	entry = io_table_lookup(&pio_table, addr);
-	if (entry) {
-		uint64_t val;
-		entry->handler(entry->opaque, 2, 0, addr, &val);
-		*value = val;
-	} else {
-		*value = -1;
-		printf("inw 0x%x\n", addr);
-	}
-
-	return 0;
-}
-
-static int test_inl(void *opaque, uint16_t addr, uint32_t *value)
-{
-	struct io_table_entry *entry;
-
-	entry = io_table_lookup(&pio_table, addr);
-	if (entry) {
-		uint64_t val;
-		entry->handler(entry->opaque, 4, 0, addr, &val);
-		*value = val;
-	} else {
-		*value = -1;
-		printf("inl 0x%x\n", addr);
-	}
-
-	return 0;
-}
-
-static int test_outb(void *opaque, uint16_t addr, uint8_t value)
-{
-	struct io_table_entry *entry;
-
-	entry = io_table_lookup(&pio_table, addr);
-	if (entry) {
-		uint64_t val = value;
-		entry->handler(entry->opaque, 1, 1, addr, &val);
-	} else
-		printf("outb $0x%x, 0x%x\n", value, addr);
-
-	return 0;
-}
-
-static int test_outw(void *opaque, uint16_t addr, uint16_t value)
-{
-	struct io_table_entry *entry;
-
-	entry = io_table_lookup(&pio_table, addr);
-	if (entry) {
-		uint64_t val = value;
-		entry->handler(entry->opaque, 2, 1, addr, &val);
-	} else
-		printf("outw $0x%x, 0x%x\n", value, addr);
-
-	return 0;
-}
-
-static int test_outl(void *opaque, uint16_t addr, uint32_t value)
-{
-	struct io_table_entry *entry;
-
-	entry = io_table_lookup(&pio_table, addr);
-	if (entry) {
-		uint64_t val = value;
-		entry->handler(entry->opaque, 4, 1, addr, &val);
-	} else
-		printf("outl $0x%x, 0x%x\n", value, addr);
-
-	return 0;
-}
-
-static int test_debug(void *opaque, int vcpu)
-{
-	printf("test_debug\n");
-	return 0;
-}
-
-static int test_halt(void *opaque, int vcpu)
-{
-	int n;
-
-	sigwait(&ipi_sigmask, &n);
-	kvm_inject_irq(kvm, vcpu, apic_ipi_vector);
-	return 0;
-}
-
-static int test_io_window(void *opaque)
-{
-	return 0;
-}
-
-static int test_try_push_interrupts(void *opaque)
-{
-	return 0;
-}
-
-static void test_post_kvm_run(void *opaque, int vcpu)
-{
-}
-
-static int test_pre_kvm_run(void *opaque, int vcpu)
-{
-	return 0;
-}
-
-static struct kvm_callbacks test_callbacks = {
-	.inb         = test_inb,
-	.inw         = test_inw,
-	.inl         = test_inl,
-	.outb        = test_outb,
-	.outw        = test_outw,
-	.outl        = test_outl,
-	.debug       = test_debug,
-	.halt        = test_halt,
-	.io_window = test_io_window,
-	.try_push_interrupts = test_try_push_interrupts,
-	.post_kvm_run = test_post_kvm_run,
-	.pre_kvm_run = test_pre_kvm_run,
-};
- 
-
-static void load_file(void *mem, const char *fname)
-{
-	int r;
-	int fd;
-
-	fd = open(fname, O_RDONLY);
-	if (fd == -1) {
-		perror("open");
-		exit(1);
-	}
-	while ((r = read(fd, mem, 4096)) != -1 && r != 0)
-		mem += r;
-	if (r == -1) {
-		perror("read");
-		exit(1);
-	}
-}
-
-static void enter_32(kvm_context_t kvm)
-{
-	struct kvm_regs regs = {
-		.rsp = 0x80000,  /* 512KB */
-		.rip = 0x100000, /* 1MB */
-		.rflags = 2,
-	};
-	struct kvm_sregs sregs = {
-		.cs = { 0, -1u,  8, 11, 1, 0, 1, 1, 0, 1, 0, 0 },
-		.ds = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
-		.es = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
-		.fs = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
-		.gs = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
-		.ss = { 0, -1u, 16,  3, 1, 0, 1, 1, 0, 1, 0, 0 },
-
-		.tr = { 0, 10000, 24, 11, 1, 0, 0, 0, 0, 0, 0, 0 },
-		.ldt = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
-		.gdt = { 0, 0 },
-		.idt = { 0, 0 },
-		.cr0 = 0x37,
-		.cr3 = 0,
-		.cr4 = 0,
-		.efer = 0,
-		.apic_base = 0,
-		.interrupt_bitmap = { 0 },
-	};
-
-	kvm_set_regs(kvm, 0, &regs);
-	kvm_set_sregs(kvm, 0, &sregs);
-}
-
-static void init_vcpu(int n)
-{
-	sigemptyset(&ipi_sigmask);
-	sigaddset(&ipi_sigmask, IPI_SIGNAL);
-	sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL);
-	sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask);
-	vcpus[n].tid = gettid();
-	vcpu = n;
-	kvm_set_signal_mask(kvm, n, &kernel_sigmask);
-	sem_post(&init_sem);
-}
-
-static void *do_create_vcpu(void *_n)
-{
-	int n = (long)_n;
-	struct kvm_regs regs;
-
-	kvm_create_vcpu(kvm, n);
-	init_vcpu(n);
-	sem_wait(&vcpus[n].sipi_sem);
-	kvm_get_regs(kvm, n, &regs);
-	regs.rip = apic_sipi_addr;
-	kvm_set_regs(kvm, n, &regs);
-	kvm_run(kvm, n);
-	return NULL;
-}
-
-static void start_vcpu(int n)
-{
-	pthread_t thread;
-
-	sem_init(&vcpus[n].sipi_sem, 0, 0);
-	pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n);
-}
-
-static void usage(const char *progname)
-{
-	fprintf(stderr,
-"Usage: %s [OPTIONS] [bootstrap] flatfile\n"
-"KVM test harness.\n"
-"\n"
-"  -s, --smp=NUM          create a VM with NUM virtual CPUs\n"
-"  -p, --protected-mode   start VM in protected mode\n"
-"  -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine.  A suffix\n"
-"                         can be used to change the unit (default: `M')\n"
-"  -h, --help             display this help screen and exit\n"
-"\n"
-"Report bugs to <kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>.\n"
-		, progname);
-}
-
-static void sig_ignore(int sig)
-{
-	write(1, "boo\n", 4);
-}
-
-int main(int argc, char **argv)
-{
-	void *vm_mem;
-	int i;
-	const char *sopts = "s:phm:";
-	struct option lopts[] = {
-		{ "smp", 1, 0, 's' },
-		{ "protected-mode", 0, 0, 'p' },
-		{ "memory", 1, 0, 'm' },
-		{ "help", 0, 0, 'h' },
-		{ 0 },
-	};
-	int opt_ind, ch;
-	bool enter_protected_mode = false;
-	int nb_args;
-	char *endptr;
-
-	while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
-		switch (ch) {
-		case 's':
-			ncpus = atoi(optarg);
-			break;
-		case 'p':
-			enter_protected_mode = true;
-			break;
-		case 'm':
-			memory_size = strtoull(optarg, &endptr, 0);
-			switch (*endptr) {
-			case 'G': case 'g':
-				memory_size <<= 30;
-				break;
-			case '\0':
-			case 'M': case 'm':
-				memory_size <<= 20;
-				break;
-			case 'K': case 'k':
-				memory_size <<= 10;
-				break;
-			default:
-				fprintf(stderr,
-					"Unrecongized memory suffix: %c\n",
-					*endptr);
-				exit(1);
-			}
-			if (memory_size == 0) {
-				fprintf(stderr,
-					"Invalid memory size: 0\n");
-				exit(1);
-			}
-			break;
-		case 'h':
-			usage(argv[0]);
-			exit(0);
-		case '?':
-		default:
-			fprintf(stderr,
-				"Try `%s --help' for more information.\n",
-				argv[0]);
-			exit(1);
-		}
-	}
-
-	nb_args = argc - optind;
-	if (nb_args < 1 || nb_args > 2) {
-		fprintf(stderr,
-			"Incorrect number of arguments.\n"
-			"Try `%s --help' for more information.\n",
-			argv[0]);
-		exit(1);
-	}
-
-	signal(IPI_SIGNAL, sig_ignore);
-
-	vcpus = calloc(ncpus, sizeof *vcpus);
-	if (!vcpus) {
-		fprintf(stderr, "calloc failed\n");
-		return 1;
-	}
-
-	kvm = kvm_init(&test_callbacks, 0);
-	if (!kvm) {
-		fprintf(stderr, "kvm_init failed\n");
-		return 1;
-	}
-	if (kvm_create(kvm, memory_size, &vm_mem) < 0) {
-		kvm_finalize(kvm);
-		fprintf(stderr, "kvm_create failed\n");
-		return 1;
-	}
-
-	if (enter_protected_mode)
-		enter_32(kvm);
-	else
-		load_file(vm_mem + 0xf0000, argv[optind]);
-
-	if (nb_args > 1)
-		load_file(vm_mem + 0x100000, argv[optind + 1]);
-
-	apic_init();
-	misc_init();
-
-	sem_init(&init_sem, 0, 0);
-	init_vcpu(0);
-	for (i = 1; i < ncpus; ++i)
-		start_vcpu(i);
-	for (i = 0; i < ncpus; ++i)
-		sem_wait(&init_sem);
-
-	kvm_run(kvm, 0);
-
-	return 0;
-}



-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2007-10-18 20:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-18 20:10 [PATCH 2/3] Split kvmctl for architectures Jerone Young
2007-10-18 20:28 ` Anthony Liguori
     [not found]   ` <4717C1E9.1050501-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-10-18 20:37     ` Jerone Young
2007-10-18 20:40       ` [kvm-ppc-devel] " Hollis Blanchard
2007-10-18 20:47         ` Jerone Young
2007-10-18 20:47 ` Izik Eidus
     [not found]   ` <4717C652.2060608-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-10-18 20:59     ` Jerone Young

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox