Merge branch 'stable-0.12-upstream' into stable-0.12

* stable-0.12-upstream: (7 commits)
  Don't load options roms intended to be loaded by the bios in qemu
  USB: Improve usbdevice error messages
  cpu-all.h: fix cpu_get_real_ticks() #ifdef
  alpha: fix compile
  user_only: compile everything with -fpie
  fdc/sparc32: don't hang on detection under OBP
  scsi-disk: Inquiry with allocation length of CDB < 36 (v4)

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
diff --git a/.gitignore b/.gitignore
index cdd6aad..bbd4d17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,4 +48,5 @@
 pc-bios/vgabios-pq/status
 pc-bios/optionrom/multiboot.bin
 pc-bios/optionrom/multiboot.raw
+pc-bios/optionrom/extboot.bin
 .stgit-*
diff --git a/Makefile b/Makefile
index c1fa08c..8e3498b 100644
--- a/Makefile
+++ b/Makefile
@@ -63,6 +63,18 @@
 
 SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
 
+ifeq ($(KVM_KMOD),yes)
+
+.PHONEY: kvm-kmod
+
+all: kvm-kmod
+
+kvm-kmod:
+	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" )
+
+
+endif
+
 subdir-%: $(GENERATED_HEADERS)
 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 
@@ -94,6 +106,7 @@
 block-obj-y += nbd.o block.o aio.o aes.o osdep.o
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
+block-obj-$(CONFIG_POSIX) += compatfd.o
 
 block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
@@ -283,6 +296,8 @@
 pxe-rtl8139.bin pxe-virtio.bin \
 bamboo.dtb petalogix-s3adsp1800.dtb \
 multiboot.bin linuxboot.bin
+BLOBS += extboot.bin
+BLOBS += vapic.bin
 else
 BLOBS=
 endif
@@ -305,7 +320,12 @@
 ifneq ($(BLOBS),)
 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
 	set -e; for x in $(BLOBS); do \
+	    if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+	    fi \
+	    ; if [ -f pc-bios/optionrom/$$x ];then \
+		$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \
+	    fi \
 	done
 endif
 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
@@ -315,6 +335,9 @@
 	for d in $(TARGET_DIRS); do \
 	$(MAKE) -C $$d $@ || exit 1 ; \
         done
+ifeq ($(KVM_KMOD),yes)
+	$(MAKE) -C kvm/kernel $@
+endif
 
 # various test targets
 test speed: all
@@ -435,6 +458,7 @@
 	$(datadir)/pxe-rtl8139.bin \
 	$(datadir)/pxe-pcnet.bin \
 	$(datadir)/pxe-e1000.bin \
+	$(datadir)/extboot.bin \
 	$(docdir)/qemu-doc.html \
 	$(docdir)/qemu-tech.html \
 	$(mandir)/man1/qemu.1 \
diff --git a/Makefile.hw b/Makefile.hw
index bd252f5..6f4dbc4 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -25,7 +25,9 @@
 # PCI watchdog devices
 obj-y += wdt_i6300esb.o
 
-obj-y += msix.o
+# MSI-X depends on kvm for interrupt injection,
+# so moved it from Makefile.hw to Makefile.target for now
+# obj-y += msix.o
 
 # PCI network cards
 obj-y += ne2000.o
diff --git a/Makefile.target b/Makefile.target
index 7c1f30c..6037fed 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -30,6 +30,8 @@
 
 kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
 
+CFLAGS += $(KVM_CFLAGS)
+
 config-target.h: config-target.h-timestamp
 config-target.h-timestamp: config-target.mak
 
@@ -40,12 +42,18 @@
 
 #########################################################
 # cpu emulator library
-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
-libobj-y += tcg/tcg.o
+libobj-y = exec.o cpu-exec.o
+libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
+libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
+libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
 libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
 libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
 libobj-y += op_helper.o helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
+
+libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
+libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
+
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 libobj-$(TARGET_ALPHA) += alpha_palcode.o
 
@@ -82,6 +90,8 @@
 # cpu_signal_handler() in cpu-exec.c.
 signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 
+qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+
 #########################################################
 # Linux user emulator target
 
@@ -158,6 +168,10 @@
 # need to fix this properly
 obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
+# MSI-X depends on kvm for interrupt injection,
+# so moved it from Makefile.hw to Makefile.target for now
+obj-y += msix.o
+
 obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 LIBS+=-lz
 
@@ -194,12 +208,25 @@
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
+obj-i386-y += extboot.o
 obj-i386-y += ne2000-isa.o
+obj-i386-y += testdev.o
+
+obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
+obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
+
+# Hardware support
+obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
+obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
+obj-ia64-y += usb-uhci.o
+obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
 
 # shared objects
 obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
 obj-ppc-y += ide/cmd646.o
 obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o
+obj-ppc-y += cirrus_vga.o
 # PREP target
 obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
 obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o
@@ -295,6 +322,11 @@
 
 obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 
+ifeq ($(TARGET_ARCH), ia64)
+firmware.o: firmware.c
+	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+endif
+
 main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 5a6a22b..6dcc651 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -27,6 +27,8 @@
 #include "qemu-log.h"
 #include "block_int.h"
 #include "module.h"
+#include "compatfd.h"
+#include <assert.h>
 #include "block/raw-posix-aio.h"
 
 #ifdef CONFIG_COCOA
diff --git a/cache-utils.h b/cache-utils.h
index b45fde4..e4f27ef 100644
--- a/cache-utils.h
+++ b/cache-utils.h
@@ -34,7 +34,28 @@
     asm volatile ("isync" : : : "memory");
 }
 
+/*
+ * Is this correct for PPC?
+ */
+static inline void dma_flush_range(unsigned long start, unsigned long stop)
+{
+}
+
+#elif defined(__ia64__)
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    while (start < stop) {
+	asm volatile ("fc %0" :: "r"(start));
+	start += 32;
+    }
+    asm volatile (";;sync.i;;srlz.i;;");
+}
+#define dma_flush_range(start, end) flush_icache_range(start, end)
+#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
 #else
+static inline void dma_flush_range(unsigned long start, unsigned long stop)
+{
+}
 #define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
 #endif
 
diff --git a/compat/sys/eventfd.h b/compat/sys/eventfd.h
new file mode 100644
index 0000000..f55d96a
--- /dev/null
+++ b/compat/sys/eventfd.h
@@ -0,0 +1,13 @@
+#ifndef _COMPAT_SYS_EVENTFD
+#define _COMPAT_SYS_EVENTFD
+
+#include <unistd.h>
+#include <syscall.h>
+
+
+static inline int eventfd (int count, int flags)
+{
+    return syscall(SYS_eventfd, count, flags);
+}
+
+#endif
diff --git a/compatfd.c b/compatfd.c
new file mode 100644
index 0000000..4a00d95
--- /dev/null
+++ b/compatfd.c
@@ -0,0 +1,143 @@
+/*
+ * signalfd/eventfd compatibility
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "compatfd.h"
+
+#include <sys/syscall.h>
+#include <pthread.h>
+
+struct sigfd_compat_info
+{
+    sigset_t mask;
+    int fd;
+};
+
+static void *sigwait_compat(void *opaque)
+{
+    struct sigfd_compat_info *info = opaque;
+    int err;
+    sigset_t all;
+
+    sigfillset(&all);
+    sigprocmask(SIG_BLOCK, &all, NULL);
+
+    do {
+        siginfo_t siginfo;
+
+        err = sigwaitinfo(&info->mask, &siginfo);
+        if (err == -1 && errno == EINTR) {
+            err = 0;
+            continue;
+        }
+
+        if (err > 0) {
+            char buffer[128];
+            size_t offset = 0;
+
+            memcpy(buffer, &err, sizeof(err));
+            while (offset < sizeof(buffer)) {
+                ssize_t len;
+
+                len = write(info->fd, buffer + offset,
+                            sizeof(buffer) - offset);
+                if (len == -1 && errno == EINTR)
+                    continue;
+
+                if (len <= 0) {
+                    err = -1;
+                    break;
+                }
+
+                offset += len;
+            }
+        }
+    } while (err >= 0);
+
+    return NULL;
+}
+
+static int qemu_signalfd_compat(const sigset_t *mask)
+{
+    pthread_attr_t attr;
+    pthread_t tid;
+    struct sigfd_compat_info *info;
+    int fds[2];
+
+    info = malloc(sizeof(*info));
+    if (info == NULL) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    if (pipe(fds) == -1) {
+        free(info);
+        return -1;
+    }
+
+    qemu_set_cloexec(fds[0]);
+    qemu_set_cloexec(fds[1]);
+
+    memcpy(&info->mask, mask, sizeof(*mask));
+    info->fd = fds[1];
+
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    pthread_create(&tid, &attr, sigwait_compat, info);
+
+    pthread_attr_destroy(&attr);
+
+    return fds[0];
+}
+
+int qemu_signalfd(const sigset_t *mask)
+{
+#if defined(CONFIG_SIGNALFD)
+    int ret;
+
+    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
+    if (ret != -1) {
+        qemu_set_cloexec(ret);
+        return ret;
+    }
+#endif
+
+    return qemu_signalfd_compat(mask);
+}
+
+int qemu_eventfd(int *fds)
+{
+    int ret;
+
+#if defined(CONFIG_EVENTFD)
+    ret = syscall(SYS_eventfd, 0);
+    if (ret >= 0) {
+        fds[0] = ret;
+        qemu_set_cloexec(ret);
+        if ((fds[1] = dup(ret)) == -1) {
+            close(ret);
+            return -1;
+        }
+        qemu_set_cloexec(fds[1]);
+        return 0;
+    }
+#endif
+
+    ret = pipe(fds);
+    if (ret != -1) {
+        qemu_set_cloexec(fds[0]);
+        qemu_set_cloexec(fds[1]);
+    }
+    return ret;
+}
diff --git a/compatfd.h b/compatfd.h
new file mode 100644
index 0000000..06b0b6b
--- /dev/null
+++ b/compatfd.h
@@ -0,0 +1,45 @@
+/*
+ * signalfd/eventfd compatibility
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_COMPATFD_H
+#define QEMU_COMPATFD_H
+
+#include <signal.h>
+
+struct qemu_signalfd_siginfo {
+    uint32_t ssi_signo;   /* Signal number */
+    int32_t  ssi_errno;   /* Error number (unused) */
+    int32_t  ssi_code;    /* Signal code */
+    uint32_t ssi_pid;     /* PID of sender */
+    uint32_t ssi_uid;     /* Real UID of sender */
+    int32_t  ssi_fd;      /* File descriptor (SIGIO) */
+    uint32_t ssi_tid;     /* Kernel timer ID (POSIX timers) */
+    uint32_t ssi_band;    /* Band event (SIGIO) */
+    uint32_t ssi_overrun; /* POSIX timer overrun count */
+    uint32_t ssi_trapno;  /* Trap number that caused signal */
+    int32_t  ssi_status;  /* Exit status or signal (SIGCHLD) */
+    int32_t  ssi_int;     /* Integer sent by sigqueue(2) */
+    uint64_t ssi_ptr;     /* Pointer sent by sigqueue(2) */
+    uint64_t ssi_utime;   /* User CPU time consumed (SIGCHLD) */
+    uint64_t ssi_stime;   /* System CPU time consumed (SIGCHLD) */
+    uint64_t ssi_addr;    /* Address that generated signal
+                             (for hardware-generated signals) */
+    uint8_t  pad[48];     /* Pad size to 128 bytes (allow for
+                             additional fields in the future) */
+};
+
+int qemu_signalfd(const sigset_t *mask);
+
+int qemu_eventfd(int *fds);
+
+#endif
diff --git a/configure b/configure
index 5f463b0..88ba002 100755
--- a/configure
+++ b/configure
@@ -160,7 +160,7 @@
   cpu=`uname -m`
 fi
 
-target_list=""
+target_list="x86_64-softmmu"
 case "$cpu" in
   alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
     cpu="$cpu"
@@ -197,6 +197,16 @@
   ;;
 esac
 
+kvm_version() {
+    local fname="$(dirname "$0")/KVM_VERSION"
+
+    if test -f "$fname"; then
+        cat "$fname"
+    else
+        echo "qemu-kvm-devel"
+    fi
+}
+
 # Default value for a variable defining feature "foo".
 #  * foo="no"  feature will only be used if --enable-foo arg is given
 #  * foo=""    feature will be searched for, and if found, will be used
@@ -250,10 +260,15 @@
 uname_release=""
 io_thread="no"
 mixemu="no"
+kvm_trace="no"
+kvm_cap_pit=""
+kvm_cap_device_assignment=""
 kerneldir=""
 aix="no"
 blobs="yes"
-pkgversion=""
+pkgversion=" ($(kvm_version))"
+cpu_emulation="yes"
+kvm_kmod="no"
 check_utests="no"
 user_pie="no"
 zero_malloc=""
@@ -389,6 +404,13 @@
   if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
     audio_possible_drivers="$audio_possible_drivers fmod"
   fi
+  if [ "$cpu" = "ia64" ] ; then
+     xen="no"
+     target_list="ia64-softmmu"
+     cpu_emulation="no"
+     gdbstub="no"
+     slirp="no"
+  fi
 ;;
 esac
 
@@ -518,6 +540,14 @@
   ;;
   --enable-kvm) kvm="yes"
   ;;
+  --disable-kvm-cap-pit) kvm_cap_pit="no"
+  ;;
+  --enable-kvm-cap-pit) kvm_cap_pit="yes"
+  ;;
+  --disable-kvm-cap-device-assignment) kvm_cap_device_assignment="no"
+  ;;
+  --enable-kvm-cap-device-assignment) kvm_cap_device_assignment="yes"
+  ;;
   --enable-profiler) profiler="yes"
   ;;
   --enable-cocoa)
@@ -595,12 +625,16 @@
   ;;
   --kerneldir=*) kerneldir="$optarg"
   ;;
+  --with-kvm-trace) kvm_trace="yes"
+  ;;
   --with-pkgversion=*) pkgversion=" ($optarg)"
   ;;
   --disable-docs) docs="no"
   ;;
   --enable-docs) docs="yes"
   ;;
+  --disable-cpu-emulation) cpu_emulation="no"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -722,6 +756,10 @@
 echo "  --enable-bluez           enable bluez stack connectivity"
 echo "  --disable-kvm            disable KVM acceleration support"
 echo "  --enable-kvm             enable KVM acceleration support"
+echo "  --disable-cap-kvm-pit    disable KVM pit support"
+echo "  --enable-cap-kvm-pit     enable KVM pit support"
+echo "  --disable-cap-device-assignment    disable KVM device assignment support"
+echo "  --enable-cap-device-assignment     enable KVM device assignment support"
 echo "  --disable-nptl           disable usermode NPTL support"
 echo "  --enable-nptl            enable usermode NPTL support"
 echo "  --enable-system          enable all system emulation targets"
@@ -753,6 +791,8 @@
 echo "  --enable-io-thread       enable IO thread"
 echo "  --disable-blobs          disable installing provided firmware blobs"
 echo "  --kerneldir=PATH         look for kernel includes in PATH"
+echo "  --with-kvm-trace         enable building the KVM module with the kvm trace option"
+echo "  --disable-cpu-emulation  disables use of qemu cpu emulation code"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -1384,8 +1424,22 @@
             kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
       fi
   else
-      kvm_cflags=""
+      case "$cpu" in
+      i386 | x86_64)
+        kvm_arch="x86"
+        ;;
+      ppc)
+        kvm_arch="powerpc"
+        ;;
+      *)
+        kvm_arch="$cpu"
+        ;;
+      esac
+      kvm_cflags="-I$source_path/kvm/include"
+      kvm_cflags="$kvm_cflags -include $source_path/kvm/include/linux/config.h"
+      kvm_cflags="$kvm_cflags -I$source_path/kvm/include/$kvm_arch"
   fi
+  kvm_cflags="$kvm_cflags -idirafter $source_path/compat"
   if compile_prog "$kvm_cflags" "" ; then
     kvm=yes
   else
@@ -1408,6 +1462,75 @@
 fi
 
 ##########################################
+# test for KVM_CAP_PIT
+
+if test "$kvm_cap_pit" != "no" ; then
+  if test "$kvm" = "no" -a "$kvm_cap_pit" = "yes" ; then
+      feature_not_found "kvm_cap_pit (kvm is not enabled)"
+  fi
+  cat > $TMPC <<EOF
+#include <linux/kvm.h>
+#ifndef KVM_CAP_PIT
+#error "kvm no pit capability"
+#endif
+int main(void) { return 0; }
+EOF
+  if compile_prog "$kvm_cflags" ""; then
+    kvm_cap_pit=yes
+  else
+    if test "$kvm_cap_pit" = "yes" ; then
+      feature_not_found "kvm_cap_pit"
+    fi
+    kvm_cap_pit=no
+  fi
+fi
+
+##########################################
+# test for KVM_CAP_DEVICE_ASSIGNMENT
+
+if test "$kvm_cap_device_assignment" != "no" ; then
+  if test "$kvm" = "no" -a "$kvm_cap_device_assignment" = "yes" ; then
+      feature_not_found "kvm_cap_device_assignment (kvm is not enabled)"
+  fi
+  cat > $TMPC <<EOF
+#include <linux/kvm.h>
+#ifndef KVM_CAP_DEVICE_ASSIGNMENT
+#error "kvm no device assignment capability"
+#endif
+int main(void) { return 0; }
+EOF
+  if compile_prog "$kvm_cflags" "" ; then
+    kvm_cap_device_assignment=yes
+  else
+    if test "$kvm_cap_device_assignment" = "yes" ; then
+      feature_not_found "kvm_cap_device_assigment"
+    fi
+    kvm_cap_device_assignment=no
+  fi
+fi
+
+##########################################
+# libpci probe for kvm_cap_device_assignment
+if test $kvm_cap_device_assignment = "yes" ; then
+  cat > $TMPC << EOF
+#include <pci/pci.h>
+#ifndef PCI_VENDOR_ID
+#error NO LIBPCI
+#endif
+int main(void) { struct pci_access a; pci_init(&a); return 0; }
+EOF
+  if compile_prog "" "-lpci -lz" ; then
+    libs_softmmu="-lpci -lz $libs_softmmu"
+  else
+    echo
+    echo "Error: libpci check failed"
+    echo "Disable KVM Device Assignment capability."
+    echo
+    kvm_cap_device_assignment=no
+  fi
+fi
+
+##########################################
 # pthread probe
 PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
 
@@ -1613,6 +1736,21 @@
   splice=yes
 fi
 
+##########################################
+# signalfd probe
+signalfd="no"
+cat > $TMPC << EOF
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <signal.h>
+int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
+EOF
+
+if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+  signalfd=yes
+fi
+
 # check if eventfd is supported
 eventfd=no
 cat > $TMPC << EOF
@@ -1842,6 +1980,20 @@
   binsuffix="/bin"
 fi
 
+if test -f kvm/kernel/configure; then
+    kvm_kmod="yes"
+    kmod_args=""
+    if test -n "$kerneldir"; then
+        kmod_args="--kerneldir=$kerneldir"
+    fi
+    if test "$kvm_trace" = "yes"; then
+        kmod_args="$kmod_args --with-kvm-trace"
+    fi
+    # hope there are no spaces in kmod_args; can't use arrays because of
+    # dash.
+    (cd kvm/kernel; ./configure $kmod_args)
+fi
+
 echo "Install prefix    $prefix"
 echo "BIOS directory    $prefix$datasuffix"
 echo "binary directory  $prefix$binsuffix"
@@ -1885,6 +2037,7 @@
     echo "Target Sparc Arch $sparc_cpu"
 fi
 echo "xen support       $xen"
+echo "CPU emulation     $cpu_emulation"
 echo "brlapi support    $brlapi"
 echo "bluez  support    $bluez"
 echo "Documentation     $docs"
@@ -1898,6 +2051,9 @@
 echo "Linux AIO support $linux_aio"
 echo "Install blobs     $blobs"
 echo "KVM support       $kvm"
+echo "KVM PIT support   $kvm_cap_pit"
+echo "KVM device assig. $kvm_cap_device_assignment"
+echo "KVM trace support $kvm_trace"
 echo "fdt support       $fdt"
 echo "preadv support    $preadv"
 echo "fdatasync         $fdatasync"
@@ -2104,6 +2260,9 @@
 if test "$fdt" = "yes" ; then
   echo "CONFIG_FDT=y" >> $config_host_mak
 fi
+if test "$signalfd" = "yes" ; then
+  echo "CONFIG_SIGNALFD=y" >> $config_host_mak
+fi
 if test "$need_offsetof" = "yes" ; then
   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 fi
@@ -2113,6 +2272,11 @@
 if test "$fdatasync" = "yes" ; then
   echo "CONFIG_FDATASYNC=y" >> $config_host_mak
 fi
+if test $cpu_emulation = "yes"; then
+  echo "CONFIG_CPU_EMULATION=y" >> $config_host_mak
+else
+  echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak
+fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
@@ -2138,6 +2302,8 @@
 ;;
 esac
 
+echo "KVM_KMOD=$kvm_kmod" >> $config_host_mak
+
 tools=
 if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
@@ -2288,6 +2454,9 @@
     TARGET_BASE_ARCH=i386
     target_phys_bits=64
   ;;
+  ia64)
+    target_phys_bits=64
+  ;;
   alpha)
     target_phys_bits=64
   ;;
@@ -2418,6 +2587,12 @@
       \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then
       echo "CONFIG_KVM=y" >> $config_target_mak
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_target_mak
+      if test $kvm_cap_pit = "yes" ; then
+        echo "CONFIG_KVM_PIT=y" >> $config_target_mak
+      fi
+      if test $kvm_cap_device_assignment = "yes" ; then
+        echo "CONFIG_KVM_DEVICE_ASSIGNMENT=y" >> $config_target_mak
+      fi
     fi
 esac
 echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
@@ -2626,7 +2801,7 @@
 fi
 
 # temporary config to build submodules
-for rom in seabios vgabios ; do
+for rom in seabios vgabios; do
     config_mak=roms/$rom/config.mak
     echo "# Automatically generated by configure - do not modify" >> $config_mak
     echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
diff --git a/cpu-all.h b/cpu-all.h
index 57b69f8..8ed76c7 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -849,6 +849,7 @@
 extern uint8_t *phys_ram_dirty;
 extern ram_addr_t ram_size;
 extern ram_addr_t last_ram_offset;
+extern uint8_t *bios_mem;
 
 /* physical memory access */
 
diff --git a/cpu-common.h b/cpu-common.h
index 6302372..5e59564 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -34,6 +34,7 @@
 /* This should only be used for ram local to a device.  */
 void *qemu_get_ram_ptr(ram_addr_t addr);
 /* This should not be used by devices.  */
+int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
 ram_addr_t qemu_ram_addr_from_host(void *ptr);
 
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
diff --git a/cpu-defs.h b/cpu-defs.h
index 95068b5..cf502e9 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -27,6 +27,7 @@
 #include <setjmp.h>
 #include <inttypes.h>
 #include <signal.h>
+#include <pthread.h>
 #include "osdep.h"
 #include "qemu-queue.h"
 #include "targphys.h"
@@ -134,6 +135,16 @@
     QTAILQ_ENTRY(CPUWatchpoint) entry;
 } CPUWatchpoint;
 
+/* forward decleration */
+struct qemu_work_item;
+
+struct KVMCPUState {
+    pthread_t thread;
+    int signalled;
+    struct qemu_work_item *queued_work_first, *queued_work_last;
+    int regs_modified;
+};
+
 #define CPU_TEMP_BUF_NLONGS 128
 #define CPU_COMMON                                                      \
     struct TranslationBlock *current_tb; /* currently executing TB  */  \
@@ -146,8 +157,6 @@
     target_ulong mem_io_vaddr; /* target virtual addr at which the      \
                                      memory was accessed */             \
     uint32_t halted; /* Nonzero if the CPU is in suspend state */       \
-    uint32_t stop;   /* Stop request */                                 \
-    uint32_t stopped; /* Artificially stopped */                        \
     uint32_t interrupt_request;                                         \
     volatile sig_atomic_t exit_request;                                 \
     /* The meaning of the MMU modes is defined in the target code. */   \
@@ -188,6 +197,7 @@
     int nr_cores;  /* number of cores within this CPU package */        \
     int nr_threads;/* number of threads within this CPU */              \
     int running; /* Nonzero if cpu is currently running(usermode).  */  \
+    int thread_id;							\
     /* user data */                                                     \
     void *opaque;                                                       \
                                                                         \
@@ -197,6 +207,9 @@
     const char *cpu_model_str;                                          \
     struct KVMState *kvm_state;                                         \
     struct kvm_run *kvm_run;                                            \
-    int kvm_fd;
+    int kvm_fd;                                                         \
+    uint32_t stop;   /* Stop request */                                 \
+    uint32_t stopped; /* Artificially stopped */                        \
+    struct KVMCPUState kvm_cpu_state;
 
 #endif
diff --git a/cpu-exec.c b/cpu-exec.c
index af4595b..0f085ea 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -19,7 +19,9 @@
 #include "config.h"
 #include "exec.h"
 #include "disas.h"
+#if !defined(TARGET_IA64)
 #include "tcg.h"
+#endif
 #include "kvm.h"
 
 #if !defined(CONFIG_SOFTMMU)
@@ -38,6 +40,8 @@
 #endif
 #endif
 
+#include "qemu-kvm.h"
+
 #if defined(__sparc__) && !defined(CONFIG_SOLARIS)
 // Work around ugly bugs in glibc that mangle global register contents
 #undef env
@@ -250,6 +254,7 @@
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_IA64)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -317,6 +322,8 @@
                     do_interrupt(env);
 #elif defined(TARGET_M68K)
                     do_interrupt(0);
+#elif defined(TARGET_IA64)
+		    do_interrupt(env);
 #endif
 #endif
                 }
@@ -672,6 +679,7 @@
 #elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
+#elif defined(TARGET_IA64)
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
diff --git a/cutils.c b/cutils.c
index 2365e68..be99b21 100644
--- a/cutils.c
+++ b/cutils.c
@@ -218,6 +218,11 @@
     }
 }
 
+/*
+ * No dma flushing needed here, as the aio code will call dma_bdrv_cb()
+ * on completion as well, which will result in a call to
+ * dma_bdrv_unmap() which will do the flushing ....
+ */
 void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
 {
     const uint8_t *p = (const uint8_t *)buf;
diff --git a/dma-helpers.c b/dma-helpers.c
index 712ed89..d4fc077 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -160,6 +160,10 @@
     dbs->is_write = is_write;
     dbs->bh = NULL;
     qemu_iovec_init(&dbs->iov, sg->nsg);
+    /*
+     * DMA flushing is handled in dma_bdrv_cb() calling dma_bdrv_unmap()
+     * so we don't need to do that here.
+     */
     dma_bdrv_cb(dbs, 0);
     if (!dbs->acb) {
         qemu_aio_release(dbs);
diff --git a/exec.c b/exec.c
index 7b7fb5b..8f873ab 100644
--- a/exec.c
+++ b/exec.c
@@ -34,7 +34,13 @@
 #include "cpu.h"
 #include "exec-all.h"
 #include "qemu-common.h"
+#include "cache-utils.h"
+
+#if !defined(TARGET_IA64)
 #include "tcg.h"
+#endif
+#include "qemu-kvm.h"
+
 #include "hw/hw.h"
 #include "osdep.h"
 #include "kvm.h"
@@ -74,6 +80,8 @@
 #define TARGET_PHYS_ADDR_SPACE_BITS 42
 #elif defined(TARGET_I386)
 #define TARGET_PHYS_ADDR_SPACE_BITS 36
+#elif defined(TARGET_IA64)
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
 #else
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
 #endif
@@ -111,6 +119,7 @@
 #if !defined(CONFIG_USER_ONLY)
 int phys_ram_fd;
 uint8_t *phys_ram_dirty;
+uint8_t *bios_mem;
 static int in_migration;
 
 typedef struct RAMBlock {
@@ -412,6 +421,9 @@
 
 static void code_gen_alloc(unsigned long tb_size)
 {
+    if (kvm_enabled())
+        return;
+
 #ifdef USE_STATIC_CODE_GEN_BUFFER
     code_gen_buffer = static_code_gen_buffer;
     code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
@@ -588,6 +600,11 @@
     env->numa_node = 0;
     QTAILQ_INIT(&env->breakpoints);
     QTAILQ_INIT(&env->watchpoints);
+#ifdef __WIN32
+    env->thread_id = GetCurrentProcessId();
+#else
+    env->thread_id = getpid();
+#endif
     *penv = env;
 #if defined(CONFIG_USER_ONLY)
     cpu_list_unlock();
@@ -1553,6 +1570,8 @@
 
     old_mask = env->interrupt_request;
     env->interrupt_request |= mask;
+    if (kvm_enabled() && !kvm_irqchip_in_kernel())
+	kvm_update_interrupt_request(env);
 
 #ifndef CONFIG_USER_ONLY
     /*
@@ -1880,7 +1899,6 @@
 
 int cpu_physical_memory_set_dirty_tracking(int enable)
 {
-    in_migration = enable;
     if (kvm_enabled()) {
         return kvm_set_migration_log(enable);
     }
@@ -2404,6 +2422,113 @@
         kvm_uncoalesce_mmio_region(addr, size);
 }
 
+#ifdef __linux__
+
+#include <sys/vfs.h>
+
+#define HUGETLBFS_MAGIC       0x958458f6
+
+static long gethugepagesize(const char *path)
+{
+    struct statfs fs;
+    int ret;
+
+    do {
+	    ret = statfs(path, &fs);
+    } while (ret != 0 && errno == EINTR);
+
+    if (ret != 0) {
+	    perror("statfs");
+	    return 0;
+    }
+
+    if (fs.f_type != HUGETLBFS_MAGIC)
+	    fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
+
+    return fs.f_bsize;
+}
+
+static void *file_ram_alloc(ram_addr_t memory, const char *path)
+{
+    char *filename;
+    void *area;
+    int fd;
+#ifdef MAP_POPULATE
+    int flags;
+#endif
+    unsigned long hpagesize;
+    extern int mem_prealloc;
+
+    if (!path) {
+        return NULL;
+    }
+
+    hpagesize = gethugepagesize(path);
+    if (!hpagesize) {
+	return NULL;
+    }
+
+    if (memory < hpagesize) {
+        return NULL;
+    }
+
+    if (kvm_enabled() && !kvm_has_sync_mmu()) {
+        fprintf(stderr, "host lacks mmu notifiers, disabling --mem-path\n");
+        return NULL;
+    }
+
+    if (asprintf(&filename, "%s/kvm.XXXXXX", path) == -1) {
+	return NULL;
+    }
+
+    fd = mkstemp(filename);
+    if (fd < 0) {
+	perror("mkstemp");
+	free(filename);
+	return NULL;
+    }
+    unlink(filename);
+    free(filename);
+
+    memory = (memory+hpagesize-1) & ~(hpagesize-1);
+
+    /*
+     * ftruncate is not supported by hugetlbfs in older
+     * hosts, so don't bother checking for errors.
+     * If anything goes wrong with it under other filesystems,
+     * mmap will fail.
+     */
+    ftruncate(fd, memory);
+
+#ifdef MAP_POPULATE
+    /* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case
+     * MAP_PRIVATE is requested.  For mem_prealloc we mmap as MAP_SHARED
+     * to sidestep this quirk.
+     */
+    flags = mem_prealloc ? MAP_POPULATE|MAP_SHARED : MAP_PRIVATE;
+    area = mmap(0, memory, PROT_READ|PROT_WRITE, flags, fd, 0);
+#else
+    area = mmap(0, memory, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+    if (area == MAP_FAILED) {
+	perror("alloc_mem_area: can't mmap hugetlbfs pages");
+	close(fd);
+	return (NULL);
+    }
+    return area;
+}
+
+#else
+
+static void *file_ram_alloc(ram_addr_t memory, const char *path)
+{
+    return NULL;
+}
+
+#endif
+
+extern const char *mem_path;
+
 ram_addr_t qemu_ram_alloc(ram_addr_t size)
 {
     RAMBlock *new_block;
@@ -2411,16 +2536,20 @@
     size = TARGET_PAGE_ALIGN(size);
     new_block = qemu_malloc(sizeof(*new_block));
 
+    new_block->host = file_ram_alloc(size, mem_path);
+    if (!new_block->host) {
 #if defined(TARGET_S390X) && defined(CONFIG_KVM)
     /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
-    new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE,
-                           MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+        new_block->host = mmap((void*)0x1000000, size,
+                               PROT_EXEC|PROT_READ|PROT_WRITE,
+                               MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 #else
-    new_block->host = qemu_vmalloc(size);
+        new_block->host = qemu_vmalloc(size);
 #endif
 #ifdef MADV_MERGEABLE
-    madvise(new_block->host, size, MADV_MERGEABLE);
+        madvise(new_block->host, size, MADV_MERGEABLE);
 #endif
+    }
     new_block->offset = last_ram_offset;
     new_block->length = size;
 
@@ -2482,9 +2611,7 @@
     return block->host + (addr - block->offset);
 }
 
-/* Some of the softmmu routines need to translate from a host pointer
-   (typically a TLB entry) back to a ram offset.  */
-ram_addr_t qemu_ram_addr_from_host(void *ptr)
+int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
 {
     RAMBlock *prev;
     RAMBlock **prevp;
@@ -2501,11 +2628,23 @@
         prev = block;
         block = block->next;
     }
-    if (!block) {
+    if (!block)
+        return -1;
+    *ram_addr = block->offset + (host - block->host);
+    return 0;
+}
+
+/* Some of the softmmu routines need to translate from a host pointer
+   (typically a TLB entry) back to a ram offset.  */
+ram_addr_t qemu_ram_addr_from_host(void *ptr)
+{
+    ram_addr_t ram_addr;
+
+    if (do_qemu_ram_addr_from_host(ptr, &ram_addr)) {
         fprintf(stderr, "Bad ram pointer %p\n", ptr);
         abort();
     }
-    return block->offset + (host - block->host);
+    return ram_addr;
 }
 
 static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -3091,6 +3230,11 @@
                     phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
                         (0xff & ~CODE_DIRTY_FLAG);
                 }
+		/* qemu doesn't execute guest code directly, but kvm does
+		   therefore flush instruction caches */
+		if (kvm_enabled())
+		    flush_icache_range((unsigned long)ptr,
+				       ((unsigned long)ptr)+l);
             }
         } else {
             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
@@ -3283,6 +3427,8 @@
 void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
                                int is_write, target_phys_addr_t access_len)
 {
+    unsigned long flush_len = (unsigned long)access_len;
+
     if (buffer != bounce.buffer) {
         if (is_write) {
             ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
@@ -3300,7 +3446,9 @@
                 }
                 addr1 += l;
                 access_len -= l;
-            }
+	    }
+	    dma_flush_range((unsigned long)buffer,
+			    (unsigned long)buffer + flush_len);
         }
         return;
     }
@@ -3668,7 +3816,9 @@
     cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count);
     cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
+#ifdef CONFIG_PROFILER
     tcg_dump_info(f, cpu_fprintf);
+#endif
 }
 
 #if !defined(CONFIG_USER_ONLY)
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index 8d64f4e..cb0e97b 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -5,6 +5,7 @@
 #if defined(CONFIG_SOLARIS)
 #include <fenv.h>
 #endif
+#include "config-host.h"
 
 void set_float_rounding_mode(int val STATUS_PARAM)
 {
diff --git a/gdbstub.c b/gdbstub.c
index 5320b1c..0a738bf 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -34,6 +34,7 @@
 #include "sysemu.h"
 #include "gdbstub.h"
 #endif
+#include "qemu-kvm.h"
 
 #define MAX_PACKET_LENGTH 4096
 
diff --git a/hw/acpi.c b/hw/acpi.c
index 9a69e7d..ec049a2 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -23,6 +23,8 @@
 #include "i2c.h"
 #include "smbus.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
+#include "string.h"
 
 //#define DEBUG
 
@@ -521,6 +523,13 @@
 
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
 
+#if defined(TARGET_IA64)
+    pci_conf[0x40] = 0x41; /* PM io base read only bit */
+    pci_conf[0x41] = 0x1f;
+    pm_write_config(s, 0x80, 0x01, 1); /*Set default pm_io_base 0x1f40*/
+    s->pmcntrl = SCI_EN;
+#endif
+
     register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
     register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
 
@@ -559,12 +568,14 @@
 }
 
 #define GPE_BASE 0xafe0
+#define PROC_BASE 0xaf00
 #define PCI_BASE 0xae00
 #define PCI_EJ_BASE 0xae08
 
 struct gpe_regs {
     uint16_t sts; /* status */
     uint16_t en;  /* enabled */
+    uint8_t cpus_sts[32];
 };
 
 struct pci_status {
@@ -587,6 +598,10 @@
     uint32_t val = 0;
     struct gpe_regs *g = opaque;
     switch (addr) {
+        case PROC_BASE ... PROC_BASE+31:
+            val = g->cpus_sts[addr - PROC_BASE];
+            break;
+
         case GPE_BASE:
         case GPE_BASE + 1:
             val = gpe_read_val(g->sts, addr);
@@ -629,6 +644,10 @@
 {
     struct gpe_regs *g = opaque;
     switch (addr) {
+        case PROC_BASE ... PROC_BASE + 31:
+            /* don't allow to change cpus_sts from inside a guest */
+            break;
+
         case GPE_BASE:
         case GPE_BASE + 1:
             gpe_reset_val(&g->sts, addr, val);
@@ -712,22 +731,72 @@
 #endif
 }
 
+static const char *model;
+
 static int piix4_device_hotplug(PCIDevice *dev, int state);
 
-void piix4_acpi_system_hot_add_init(PCIBus *bus)
+void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *cpu_model)
 {
+    int i = 0, cpus = smp_cpus;
+
+    while (cpus > 0) {
+        gpe.cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff;
+        cpus -= 8;
+    }
     register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe);
     register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, &gpe);
 
+    register_ioport_write(PROC_BASE, 32, 1, gpe_writeb, &gpe);
+    register_ioport_read(PROC_BASE, 32, 1,  gpe_readb, &gpe);
+
     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status);
     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, &pci0_status);
 
     register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
     register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, bus);
 
+    model = cpu_model;
+
     pci_bus_hotplug(bus, piix4_device_hotplug);
 }
 
+#if defined(TARGET_I386)
+static void enable_processor(struct gpe_regs *g, int cpu)
+{
+    g->sts |= 4;
+    g->cpus_sts[cpu/8] |= (1 << (cpu%8));
+}
+
+static void disable_processor(struct gpe_regs *g, int cpu)
+{
+    g->sts |= 4;
+    g->cpus_sts[cpu/8] &= ~(1 << (cpu%8));
+}
+
+void qemu_system_cpu_hot_add(int cpu, int state)
+{
+    CPUState *env;
+
+    if (state && !qemu_get_cpu(cpu)) {
+        env = pc_new_cpu(model);
+        if (!env) {
+            fprintf(stderr, "cpu %d creation failed\n", cpu);
+            return;
+        }
+        env->cpuid_apic_id = cpu;
+    }
+
+    if (state)
+        enable_processor(&gpe, cpu);
+    else
+        disable_processor(&gpe, cpu);
+    if (gpe.en & 4) {
+        qemu_set_irq(pm_state->irq, 1);
+        qemu_set_irq(pm_state->irq, 0);
+    }
+}
+#endif
+
 static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot)
 {
     g->sts |= 2;
diff --git a/hw/apic.c b/hw/apic.c
index 87e7dc0..ae805dc 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -24,6 +24,8 @@
 #include "host-utils.h"
 #include "kvm.h"
 
+#include "qemu-kvm.h"
+
 //#define DEBUG_APIC
 
 /* APIC Local Vector Table */
@@ -299,8 +301,11 @@
 #endif
     if (!s)
         return;
-    s->apicbase = (val & 0xfffff000) |
-        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
+    if (kvm_enabled() && kvm_irqchip_in_kernel())
+        s->apicbase = val;
+    else
+        s->apicbase = (val & 0xfffff000) |
+            (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
     /* if disabled, cannot be enabled again */
     if (!(val & MSR_IA32_APICBASE_ENABLE)) {
         s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
@@ -393,6 +398,11 @@
     return apic_irq_delivered;
 }
 
+void apic_set_irq_delivered(void)
+{
+    apic_irq_delivered = 1;
+}
+
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
 {
     apic_irq_delivered += !get_bit(s->irr, vector_num);
@@ -478,6 +488,7 @@
     if (!s)
         return;
 
+    cpu_synchronize_state(env);
     s->tpr = 0;
     s->spurious_vec = 0xff;
     s->log_dest = 0;
@@ -497,6 +508,13 @@
     s->wait_for_sipi = 1;
 
     env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP);
+#ifdef KVM_CAP_MP_STATE
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        env->mp_state
+            = env->halted ? KVM_MP_STATE_UNINITIALIZED : KVM_MP_STATE_RUNNABLE;
+        kvm_load_mpstate(env);
+    }
+#endif
 }
 
 static void apic_startup(APICState *s, int vector_num)
@@ -864,6 +882,115 @@
     }
 }
 
+#ifdef KVM_CAP_IRQCHIP
+
+static inline uint32_t kapic_reg(struct kvm_lapic_state *kapic, int reg_id)
+{
+    return *((uint32_t *) (kapic->regs + (reg_id << 4)));
+}
+
+static inline void kapic_set_reg(struct kvm_lapic_state *kapic,
+                                 int reg_id, uint32_t val)
+{
+    *((uint32_t *) (kapic->regs + (reg_id << 4))) = val;
+}
+
+static void kvm_kernel_lapic_save_to_user(APICState *s)
+{
+    struct kvm_lapic_state apic;
+    struct kvm_lapic_state *kapic = &apic;
+    int i, v;
+
+    kvm_get_lapic(s->cpu_env, kapic);
+
+    s->id = kapic_reg(kapic, 0x2) >> 24;
+    s->tpr = kapic_reg(kapic, 0x8);
+    s->arb_id = kapic_reg(kapic, 0x9);
+    s->log_dest = kapic_reg(kapic, 0xd) >> 24;
+    s->dest_mode = kapic_reg(kapic, 0xe) >> 28;
+    s->spurious_vec = kapic_reg(kapic, 0xf);
+    for (i = 0; i < 8; i++) {
+        s->isr[i] = kapic_reg(kapic, 0x10 + i);
+        s->tmr[i] = kapic_reg(kapic, 0x18 + i);
+        s->irr[i] = kapic_reg(kapic, 0x20 + i);
+    }
+    s->esr = kapic_reg(kapic, 0x28);
+    s->icr[0] = kapic_reg(kapic, 0x30);
+    s->icr[1] = kapic_reg(kapic, 0x31);
+    for (i = 0; i < APIC_LVT_NB; i++)
+	s->lvt[i] = kapic_reg(kapic, 0x32 + i);
+    s->initial_count = kapic_reg(kapic, 0x38);
+    s->divide_conf = kapic_reg(kapic, 0x3e);
+
+    v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+    s->count_shift = (v + 1) & 7;
+
+    s->initial_count_load_time = qemu_get_clock(vm_clock);
+    apic_timer_update(s, s->initial_count_load_time);
+}
+
+static void kvm_kernel_lapic_load_from_user(APICState *s)
+{
+    struct kvm_lapic_state apic;
+    struct kvm_lapic_state *klapic = &apic;
+    int i;
+
+    memset(klapic, 0, sizeof apic);
+    kapic_set_reg(klapic, 0x2, s->id << 24);
+    kapic_set_reg(klapic, 0x8, s->tpr);
+    kapic_set_reg(klapic, 0xd, s->log_dest << 24);
+    kapic_set_reg(klapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
+    kapic_set_reg(klapic, 0xf, s->spurious_vec);
+    for (i = 0; i < 8; i++) {
+        kapic_set_reg(klapic, 0x10 + i, s->isr[i]);
+        kapic_set_reg(klapic, 0x18 + i, s->tmr[i]);
+        kapic_set_reg(klapic, 0x20 + i, s->irr[i]);
+    }
+    kapic_set_reg(klapic, 0x28, s->esr);
+    kapic_set_reg(klapic, 0x30, s->icr[0]);
+    kapic_set_reg(klapic, 0x31, s->icr[1]);
+    for (i = 0; i < APIC_LVT_NB; i++)
+        kapic_set_reg(klapic, 0x32 + i, s->lvt[i]);
+    kapic_set_reg(klapic, 0x38, s->initial_count);
+    kapic_set_reg(klapic, 0x3e, s->divide_conf);
+
+    kvm_set_lapic(s->cpu_env, klapic);
+}
+
+#endif
+
+void qemu_kvm_load_lapic(CPUState *env)
+{
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && kvm_vcpu_inited(env) && kvm_irqchip_in_kernel()) {
+        kvm_kernel_lapic_load_from_user(env->apic_state);
+    }
+#endif
+}
+
+static void apic_pre_save(void *opaque)
+{
+#ifdef KVM_CAP_IRQCHIP
+    APICState *s = (void *)opaque;
+
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_lapic_save_to_user(s);
+    }
+#endif
+}
+
+static int apic_post_load(void *opaque, int version_id)
+{
+#ifdef KVM_CAP_IRQCHIP
+    APICState *s = opaque;
+
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_lapic_load_from_user(s);
+    }
+#endif
+    return 0;
+}
+
 /* This function is only used for old state version 1 and 2 */
 static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
 {
@@ -900,6 +1027,9 @@
 
     if (version_id >= 2)
         qemu_get_timer(f, s->timer);
+
+    qemu_kvm_load_lapic(s->cpu_env);
+
     return 0;
 }
 
@@ -930,7 +1060,9 @@
         VMSTATE_INT64(next_time, APICState),
         VMSTATE_TIMER(timer, APICState),
         VMSTATE_END_OF_LIST()
-    }
+    },
+    .pre_save = apic_pre_save,
+    .post_load = apic_post_load,
 };
 
 static void apic_reset(void *opaque)
@@ -955,6 +1087,7 @@
          */
         s->lvt[APIC_LVT_LINT0] = 0x700;
     }
+    qemu_kvm_load_lapic(s->cpu_env);
 }
 
 static CPUReadMemoryFunc * const apic_mem_read[3] = {
@@ -998,6 +1131,11 @@
     vmstate_register(s->idx, &vmstate_apic, s);
     qemu_register_reset(apic_reset, s);
 
+    /* apic_reset must be called before the vcpu threads are initialized and load
+     * registers, in qemu-kvm.
+     */
+    apic_reset(s);
+
     local_apics[s->idx] = s;
     return 0;
 }
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 6fe433d..25c68b1 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -32,6 +32,7 @@
 #include "console.h"
 #include "vga_int.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 #include "loader.h"
 
 /*
@@ -2552,6 +2553,7 @@
 
 static void map_linear_vram(CirrusVGAState *s)
 {
+    vga_dirty_log_stop(&s->vga);
     if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
         s->vga.map_addr = s->vga.lfb_addr;
         s->vga.map_end = s->vga.lfb_end;
@@ -2561,13 +2563,19 @@
     if (!s->vga.map_addr)
         return;
 
+#ifndef TARGET_IA64
     s->vga.lfb_vram_mapped = 0;
 
+    cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
+                                (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_UNASSIGNED);
+    cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
+                                (s->vga.vram_offset + s->cirrus_bank_base[1]) | IO_MEM_UNASSIGNED);
     if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
         && !((s->vga.sr[0x07] & 0x01) == 0)
         && !((s->vga.gr[0x0B] & 0x14) == 0x14)
         && !(s->vga.gr[0x0B] & 0x02)) {
 
+        vga_dirty_log_stop(&s->vga);
         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
                                     (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
         cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
@@ -2579,17 +2587,21 @@
         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
                                      s->vga.vga_io_memory);
     }
+#endif
 
     vga_dirty_log_start(&s->vga);
 }
 
 static void unmap_linear_vram(CirrusVGAState *s)
 {
+    vga_dirty_log_stop(&s->vga);
     if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end)
         s->vga.map_addr = s->vga.map_end = 0;
 
     cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
                                  s->vga.vga_io_memory);
+
+    vga_dirty_log_start(&s->vga);
 }
 
 /* Compute the memory access functions */
@@ -3143,6 +3155,8 @@
 {
     CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
 
+    vga_dirty_log_stop(&s->vga);
+
     /* XXX: add byte swapping apertures */
     cpu_register_physical_memory(addr, s->vga.vram_size,
 				 s->cirrus_linear_io_addr);
@@ -3174,10 +3188,14 @@
     PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d);
     CirrusVGAState *s = &pvs->cirrus_vga;
 
+    vga_dirty_log_stop(&s->vga);
+
     pci_default_write_config(d, address, val, len);
     if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED)
         s->vga.map_addr = 0;
     cirrus_update_memory_access(s);
+
+    vga_dirty_log_start(&s->vga);
 }
 
 static int pci_cirrus_vga_initfn(PCIDevice *dev)
diff --git a/hw/device-assignment.c b/hw/device-assignment.c
new file mode 100644
index 0000000..fb04047
--- /dev/null
+++ b/hw/device-assignment.c
@@ -0,0 +1,1452 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ *
+ *  Assign a PCI device from the host to a guest VM.
+ *
+ *  Adapted for KVM by Qumranet.
+ *
+ *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "qemu-kvm.h"
+#include "hw.h"
+#include "pc.h"
+#include "sysemu.h"
+#include "console.h"
+#include "device-assignment.h"
+#include "loader.h"
+#include <pci/pci.h>
+
+/* From linux/ioport.h */
+#define IORESOURCE_IO       0x00000100  /* Resource type */
+#define IORESOURCE_MEM      0x00000200
+#define IORESOURCE_IRQ      0x00000400
+#define IORESOURCE_DMA      0x00000800
+#define IORESOURCE_PREFETCH 0x00001000  /* No side effects */
+
+/* #define DEVICE_ASSIGNMENT_DEBUG 1 */
+
+#ifdef DEVICE_ASSIGNMENT_DEBUG
+#define DEBUG(fmt, ...)                                       \
+    do {                                                      \
+      fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__);    \
+    } while (0)
+#else
+#define DEBUG(fmt, ...) do { } while(0)
+#endif
+
+static void assigned_dev_load_option_rom(AssignedDevice *dev);
+
+static uint32_t guest_to_host_ioport(AssignedDevRegion *region, uint32_t addr)
+{
+    return region->u.r_baseport + (addr - region->e_physbase);
+}
+
+static void assigned_dev_ioport_writeb(void *opaque, uint32_t addr,
+                                       uint32_t value)
+{
+    AssignedDevRegion *r_access = opaque;
+    uint32_t r_pio = guest_to_host_ioport(r_access, addr);
+
+    DEBUG("r_pio=%08x e_physbase=%08x r_baseport=%08lx value=%08x\n",
+	  r_pio, (int)r_access->e_physbase,
+	  (unsigned long)r_access->u.r_baseport, value);
+
+    outb(value, r_pio);
+}
+
+static void assigned_dev_ioport_writew(void *opaque, uint32_t addr,
+                                       uint32_t value)
+{
+    AssignedDevRegion *r_access = opaque;
+    uint32_t r_pio = guest_to_host_ioport(r_access, addr);
+
+    DEBUG("r_pio=%08x e_physbase=%08x r_baseport=%08lx value=%08x\n",
+          r_pio, (int)r_access->e_physbase,
+	  (unsigned long)r_access->u.r_baseport, value);
+
+    outw(value, r_pio);
+}
+
+static void assigned_dev_ioport_writel(void *opaque, uint32_t addr,
+                       uint32_t value)
+{
+    AssignedDevRegion *r_access = opaque;
+    uint32_t r_pio = guest_to_host_ioport(r_access, addr);
+
+    DEBUG("r_pio=%08x e_physbase=%08x r_baseport=%08lx value=%08x\n",
+	  r_pio, (int)r_access->e_physbase,
+          (unsigned long)r_access->u.r_baseport, value);
+
+    outl(value, r_pio);
+}
+
+static uint32_t assigned_dev_ioport_readb(void *opaque, uint32_t addr)
+{
+    AssignedDevRegion *r_access = opaque;
+    uint32_t r_pio = guest_to_host_ioport(r_access, addr);
+    uint32_t value;
+
+    value = inb(r_pio);
+
+    DEBUG("r_pio=%08x e_physbase=%08x r_=%08lx value=%08x\n",
+          r_pio, (int)r_access->e_physbase,
+          (unsigned long)r_access->u.r_baseport, value);
+
+    return value;
+}
+
+static uint32_t assigned_dev_ioport_readw(void *opaque, uint32_t addr)
+{
+    AssignedDevRegion *r_access = opaque;
+    uint32_t r_pio = guest_to_host_ioport(r_access, addr);
+    uint32_t value;
+
+    value = inw(r_pio);
+
+    DEBUG("r_pio=%08x e_physbase=%08x r_baseport=%08lx value=%08x\n",
+          r_pio, (int)r_access->e_physbase,
+	  (unsigned long)r_access->u.r_baseport, value);
+
+    return value;
+}
+
+static uint32_t assigned_dev_ioport_readl(void *opaque, uint32_t addr)
+{
+    AssignedDevRegion *r_access = opaque;
+    uint32_t r_pio = guest_to_host_ioport(r_access, addr);
+    uint32_t value;
+
+    value = inl(r_pio);
+
+    DEBUG("r_pio=%08x e_physbase=%08x r_baseport=%08lx value=%08x\n",
+          r_pio, (int)r_access->e_physbase,
+          (unsigned long)r_access->u.r_baseport, value);
+
+    return value;
+}
+
+static void assigned_dev_iomem_map(PCIDevice *pci_dev, int region_num,
+                                   pcibus_t e_phys, pcibus_t e_size, int type)
+{
+    AssignedDevice *r_dev = container_of(pci_dev, AssignedDevice, dev);
+    AssignedDevRegion *region = &r_dev->v_addrs[region_num];
+    PCIRegion *real_region = &r_dev->real_device.regions[region_num];
+    pcibus_t old_ephys = region->e_physbase;
+    pcibus_t old_esize = region->e_size;
+    int first_map = (region->e_size == 0);
+    int ret = 0;
+
+    DEBUG("e_phys=%08x r_virt=%p type=%d len=%08x region_num=%d \n",
+          e_phys, region->u.r_virtbase, type, e_size, region_num);
+
+    region->e_physbase = e_phys;
+    region->e_size = e_size;
+
+    if (!first_map)
+	kvm_destroy_phys_mem(kvm_context, old_ephys,
+                             TARGET_PAGE_ALIGN(old_esize));
+
+    if (e_size > 0) {
+        /* deal with MSI-X MMIO page */
+        if (real_region->base_addr <= r_dev->msix_table_addr &&
+                real_region->base_addr + real_region->size >=
+                r_dev->msix_table_addr) {
+            int offset = r_dev->msix_table_addr - real_region->base_addr;
+            ret = munmap(region->u.r_virtbase + offset, TARGET_PAGE_SIZE);
+            if (ret == 0)
+                DEBUG("munmap done, virt_base 0x%p\n",
+                        region->u.r_virtbase + offset);
+            else {
+                fprintf(stderr, "%s: fail munmap msix table!\n", __func__);
+                exit(1);
+            }
+            cpu_register_physical_memory(e_phys + offset,
+                    TARGET_PAGE_SIZE, r_dev->mmio_index);
+        }
+	ret = kvm_register_phys_mem(kvm_context, e_phys,
+                                    region->u.r_virtbase,
+                                    TARGET_PAGE_ALIGN(e_size), 0);
+    }
+
+    if (ret != 0) {
+	fprintf(stderr, "%s: Error: create new mapping failed\n", __func__);
+	exit(1);
+    }
+}
+
+static void assigned_dev_ioport_map(PCIDevice *pci_dev, int region_num,
+                                    pcibus_t addr, pcibus_t size, int type)
+{
+    AssignedDevice *r_dev = container_of(pci_dev, AssignedDevice, dev);
+    AssignedDevRegion *region = &r_dev->v_addrs[region_num];
+    int first_map = (region->e_size == 0);
+    CPUState *env;
+
+    region->e_physbase = addr;
+    region->e_size = size;
+
+    DEBUG("e_phys=0x%x r_baseport=%x type=0x%x len=%d region_num=%d \n",
+          addr, region->u.r_baseport, type, size, region_num);
+
+    if (first_map) {
+	struct ioperm_data *data;
+
+	data = qemu_mallocz(sizeof(struct ioperm_data));
+	if (data == NULL) {
+	    fprintf(stderr, "%s: Out of memory\n", __func__);
+	    exit(1);
+	}
+
+	data->start_port = region->u.r_baseport;
+	data->num = region->r_size;
+	data->turn_on = 1;
+
+	kvm_add_ioperm_data(data);
+
+	for (env = first_cpu; env; env = env->next_cpu)
+	    kvm_ioperm(env, data);
+    }
+
+    register_ioport_read(addr, size, 1, assigned_dev_ioport_readb,
+                         (r_dev->v_addrs + region_num));
+    register_ioport_read(addr, size, 2, assigned_dev_ioport_readw,
+                         (r_dev->v_addrs + region_num));
+    register_ioport_read(addr, size, 4, assigned_dev_ioport_readl,
+                         (r_dev->v_addrs + region_num));
+    register_ioport_write(addr, size, 1, assigned_dev_ioport_writeb,
+                          (r_dev->v_addrs + region_num));
+    register_ioport_write(addr, size, 2, assigned_dev_ioport_writew,
+                          (r_dev->v_addrs + region_num));
+    register_ioport_write(addr, size, 4, assigned_dev_ioport_writel,
+                          (r_dev->v_addrs + region_num));
+}
+
+static uint8_t pci_find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
+{
+    int id;
+    int max_cap = 48;
+    int pos = PCI_CAPABILITY_LIST;
+    int status;
+
+    status = pci_read_byte(pci_dev, PCI_STATUS);
+    if ((status & PCI_STATUS_CAP_LIST) == 0)
+        return 0;
+
+    while (max_cap--) {
+        pos = pci_read_byte(pci_dev, pos);
+        if (pos < 0x40)
+            break;
+
+        pos &= ~3;
+        id = pci_read_byte(pci_dev, pos + PCI_CAP_LIST_ID);
+
+        if (id == 0xff)
+            break;
+        if (id == cap)
+            return pos;
+
+        pos += PCI_CAP_LIST_NEXT;
+    }
+    return 0;
+}
+
+static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
+                                          uint32_t val, int len)
+{
+    int fd;
+    ssize_t ret;
+    AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev);
+
+    DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
+          ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+          (uint16_t) address, val, len);
+
+    if (address == 0x4) {
+        pci_default_write_config(d, address, val, len);
+        /* Continue to program the card */
+    }
+
+    if ((address >= 0x10 && address <= 0x24) || address == 0x30 ||
+        address == 0x34 || address == 0x3c || address == 0x3d ||
+        pci_access_cap_config(d, address, len)) {
+        /* used for update-mappings (BAR emulation) */
+        pci_default_write_config(d, address, val, len);
+        return;
+    }
+
+    DEBUG("NON BAR (%x.%x): address=%04x val=0x%08x len=%d\n",
+          ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+          (uint16_t) address, val, len);
+
+    fd = pci_dev->real_device.config_fd;
+
+again:
+    ret = pwrite(fd, &val, len, address);
+    if (ret != len) {
+	if ((ret < 0) && (errno == EINTR || errno == EAGAIN))
+	    goto again;
+
+	fprintf(stderr, "%s: pwrite failed, ret = %zd errno = %d\n",
+		__func__, ret, errno);
+
+	exit(1);
+    }
+}
+
+static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address,
+                                             int len)
+{
+    uint32_t val = 0;
+    int fd;
+    ssize_t ret;
+    AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev);
+
+    if (address < 0x4 || (pci_dev->need_emulate_cmd && address == 0x4) ||
+	(address >= 0x10 && address <= 0x24) || address == 0x30 ||
+        address == 0x34 || address == 0x3c || address == 0x3d ||
+        pci_access_cap_config(d, address, len)) {
+        val = pci_default_read_config(d, address, len);
+        DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
+              (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
+        return val;
+    }
+
+    /* vga specific, remove later */
+    if (address == 0xFC)
+        goto do_log;
+
+    fd = pci_dev->real_device.config_fd;
+
+again:
+    ret = pread(fd, &val, len, address);
+    if (ret != len) {
+	if ((ret < 0) && (errno == EINTR || errno == EAGAIN))
+	    goto again;
+
+	fprintf(stderr, "%s: pread failed, ret = %zd errno = %d\n",
+		__func__, ret, errno);
+
+	exit(1);
+    }
+
+do_log:
+    DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
+          (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
+
+    if (!pci_dev->cap.available) {
+        /* kill the special capabilities */
+        if (address == 4 && len == 4)
+            val &= ~0x100000;
+        else if (address == 6)
+            val &= ~0x10;
+    }
+
+    return val;
+}
+
+static int assigned_dev_register_regions(PCIRegion *io_regions,
+                                         unsigned long regions_num,
+                                         AssignedDevice *pci_dev)
+{
+    uint32_t i;
+    PCIRegion *cur_region = io_regions;
+
+    for (i = 0; i < regions_num; i++, cur_region++) {
+        if (!cur_region->valid)
+            continue;
+        pci_dev->v_addrs[i].num = i;
+
+        /* handle memory io regions */
+        if (cur_region->type & IORESOURCE_MEM) {
+            int t = cur_region->type & IORESOURCE_PREFETCH
+                ? PCI_BASE_ADDRESS_MEM_PREFETCH
+                : PCI_BASE_ADDRESS_SPACE_MEMORY;
+            if (cur_region->size & 0xFFF) {
+                fprintf(stderr, "Unable to assign device: PCI region %d "
+                        "at address 0x%llx has size 0x%x, "
+                        " which is not a multiple of 4K\n",
+                        i, (unsigned long long)cur_region->base_addr,
+                        cur_region->size);
+                return -1;
+            }
+
+            /* map physical memory */
+            pci_dev->v_addrs[i].e_physbase = cur_region->base_addr;
+            if (i == PCI_ROM_SLOT) {
+                pci_dev->v_addrs[i].u.r_virtbase =
+                    mmap(NULL,
+                         (cur_region->size + 0xFFF) & 0xFFFFF000,
+                         PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE,
+                         0, (off_t) 0);
+
+            } else {
+                pci_dev->v_addrs[i].u.r_virtbase =
+                    mmap(NULL,
+                         (cur_region->size + 0xFFF) & 0xFFFFF000,
+                         PROT_WRITE | PROT_READ, MAP_SHARED,
+                         cur_region->resource_fd, (off_t) 0);
+            }
+
+            if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) {
+                pci_dev->v_addrs[i].u.r_virtbase = NULL;
+                fprintf(stderr, "%s: Error: Couldn't mmap 0x%x!"
+                        "\n", __func__,
+                        (uint32_t) (cur_region->base_addr));
+                return -1;
+            }
+
+            if (i == PCI_ROM_SLOT) {
+                memset(pci_dev->v_addrs[i].u.r_virtbase, 0,
+                       (cur_region->size + 0xFFF) & 0xFFFFF000);
+                mprotect(pci_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+                         (cur_region->size + 0xFFF) & 0xFFFFF000, PROT_READ);
+            }
+
+            pci_dev->v_addrs[i].r_size = cur_region->size;
+            pci_dev->v_addrs[i].e_size = 0;
+
+            /* add offset */
+            pci_dev->v_addrs[i].u.r_virtbase +=
+                (cur_region->base_addr & 0xFFF);
+
+            pci_register_bar((PCIDevice *) pci_dev, i,
+                             cur_region->size, t,
+                             assigned_dev_iomem_map);
+            continue;
+        }
+        /* handle port io regions */
+        pci_dev->v_addrs[i].e_physbase = cur_region->base_addr;
+        pci_dev->v_addrs[i].u.r_baseport = cur_region->base_addr;
+        pci_dev->v_addrs[i].r_size = cur_region->size;
+        pci_dev->v_addrs[i].e_size = 0;
+
+        pci_register_bar((PCIDevice *) pci_dev, i,
+                         cur_region->size, PCI_BASE_ADDRESS_SPACE_IO,
+                         assigned_dev_ioport_map);
+
+        /* not relevant for port io */
+        pci_dev->v_addrs[i].memory_index = 0;
+    }
+
+    /* success */
+    return 0;
+}
+
+static int get_real_device(AssignedDevice *pci_dev, uint8_t r_bus,
+                           uint8_t r_dev, uint8_t r_func)
+{
+    char dir[128], name[128];
+    int fd, r = 0;
+    FILE *f;
+    unsigned long long start, end, size, flags;
+    unsigned long id;
+    struct stat statbuf;
+    PCIRegion *rp;
+    PCIDevRegions *dev = &pci_dev->real_device;
+
+    dev->region_number = 0;
+
+    snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/0000:%02x:%02x.%x/",
+	     r_bus, r_dev, r_func);
+
+    snprintf(name, sizeof(name), "%sconfig", dir);
+
+    fd = open(name, O_RDWR);
+    if (fd == -1) {
+        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+        return 1;
+    }
+    dev->config_fd = fd;
+again:
+    r = read(fd, pci_dev->dev.config, pci_config_size(&pci_dev->dev));
+    if (r < 0) {
+        if (errno == EINTR || errno == EAGAIN)
+            goto again;
+        fprintf(stderr, "%s: read failed, errno = %d\n", __func__, errno);
+    }
+
+    snprintf(name, sizeof(name), "%sresource", dir);
+
+    f = fopen(name, "r");
+    if (f == NULL) {
+        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+        return 1;
+    }
+
+    for (r = 0; r < PCI_NUM_REGIONS; r++) {
+	if (fscanf(f, "%lli %lli %lli\n", &start, &end, &flags) != 3)
+	    break;
+
+        rp = dev->regions + r;
+        rp->valid = 0;
+        size = end - start + 1;
+        flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+        if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0)
+            continue;
+        if (flags & IORESOURCE_MEM) {
+            flags &= ~IORESOURCE_IO;
+            if (r != PCI_ROM_SLOT) {
+                snprintf(name, sizeof(name), "%sresource%d", dir, r);
+                fd = open(name, O_RDWR);
+                if (fd == -1)
+                    continue;
+                rp->resource_fd = fd;
+            }
+        } else
+            flags &= ~IORESOURCE_PREFETCH;
+
+        rp->type = flags;
+        rp->valid = 1;
+        rp->base_addr = start;
+        rp->size = size;
+        DEBUG("region %d size %d start 0x%llx type %d resource_fd %d\n",
+              r, rp->size, start, rp->type, rp->resource_fd);
+    }
+
+    fclose(f);
+
+    /* read and fill device ID */
+    snprintf(name, sizeof(name), "%svendor", dir);
+    f = fopen(name, "r");
+    if (f == NULL) {
+        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+        return 1;
+    }
+    if (fscanf(f, "%li\n", &id) == 1) {
+	pci_dev->dev.config[0] = id & 0xff;
+	pci_dev->dev.config[1] = (id & 0xff00) >> 8;
+    }
+    fclose(f);
+
+    /* read and fill vendor ID */
+    snprintf(name, sizeof(name), "%sdevice", dir);
+    f = fopen(name, "r");
+    if (f == NULL) {
+        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+        return 1;
+    }
+    if (fscanf(f, "%li\n", &id) == 1) {
+	pci_dev->dev.config[2] = id & 0xff;
+	pci_dev->dev.config[3] = (id & 0xff00) >> 8;
+    }
+    fclose(f);
+
+    /* dealing with virtual function device */
+    snprintf(name, sizeof(name), "%sphysfn/", dir);
+    if (!stat(name, &statbuf))
+	    pci_dev->need_emulate_cmd = 1;
+    else
+	    pci_dev->need_emulate_cmd = 0;
+
+    dev->region_number = r;
+    return 0;
+}
+
+static QLIST_HEAD(, AssignedDevice) devs = QLIST_HEAD_INITIALIZER(devs);
+
+#ifdef KVM_CAP_IRQ_ROUTING
+static void free_dev_irq_entries(AssignedDevice *dev)
+{
+    int i;
+
+    for (i = 0; i < dev->irq_entries_nr; i++)
+        kvm_del_routing_entry(kvm_context, &dev->entry[i]);
+    free(dev->entry);
+    dev->entry = NULL;
+    dev->irq_entries_nr = 0;
+}
+#endif
+
+static void free_assigned_device(AssignedDevice *dev)
+{
+    if (dev) {
+        int i;
+
+        for (i = 0; i < dev->real_device.region_number; i++) {
+            PCIRegion *pci_region = &dev->real_device.regions[i];
+            AssignedDevRegion *region = &dev->v_addrs[i];
+
+            if (!pci_region->valid)
+                continue;
+
+            if (pci_region->type & IORESOURCE_IO) {
+                kvm_remove_ioperm_data(region->u.r_baseport, region->r_size);
+                continue;
+            } else if (pci_region->type & IORESOURCE_MEM) {
+                if (region->e_size > 0)
+                    kvm_destroy_phys_mem(kvm_context, region->e_physbase,
+                                         TARGET_PAGE_ALIGN(region->e_size));
+
+                if (region->u.r_virtbase) {
+                    int ret = munmap(region->u.r_virtbase,
+                                     (pci_region->size + 0xFFF) & 0xFFFFF000);
+                    if (ret != 0)
+                        fprintf(stderr,
+				"Failed to unmap assigned device region: %s\n",
+				strerror(errno));
+                }
+	    }
+        }
+
+        if (dev->real_device.config_fd) {
+            close(dev->real_device.config_fd);
+            dev->real_device.config_fd = 0;
+        }
+
+#ifdef KVM_CAP_IRQ_ROUTING
+        free_dev_irq_entries(dev);
+#endif
+    }
+}
+
+static uint32_t calc_assigned_dev_id(uint8_t bus, uint8_t devfn)
+{
+    return (uint32_t)bus << 8 | (uint32_t)devfn;
+}
+
+static int assign_device(AssignedDevice *dev)
+{
+    struct kvm_assigned_pci_dev assigned_dev_data;
+    int r;
+
+    memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
+    assigned_dev_data.assigned_dev_id  =
+	calc_assigned_dev_id(dev->h_busnr, dev->h_devfn);
+    assigned_dev_data.busnr = dev->h_busnr;
+    assigned_dev_data.devfn = dev->h_devfn;
+
+#ifdef KVM_CAP_IOMMU
+    /* We always enable the IOMMU if present
+     * (or when not disabled on the command line)
+     */
+    r = kvm_check_extension(kvm_state, KVM_CAP_IOMMU);
+    if (!r)
+        dev->use_iommu = 0;
+    if (dev->use_iommu)
+	assigned_dev_data.flags |= KVM_DEV_ASSIGN_ENABLE_IOMMU;
+#else
+    dev->use_iommu = 0;
+#endif
+
+    r = kvm_assign_pci_device(kvm_context, &assigned_dev_data);
+    if (r < 0)
+	fprintf(stderr, "Failed to assign device \"%s\" : %s\n",
+                dev->dev.qdev.id, strerror(-r));
+    return r;
+}
+
+static int assign_irq(AssignedDevice *dev)
+{
+    struct kvm_assigned_irq assigned_irq_data;
+    int irq, r = 0;
+
+    /* Interrupt PIN 0 means don't use INTx */
+    if (pci_read_byte(dev->pdev, PCI_INTERRUPT_PIN) == 0)
+        return 0;
+
+    irq = pci_map_irq(&dev->dev, dev->intpin);
+    irq = piix_get_irq(irq);
+
+#ifdef TARGET_IA64
+    irq = ipf_map_irq(&dev->dev, irq);
+#endif
+
+    if (dev->girq == irq)
+        return r;
+
+    memset(&assigned_irq_data, 0, sizeof(assigned_irq_data));
+    assigned_irq_data.assigned_dev_id =
+        calc_assigned_dev_id(dev->h_busnr, dev->h_devfn);
+    assigned_irq_data.guest_irq = irq;
+    assigned_irq_data.host_irq = dev->real_device.irq;
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+    if (dev->irq_requested_type) {
+        assigned_irq_data.flags = dev->irq_requested_type;
+        r = kvm_deassign_irq(kvm_context, &assigned_irq_data);
+        /* -ENXIO means no assigned irq */
+        if (r && r != -ENXIO)
+            perror("assign_irq: deassign");
+    }
+
+    assigned_irq_data.flags = KVM_DEV_IRQ_GUEST_INTX;
+    if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSI)
+        assigned_irq_data.flags |= KVM_DEV_IRQ_HOST_MSI;
+    else
+        assigned_irq_data.flags |= KVM_DEV_IRQ_HOST_INTX;
+#endif
+
+    r = kvm_assign_irq(kvm_context, &assigned_irq_data);
+    if (r < 0) {
+        fprintf(stderr, "Failed to assign irq for \"%s\": %s\n",
+                dev->dev.qdev.id, strerror(-r));
+        fprintf(stderr, "Perhaps you are assigning a device "
+                "that shares an IRQ with another device?\n");
+        return r;
+    }
+
+    dev->girq = irq;
+    dev->irq_requested_type = assigned_irq_data.flags;
+    return r;
+}
+
+static void deassign_device(AssignedDevice *dev)
+{
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+    struct kvm_assigned_pci_dev assigned_dev_data;
+    int r;
+
+    memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
+    assigned_dev_data.assigned_dev_id  =
+	calc_assigned_dev_id(dev->h_busnr, dev->h_devfn);
+
+    r = kvm_deassign_pci_device(kvm_context, &assigned_dev_data);
+    if (r < 0)
+	fprintf(stderr, "Failed to deassign device \"%s\" : %s\n",
+                dev->dev.qdev.id, strerror(-r));
+#endif
+}
+
+#if 0
+AssignedDevInfo *get_assigned_device(int pcibus, int slot)
+{
+    AssignedDevice *assigned_dev = NULL;
+    AssignedDevInfo *adev = NULL;
+
+    QLIST_FOREACH(adev, &adev_head, next) {
+        assigned_dev = adev->assigned_dev;
+        if (pci_bus_num(assigned_dev->dev.bus) == pcibus &&
+            PCI_SLOT(assigned_dev->dev.devfn) == slot)
+            return adev;
+    }
+
+    return NULL;
+}
+#endif
+
+/* The pci config space got updated. Check if irq numbers have changed
+ * for our devices
+ */
+void assigned_dev_update_irqs(void)
+{
+    AssignedDevice *dev, *next;
+    int r;
+
+    dev = QLIST_FIRST(&devs);
+    while (dev) {
+        next = QLIST_NEXT(dev, next);
+        r = assign_irq(dev);
+        if (r < 0)
+            qdev_unplug(&dev->dev.qdev);
+        dev = next;
+    }
+}
+
+#ifdef KVM_CAP_IRQ_ROUTING
+
+#ifdef KVM_CAP_DEVICE_MSI
+static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
+{
+    struct kvm_assigned_irq assigned_irq_data;
+    AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+    uint8_t ctrl_byte = pci_dev->config[ctrl_pos];
+    int r;
+
+    memset(&assigned_irq_data, 0, sizeof assigned_irq_data);
+    assigned_irq_data.assigned_dev_id  =
+        calc_assigned_dev_id(assigned_dev->h_busnr,
+                (uint8_t)assigned_dev->h_devfn);
+
+    if (assigned_dev->irq_requested_type) {
+	    assigned_irq_data.flags = assigned_dev->irq_requested_type;
+	    free_dev_irq_entries(assigned_dev);
+	    r = kvm_deassign_irq(kvm_context, &assigned_irq_data);
+	    /* -ENXIO means no assigned irq */
+	    if (r && r != -ENXIO)
+		    perror("assigned_dev_update_msi: deassign irq");
+    }
+
+    if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
+        assigned_dev->entry = calloc(1, sizeof(struct kvm_irq_routing_entry));
+        if (!assigned_dev->entry) {
+            perror("assigned_dev_update_msi: ");
+            return;
+        }
+        assigned_dev->entry->u.msi.address_lo =
+                *(uint32_t *)(pci_dev->config + pci_dev->cap.start +
+                              PCI_MSI_ADDRESS_LO);
+        assigned_dev->entry->u.msi.address_hi = 0;
+        assigned_dev->entry->u.msi.data = *(uint16_t *)(pci_dev->config +
+                pci_dev->cap.start + PCI_MSI_DATA_32);
+        assigned_dev->entry->type = KVM_IRQ_ROUTING_MSI;
+        r = kvm_get_irq_route_gsi(kvm_context);
+        if (r < 0) {
+            perror("assigned_dev_update_msi: kvm_get_irq_route_gsi");
+            return;
+        }
+        assigned_dev->entry->gsi = r;
+
+        kvm_add_routing_entry(kvm_context, assigned_dev->entry);
+        if (kvm_commit_irq_routes(kvm_context) < 0) {
+            perror("assigned_dev_update_msi: kvm_commit_irq_routes");
+            assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSI_ENABLED;
+            return;
+        }
+	assigned_dev->irq_entries_nr = 1;
+
+        assigned_irq_data.guest_irq = assigned_dev->entry->gsi;
+	assigned_irq_data.flags = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI;
+        if (kvm_assign_irq(kvm_context, &assigned_irq_data) < 0)
+            perror("assigned_dev_enable_msi: assign irq");
+
+        assigned_dev->irq_requested_type = assigned_irq_data.flags;
+    }
+}
+#endif
+
+#ifdef KVM_CAP_DEVICE_MSIX
+static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
+{
+    AssignedDevice *adev = container_of(pci_dev, AssignedDevice, dev);
+    u16 entries_nr = 0, entries_max_nr;
+    int pos = 0, i, r = 0;
+    u32 msg_addr, msg_upper_addr, msg_data, msg_ctrl;
+    struct kvm_assigned_msix_nr msix_nr;
+    struct kvm_assigned_msix_entry msix_entry;
+    void *va = adev->msix_table_page;
+
+    if (adev->cap.available & ASSIGNED_DEVICE_CAP_MSI)
+        pos = pci_dev->cap.start + PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+    else
+        pos = pci_dev->cap.start;
+
+    entries_max_nr = pci_dev->config[pos + 2];
+    entries_max_nr &= PCI_MSIX_TABSIZE;
+    entries_max_nr += 1;
+
+    /* Get the usable entry number for allocating */
+    for (i = 0; i < entries_max_nr; i++) {
+        memcpy(&msg_ctrl, va + i * 16 + 12, 4);
+        memcpy(&msg_data, va + i * 16 + 8, 4);
+        /* Ignore unused entry even it's unmasked */
+        if (msg_data == 0)
+            continue;
+        entries_nr ++;
+    }
+
+    if (entries_nr == 0) {
+        fprintf(stderr, "MSI-X entry number is zero!\n");
+        return -EINVAL;
+    }
+    msix_nr.assigned_dev_id = calc_assigned_dev_id(adev->h_busnr,
+                                          (uint8_t)adev->h_devfn);
+    msix_nr.entry_nr = entries_nr;
+    r = kvm_assign_set_msix_nr(kvm_context, &msix_nr);
+    if (r != 0) {
+        fprintf(stderr, "fail to set MSI-X entry number for MSIX! %s\n",
+			strerror(-r));
+        return r;
+    }
+
+    free_dev_irq_entries(adev);
+    adev->irq_entries_nr = entries_nr;
+    adev->entry = calloc(entries_nr, sizeof(struct kvm_irq_routing_entry));
+    if (!adev->entry) {
+        perror("assigned_dev_update_msix_mmio: ");
+        return -errno;
+    }
+
+    msix_entry.assigned_dev_id = msix_nr.assigned_dev_id;
+    entries_nr = 0;
+    for (i = 0; i < entries_max_nr; i++) {
+        if (entries_nr >= msix_nr.entry_nr)
+            break;
+        memcpy(&msg_ctrl, va + i * 16 + 12, 4);
+        memcpy(&msg_data, va + i * 16 + 8, 4);
+        if (msg_data == 0)
+            continue;
+
+        memcpy(&msg_addr, va + i * 16, 4);
+        memcpy(&msg_upper_addr, va + i * 16 + 4, 4);
+
+        r = kvm_get_irq_route_gsi(kvm_context);
+        if (r < 0)
+            return r;
+
+        adev->entry[entries_nr].gsi = r;
+        adev->entry[entries_nr].type = KVM_IRQ_ROUTING_MSI;
+        adev->entry[entries_nr].flags = 0;
+        adev->entry[entries_nr].u.msi.address_lo = msg_addr;
+        adev->entry[entries_nr].u.msi.address_hi = msg_upper_addr;
+        adev->entry[entries_nr].u.msi.data = msg_data;
+        DEBUG("MSI-X data 0x%x, MSI-X addr_lo 0x%x\n!", msg_data, msg_addr);
+	kvm_add_routing_entry(kvm_context, &adev->entry[entries_nr]);
+
+        msix_entry.gsi = adev->entry[entries_nr].gsi;
+        msix_entry.entry = i;
+        r = kvm_assign_set_msix_entry(kvm_context, &msix_entry);
+        if (r) {
+            fprintf(stderr, "fail to set MSI-X entry! %s\n", strerror(-r));
+            break;
+        }
+        DEBUG("MSI-X entry gsi 0x%x, entry %d\n!",
+                msix_entry.gsi, msix_entry.entry);
+        entries_nr ++;
+    }
+
+    if (r == 0 && kvm_commit_irq_routes(kvm_context) < 0) {
+	    perror("assigned_dev_update_msix_mmio: kvm_commit_irq_routes");
+	    return -EINVAL;
+    }
+
+    return r;
+}
+
+static void assigned_dev_update_msix(PCIDevice *pci_dev, unsigned int ctrl_pos)
+{
+    struct kvm_assigned_irq assigned_irq_data;
+    AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+    uint16_t *ctrl_word = (uint16_t *)(pci_dev->config + ctrl_pos);
+    int r;
+
+    memset(&assigned_irq_data, 0, sizeof assigned_irq_data);
+    assigned_irq_data.assigned_dev_id  =
+            calc_assigned_dev_id(assigned_dev->h_busnr,
+                    (uint8_t)assigned_dev->h_devfn);
+
+    if (assigned_dev->irq_requested_type) {
+        assigned_irq_data.flags = assigned_dev->irq_requested_type;
+        free_dev_irq_entries(assigned_dev);
+        r = kvm_deassign_irq(kvm_context, &assigned_irq_data);
+        /* -ENXIO means no assigned irq */
+        if (r && r != -ENXIO)
+            perror("assigned_dev_update_msix: deassign irq");
+    }
+    assigned_irq_data.flags = KVM_DEV_IRQ_HOST_MSIX | KVM_DEV_IRQ_GUEST_MSIX;
+
+    if (*ctrl_word & PCI_MSIX_ENABLE) {
+        if (assigned_dev_update_msix_mmio(pci_dev) < 0) {
+            perror("assigned_dev_update_msix_mmio");
+            return;
+        }
+        if (kvm_assign_irq(kvm_context, &assigned_irq_data) < 0) {
+            perror("assigned_dev_enable_msix: assign irq");
+            return;
+        }
+        assigned_dev->irq_requested_type = assigned_irq_data.flags;
+    }
+}
+#endif
+#endif
+
+static void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint32_t address,
+                                                 uint32_t val, int len)
+{
+    AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+    unsigned int pos = pci_dev->cap.start, ctrl_pos;
+
+    pci_default_cap_write_config(pci_dev, address, val, len);
+#ifdef KVM_CAP_IRQ_ROUTING
+#ifdef KVM_CAP_DEVICE_MSI
+    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+        ctrl_pos = pos + PCI_MSI_FLAGS;
+        if (address <= ctrl_pos && address + len > ctrl_pos)
+            assigned_dev_update_msi(pci_dev, ctrl_pos);
+        pos += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+    }
+#endif
+#ifdef KVM_CAP_DEVICE_MSIX
+    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
+        ctrl_pos = pos + 3;
+        if (address <= ctrl_pos && address + len > ctrl_pos) {
+            ctrl_pos--; /* control is word long */
+            assigned_dev_update_msix(pci_dev, ctrl_pos);
+	}
+        pos += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+    }
+#endif
+#endif
+    return;
+}
+
+static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
+{
+    AssignedDevice *dev = container_of(pci_dev, AssignedDevice, dev);
+    PCIRegion *pci_region = dev->real_device.regions;
+    int next_cap_pt = 0;
+
+    pci_dev->cap.length = 0;
+#ifdef KVM_CAP_IRQ_ROUTING
+#ifdef KVM_CAP_DEVICE_MSI
+    /* Expose MSI capability
+     * MSI capability is the 1st capability in capability config */
+    if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSI)) {
+        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
+        memset(&pci_dev->config[pci_dev->cap.start + pci_dev->cap.length],
+               0, PCI_CAPABILITY_CONFIG_MSI_LENGTH);
+        pci_dev->config[pci_dev->cap.start + pci_dev->cap.length] =
+                        PCI_CAP_ID_MSI;
+        pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+        next_cap_pt = 1;
+    }
+#endif
+#ifdef KVM_CAP_DEVICE_MSIX
+    /* Expose MSI-X capability */
+    if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSIX)) {
+        int pos, entry_nr, bar_nr;
+        u32 msix_table_entry;
+        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
+        memset(&pci_dev->config[pci_dev->cap.start + pci_dev->cap.length],
+               0, PCI_CAPABILITY_CONFIG_MSIX_LENGTH);
+        pos = pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSIX);
+        entry_nr = pci_read_word(dev->pdev, pos + 2) & PCI_MSIX_TABSIZE;
+        pci_dev->config[pci_dev->cap.start + pci_dev->cap.length] = 0x11;
+        pci_dev->config[pci_dev->cap.start +
+                        pci_dev->cap.length + 2] = entry_nr;
+        msix_table_entry = pci_read_long(dev->pdev, pos + PCI_MSIX_TABLE);
+        *(uint32_t *)(pci_dev->config + pci_dev->cap.start +
+                      pci_dev->cap.length + PCI_MSIX_TABLE) = msix_table_entry;
+        *(uint32_t *)(pci_dev->config + pci_dev->cap.start +
+                      pci_dev->cap.length + PCI_MSIX_PBA) =
+                    pci_read_long(dev->pdev, pos + PCI_MSIX_PBA);
+        bar_nr = msix_table_entry & PCI_MSIX_BIR;
+        msix_table_entry &= ~PCI_MSIX_BIR;
+        dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;
+        if (next_cap_pt != 0) {
+            pci_dev->config[pci_dev->cap.start + next_cap_pt] =
+                pci_dev->cap.start + pci_dev->cap.length;
+            next_cap_pt += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+        } else
+            next_cap_pt = 1;
+        pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+    }
+#endif
+#endif
+
+    return 0;
+}
+
+static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    AssignedDevice *adev = opaque;
+    unsigned int offset = addr & 0xfff;
+    void *page = adev->msix_table_page;
+    uint32_t val = 0;
+
+    memcpy(&val, (void *)((char *)page + offset), 4);
+
+    return val;
+}
+
+static uint32_t msix_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    return ((msix_mmio_readl(opaque, addr & ~3)) >>
+            (8 * (addr & 3))) & 0xff;
+}
+
+static uint32_t msix_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    return ((msix_mmio_readl(opaque, addr & ~3)) >>
+            (8 * (addr & 3))) & 0xffff;
+}
+
+static void msix_mmio_writel(void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    AssignedDevice *adev = opaque;
+    unsigned int offset = addr & 0xfff;
+    void *page = adev->msix_table_page;
+
+    DEBUG("write to MSI-X entry table mmio offset 0x%lx, val 0x%lx\n",
+		    addr, val);
+    memcpy((void *)((char *)page + offset), &val, 4);
+}
+
+static void msix_mmio_writew(void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    msix_mmio_writel(opaque, addr & ~3,
+                     (val & 0xffff) << (8*(addr & 3)));
+}
+
+static void msix_mmio_writeb(void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    msix_mmio_writel(opaque, addr & ~3,
+                     (val & 0xff) << (8*(addr & 3)));
+}
+
+static CPUWriteMemoryFunc *msix_mmio_write[] = {
+    msix_mmio_writeb,	msix_mmio_writew,	msix_mmio_writel
+};
+
+static CPUReadMemoryFunc *msix_mmio_read[] = {
+    msix_mmio_readb,	msix_mmio_readw,	msix_mmio_readl
+};
+
+static int assigned_dev_register_msix_mmio(AssignedDevice *dev)
+{
+    dev->msix_table_page = mmap(NULL, 0x1000,
+                                PROT_READ|PROT_WRITE,
+                                MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
+    if (dev->msix_table_page == MAP_FAILED) {
+        fprintf(stderr, "fail allocate msix_table_page! %s\n",
+                strerror(errno));
+        return -EFAULT;
+    }
+    memset(dev->msix_table_page, 0, 0x1000);
+    dev->mmio_index = cpu_register_io_memory(
+                        msix_mmio_read, msix_mmio_write, dev);
+    return 0;
+}
+
+static int assigned_initfn(struct PCIDevice *pci_dev)
+{
+    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    struct pci_access *pacc;
+    uint8_t e_device, e_intx;
+    int r;
+
+    if (!dev->host.bus && !dev->host.dev && !dev->host.func) {
+        qemu_error("pci-assign: error: no host device specified\n");
+        goto out;
+    }
+
+    if (get_real_device(dev, dev->host.bus, dev->host.dev, dev->host.func)) {
+        qemu_error("pci-assign: Error: Couldn't get real device (%s)!\n",
+                   dev->dev.qdev.id);
+        goto out;
+    }
+
+    /* handle real device's MMIO/PIO BARs */
+    if (assigned_dev_register_regions(dev->real_device.regions,
+                                      dev->real_device.region_number,
+                                      dev))
+        goto out;
+
+    /* handle interrupt routing */
+    e_device = (dev->dev.devfn >> 3) & 0x1f;
+    e_intx = dev->dev.config[0x3d] - 1;
+    dev->intpin = e_intx;
+    dev->run = 0;
+    dev->girq = 0;
+    dev->h_busnr = dev->host.bus;
+    dev->h_devfn = PCI_DEVFN(dev->host.dev, dev->host.func);
+
+    pacc = pci_alloc();
+    pci_init(pacc);
+    dev->pdev = pci_get_dev(pacc, 0, dev->host.bus, dev->host.dev, dev->host.func);
+
+    if (pci_enable_capability_support(pci_dev, 0, NULL,
+                    assigned_device_pci_cap_write_config,
+                    assigned_device_pci_cap_init) < 0)
+        goto assigned_out;
+
+    /* assign device to guest */
+    r = assign_device(dev);
+    if (r < 0)
+        goto assigned_out;
+
+    /* assign irq for the device */
+    r = assign_irq(dev);
+    if (r < 0)
+        goto assigned_out;
+
+    /* intercept MSI-X entry page in the MMIO */
+    if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX)
+        if (assigned_dev_register_msix_mmio(dev))
+            goto assigned_out;
+
+    assigned_dev_load_option_rom(dev);
+    QLIST_INSERT_HEAD(&devs, dev, next);
+    return 0;
+
+assigned_out:
+    deassign_device(dev);
+out:
+    free_assigned_device(dev);
+    return -1;
+}
+
+static int assigned_exitfn(struct PCIDevice *pci_dev)
+{
+    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+
+    deassign_device(dev);
+    free_assigned_device(dev);
+    return 0;
+}
+
+static int parse_hostaddr(DeviceState *dev, Property *prop, const char *str)
+{
+    PCIHostDevice *ptr = qdev_get_prop_ptr(dev, prop);
+    int rc;
+
+    rc = pci_parse_host_devaddr(str, &ptr->bus, &ptr->dev, &ptr->func);
+    if (rc != 0)
+        return -1;
+    return 0;
+}
+
+static int print_hostaddr(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    PCIHostDevice *ptr = qdev_get_prop_ptr(dev, prop);
+
+    return snprintf(dest, len, "%02x:%02x.%x", ptr->bus, ptr->dev, ptr->func);
+}
+
+PropertyInfo qdev_prop_hostaddr = {
+    .name  = "pci-hostaddr",
+    .type  = -1,
+    .size  = sizeof(PCIHostDevice),
+    .parse = parse_hostaddr,
+    .print = print_hostaddr,
+};
+
+static PCIDeviceInfo assign_info = {
+    .qdev.name    = "pci-assign",
+    .qdev.desc    = "pass through host pci devices to the guest",
+    .qdev.size    = sizeof(AssignedDevice),
+    .init         = assigned_initfn,
+    .exit         = assigned_exitfn,
+    .config_read  = assigned_dev_pci_read_config,
+    .config_write = assigned_dev_pci_write_config,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP("host", AssignedDevice, host, qdev_prop_hostaddr, PCIHostDevice),
+        DEFINE_PROP_UINT32("iommu", AssignedDevice, use_iommu, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void assign_register_devices(void)
+{
+    pci_qdev_register(&assign_info);
+}
+
+device_init(assign_register_devices)
+
+
+/*
+ * Syntax to assign device:
+ *
+ * -pcidevice host=bus:dev.func[,dma=none][,name=Foo]
+ *
+ * Example:
+ * -pcidevice host=00:13.0,dma=pvdma
+ *
+ * dma can currently only be 'none' to disable iommu support.
+ */
+QemuOpts *add_assigned_device(const char *arg)
+{
+    QemuOpts *opts = NULL;
+    char host[64], id[64], dma[8];
+    int r;
+
+    r = get_param_value(host, sizeof(host), "host", arg);
+    if (!r)
+         goto bad;
+    r = get_param_value(id, sizeof(id), "id", arg);
+    if (!r)
+        r = get_param_value(id, sizeof(id), "name", arg);
+    if (!r)
+        r = get_param_value(id, sizeof(id), "host", arg);
+
+    opts = qemu_opts_create(&qemu_device_opts, id, 0);
+    if (!opts)
+        goto bad;
+    qemu_opt_set(opts, "driver", "pci-assign");
+    qemu_opt_set(opts, "host", host);
+
+#ifdef KVM_CAP_IOMMU
+    r = get_param_value(dma, sizeof(dma), "dma", arg);
+    if (r && !strncmp(dma, "none", 4))
+        qemu_opt_set(opts, "iommu", "0");
+#endif
+    qemu_opts_print(opts, NULL);
+    return opts;
+
+bad:
+    fprintf(stderr, "pcidevice argument parse error; "
+            "please check the help text for usage\n");
+    if (opts)
+        qemu_opts_del(opts);
+    return NULL;
+}
+
+void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices)
+{
+    QemuOpts *opts;
+    int i;
+
+    for (i = 0; i < n_devices; i++) {
+        opts = add_assigned_device(devices[i]);
+        if (opts == NULL) {
+            fprintf(stderr, "Could not add assigned device %s\n", devices[i]);
+            exit(1);
+        }
+        /* generic code will call qdev_device_add() for the device */
+    }
+}
+
+/* Option ROM header */
+struct option_rom_header {
+    uint8_t signature[2];
+    uint8_t rom_size;
+    uint32_t entry_point;
+    uint8_t reserved[17];
+    uint16_t pci_header_offset;
+    uint16_t expansion_header_offset;
+} __attribute__ ((packed));
+
+/* Option ROM PCI data structure */
+struct option_rom_pci_header {
+    uint8_t signature[4];
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t vital_product_data_offset;
+    uint16_t structure_length;
+    uint8_t structure_revision;
+    uint8_t class_code[3];
+    uint16_t image_length;
+    uint16_t image_revision;
+    uint8_t code_type;
+    uint8_t indicator;
+    uint16_t reserved;
+} __attribute__ ((packed));
+
+/*
+ * Scan the list of Option ROMs at roms. If a suitable Option ROM is found,
+ * allocate a ram space and copy it there. Then return its size aligned to
+ * both 2KB and target page size.
+ */
+#define OPTION_ROM_ALIGN(x) (((x) + 2047) & ~2047)
+static void scan_option_rom(const char *name, uint8_t devfn, void *roms)
+{
+    int i, size;
+    uint8_t csum;
+    struct option_rom_header *rom;
+    struct option_rom_pci_header *pcih;
+
+    rom = roms;
+
+    for ( ; ; ) {
+        /* Invalid signature means we're out of option ROMs. */
+        if (strncmp((char *)rom->signature, "\x55\xaa", 2) ||
+             (rom->rom_size == 0))
+            break;
+
+        size = rom->rom_size * 512;
+        /* Invalid checksum means we're out of option ROMs. */
+        csum = 0;
+        for (i = 0; i < size; i++)
+            csum += ((uint8_t *)rom)[i];
+        if (csum != 0)
+            break;
+
+        /* Check the PCI header (if any) for a match. */
+        pcih = (struct option_rom_pci_header *)
+                ((char *)rom + rom->pci_header_offset);
+        if ((rom->pci_header_offset != 0) &&
+             !strncmp((char *)pcih->signature, "PCIR", 4))
+            goto found;
+
+        rom = (struct option_rom_header *)((char *)rom + size);
+    }
+    return;
+
+ found:
+    rom_add_blob(name ? name : "assigned device", rom, size, 0);
+    return;
+}
+
+/*
+ * Scan the assigned devices for the devices that have an option ROM, and then
+ * load the corresponding ROM data to RAM. If an error occurs while loading an
+ * option ROM, we just ignore that option ROM and continue with the next one.
+ */
+static void assigned_dev_load_option_rom(AssignedDevice *dev)
+{
+    int size, len;
+    void *buf;
+    FILE *fp;
+    uint8_t i = 1;
+    char rom_file[64];
+
+    snprintf(rom_file, sizeof(rom_file),
+             "/sys/bus/pci/devices/0000:%02x:%02x.%01x/rom",
+             dev->host.bus, dev->host.dev, dev->host.func);
+
+    if (access(rom_file, F_OK))
+        return;
+
+    /* Write something to the ROM file to enable it */
+    fp = fopen(rom_file, "wb");
+    if (fp == NULL)
+        return;
+    len = fwrite(&i, 1, 1, fp);
+    fclose(fp);
+    if (len != 1)
+        return;
+
+    /* The file has to be closed and reopened, otherwise it won't work */
+    fp = fopen(rom_file, "rb");
+    if (fp == NULL)
+        return;
+
+    fseek(fp, 0, SEEK_END);
+    size = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+
+    buf = malloc(size);
+    if (buf == NULL) {
+        fclose(fp);
+        return;
+    }
+
+    fread(buf, size, 1, fp);
+    if (!feof(fp) || ferror(fp)) {
+        free(buf);
+        fclose(fp);
+        return;
+    }
+    fclose(fp);
+
+    /* Copy ROM contents into the space backing the ROM BAR */
+    if (dev->v_addrs[PCI_ROM_SLOT].r_size >= size &&
+        dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase) {
+        mprotect(dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+                 size, PROT_READ | PROT_WRITE);
+        memcpy(dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+               buf, size);
+        mprotect(dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+                 size, PROT_READ);
+    }
+
+    if (!dev->dev.qdev.hotplugged) {
+        /* Scan the buffer for suitable ROMs and increase the offset */
+        scan_option_rom(dev->dev.qdev.id, dev->dev.devfn, buf);
+    }
+    free(buf);
+}
diff --git a/hw/device-assignment.h b/hw/device-assignment.h
new file mode 100644
index 0000000..a231260
--- /dev/null
+++ b/hw/device-assignment.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ *  Data structures for storing PCI state
+ *
+ *  Adapted to kvm by Qumranet
+ *
+ *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ */
+
+#ifndef __DEVICE_ASSIGNMENT_H__
+#define __DEVICE_ASSIGNMENT_H__
+
+#include <sys/mman.h>
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#include "pci.h"
+
+/* From include/linux/pci.h in the kernel sources */
+#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+
+typedef struct PCIHostDevice {
+    int bus;
+    int dev;
+    int func;
+} PCIHostDevice;
+
+typedef struct {
+    int type;           /* Memory or port I/O */
+    int valid;
+    uint32_t base_addr;
+    uint32_t size;    /* size of the region */
+    int resource_fd;
+} PCIRegion;
+
+typedef struct {
+    uint8_t bus, dev, func; /* Bus inside domain, device and function */
+    int irq;                /* IRQ number */
+    uint16_t region_number; /* number of active regions */
+
+    /* Port I/O or MMIO Regions */
+    PCIRegion regions[PCI_NUM_REGIONS];
+    int config_fd;
+} PCIDevRegions;
+
+typedef struct {
+    pcibus_t e_physbase;
+    uint32_t memory_index;
+    union {
+        void *r_virtbase;    /* mmapped access address for memory regions */
+        uint32_t r_baseport; /* the base guest port for I/O regions */
+    } u;
+    int num;            /* our index within v_addrs[] */
+    pcibus_t e_size;    /* emulated size of region in bytes */
+    pcibus_t r_size;    /* real size of region in bytes */
+} AssignedDevRegion;
+
+typedef struct AssignedDevice {
+    PCIDevice dev;
+    PCIHostDevice host;
+    uint32_t use_iommu;
+    int intpin;
+    uint8_t debug_flags;
+    AssignedDevRegion v_addrs[PCI_NUM_REGIONS];
+    PCIDevRegions real_device;
+    int run;
+    int girq;
+    unsigned char h_busnr;
+    unsigned int h_devfn;
+    int irq_requested_type;
+    int bound;
+    struct pci_dev *pdev;
+    struct {
+#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
+#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
+        uint32_t available;
+#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
+#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
+        uint32_t state;
+    } cap;
+    int irq_entries_nr;
+    struct kvm_irq_routing_entry *entry;
+    void *msix_table_page;
+    target_phys_addr_t msix_table_addr;
+    int mmio_index;
+    int need_emulate_cmd;
+    QLIST_ENTRY(AssignedDevice) next;
+} AssignedDevice;
+
+QemuOpts *add_assigned_device(const char *arg);
+void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices);
+void assigned_dev_update_irqs(void);
+
+#define MAX_DEV_ASSIGN_CMDLINE 8
+
+extern const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE];
+extern int assigned_devices_index;
+
+#endif              /* __DEVICE_ASSIGNMENT_H__ */
diff --git a/hw/extboot.c b/hw/extboot.c
new file mode 100644
index 0000000..b91d54f
--- /dev/null
+++ b/hw/extboot.c
@@ -0,0 +1,135 @@
+/*
+ * Extended boot option ROM support.
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "block.h"
+
+/* Extended Boot ROM suport */
+
+union extboot_cmd
+{
+    uint16_t type;
+    struct {
+	uint16_t type;
+	uint16_t cylinders;
+	uint16_t heads;
+	uint16_t sectors;
+	uint64_t nb_sectors;
+    } query_geometry;
+    struct {
+	uint16_t type;
+	uint16_t nb_sectors;
+	uint16_t segment;
+	uint16_t offset;
+	uint64_t sector;
+    } xfer;
+};
+
+static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
+{
+    bdrv_get_geometry_hint(bs, c, h, s);
+
+    if (*c <= 1024) {
+	*c >>= 0;
+	*h <<= 0;
+    } else if (*c <= 2048) {
+	*c >>= 1;
+	*h <<= 1;
+    } else if (*c <= 4096) {
+	*c >>= 2;
+	*h <<= 2;
+    } else if (*c <= 8192) {
+	*c >>= 3;
+	*h <<= 3;
+    } else {
+	*c >>= 4;
+	*h <<= 4;
+    }
+
+    /* what is the correct algorithm for this?? */
+    if (*h == 256) {
+	*h = 255;
+	*c = *c + 1;
+    }
+}
+
+static uint32_t extboot_read(void *opaque, uint32_t addr)
+{
+    int *pcmd = opaque;
+    return *pcmd;
+}
+
+static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
+{
+    union extboot_cmd cmd;
+    BlockDriverState *bs = opaque;
+    int cylinders, heads, sectors, err;
+    uint64_t nb_sectors;
+    target_phys_addr_t pa = 0;
+    int blen = 0;
+    void *buf = NULL;
+
+    cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&cmd,
+                             sizeof(cmd));
+
+    if (cmd.type == 0x01 || cmd.type == 0x02) {
+	pa = cmd.xfer.segment * 16 + cmd.xfer.offset;
+        blen = cmd.xfer.nb_sectors * 512;
+        buf = qemu_memalign(512, blen);
+    }
+
+    switch (cmd.type) {
+    case 0x00:
+        get_translated_chs(bs, &cylinders, &heads, &sectors);
+	bdrv_get_geometry(bs, &nb_sectors);
+	cmd.query_geometry.cylinders = cylinders;
+	cmd.query_geometry.heads = heads;
+	cmd.query_geometry.sectors = sectors;
+	cmd.query_geometry.nb_sectors = nb_sectors;
+	break;
+    case 0x01:
+	err = bdrv_read(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
+	if (err)
+	    printf("Read failed\n");
+
+        cpu_physical_memory_write(pa, buf, blen);
+
+	break;
+    case 0x02:
+        cpu_physical_memory_read(pa, buf, blen);
+
+	err = bdrv_write(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
+	if (err)
+	    printf("Write failed\n");
+
+	break;
+    }
+
+    cpu_physical_memory_write((value & 0xFFFF) << 4, (uint8_t *)&cmd,
+                              sizeof(cmd));
+    if (buf)
+        qemu_free(buf);
+}
+
+void extboot_init(BlockDriverState *bs, int cmd)
+{
+    int *pcmd;
+
+    pcmd = qemu_mallocz(sizeof(int));
+
+    *pcmd = cmd;
+    register_ioport_read(0x404, 1, 1, extboot_read, pcmd);
+    register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
+}
diff --git a/hw/hpet.c b/hw/hpet.c
index 6f39711..92382e7 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -170,6 +170,11 @@
 
     /* Recalculate the offset between the main counter and guest time */
     s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
+
+    if (hpet_in_legacy_mode()) {
+        hpet_disable_pit();
+    }
+
     return 0;
 }
 
@@ -473,9 +478,11 @@
                 }
                 /* i8254 and RTC are disabled when HPET is in legacy mode */
                 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                    hpet_pit_disable();
+                    hpet_disable_pit();
+                    dprintf("qemu: hpet disabled pit\n");
                 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                    hpet_pit_enable();
+                    hpet_enable_pit();
+                    dprintf("qemu: hpet enabled pit\n");
                 }
                 break;
             case HPET_CFG + 4:
@@ -559,7 +566,7 @@
          * hpet_reset is called due to system reset. At this point control must
          * be returned to pit until SW reenables hpet.
          */
-        hpet_pit_enable();
+        hpet_enable_pit();
     count = 1;
 }
 
diff --git a/hw/hw.h b/hw/hw.h
index 7b500f4..05131a0 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -342,6 +342,10 @@
 extern const VMStateInfo vmstate_info_uint32;
 extern const VMStateInfo vmstate_info_uint64;
 
+#ifdef __linux__
+extern const VMStateInfo vmstate_info_u64;
+#endif
+
 extern const VMStateInfo vmstate_info_timer;
 extern const VMStateInfo vmstate_info_ptimer;
 extern const VMStateInfo vmstate_info_buffer;
@@ -622,6 +626,15 @@
 #define VMSTATE_UINT64(_f, _s)                                        \
     VMSTATE_UINT64_V(_f, _s, 0)
 
+/* This is needed because on linux __u64 is unsigned long long
+   and on glibc uint64_t is unsigned long on 64 bits */
+#ifdef __linux__
+#define VMSTATE_U64_V(_f, _s, _v)                                     \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_u64, __u64)
+#define VMSTATE_U64(_f, _s)                                           \
+    VMSTATE_U64_V(_f, _s, 0)
+#endif
+
 #define VMSTATE_UINT8_EQUAL(_f, _s)                                   \
     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)
 
diff --git a/hw/i8254-kvm.c b/hw/i8254-kvm.c
new file mode 100644
index 0000000..c62ab6a
--- /dev/null
+++ b/hw/i8254-kvm.c
@@ -0,0 +1,122 @@
+/*
+ * QEMU 8253/8254 interval timer emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "qemu-timer.h"
+#include "i8254.h"
+#include "qemu-kvm.h"
+
+extern VMStateDescription vmstate_pit;
+
+static PITState pit_state;
+
+static void kvm_pit_pre_save(void *opaque)
+{
+    PITState *s = (void *)opaque;
+    struct kvm_pit_state2 pit2;
+    struct kvm_pit_channel_state *c;
+    struct PITChannelState *sc;
+    int i;
+
+    if(qemu_kvm_has_pit_state2()) {
+        kvm_get_pit2(kvm_context, &pit2);
+        s->flags = pit2.flags;
+    } else {
+        /* pit2 is superset of pit struct so just cast it and use it */
+        kvm_get_pit(kvm_context, (struct kvm_pit_state *)&pit2);
+    }
+    for (i = 0; i < 3; i++) {
+	c = &pit2.channels[i];
+	sc = &s->channels[i];
+	sc->count = c->count;
+	sc->latched_count = c->latched_count;
+	sc->count_latched = c->count_latched;
+	sc->status_latched = c->status_latched;
+	sc->status = c->status;
+	sc->read_state = c->read_state;
+	sc->write_state = c->write_state;
+	sc->write_latch = c->write_latch;
+	sc->rw_mode = c->rw_mode;
+	sc->mode = c->mode;
+	sc->bcd = c->bcd;
+	sc->gate = c->gate;
+	sc->count_load_time = c->count_load_time;
+    }
+}
+
+static int kvm_pit_post_load(void *opaque, int version_id)
+{
+    PITState *s = opaque;
+    struct kvm_pit_state2 pit2;
+    struct kvm_pit_channel_state *c;
+    struct PITChannelState *sc;
+    int i;
+
+    pit2.flags = s->flags;
+    for (i = 0; i < 3; i++) {
+	c = &pit2.channels[i];
+	sc = &s->channels[i];
+	c->count = sc->count;
+	c->latched_count = sc->latched_count;
+	c->count_latched = sc->count_latched;
+	c->status_latched = sc->status_latched;
+	c->status = sc->status;
+	c->read_state = sc->read_state;
+	c->write_state = sc->write_state;
+	c->write_latch = sc->write_latch;
+	c->rw_mode = sc->rw_mode;
+	c->mode = sc->mode;
+	c->bcd = sc->bcd;
+	c->gate = sc->gate;
+	c->count_load_time = sc->count_load_time;
+    }
+
+    if(qemu_kvm_has_pit_state2()) {
+        kvm_set_pit2(kvm_context, &pit2);
+    } else {
+        kvm_set_pit(kvm_context, (struct kvm_pit_state *)&pit2);
+    }
+    return 0;
+}
+
+static void dummy_timer(void *opaque)
+{
+}
+
+PITState *kvm_pit_init(int base, qemu_irq irq)
+{
+    PITState *pit = &pit_state;
+    PITChannelState *s;
+
+    s = &pit->channels[0];
+    s->irq_timer = qemu_new_timer(vm_clock, dummy_timer, s);
+    vmstate_pit.pre_save = kvm_pit_pre_save;
+    vmstate_pit.post_load = kvm_pit_post_load;
+    vmstate_register(base, &vmstate_pit, pit);
+    qemu_register_reset(pit_reset, pit);
+    pit_reset(pit);
+
+    return pit;
+}
diff --git a/hw/i8254.c b/hw/i8254.c
index faaa884..c4f8d2e 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -25,38 +25,11 @@
 #include "pc.h"
 #include "isa.h"
 #include "qemu-timer.h"
+#include "qemu-kvm.h"
+#include "i8254.h"
 
 //#define DEBUG_PIT
 
-#define RW_STATE_LSB 1
-#define RW_STATE_MSB 2
-#define RW_STATE_WORD0 3
-#define RW_STATE_WORD1 4
-
-typedef struct PITChannelState {
-    int count; /* can be 65536 */
-    uint16_t latched_count;
-    uint8_t count_latched;
-    uint8_t status_latched;
-    uint8_t status;
-    uint8_t read_state;
-    uint8_t write_state;
-    uint8_t write_latch;
-    uint8_t rw_mode;
-    uint8_t mode;
-    uint8_t bcd; /* not supported */
-    uint8_t gate; /* timer start */
-    int64_t count_load_time;
-    /* irq handling */
-    int64_t next_transition_time;
-    QEMUTimer *irq_timer;
-    qemu_irq irq;
-} PITChannelState;
-
-struct PITState {
-    PITChannelState channels[3];
-};
-
 static PITState pit_state;
 
 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
@@ -228,13 +201,18 @@
     return s->mode;
 }
 
-static inline void pit_load_count(PITChannelState *s, int val)
+static inline void pit_load_count(PITState *s, int val, int chan)
 {
     if (val == 0)
         val = 0x10000;
-    s->count_load_time = qemu_get_clock(vm_clock);
-    s->count = val;
-    pit_irq_timer_update(s, s->count_load_time);
+    s->channels[chan].count_load_time = qemu_get_clock(vm_clock);
+    s->channels[chan].count = val;
+#ifdef TARGET_I386
+    if (chan == 0 && pit_state.flags & PIT_FLAGS_HPET_LEGACY) {
+        return;
+    }
+#endif
+    pit_irq_timer_update(&s->channels[chan], s->channels[chan].count_load_time);
 }
 
 /* if already latched, do not latch again */
@@ -294,17 +272,17 @@
         switch(s->write_state) {
         default:
         case RW_STATE_LSB:
-            pit_load_count(s, val);
+            pit_load_count(pit, val, addr);
             break;
         case RW_STATE_MSB:
-            pit_load_count(s, val << 8);
+            pit_load_count(pit, val << 8, addr);
             break;
         case RW_STATE_WORD0:
             s->write_latch = val;
             s->write_state = RW_STATE_WORD1;
             break;
         case RW_STATE_WORD1:
-            pit_load_count(s, s->write_latch | (val << 8));
+            pit_load_count(pit, s->write_latch | (val << 8), addr);
             s->write_state = RW_STATE_WORD0;
             break;
         }
@@ -364,6 +342,11 @@
     return ret;
 }
 
+/* global counters for time-drift fix */
+int64_t timer_acks=0, timer_interrupts=0, timer_ints_to_push=0;
+
+extern int time_drift_fix;
+
 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
 {
     int64_t expire_time;
@@ -374,16 +357,35 @@
     expire_time = pit_get_next_transition_time(s, current_time);
     irq_level = pit_get_out1(s, current_time);
     qemu_set_irq(s->irq, irq_level);
+    if (time_drift_fix && irq_level==1) {
+        /* FIXME: fine tune timer_max_fix (max fix per tick). 
+         *        Should it be 1 (double time), 2 , 4, 10 ? 
+         *        Currently setting it to 5% of PIT-ticks-per-second (per PIT-tick)
+         */
+        const long pit_ticks_per_sec = (s->count>0) ? (PIT_FREQ/s->count) : 0;
+        const long timer_max_fix = pit_ticks_per_sec/20;
+        const long delta = timer_interrupts - timer_acks;
+        const long max_delta = pit_ticks_per_sec * 60; /* one minute */
+        if ((delta >  max_delta) && (pit_ticks_per_sec > 0)) {
+            printf("time drift is too long, %ld seconds were lost\n", delta/pit_ticks_per_sec);
+            timer_acks = timer_interrupts;
+            timer_ints_to_push = 0;
+        } else if (delta > 0) {
+            timer_ints_to_push = MIN(delta, timer_max_fix);
+        }
+        timer_interrupts++;
+    }
 #ifdef DEBUG_PIT
     printf("irq_level=%d next_delay=%f\n",
            irq_level,
            (double)(expire_time - current_time) / get_ticks_per_sec());
 #endif
     s->next_transition_time = expire_time;
-    if (expire_time != -1)
+    if (expire_time != -1) {
         qemu_mod_timer(s->irq_timer, expire_time);
-    else
+    } else {
         qemu_del_timer(s->irq_timer);
+    }
 }
 
 static void pit_irq_timer(void *opaque)
@@ -423,9 +425,10 @@
     PITChannelState *s;
     int i;
 
-    if (version_id != 1)
+    if (version_id != PIT_SAVEVM_VERSION)
         return -EINVAL;
 
+    pit->flags = qemu_get_be32(f);
     for(i = 0; i < 3; i++) {
         s = &pit->channels[i];
         s->count=qemu_get_be32(f);
@@ -446,57 +449,85 @@
             qemu_get_timer(f, s->irq_timer);
         }
     }
+
     return 0;
 }
 
-static const VMStateDescription vmstate_pit = {
+VMStateDescription vmstate_pit = {
     .name = "i8254",
     .version_id = 2,
     .minimum_version_id = 2,
     .minimum_version_id_old = 1,
     .load_state_old = pit_load_old,
     .fields      = (VMStateField []) {
+        VMSTATE_UINT32(flags, PITState),
         VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
         VMSTATE_TIMER(channels[0].irq_timer, PITState),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static void pit_reset(void *opaque)
+void pit_reset(void *opaque)
 {
     PITState *pit = opaque;
     PITChannelState *s;
     int i;
 
+#ifdef TARGET_I386
+    pit->flags &= ~PIT_FLAGS_HPET_LEGACY;
+#endif
     for(i = 0;i < 3; i++) {
         s = &pit->channels[i];
         s->mode = 3;
         s->gate = (i != 2);
-        pit_load_count(s, 0);
+        pit_load_count(pit, 0, i);
     }
 }
 
+#ifdef TARGET_I386
 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
-void hpet_pit_disable(void) {
-    PITChannelState *s;
-    s = &pit_state.channels[0];
-    if (s->irq_timer)
-        qemu_del_timer(s->irq_timer);
+
+void hpet_disable_pit(void)
+{
+    PITChannelState *s = &pit_state.channels[0];
+
+    if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
+        if (qemu_kvm_has_pit_state2()) {
+            kvm_hpet_disable_kpit();
+        } else {
+             fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
+             exit(1);
+        }
+    } else {
+        pit_state.flags |= PIT_FLAGS_HPET_LEGACY;
+        if (s->irq_timer) {
+            qemu_del_timer(s->irq_timer);
+        }
+    }
 }
 
 /* When HPET is reset or leaving legacy mode, it must reenable i8254
  * timer 0
  */
 
-void hpet_pit_enable(void)
+void hpet_enable_pit(void)
 {
     PITState *pit = &pit_state;
-    PITChannelState *s;
-    s = &pit->channels[0];
-    s->mode = 3;
-    s->gate = 1;
-    pit_load_count(s, 0);
+    PITChannelState *s = &pit->channels[0];
+
+    if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
+        if (qemu_kvm_has_pit_state2()) {
+            kvm_hpet_enable_kpit();
+        } else {
+             fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
+             exit(1);
+        }
+    } else {
+        pit_state.flags &= ~PIT_FLAGS_HPET_LEGACY;
+        pit_load_count(pit, s->count, 0);
+    }
 }
+#endif
 
 PITState *pit_init(int base, qemu_irq irq)
 {
diff --git a/hw/i8254.h b/hw/i8254.h
new file mode 100644
index 0000000..d23303a
--- /dev/null
+++ b/hw/i8254.h
@@ -0,0 +1,69 @@
+/*
+ * QEMU 8253/8254 interval timer emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8254_H
+#define QEMU_I8254_H
+
+#define PIT_SAVEVM_NAME "i8254"
+#define PIT_SAVEVM_VERSION 2
+
+#define RW_STATE_LSB 1
+#define RW_STATE_MSB 2
+#define RW_STATE_WORD0 3
+#define RW_STATE_WORD1 4
+
+#define PIT_FLAGS_HPET_LEGACY  1
+
+typedef struct PITChannelState {
+    int count; /* can be 65536 */
+    uint16_t latched_count;
+    uint8_t count_latched;
+    uint8_t status_latched;
+    uint8_t status;
+    uint8_t read_state;
+    uint8_t write_state;
+    uint8_t write_latch;
+    uint8_t rw_mode;
+    uint8_t mode;
+    uint8_t bcd; /* not supported */
+    uint8_t gate; /* timer start */
+    int64_t count_load_time;
+    /* irq handling */
+    int64_t next_transition_time;
+    QEMUTimer *irq_timer;
+    qemu_irq irq;
+} PITChannelState;
+
+struct PITState {
+    PITChannelState channels[3];
+    uint32_t flags;
+};
+
+void pit_save(QEMUFile *f, void *opaque);
+
+int pit_load(QEMUFile *f, void *opaque, int version_id);
+
+void pit_reset(void *opaque);
+
+#endif
diff --git a/hw/i8259.c b/hw/i8259.c
index 3de22e3..7a484c0 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -27,6 +27,8 @@
 #include "monitor.h"
 #include "qemu-timer.h"
 
+#include "qemu-kvm.h"
+
 /* debug PIC */
 //#define DEBUG_PIC
 
@@ -181,7 +183,6 @@
 static void i8259_set_irq(void *opaque, int irq, int level)
 {
     PicState2 *s = opaque;
-
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
     if (level != irq_level[irq]) {
 #if defined(DEBUG_PIC)
@@ -212,18 +213,35 @@
     } else {
         s->isr |= (1 << irq);
     }
+
     /* We don't clear a level sensitive interrupt here */
     if (!(s->elcr & (1 << irq)))
         s->irr &= ~(1 << irq);
+
 }
 
+extern int time_drift_fix;
+
 int pic_read_irq(PicState2 *s)
 {
     int irq, irq2, intno;
 
     irq = pic_get_irq(&s->pics[0]);
     if (irq >= 0) {
+
         pic_intack(&s->pics[0], irq);
+#ifndef TARGET_IA64
+	if (time_drift_fix && irq == 0) {
+	    extern int64_t timer_acks, timer_ints_to_push;
+	    timer_acks++;
+	    if (timer_ints_to_push > 0) {
+		timer_ints_to_push--;
+                /* simulate an edge irq0, like the one generated by i8254 */
+                pic_set_irq1(&s->pics[0], 0, 0);
+                pic_set_irq1(&s->pics[0], 0, 1);
+	    }
+	}
+#endif
         if (irq == 2) {
             irq2 = pic_get_irq(&s->pics[1]);
             if (irq2 >= 0) {
@@ -446,9 +464,33 @@
     return s->elcr;
 }
 
+static void kvm_kernel_pic_save_to_user(PicState *s);
+static int kvm_kernel_pic_load_from_user(PicState *s);
+
+static void pic_pre_save(void *opaque)
+{
+    PicState *s = opaque;
+
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_pic_save_to_user(s);
+    }
+}
+
+static int pic_post_load(void *opaque, int version_id)
+{
+    PicState *s = opaque;
+
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_pic_load_from_user(s);
+    }
+    return 0;
+}
+
 static const VMStateDescription vmstate_pic = {
     .name = "i8259",
     .version_id = 1,
+    .pre_save = pic_pre_save,
+    .post_load = pic_post_load,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
@@ -535,3 +577,103 @@
     isa_pic = s;
     return qemu_allocate_irqs(i8259_set_irq, s, 16);
 }
+
+static void kvm_kernel_pic_save_to_user(PicState *s)
+{
+#ifdef KVM_CAP_IRQCHIP
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+
+    chip.chip_id = (&s->pics_state->pics[0] == s) ?
+                   KVM_IRQCHIP_PIC_MASTER :
+                   KVM_IRQCHIP_PIC_SLAVE;
+    kvm_get_irqchip(kvm_context, &chip);
+    kpic = &chip.chip.pic;
+
+    s->last_irr = kpic->last_irr;
+    s->irr = kpic->irr;
+    s->imr = kpic->imr;
+    s->isr = kpic->isr;
+    s->priority_add = kpic->priority_add;
+    s->irq_base = kpic->irq_base;
+    s->read_reg_select = kpic->read_reg_select;
+    s->poll = kpic->poll;
+    s->special_mask = kpic->special_mask;
+    s->init_state = kpic->init_state;
+    s->auto_eoi = kpic->auto_eoi;
+    s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
+    s->special_fully_nested_mode = kpic->special_fully_nested_mode;
+    s->init4 = kpic->init4;
+    s->elcr = kpic->elcr;
+    s->elcr_mask = kpic->elcr_mask;
+#endif
+}
+
+static int kvm_kernel_pic_load_from_user(PicState *s)
+{
+#ifdef KVM_CAP_IRQCHIP
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+
+    chip.chip_id = (&s->pics_state->pics[0] == s) ?
+                   KVM_IRQCHIP_PIC_MASTER :
+                   KVM_IRQCHIP_PIC_SLAVE;
+    kpic = &chip.chip.pic;
+
+    kpic->last_irr = s->last_irr;
+    kpic->irr = s->irr;
+    kpic->imr = s->imr;
+    kpic->isr = s->isr;
+    kpic->priority_add = s->priority_add;
+    kpic->irq_base = s->irq_base;
+    kpic->read_reg_select = s->read_reg_select;
+    kpic->poll = s->poll;
+    kpic->special_mask = s->special_mask;
+    kpic->init_state = s->init_state;
+    kpic->auto_eoi = s->auto_eoi;
+    kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
+    kpic->special_fully_nested_mode = s->special_fully_nested_mode;
+    kpic->init4 = s->init4;
+    kpic->elcr = s->elcr;
+    kpic->elcr_mask = s->elcr_mask;
+
+    kvm_set_irqchip(kvm_context, &chip);
+#endif
+    return 0;
+}
+
+#ifdef KVM_CAP_IRQCHIP
+static void kvm_i8259_set_irq(void *opaque, int irq, int level)
+{
+    int pic_ret;
+    if (kvm_set_irq(irq, level, &pic_ret)) {
+        if (pic_ret != 0)
+            apic_set_irq_delivered();
+        return;
+    }
+}
+
+static void kvm_pic_init1(int io_addr, PicState *s)
+{
+    vmstate_register(io_addr, &vmstate_pic, s);
+    qemu_register_reset(pic_reset, s);
+}
+
+qemu_irq *kvm_i8259_init(qemu_irq parent_irq)
+{
+    PicState2 *s;
+
+    s = qemu_mallocz(sizeof(PicState2));
+
+    kvm_pic_init1(0x20, &s->pics[0]);
+    kvm_pic_init1(0xa0, &s->pics[1]);
+    s->parent_irq = parent_irq;
+    s->pics[0].pics_state = s;
+    s->pics[1].pics_state = s;
+    isa_pic = s;
+    return qemu_allocate_irqs(kvm_i8259_set_irq, s, 24);
+}
+#endif
+
+
+
diff --git a/hw/ioapic.c b/hw/ioapic.c
index b0ad78f..a66325d 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -22,12 +22,16 @@
 
 #include "hw.h"
 #include "pc.h"
+#include "sysemu.h"
 #include "qemu-timer.h"
 #include "host-utils.h"
 
+#include "qemu-kvm.h"
+
 //#define DEBUG_IOAPIC
 
 #define IOAPIC_NUM_PINS			0x18
+#define IOAPIC_DEFAULT_BASE_ADDRESS  0xfec00000
 #define IOAPIC_LVT_MASKED 		(1<<16)
 
 #define IOAPIC_TRIGGER_EDGE		0
@@ -45,6 +49,7 @@
 struct IOAPICState {
     uint8_t id;
     uint8_t ioregsel;
+    uint64_t base_address;
 
     uint32_t irr;
     uint64_t ioredtbl[IOAPIC_NUM_PINS];
@@ -94,8 +99,9 @@
      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
      * the cleanest way of doing it but it should work. */
 
-    if (vector == 0)
+    if (vector == 0 && irq0override) {
         vector = 2;
+    }
 
     if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
         uint32_t mask = 1 << vector;
@@ -191,14 +197,91 @@
     }
 }
 
+static void kvm_kernel_ioapic_save_to_user(IOAPICState *s)
+{
+#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386)
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    kvm_get_irqchip(kvm_context, &chip);
+    kioapic = &chip.chip.ioapic;
+
+    s->id = kioapic->id;
+    s->ioregsel = kioapic->ioregsel;
+    s->base_address = kioapic->base_address;
+    s->irr = kioapic->irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = kioapic->redirtbl[i].bits;
+    }
+#endif
+}
+
+static void kvm_kernel_ioapic_load_from_user(IOAPICState *s)
+{
+#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386)
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    kioapic = &chip.chip.ioapic;
+
+    kioapic->id = s->id;
+    kioapic->ioregsel = s->ioregsel;
+    kioapic->base_address = s->base_address;
+    kioapic->irr = s->irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        kioapic->redirtbl[i].bits = s->ioredtbl[i];
+    }
+
+    kvm_set_irqchip(kvm_context, &chip);
+#endif
+}
+
+static void ioapic_pre_save(void *opaque)
+{
+    IOAPICState *s = (void *)opaque;
+ 
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_ioapic_save_to_user(s);
+    }
+}
+
+static int ioapic_pre_load(void *opaque)
+{
+    IOAPICState *s = opaque;
+
+    /* in case we are doing version 1, we just set these to sane values */
+    s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
+    s->irr = 0;
+    return 0;
+}
+
+static int ioapic_post_load(void *opaque, int version_id)
+{
+    IOAPICState *s = opaque;
+
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_ioapic_load_from_user(s);
+    }
+    return 0;
+}
+
 static const VMStateDescription vmstate_ioapic = {
     .name = "ioapic",
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
+    .pre_load = ioapic_pre_load,
+    .post_load = ioapic_post_load,
+    .pre_save = ioapic_pre_save,
     .fields      = (VMStateField []) {
         VMSTATE_UINT8(id, IOAPICState),
         VMSTATE_UINT8(ioregsel, IOAPICState),
+        VMSTATE_UINT64_V(base_address, IOAPICState, 2),
+        VMSTATE_UINT32_V(irr, IOAPICState, 2),
         VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
         VMSTATE_END_OF_LIST()
     }
@@ -210,8 +293,14 @@
     int i;
 
     memset(s, 0, sizeof(*s));
+    s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
     for(i = 0; i < IOAPIC_NUM_PINS; i++)
         s->ioredtbl[i] = 1 << 16; /* mask LVT */
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_kernel_ioapic_load_from_user(s);
+    }
+#endif
 }
 
 static CPUReadMemoryFunc * const ioapic_mem_read[3] = {
diff --git a/hw/ipf.c b/hw/ipf.c
new file mode 100644
index 0000000..21cff72
--- /dev/null
+++ b/hw/ipf.c
@@ -0,0 +1,713 @@
+/*
+ * Itanium Platform Emulator derived from QEMU PC System Emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Copyright (c) 2007 Intel
+ * Ported for IA64 Platform Zhang Xiantao <xiantao.zhang@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "fdc.h"
+#include "pci.h"
+#include "block.h"
+#include "sysemu.h"
+#include "audio/audio.h"
+#include "net.h"
+#include "smbus.h"
+#include "boards.h"
+#include "firmware.h"
+#include "ia64intrin.h"
+#include <unistd.h>
+#include "device-assignment.h"
+#include "virtio-blk.h"
+
+#include "qemu-kvm.h"
+
+#define FW_FILENAME "Flash.fd"
+
+/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
+#define ACPI_DATA_SIZE       0x10000
+
+#define MAX_IDE_BUS 2
+
+static fdctrl_t *floppy_controller;
+static RTCState *rtc_state;
+static PCIDevice *i440fx_state;
+
+static uint32_t ipf_to_legacy_io(target_phys_addr_t addr)
+{
+    return (uint32_t)(((addr&0x3ffffff) >> 12 << 2)|((addr) & 0x3));
+}
+
+static void ipf_legacy_io_writeb(void *opaque, target_phys_addr_t addr,
+				 uint32_t val) {
+    uint32_t port = ipf_to_legacy_io(addr);
+
+    cpu_outb(0, port, val);
+}
+
+static void ipf_legacy_io_writew(void *opaque, target_phys_addr_t addr,
+				 uint32_t val) {
+    uint32_t port = ipf_to_legacy_io(addr);
+
+    cpu_outw(0, port, val);
+}
+
+static void ipf_legacy_io_writel(void *opaque, target_phys_addr_t addr,
+				 uint32_t val) {
+    uint32_t port = ipf_to_legacy_io(addr);
+
+    cpu_outl(0, port, val);
+}
+
+static uint32_t ipf_legacy_io_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t port = ipf_to_legacy_io(addr);
+
+    return cpu_inb(0, port);
+}
+
+static uint32_t ipf_legacy_io_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t port = ipf_to_legacy_io(addr);
+
+    return cpu_inw(0, port);
+}
+
+static uint32_t ipf_legacy_io_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t port = ipf_to_legacy_io(addr);
+
+    return cpu_inl(0, port);
+}
+
+static CPUReadMemoryFunc *ipf_legacy_io_read[3] = {
+    ipf_legacy_io_readb,
+    ipf_legacy_io_readw,
+    ipf_legacy_io_readl,
+};
+
+static CPUWriteMemoryFunc *ipf_legacy_io_write[3] = {
+    ipf_legacy_io_writeb,
+    ipf_legacy_io_writew,
+    ipf_legacy_io_writel,
+};
+
+static void pic_irq_request(void *opaque, int irq, int level)
+{
+    fprintf(stderr,"pic_irq_request called!\n");
+}
+
+/* PC cmos mappings */
+
+#define REG_EQUIPMENT_BYTE          0x14
+
+static int cmos_get_fd_drive_type(int fd0)
+{
+    int val;
+
+    switch (fd0) {
+    case 0:
+        /* 1.44 Mb 3"5 drive */
+        val = 4;
+        break;
+    case 1:
+        /* 2.88 Mb 3"5 drive */
+        val = 5;
+        break;
+    case 2:
+        /* 1.2 Mb 5"5 drive */
+        val = 2;
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    return val;
+}
+
+static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
+{
+    RTCState *s = rtc_state;
+    int cylinders, heads, sectors;
+
+    bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
+    rtc_set_memory(s, type_ofs, 47);
+    rtc_set_memory(s, info_ofs, cylinders);
+    rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
+    rtc_set_memory(s, info_ofs + 2, heads);
+    rtc_set_memory(s, info_ofs + 3, 0xff);
+    rtc_set_memory(s, info_ofs + 4, 0xff);
+    rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
+    rtc_set_memory(s, info_ofs + 6, cylinders);
+    rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
+    rtc_set_memory(s, info_ofs + 8, sectors);
+}
+
+/* convert boot_device letter to something recognizable by the bios */
+static int boot_device2nibble(char boot_device)
+{
+    switch(boot_device) {
+    case 'a':
+    case 'b':
+        return 0x01; /* floppy boot */
+    case 'c':
+        return 0x02; /* hard drive boot */
+    case 'd':
+        return 0x03; /* CD-ROM boot */
+    case 'n':
+        return 0x04; /* Network boot */
+    }
+    return 0;
+}
+
+/* hd_table must contain 4 block drivers */
+static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+                      const char *boot_device, BlockDriverState **hd_table)
+{
+    RTCState *s = rtc_state;
+    int nbds, bds[3] = { 0, };
+    int val;
+    int fd0, fd1, nb;
+    int i;
+
+    /* various important CMOS locations needed by PC/Bochs bios */
+
+    /* memory size */
+    val = 640; /* base memory in K */
+    rtc_set_memory(s, 0x15, val);
+    rtc_set_memory(s, 0x16, val >> 8);
+
+    val = (ram_size / 1024) - 1024;
+    if (val > 65535)
+        val = 65535;
+    rtc_set_memory(s, 0x17, val);
+    rtc_set_memory(s, 0x18, val >> 8);
+    rtc_set_memory(s, 0x30, val);
+    rtc_set_memory(s, 0x31, val >> 8);
+
+    if (above_4g_mem_size) {
+        rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
+        rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
+        rtc_set_memory(s, 0x5d, above_4g_mem_size >> 32);
+    }
+    rtc_set_memory(s, 0x5f, smp_cpus - 1);
+
+    if (ram_size > (16 * 1024 * 1024))
+        val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
+    else
+        val = 0;
+    if (val > 65535)
+        val = 65535;
+    rtc_set_memory(s, 0x34, val);
+    rtc_set_memory(s, 0x35, val >> 8);
+
+    /* set boot devices, and disable floppy signature check if requested */
+#define PC_MAX_BOOT_DEVICES 3
+    nbds = strlen(boot_device);
+
+    if (nbds > PC_MAX_BOOT_DEVICES) {
+        fprintf(stderr, "Too many boot devices for PC\n");
+        exit(1);
+    }
+
+    for (i = 0; i < nbds; i++) {
+        bds[i] = boot_device2nibble(boot_device[i]);
+        if (bds[i] == 0) {
+            fprintf(stderr, "Invalid boot device for PC: '%c'\n",
+                    boot_device[i]);
+            exit(1);
+        }
+    }
+
+    rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
+    rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ?  0x0 : 0x1));
+
+    /* floppy type */
+
+    fd0 = fdctrl_get_drive_type(floppy_controller, 0);
+    fd1 = fdctrl_get_drive_type(floppy_controller, 1);
+
+    val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
+    rtc_set_memory(s, 0x10, val);
+
+    val = 0;
+    nb = 0;
+    if (fd0 < 3)
+        nb++;
+    if (fd1 < 3)
+        nb++;
+
+    switch (nb) {
+    case 0:
+        break;
+    case 1:
+        val |= 0x01; /* 1 drive, ready for boot */
+        break;
+    case 2:
+        val |= 0x41; /* 2 drives, ready for boot */
+        break;
+    }
+
+    val |= 0x02; /* FPU is there */
+    val |= 0x04; /* PS/2 mouse installed */
+    rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
+
+    /* hard drives */
+
+    rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
+    if (hd_table[0])
+        cmos_init_hd(0x19, 0x1b, hd_table[0]);
+    if (hd_table[1])
+        cmos_init_hd(0x1a, 0x24, hd_table[1]);
+
+    val = 0;
+    for (i = 0; i < 4; i++) {
+        if (hd_table[i]) {
+            int cylinders, heads, sectors, translation;
+            /* NOTE: bdrv_get_geometry_hint() returns the physical
+               geometry.  It is always such that: 1 <= sects <= 63, 1
+               <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
+               geometry can be different if a translation is done. */
+            translation = bdrv_get_translation_hint(hd_table[i]);
+            if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+                bdrv_get_geometry_hint(hd_table[i], &cylinders,
+                                       &heads, &sectors);
+                if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
+                    /* No translation. */
+                    translation = 0;
+                } else {
+                    /* LBA translation. */
+                    translation = 1;
+                }
+            } else {
+                translation--;
+            }
+            val |= translation << (i * 2);
+        }
+    }
+    rtc_set_memory(s, 0x39, val);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+}
+
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
+#define NE2000_NB_MAX 6
+
+static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340,
+                                        0x360, 0x280, 0x380 };
+static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
+
+static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
+
+static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
+static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
+
+#ifdef HAS_AUDIO
+static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
+{
+    struct soundhw *c;
+    int audio_enabled = 0;
+
+    for (c = soundhw; !audio_enabled && c->name; ++c) {
+        audio_enabled = c->enabled;
+    }
+
+    if (audio_enabled) {
+        AudioState *s;
+
+        s = AUD_init ();
+        if (s) {
+            for (c = soundhw; c->name; ++c) {
+                if (c->enabled) {
+                    if (c->isa) {
+                        c->init.init_isa (s, pic);
+                    } else {
+                        if (pci_bus) {
+                            c->init.init_pci (pci_bus, s);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
+static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
+{
+    static int nb_ne2k = 0;
+
+    if (nb_ne2k == NE2000_NB_MAX)
+        return;
+    isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
+    nb_ne2k++;
+}
+
+/* Itanium hardware initialisation */
+static void ipf_init1(ram_addr_t ram_size,
+                      const char *boot_device, DisplayState *ds,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename,
+                      int pci_enabled, const char *cpu_model)
+{
+    char buf[1024];
+    int i;
+    ram_addr_t ram_addr;
+    ram_addr_t above_4g_mem_size = 0;
+    PCIBus *pci_bus;
+    PCIDevice *pci_dev;
+    int piix3_devfn = -1;
+    CPUState *env;
+    qemu_irq *cpu_irq;
+    qemu_irq *i8259;
+    int page_size;
+    int index;
+    unsigned long ipf_legacy_io_base, ipf_legacy_io_mem;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BlockDriverState *fd[MAX_FD];
+
+    page_size = getpagesize();
+    if (page_size != TARGET_PAGE_SIZE) {
+	fprintf(stderr,"Error! Host page size != qemu target page size,"
+                " you may need to change TARGET_PAGE_BITS in qemu!"
+                "host page size:0x%x\n", page_size);
+        exit(-1);
+    };
+
+    if (ram_size >= 0xc0000000 ) {
+        above_4g_mem_size = ram_size - 0xc0000000;
+        ram_size = 0xc0000000;
+    }
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "IA64";
+    }
+
+    for(i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        if (i != 0)
+            env->hflags |= HF_HALTED_MASK;
+        register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
+        qemu_register_reset(main_cpu_reset, 0, env);
+    }
+
+    /* allocate RAM */
+    if (kvm_enabled()) {
+        ram_addr = qemu_ram_alloc(0xa0000);
+        cpu_register_physical_memory(0, 0xa0000, ram_addr);
+
+        ram_addr = qemu_ram_alloc(0x20000); // Workaround 0xa0000-0xc0000
+
+        ram_addr = qemu_ram_alloc(0x40000);
+        cpu_register_physical_memory(0xc0000, 0x40000, ram_addr);
+
+        ram_addr = qemu_ram_alloc(ram_size - 0x100000);
+        cpu_register_physical_memory(0x100000, ram_size - 0x100000, ram_addr);
+    } else {
+        ram_addr = qemu_ram_alloc(ram_size);
+        cpu_register_physical_memory(0, ram_size, ram_addr);
+    }
+
+    /* above 4giga memory allocation */
+    if (above_4g_mem_size > 0) {
+        ram_addr = qemu_ram_alloc(above_4g_mem_size);
+        cpu_register_physical_memory(0x100000000, above_4g_mem_size, ram_addr);
+    }
+
+    /*Load firware to its proper position.*/
+    if (kvm_enabled()) {
+        unsigned long  image_size;
+        uint8_t *image = NULL;
+        unsigned long nvram_addr;
+        unsigned long nvram_fd = 0;
+        unsigned long type = READ_FROM_NVRAM;
+        unsigned long i = 0;
+        unsigned long fw_offset;
+        ram_addr_t fw_mem = qemu_ram_alloc(GFW_SIZE);
+
+        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, FW_FILENAME);
+        image = read_image(buf, &image_size );
+        if (NULL == image || !image_size) {
+            fprintf(stderr, "Error when reading Guest Firmware!\n");
+            fprintf(stderr, "Please check Guest firmware at %s\n", buf);
+            exit(1);
+        }
+        fw_offset = GFW_START + GFW_SIZE - image_size;
+
+        cpu_register_physical_memory(GFW_START, GFW_SIZE, fw_mem);
+        cpu_physical_memory_write(fw_offset, image, image_size);
+
+        free(image);
+
+        if (nvram) {
+            nvram_addr = NVRAM_START;
+            nvram_fd = kvm_ia64_nvram_init(type);
+            if (nvram_fd != -1) {
+                kvm_ia64_copy_from_nvram_to_GFW(nvram_fd);
+                close(nvram_fd);
+            }
+            i = atexit((void *)kvm_ia64_copy_from_GFW_to_nvram);
+            if (i != 0)
+                fprintf(stderr, "cannot set exit function\n");
+        } else
+            nvram_addr = 0;
+
+        kvm_ia64_build_hob(ram_size + above_4g_mem_size, smp_cpus, nvram_addr);
+    }
+
+    /*Register legacy io address space, size:64M*/
+    ipf_legacy_io_base = 0xE0000000;
+    ipf_legacy_io_mem = cpu_register_io_memory(0, ipf_legacy_io_read,
+                                               ipf_legacy_io_write, NULL);
+    cpu_register_physical_memory(ipf_legacy_io_base, 64*1024*1024,
+                                 ipf_legacy_io_mem);
+
+    cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
+    i8259 = kvm_i8259_init(cpu_irq[0]);
+
+    if (pci_enabled) {
+        pci_bus = i440fx_init(&i440fx_state, i8259);
+        piix3_devfn = piix3_init(pci_bus, -1);
+    } else {
+        pci_bus = NULL;
+    }
+
+    if (cirrus_vga_enabled) {
+        if (pci_enabled)
+            pci_cirrus_vga_init(pci_bus);
+        else
+            isa_cirrus_vga_init();
+    } else {
+        if (pci_enabled)
+            pci_vga_init(pci_bus, 0, 0);
+        else
+            isa_vga_init();
+    }
+
+    rtc_state = rtc_init(0x70, i8259[8], 2000);
+
+    if (pci_enabled) {
+        pic_set_alt_irq_func(isa_pic, NULL, NULL);
+    }
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_init(serial_io[i], i8259[serial_irq[i]], 115200,
+                        serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(parallel_io[i], i8259[parallel_irq[i]],
+                          parallel_hds[i]);
+        }
+    }
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
+            pc_init_ne2k_isa(nd, i8259);
+        else
+            pci_nic_init(nd, "e1000", NULL);
+    }
+
+#undef USE_HYPERCALL  //Disable it now, need to implement later!
+#ifdef USE_HYPERCALL
+    pci_hypercall_init(pci_bus);
+#endif
+
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+	if (index != -1)
+	    hd[i] = drives_table[index].bdrv;
+	else
+	    hd[i] = NULL;
+    }
+
+    if (pci_enabled) {
+        pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
+    } else {
+        for(i = 0; i < MAX_IDE_BUS; i++) {
+            isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
+	                 hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+        }
+    }
+
+    i8042_init(i8259[1], i8259[12], 0x60);
+    DMA_init(0);
+#ifdef HAS_AUDIO
+    audio_init(pci_enabled ? pci_bus : NULL, i8259);
+#endif
+
+    for(i = 0; i < MAX_FD; i++) {
+        index = drive_get_index(IF_FLOPPY, 0, i);
+	if (index != -1)
+	    fd[i] = drives_table[index].bdrv;
+	else
+	    fd[i] = NULL;
+    }
+    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
+
+    cmos_init(ram_size, above_4g_mem_size, boot_device, hd);
+
+    if (pci_enabled && usb_enabled) {
+        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+    }
+
+    if (pci_enabled && acpi_enabled) {
+        uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+        i2c_bus *smbus;
+
+        /* TODO: Populate SPD eeprom data.  */
+        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
+        for (i = 0; i < 8; i++) {
+            DeviceState *eeprom;
+            eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+            qdev_set_prop_int(eeprom, "address", 0x50 + i);
+            qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
+            qdev_init(eeprom);
+        }
+    }
+
+    if (i440fx_state) {
+        i440fx_init_memory_mappings(i440fx_state);
+    }
+
+    if (pci_enabled) {
+	int max_bus;
+        int bus;
+
+        max_bus = drive_get_max_bus(IF_SCSI);
+	for (bus = 0; bus <= max_bus; bus++) {
+            pci_create_simple(pci_bus, -1, "lsi53c895a");
+        }
+    }
+    /* Add virtio block devices */
+    if (pci_enabled) {
+	int index;
+	int unit_id = 0;
+
+	while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
+            pci_dev = pci_create("virtio-blk-pci",
+                                 drives_table[index].devaddr);
+            qdev_init(&pci_dev->qdev);
+	    unit_id++;
+	}
+    }
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+    if (kvm_enabled())
+	add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
+#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
+
+}
+
+static void ipf_init_pci(ram_addr_t ram_size,
+                         const char *boot_device, DisplayState *ds,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename,
+                         const char *cpu_model)
+{
+    ipf_init1(ram_size, boot_device, ds, kernel_filename,
+              kernel_cmdline, initrd_filename, 1, cpu_model);
+}
+
+QEMUMachine ipf_machine = {
+    .name = "itanium",
+    .desc = "Itanium Platform",
+    .init = (QEMUMachineInitFunc *)ipf_init_pci,
+    .max_cpus = 255,
+    .is_default = 1,
+};
+
+static void ipf_machine_init(void)
+{
+    qemu_register_machine(&ipf_machine);
+}
+
+machine_init(ipf_machine_init);
+
+#define IOAPIC_NUM_PINS 48
+
+static int ioapic_irq_count[IOAPIC_NUM_PINS];
+
+static int ioapic_map_irq(int devfn, int irq_num)
+{
+    int irq, dev;
+    dev = devfn >> 3;
+    irq = ((((dev << 2) + (dev >> 3) + irq_num) & 31) + 16);
+    return irq;
+}
+
+/*
+ * Dummy function to provide match for call from hw/apic.c
+ */
+void apic_set_irq_delivered(void) {
+}
+
+void ioapic_set_irq(void *opaque, int irq_num, int level)
+{
+    int vector, pic_ret;
+
+    PCIDevice *pci_dev = (PCIDevice *)opaque;
+    vector = ioapic_map_irq(pci_dev->devfn, irq_num);
+
+    if (level)
+        ioapic_irq_count[vector] += 1;
+    else
+        ioapic_irq_count[vector] -= 1;
+
+    if (kvm_enabled()) {
+	if (kvm_set_irq(vector, ioapic_irq_count[vector] == 0, &pic_ret))
+            if (pic_ret != 0)
+                apic_set_irq_delivered();
+	    return;
+    }
+}
+
+int ipf_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+	return ioapic_map_irq(pci_dev->devfn, irq_num);
+}
diff --git a/hw/msix.c b/hw/msix.c
index 0baedef..d117bcf 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -14,6 +14,8 @@
 #include "hw.h"
 #include "msix.h"
 #include "pci.h"
+#define QEMU_KVM_NO_CPU
+#include "qemu-kvm.h"
 
 /* Declaration from linux/pci_regs.h */
 #define  PCI_CAP_ID_MSIX 0x11 /* MSI-X */
@@ -62,6 +64,117 @@
 /* Flag for interrupt controller to declare MSI-X support */
 int msix_supported;
 
+#ifdef CONFIG_KVM
+/* KVM specific MSIX helpers */
+static void kvm_msix_free(PCIDevice *dev)
+{
+    int vector, changed = 0;
+    for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+        if (dev->msix_entry_used[vector]) {
+            kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]);
+            changed = 1;
+        }
+    }
+    if (changed) {
+        kvm_commit_irq_routes(kvm_context);
+    }
+}
+
+static void kvm_msix_routing_entry(PCIDevice *dev, unsigned vector,
+                                   struct kvm_irq_routing_entry *entry)
+{
+    uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE;
+    entry->type = KVM_IRQ_ROUTING_MSI;
+    entry->flags = 0;
+    entry->u.msi.address_lo = pci_get_long(table_entry + MSIX_MSG_ADDR);
+    entry->u.msi.address_hi = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
+    entry->u.msi.data = pci_get_long(table_entry + MSIX_MSG_DATA);
+}
+
+static void kvm_msix_update(PCIDevice *dev, int vector,
+                            int was_masked, int is_masked)
+{
+    struct kvm_irq_routing_entry e = {}, *entry;
+    int mask_cleared = was_masked && !is_masked;
+    /* It is only legal to change an entry when it is masked. Therefore, it is
+     * enough to update the routing in kernel when mask is being cleared. */
+    if (!mask_cleared) {
+        return;
+    }
+    if (!dev->msix_entry_used[vector]) {
+        return;
+    }
+    entry = dev->msix_irq_entries + vector;
+    e.gsi = entry->gsi;
+    kvm_msix_routing_entry(dev, vector, &e);
+    if (memcmp(&entry->u.msi, &e.u.msi, sizeof entry->u.msi)) {
+        int r;
+        r = kvm_update_routing_entry(kvm_context, entry, &e);
+        if (r) {
+            fprintf(stderr, "%s: kvm_update_routing_entry failed: %s\n", __func__,
+		    strerror(-r));
+            exit(1);
+        }
+        memcpy(&entry->u.msi, &e.u.msi, sizeof entry->u.msi);
+        r = kvm_commit_irq_routes(kvm_context);
+        if (r) {
+            fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__,
+		    strerror(-r));
+            exit(1);
+        }
+    }
+}
+
+static int kvm_msix_add(PCIDevice *dev, unsigned vector)
+{
+    struct kvm_irq_routing_entry *entry = dev->msix_irq_entries + vector;
+    int r;
+
+    if (!kvm_has_gsi_routing(kvm_context)) {
+        fprintf(stderr, "Warning: no MSI-X support found. "
+                "At least kernel 2.6.30 is required for MSI-X support.\n"
+               );
+        return -EOPNOTSUPP;
+    }
+
+    r = kvm_get_irq_route_gsi(kvm_context);
+    if (r < 0) {
+        fprintf(stderr, "%s: kvm_get_irq_route_gsi failed: %s\n", __func__, strerror(-r));
+        return r;
+    }
+    entry->gsi = r;
+    kvm_msix_routing_entry(dev, vector, entry);
+    r = kvm_add_routing_entry(kvm_context, entry);
+    if (r < 0) {
+        fprintf(stderr, "%s: kvm_add_routing_entry failed: %s\n", __func__, strerror(-r));
+        return r;
+    }
+
+    r = kvm_commit_irq_routes(kvm_context);
+    if (r < 0) {
+        fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__, strerror(-r));
+        return r;
+    }
+    return 0;
+}
+
+static void kvm_msix_del(PCIDevice *dev, unsigned vector)
+{
+    if (dev->msix_entry_used[vector]) {
+        return;
+    }
+    kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]);
+    kvm_commit_irq_routes(kvm_context);
+}
+#else
+
+static void kvm_msix_free(PCIDevice *dev) {}
+static void kvm_msix_update(PCIDevice *dev, int vector,
+                            int was_masked, int is_masked) {}
+static int kvm_msix_add(PCIDevice *dev, unsigned vector) { return -1; }
+static void kvm_msix_del(PCIDevice *dev, unsigned vector) {}
+#endif
+
 /* Add MSI-X capability to the config space for the device. */
 /* Given a bar and its size, add MSI-X table on top of it
  * and fill MSI-X capability in the config space.
@@ -200,7 +313,11 @@
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
     int vector = offset / MSIX_ENTRY_SIZE;
+    int was_masked = msix_is_masked(dev, vector);
     pci_set_long(dev->msix_table_page + offset, val);
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
+    }
     msix_handle_mask_update(dev, vector);
 }
 
@@ -259,6 +376,12 @@
     if (nentries > MSIX_MAX_ENTRIES)
         return -EINVAL;
 
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev->msix_irq_entries = qemu_malloc(nentries *
+                                            sizeof *dev->msix_irq_entries);
+    }
+#endif
     dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
                                         sizeof *dev->msix_entry_used);
 
@@ -295,6 +418,10 @@
 {
     int vector;
 
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_msix_free(dev);
+    }
+
     for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
         dev->msix_entry_used[vector] = 0;
         msix_clr_pending(dev, vector);
@@ -315,6 +442,8 @@
     dev->msix_table_page = NULL;
     qemu_free(dev->msix_entry_used);
     dev->msix_entry_used = NULL;
+    qemu_free(dev->msix_irq_entries);
+    dev->msix_irq_entries = NULL;
     dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
     return 0;
 }
@@ -323,10 +452,13 @@
 {
     unsigned n = dev->msix_entries_nr;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+    if (!msix_supported) {
         return;
     }
 
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+        return;
+    }
     qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE);
     qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
 }
@@ -336,6 +468,9 @@
 {
     unsigned n = dev->msix_entries_nr;
 
+    if (!msix_supported)
+        return;
+
     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
         return;
     }
@@ -380,6 +515,13 @@
         return;
     }
 
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_set_irq(dev->msix_irq_entries[vector].gsi, 1, NULL);
+        return;
+    }
+#endif
+
     address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
     address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR);
     data = pci_get_long(table_entry + MSIX_MSG_DATA);
@@ -408,9 +550,19 @@
 /* Mark vector as used. */
 int msix_vector_use(PCIDevice *dev, unsigned vector)
 {
+    int ret;
     if (vector >= dev->msix_entries_nr)
         return -EINVAL;
-    dev->msix_entry_used[vector]++;
+    if (dev->msix_entry_used[vector]) {
+        return 0;
+    }
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        ret = kvm_msix_add(dev, vector);
+        if (ret) {
+            return ret;
+        }
+    }
+    ++dev->msix_entry_used[vector];
     return 0;
 }
 
@@ -423,6 +575,9 @@
     if (--dev->msix_entry_used[vector]) {
         return;
     }
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_msix_del(dev, vector);
+    }
     msix_clr_pending(dev, vector);
 }
 
diff --git a/hw/pc.c b/hw/pc.c
index db7d58e..51603f8 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -44,6 +44,9 @@
 #include "ide.h"
 #include "loader.h"
 #include "elf.h"
+#include "device-assignment.h"
+
+#include "qemu-kvm.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -52,6 +55,8 @@
 //#define DEBUG_MULTIBOOT
 
 #define BIOS_FILENAME "bios.bin"
+#define EXTBOOT_FILENAME "extboot.bin"
+#define VAPIC_FILENAME "vapic.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
 
@@ -69,6 +74,8 @@
 static PITState *pit;
 static PCII440FXState *i440fx_state;
 
+qemu_irq *ioapic_irq_hack;
+
 typedef struct isa_irq_state {
     qemu_irq *i8259;
     qemu_irq *ioapic;
@@ -952,7 +959,7 @@
     return env->cpuid_apic_id == 0;
 }
 
-static CPUState *pc_new_cpu(const char *cpu_model)
+CPUState *pc_new_cpu(const char *cpu_model)
 {
     CPUState *env;
 
@@ -961,6 +968,7 @@
         fprintf(stderr, "Unable to find x86 CPU definition\n");
         exit(1);
     }
+    env->kvm_cpu_state.regs_modified = 1;
     if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
         env->cpuid_apic_id = env->cpu_index;
         /* APIC reset callback resets cpu */
@@ -968,6 +976,11 @@
     } else {
         qemu_register_reset((QEMUResetHandler*)cpu_reset, env);
     }
+
+    /* kvm needs this to run after the apic is initialized. Otherwise,
+     * it can access invalid state and crash.
+     */
+    qemu_init_vcpu(env);
     return env;
 }
 
@@ -1015,6 +1028,9 @@
 #endif
     }
 
+    if (kvm_enabled()) {
+        kvm_set_boot_cpu_id(0);
+    }
     for (i = 0; i < smp_cpus; i++) {
         env = pc_new_cpu(cpu_model);
     }
@@ -1022,18 +1038,11 @@
     vmport_init();
 
     /* allocate RAM */
-    ram_addr = qemu_ram_alloc(0xa0000);
+    ram_addr = qemu_ram_alloc(below_4g_mem_size);
     cpu_register_physical_memory(0, 0xa0000, ram_addr);
-
-    /* Allocate, even though we won't register, so we don't break the
-     * phys_ram_base + PA assumption. This range includes vga (0xa0000 - 0xc0000),
-     * and some bios areas, which will be registered later
-     */
-    ram_addr = qemu_ram_alloc(0x100000 - 0xa0000);
-    ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000);
     cpu_register_physical_memory(0x100000,
                  below_4g_mem_size - 0x100000,
-                 ram_addr);
+                 ram_addr + 0x100000);
 
     /* above 4giga memory allocation */
     if (above_4g_mem_size > 0) {
@@ -1075,11 +1084,17 @@
     isa_bios_size = bios_size;
     if (isa_bios_size > (128 * 1024))
         isa_bios_size = 128 * 1024;
+    cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
+                                 IO_MEM_UNASSIGNED);
+    /* kvm tpr optimization needs the bios accessible for write, at least to qemu itself */
     cpu_register_physical_memory(0x100000 - isa_bios_size,
                                  isa_bios_size,
-                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
+                                 (bios_offset + bios_size - isa_bios_size) /* | IO_MEM_ROM */);
 
-
+    if (extboot_drive) {
+        option_rom[nb_option_roms++] = qemu_strdup(EXTBOOT_FILENAME);
+    }
+    option_rom[nb_option_roms++] = qemu_strdup(VAPIC_FILENAME);
 
     rom_enable_driver_roms = 1;
     option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE);
@@ -1100,10 +1115,18 @@
     }
 
     cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
-    i8259 = i8259_init(cpu_irq[0]);
-    isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
-    isa_irq_state->i8259 = i8259;
-    isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+        isa_irq = i8259 = kvm_i8259_init(cpu_irq[0]);
+    } else
+#endif
+    {
+        i8259 = i8259_init(cpu_irq[0]);
+        isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+        isa_irq_state->i8259 = i8259;
+        isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+    }
 
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq);
@@ -1148,8 +1171,14 @@
 
     if (pci_enabled) {
         isa_irq_state->ioapic = ioapic_init();
+        ioapic_irq_hack = isa_irq;
     }
-    pit = pit_init(0x40, isa_reserve_irq(0));
+#ifdef CONFIG_KVM_PIT
+    if (kvm_enabled() && qemu_kvm_pit_in_kernel())
+	pit = kvm_pit_init(0x40, isa_reserve_irq(0));
+    else
+#endif
+	pit = pit_init(0x40, isa_reserve_irq(0));
     pcspk_init(pit);
     if (!no_hpet) {
         hpet_init(isa_irq);
@@ -1173,7 +1202,7 @@
         if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
             pc_init_ne2k_isa(nd);
         else
-            pci_nic_init_nofail(nd, "e1000", NULL);
+            pci_nic_init_nofail(nd, "rtl8139", NULL);
     }
 
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
@@ -1225,7 +1254,7 @@
             qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
             qdev_init_nofail(eeprom);
         }
-        piix4_acpi_system_hot_add_init(pci_bus);
+        piix4_acpi_system_hot_add_init(pci_bus, cpu_model);
     }
 
     if (i440fx_state) {
@@ -1242,6 +1271,18 @@
         }
     }
 
+    if (extboot_drive) {
+	DriveInfo *info = extboot_drive;
+	int cyls, heads, secs;
+
+	if (info->type != IF_IDE && info->type != IF_VIRTIO) {
+	    bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs);
+	    bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs);
+	}
+
+	extboot_init(info->bdrv, 1);
+    }
+
     /* Add virtio console devices */
     if (pci_enabled) {
         for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
@@ -1252,6 +1293,12 @@
     }
 
     rom_load_fw(fw_cfg);
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+    if (kvm_enabled()) {
+        add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
+    }
+#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
 }
 
 static void pc_init_pci(ram_addr_t ram_size,
diff --git a/hw/pc.h b/hw/pc.h
index 03ffc91..b00f311 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -28,6 +28,7 @@
 void pic_set_irq(int irq, int level);
 void pic_set_irq_new(void *opaque, int irq, int level);
 qemu_irq *i8259_init(qemu_irq parent_irq);
+qemu_irq *kvm_i8259_init(qemu_irq parent_irq);
 int pic_read_irq(PicState2 *s);
 void pic_update_irq(PicState2 *s);
 uint32_t pic_intack_read(PicState2 *s);
@@ -48,6 +49,7 @@
 void ioapic_set_irq(void *opaque, int vector, int level);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
+void apic_set_irq_delivered(void);
 
 /* i8254.c */
 
@@ -62,8 +64,12 @@
 int pit_get_mode(PITState *pit, int channel);
 int pit_get_out(PITState *pit, int channel, int64_t current_time);
 
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
+/* i8254-kvm.c */
+
+PITState *kvm_pit_init(int base, qemu_irq irq);
+
+void hpet_disable_pit(void);
+void hpet_enable_pit(void);
 
 /* vmport.c */
 void vmport_init(void);
@@ -93,6 +99,7 @@
 
 void ioport_set_a20(int enable);
 int ioport_get_a20(void);
+CPUState *pc_new_cpu(const char *cpu_model);
 
 /* acpi.c */
 extern int acpi_enabled;
@@ -106,7 +113,7 @@
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq);
 void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
-void piix4_acpi_system_hot_add_init(PCIBus *bus);
+void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *model);
 
 /* hpet.c */
 extern int no_hpet;
@@ -116,6 +123,9 @@
 int pcspk_audio_init(qemu_irq *pic);
 
 /* piix_pci.c */
+/* config space register for IRQ routing */
+#define PIIX_CONFIG_IRQ_ROUTE 0x60
+
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
 
@@ -127,6 +137,10 @@
 extern PCIDevice *piix4_dev;
 int piix4_init(PCIBus *bus, int devfn);
 
+int piix_get_irq(int pin);
+
+int ipf_map_irq(PCIDevice *pci_dev, int irq_num);
+
 /* vga.c */
 enum vga_retrace_method {
     VGA_RETRACE_DUMB,
@@ -149,5 +163,10 @@
 
 void isa_ne2000_init(int base, int irq, NICInfo *nd);
 
+/* extboot.c */
+
+void extboot_init(BlockDriverState *bs, int cmd);
+
 int cpu_is_bsp(CPUState *env);
+
 #endif
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index ba13d2b..41ce004 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -34,6 +34,7 @@
 #include "virtio-blk.h"
 #include "qemu-config.h"
 #include "qemu-objects.h"
+#include "device-assignment.h"
 
 #if defined(TARGET_I386)
 static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
@@ -225,6 +226,24 @@
     return dev;
 }
 
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+static PCIDevice *qemu_pci_hot_assign_device(Monitor *mon,
+                                             const char *devaddr,
+                                             const char *opts_str)
+{
+    QemuOpts *opts;
+    DeviceState *dev;
+
+    opts = add_assigned_device(opts_str);
+    if (opts == NULL) {
+        monitor_printf(mon, "Error adding device; check syntax\n");
+        return NULL;
+    }
+    dev = qdev_device_add(opts);
+    return DO_UPCAST(PCIDevice, qdev, dev);
+}
+#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
+
 void pci_device_hot_add_print(Monitor *mon, const QObject *data)
 {
     QDict *qdict;
@@ -277,6 +296,10 @@
         dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
     else if (strcmp(type, "storage") == 0)
         dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+    else if (strcmp(type, "host") == 0)
+        dev = qemu_pci_hot_assign_device(mon, pci_addr, opts);
+#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
     else
         monitor_printf(mon, "invalid type: %s\n", type);
 
diff --git a/hw/pci.c b/hw/pci.c
index 9cc5a6a..637289b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -27,6 +27,9 @@
 #include "net.h"
 #include "sysemu.h"
 #include "loader.h"
+#include "qemu-kvm.h"
+#include "hw/pc.h"
+#include "device-assignment.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -422,6 +425,7 @@
 }
 
 /*
+ * Parse pci address in qemu command
  * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
  */
 static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
@@ -470,6 +474,55 @@
     return 0;
 }
 
+/*
+ * Parse device bdf in device assignment command:
+ *
+ * -pcidevice host=bus:dev.func
+ *
+ * Parse <bus>:<slot>.<func> return -1 on error
+ */
+int pci_parse_host_devaddr(const char *addr, int *busp,
+                           int *slotp, int *funcp)
+{
+    const char *p;
+    char *e;
+    int val;
+    int bus = 0, slot = 0, func = 0;
+
+    p = addr;
+    val = strtoul(p, &e, 16);
+    if (e == p)
+	return -1;
+    if (*e == ':') {
+	bus = val;
+	p = e + 1;
+	val = strtoul(p, &e, 16);
+	if (e == p)
+	    return -1;
+	if (*e == '.') {
+	    slot = val;
+	    p = e + 1;
+	    val = strtoul(p, &e, 16);
+	    if (e == p)
+		return -1;
+	    func = val;
+	} else
+	    return -1;
+    } else
+	return -1;
+
+    if (bus > 0xff || slot > 0x1f || func > 0x7)
+	return -1;
+
+    if (*e)
+	return -1;
+
+    *busp = bus;
+    *slotp = slot;
+    *funcp = func;
+    return 0;
+}
+
 int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
                      unsigned *slotp)
 {
@@ -946,25 +999,80 @@
     }
 }
 
-uint32_t pci_default_read_config(PCIDevice *d,
-                                 uint32_t address, int len)
+static uint32_t pci_read_config(PCIDevice *d,
+                                uint32_t address, int len)
 {
     uint32_t val = 0;
-    assert(len == 1 || len == 2 || len == 4);
+
     len = MIN(len, pci_config_size(d) - address);
     memcpy(&val, d->config + address, len);
     return le32_to_cpu(val);
 }
 
+uint32_t pci_default_read_config(PCIDevice *d,
+                                 uint32_t address, int len)
+{
+    assert(len == 1 || len == 2 || len == 4);
+
+    if (pci_access_cap_config(d, address, len)) {
+        return d->cap.config_read(d, address, len);
+    }
+
+    return pci_read_config(d, address, len);
+}
+
+static void pci_write_config(PCIDevice *pci_dev,
+                             uint32_t address, uint32_t val, int len)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        pci_dev->config[address + i] = val & 0xff;
+        val >>= 8;
+    }
+}
+
+int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len)
+{
+    if (pci_dev->cap.supported && address >= pci_dev->cap.start &&
+            (address + len) < pci_dev->cap.start + pci_dev->cap.length)
+        return 1;
+    return 0;
+}
+
+uint32_t pci_default_cap_read_config(PCIDevice *pci_dev,
+                                     uint32_t address, int len)
+{
+    return pci_read_config(pci_dev, address, len);
+}
+
+void pci_default_cap_write_config(PCIDevice *pci_dev,
+                                  uint32_t address, uint32_t val, int len)
+{
+    pci_write_config(pci_dev, address, val, len);
+}
+
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
     int i;
     uint32_t config_size = pci_config_size(d);
 
+    if (pci_access_cap_config(d, addr, l)) {
+        d->cap.config_write(d, addr, val, l);
+        return;
+    }
+
     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];
         d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
     }
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+    if (kvm_enabled() && kvm_irqchip_in_kernel() &&
+        addr >= PIIX_CONFIG_IRQ_ROUTE &&
+	addr < PIIX_CONFIG_IRQ_ROUTE + 4)
+        assigned_dev_update_irqs();
+#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
+
     if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
         ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
         ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
@@ -985,11 +1093,20 @@
     if (!change)
         return;
 
+#if defined(TARGET_IA64)
+    ioapic_set_irq(pci_dev, irq_num, level);
+#endif
+
     pci_set_irq_state(pci_dev, irq_num, level);
     pci_update_irq_status(pci_dev);
     pci_change_irq_level(pci_dev, irq_num, change);
 }
 
+int pci_map_irq(PCIDevice *pci_dev, int pin)
+{
+    return pci_dev->bus->map_irq(pci_dev, pin);
+}
+
 /***********************************************************/
 /* monitor info on PCI */
 
@@ -1416,6 +1533,37 @@
     return dev;
 }
 
+int pci_enable_capability_support(PCIDevice *pci_dev,
+                                  uint32_t config_start,
+                                  PCICapConfigReadFunc *config_read,
+                                  PCICapConfigWriteFunc *config_write,
+                                  PCICapConfigInitFunc *config_init)
+{
+    if (!pci_dev)
+        return -ENODEV;
+
+    pci_dev->config[0x06] |= 0x10; // status = capabilities
+
+    if (config_start == 0)
+	pci_dev->cap.start = PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR;
+    else if (config_start >= 0x40 && config_start < 0xff)
+        pci_dev->cap.start = config_start;
+    else
+        return -EINVAL;
+
+    if (config_read)
+        pci_dev->cap.config_read = config_read;
+    else
+        pci_dev->cap.config_read = pci_default_cap_read_config;
+    if (config_write)
+        pci_dev->cap.config_write = config_write;
+    else
+        pci_dev->cap.config_write = pci_default_cap_write_config;
+    pci_dev->cap.supported = 1;
+    pci_dev->config[PCI_CAPABILITY_LIST] = pci_dev->cap.start;
+    return config_init(pci_dev);
+}
+
 static int pci_find_space(PCIDevice *pdev, uint8_t size)
 {
     int config_size = pci_config_size(pdev);
diff --git a/hw/pci.h b/hw/pci.h
index e52e632..5d82cce 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -5,11 +5,16 @@
 
 #include "qdev.h"
 
+struct kvm_irq_routing_entry;
+
 /* PCI includes legacy ISA access.  */
 #include "isa.h"
 
-/* PCI bus */
+/* imported from <linux/pci.h> */
+#define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn)         ((devfn) & 0x07)
 
+/* PCI bus */
 extern target_phys_addr_t pci_mem_base;
 
 #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
@@ -82,6 +87,12 @@
                                 pcibus_t addr, pcibus_t size, int type);
 typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
 
+typedef void PCICapConfigWriteFunc(PCIDevice *pci_dev,
+                                   uint32_t address, uint32_t val, int len);
+typedef uint32_t PCICapConfigReadFunc(PCIDevice *pci_dev,
+                                      uint32_t address, int len);
+typedef int PCICapConfigInitFunc(PCIDevice *pci_dev);
+
 typedef struct PCIIORegion {
     pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
 #define PCI_BAR_UNMAPPED (~(pcibus_t)0)
@@ -160,10 +171,19 @@
 /* Bits in the PCI Status Register (PCI 2.3 spec) */
 #define PCI_STATUS_RESERVED1	0x007
 #define PCI_STATUS_INT_STATUS	0x008
+#ifndef PCI_STATUS_CAP_LIST
 #define PCI_STATUS_CAP_LIST	0x010
+#endif
+#ifndef PCI_STATUS_66MHZ
 #define PCI_STATUS_66MHZ	0x020
+#endif
+
 #define PCI_STATUS_RESERVED2	0x040
+
+#ifndef PCI_STATUS_FAST_BACK
 #define PCI_STATUS_FAST_BACK	0x080
+#endif
+
 #define PCI_STATUS_DEVSEL	0x600
 
 #define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \
@@ -192,6 +212,11 @@
     QEMU_PCI_CAP_EXPRESS = 0x2,
 };
 
+#define PCI_CAPABILITY_CONFIG_MAX_LENGTH 0x60
+#define PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR 0x40
+#define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10
+#define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10
+
 struct PCIDevice {
     DeviceState qdev;
     /* PCI config space */
@@ -246,6 +271,23 @@
     /* Location of option rom */
     char *romfile;
     ram_addr_t rom_offset;
+
+    /* How much space does an MSIX table need. */
+    /* The spec requires giving the table structure
+     * a 4K aligned region all by itself. Align it to
+     * target pages so that drivers can do passthrough
+     * on the rest of the region. */
+    target_phys_addr_t msix_page_size;
+
+    struct kvm_irq_routing_entry *msix_irq_entries;
+
+    /* Device capability configuration space */
+    struct {
+        int supported;
+        unsigned int start, length;
+        PCICapConfigReadFunc *config_read;
+        PCICapConfigWriteFunc *config_write;
+    } cap;
 };
 
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
@@ -257,6 +299,14 @@
                             pcibus_t size, int type,
                             PCIMapIORegionFunc *map_func);
 
+int pci_enable_capability_support(PCIDevice *pci_dev,
+                                  uint32_t config_start,
+                                  PCICapConfigReadFunc *config_read,
+                                  PCICapConfigWriteFunc *config_write,
+                                  PCICapConfigInitFunc *config_init);
+
+int pci_map_irq(PCIDevice *pci_dev, int pin);
+
 int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 
 void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
@@ -265,13 +315,17 @@
 
 uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
 
-
 uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len);
 void pci_default_write_config(PCIDevice *d,
                               uint32_t address, uint32_t val, int len);
 void pci_device_save(PCIDevice *s, QEMUFile *f);
 int pci_device_load(PCIDevice *s, QEMUFile *f);
+uint32_t pci_default_cap_read_config(PCIDevice *pci_dev,
+                                     uint32_t address, int len);
+void pci_default_cap_write_config(PCIDevice *pci_dev,
+                                  uint32_t address, uint32_t val, int len);
+int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len);
 
 typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
@@ -300,6 +354,9 @@
 int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
                      unsigned *slotp);
 
+int pci_parse_host_devaddr(const char *addr, int *busp,
+                           int *slotp, int *funcp);
+
 void pci_info(Monitor *mon);
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
                         pci_map_irq_fn map_irq, const char *name);
diff --git a/hw/pcspk.c b/hw/pcspk.c
index 26a0ecb..128836b 100644
--- a/hw/pcspk.c
+++ b/hw/pcspk.c
@@ -27,6 +27,8 @@
 #include "isa.h"
 #include "audio/audio.h"
 #include "qemu-timer.h"
+#include "i8254.h"
+#include "qemu-kvm.h"
 
 #define PCSPK_BUF_LEN 1792
 #define PCSPK_SAMPLE_RATE 32000
@@ -48,6 +50,43 @@
 static const char *s_spk = "pcspk";
 static PCSpkState pcspk_state;
 
+#ifdef CONFIG_KVM_PIT
+static void kvm_get_pit_ch2(PITState *pit,
+                            struct kvm_pit_state *inkernel_state)
+{
+    struct kvm_pit_state pit_state;
+
+    if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
+        kvm_get_pit(kvm_context, &pit_state);
+        pit->channels[2].mode = pit_state.channels[2].mode;
+        pit->channels[2].count = pit_state.channels[2].count;
+        pit->channels[2].count_load_time = pit_state.channels[2].count_load_time;
+        pit->channels[2].gate = pit_state.channels[2].gate;
+        if (inkernel_state) {
+            memcpy(inkernel_state, &pit_state, sizeof(*inkernel_state));
+        }
+    }
+}
+
+static void kvm_set_pit_ch2(PITState *pit,
+                            struct kvm_pit_state *inkernel_state)
+{
+    if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
+        inkernel_state->channels[2].mode = pit->channels[2].mode;
+        inkernel_state->channels[2].count = pit->channels[2].count;
+        inkernel_state->channels[2].count_load_time =
+            pit->channels[2].count_load_time;
+        inkernel_state->channels[2].gate = pit->channels[2].gate;
+        kvm_set_pit(kvm_context, inkernel_state);
+    }
+}
+#else
+static inline void kvm_get_pit_ch2(PITState *pit,
+                                   struct kvm_pit_state *inkernel_state) { }
+static inline void kvm_set_pit_ch2(PITState *pit,
+                                   struct kvm_pit_state *inkernel_state) { }
+#endif
+
 static inline void generate_samples(PCSpkState *s)
 {
     unsigned int i;
@@ -72,6 +111,8 @@
     PCSpkState *s = opaque;
     unsigned int n;
 
+    kvm_get_pit_ch2(s->pit, NULL);
+
     if (pit_get_mode(s->pit, 2) != 3)
         return;
 
@@ -117,6 +158,8 @@
     PCSpkState *s = opaque;
     int out;
 
+    kvm_get_pit_ch2(s->pit, NULL);
+
     s->dummy_refresh_clock ^= (1 << 4);
     out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5;
 
@@ -125,9 +168,12 @@
 
 static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
+    struct kvm_pit_state inkernel_state;
     PCSpkState *s = opaque;
     const int gate = val & 1;
 
+    kvm_get_pit_ch2(s->pit, &inkernel_state);
+
     s->data_on = (val >> 1) & 1;
     pit_set_gate(s->pit, 2, gate);
     if (s->voice) {
@@ -135,6 +181,8 @@
             s->play_pos = 0;
         AUD_set_active_out(s->voice, gate & s->data_on);
     }
+
+    kvm_set_pit_ch2(s->pit, &inkernel_state);
 }
 
 void pcspk_init(PITState *pit)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 1b67475..001bc93 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -29,6 +29,8 @@
 #include "isa.h"
 #include "sysbus.h"
 
+#include "qemu-kvm.h"
+
 typedef PCIHostState I440FXState;
 
 typedef struct PIIX3State {
@@ -88,6 +90,10 @@
     int i, r;
     uint32_t smram, addr;
 
+    if (kvm_enabled()) {
+        /* FIXME: Support remappings and protection changes. */
+        return;
+    }
     update_pam(d, 0xf0000, 0x100000, (d->dev.config[0x59] >> 4) & 3);
     for(i = 0; i < 12; i++) {
         r = (d->dev.config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
@@ -201,6 +207,8 @@
     return 0;
 }
 
+static PIIX3State *piix3_dev;
+
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic)
 {
     DeviceState *dev;
@@ -226,6 +234,8 @@
 
     *piix3_devfn = piix3->dev.devfn;
 
+    piix3_dev = piix3;
+
     return b;
 }
 
@@ -253,6 +263,13 @@
     }
 }
 
+int piix_get_irq(int pin)
+{
+    if (piix3_dev)
+        return piix3_dev->dev.config[0x60+pin];
+    return 0;
+}
+
 static void piix3_reset(void *opaque)
 {
     PIIX3State *d = opaque;
diff --git a/hw/ppc440.c b/hw/ppc440.c
index abe0a56..ef88373 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -20,6 +20,7 @@
 #include "ppc405.h"
 #include "sysemu.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 #define PPC440EP_PCI_CONFIG     0xeec00000
 #define PPC440EP_PCI_INTACK     0xeed00000
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index a488240..25417e3 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -24,6 +24,7 @@
 #include "device_tree.h"
 #include "loader.h"
 #include "elf.h"
+#include "qemu-kvm.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index ea30816..45356ca 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -31,6 +31,7 @@
 #include "ppce500.h"
 #include "loader.h"
 #include "elf.h"
+#include "qemu-kvm.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
diff --git a/hw/testdev.c b/hw/testdev.c
new file mode 100644
index 0000000..ac5b9cd
--- /dev/null
+++ b/hw/testdev.c
@@ -0,0 +1,63 @@
+#include "hw.h"
+#include "qdev.h"
+#include "isa.h"
+
+struct testdev {
+    ISADevice dev;
+    CharDriverState *chr;
+};
+
+static void test_device_serial_write(void *opaque, uint32_t addr, uint32_t data)
+{
+    struct testdev *dev = opaque;
+    uint8_t buf[1] = { data };
+
+    if (dev->chr) {
+        qemu_chr_write(dev->chr, buf, 1);
+    }
+}
+
+static void test_device_exit(void *opaque, uint32_t addr, uint32_t data)
+{
+    exit(data);
+}
+
+static uint32_t test_device_memsize_read(void *opaque, uint32_t addr)
+{
+    return ram_size;
+}
+
+static void test_device_irq_line(void *opaque, uint32_t addr, uint32_t data)
+{
+    extern qemu_irq *ioapic_irq_hack;
+
+    qemu_set_irq(ioapic_irq_hack[addr - 0x2000], !!data);
+}
+
+static int init_test_device(ISADevice *isa)
+{
+    struct testdev *dev = DO_UPCAST(struct testdev, dev, isa);
+
+    register_ioport_write(0xf1, 1, 1, test_device_serial_write, dev);
+    register_ioport_write(0xf4, 1, 4, test_device_exit, dev);
+    register_ioport_read(0xd1, 1, 4, test_device_memsize_read, dev);
+    register_ioport_write(0x2000, 24, 1, test_device_irq_line, NULL);
+    return 0;
+}
+
+static ISADeviceInfo testdev_info = {
+    .qdev.name  = "testdev",
+    .qdev.size  = sizeof(struct testdev),
+    .init       = init_test_device,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", struct testdev, chr),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void testdev_register_devices(void)
+{
+    isa_qdev_register(&testdev_info);
+}
+
+device_init(testdev_register_devices)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index eef78ed..9089c9f 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -68,9 +68,11 @@
     PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
     VGACommonState *s = &pvs->vga;
 
+    vga_dirty_log_stop(s);
     pci_default_write_config(d, address, val, len);
     if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
         s->map_addr = 0;
+    vga_dirty_log_start(s);
 }
 
 static int pci_vga_initfn(PCIDevice *dev)
diff --git a/hw/vga.c b/hw/vga.c
index d05f1f9..2ad2dcd 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1277,6 +1277,8 @@
     vga_draw_glyph8_func *vga_draw_glyph8;
     vga_draw_glyph9_func *vga_draw_glyph9;
 
+    vga_dirty_log_stop(s);
+
     /* compute font data address (in plane 2) */
     v = s->sr[3];
     offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
@@ -1589,40 +1591,65 @@
     }
 #endif
 
+    vga_dirty_log_start(s);
+}
+
+static int s1, s2, s3;
+
+static void mark_dirty(target_phys_addr_t start, target_phys_addr_t len)
+{
+    target_phys_addr_t end = start + len;
+
+    while (start < end) {
+        cpu_physical_memory_set_dirty(cpu_get_physical_page_desc(start));
+        start += TARGET_PAGE_SIZE;
+    }
 }
 
 void vga_dirty_log_start(VGACommonState *s)
 {
     if (kvm_enabled() && s->map_addr)
-        kvm_log_start(s->map_addr, s->map_end - s->map_addr);
-
+        if (!s1) {
+            kvm_log_start(s->map_addr, s->map_end - s->map_addr);
+            mark_dirty(s->map_addr, s->map_end - s->map_addr);
+            s1 = 1;
+        }
     if (kvm_enabled() && s->lfb_vram_mapped) {
-        kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
-        kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
+        if (!s2) {
+            kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
+            kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
+            mark_dirty(isa_mem_base + 0xa0000, 0x10000);
+        }
+        s2 = 1;
     }
 
 #ifdef CONFIG_BOCHS_VBE
     if (kvm_enabled() && s->vbe_mapped) {
-        kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
+        if (!s3) {
+            kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
+        }
+        s3 = 1;
     }
 #endif
 }
 
 void vga_dirty_log_stop(VGACommonState *s)
 {
-    if (kvm_enabled() && s->map_addr)
+    if (kvm_enabled() && s->map_addr && s1)
 	kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
 
-    if (kvm_enabled() && s->lfb_vram_mapped) {
+    if (kvm_enabled() && s->lfb_vram_mapped && s2) {
 	kvm_log_stop(isa_mem_base + 0xa0000, 0x80000);
 	kvm_log_stop(isa_mem_base + 0xa8000, 0x80000);
     }
 
 #ifdef CONFIG_BOCHS_VBE
-    if (kvm_enabled() && s->vbe_mapped) {
+    if (kvm_enabled() && s->vbe_mapped && s3) {
 	kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
     }
 #endif
+
+    s1 = s2 = s3 = 0;
 }
 
 void vga_dirty_log_restart(VGACommonState *s)
@@ -1860,6 +1887,7 @@
         return;
     if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
         return;
+    vga_dirty_log_stop(s);
 
     s->rgb_to_pixel =
         rgb_to_pixel_dup_table[get_depth_index(s->ds)];
@@ -1904,6 +1932,9 @@
             vga_draw_text(s, full_update);
             break;
         case GMODE_GRAPH:
+#ifdef TARGET_IA64
+            full_update = 1;
+#endif
             vga_draw_graphic(s, full_update);
             break;
         case GMODE_BLANK:
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 23a42ef..9e52e70 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -33,8 +33,8 @@
 /* bochs VBE support */
 #define CONFIG_BOCHS_VBE
 
-#define VBE_DISPI_MAX_XRES              1600
-#define VBE_DISPI_MAX_YRES              1200
+#define VBE_DISPI_MAX_XRES              2560
+#define VBE_DISPI_MAX_YRES              1600
 #define VBE_DISPI_MAX_BPP               32
 
 #define VBE_DISPI_INDEX_ID              0x0
@@ -224,7 +224,7 @@
 extern const uint8_t sr_mask[8];
 extern const uint8_t gr_mask[16];
 
-#define VGA_RAM_SIZE (8192 * 1024)
+#define VGA_RAM_SIZE (16 * 1024 * 1024)
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
 
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index cfd3b41..7ca783e 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -19,6 +19,7 @@
 #include "balloon.h"
 #include "virtio-balloon.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 #if defined(__linux__)
 #include <sys/mman.h>
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 57f8f89..92c953c 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -129,6 +129,9 @@
     s = (VirtIOConsole *)virtio_common_init("virtio-console",
                                             VIRTIO_ID_CONSOLE,
                                             0, sizeof(VirtIOConsole));
+    if (s == NULL)
+        return NULL;
+
     s->vdev.get_features = virtio_console_get_features;
 
     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
diff --git a/hw/vmport.c b/hw/vmport.c
index 884af3f..648861b 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -21,10 +21,12 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+
 #include "hw.h"
 #include "isa.h"
 #include "pc.h"
 #include "sysemu.h"
+#include "qemu-kvm.h"
 
 //#define VMPORT_DEBUG
 
@@ -57,6 +59,10 @@
     CPUState *env = cpu_single_env;
     unsigned char command;
     uint32_t eax;
+    uint32_t ret;
+
+    if (kvm_enabled())
+	kvm_save_registers(env);
 
     eax = env->regs[R_EAX];
     if (eax != VMPORT_MAGIC)
@@ -73,7 +79,12 @@
         return eax;
     }
 
-    return s->func[command](s->opaque[command], addr);
+    ret = s->func[command](s->opaque[command], addr);
+
+    if (kvm_enabled())
+	kvm_load_registers(env);
+
+    return ret;
 }
 
 static void vmport_ioport_write(void *opaque, uint32_t addr, uint32_t val)
diff --git a/ia64.ld b/ia64.ld
index 0c37796..081aaf1 100644
--- a/ia64.ld
+++ b/ia64.ld
@@ -7,7 +7,7 @@
 SECTIONS
 {
   /* Read-only sections, merged into text segment: */
-  PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
+  PROVIDE (__executable_start = 0x4000000060000000); . = 0x4000000060000000 + SIZEOF_HEADERS;
   .interp         : { *(.interp) }
   .hash           : { *(.hash) }
   .dynsym         : { *(.dynsym) }
diff --git a/ia64intrin.h b/ia64intrin.h
new file mode 100644
index 0000000..ddd5ed9
--- /dev/null
+++ b/ia64intrin.h
@@ -0,0 +1,150 @@
+#ifndef IA64_INTRINSIC_H
+#define IA64_INTRINSIC_H
+
+/*
+ * Compiler-dependent Intrinsics
+ *
+ * Copyright (C) 2002,2003 Jun Nakajima <jun.nakajima@intel.com>
+ * Copyright (C) 2002,2003 Suresh Siddha <suresh.b.siddha@intel.com>
+ *
+ */
+extern long ia64_cmpxchg_called_with_bad_pointer (void);
+extern void ia64_bad_param_for_getreg (void);
+#define ia64_cmpxchg(sem,ptr,o,n,s) ({					\
+	uint64_t _o, _r;						\
+	switch(s) {							\
+		case 1: _o = (uint8_t)(long)(o); break;			\
+		case 2: _o = (uint16_t)(long)(o); break;		\
+		case 4: _o = (uint32_t)(long)(o); break;		\
+		case 8: _o = (uint64_t)(long)(o); break;		\
+		default: break;						\
+	}								\
+	switch(s) {							\
+		case 1:							\
+		_r = ia64_cmpxchg1_##sem((uint8_t*)ptr,n,_o); break;	\
+		case 2:							\
+		_r = ia64_cmpxchg2_##sem((uint16_t*)ptr,n,_o); break;	\
+		case 4:							\
+		_r = ia64_cmpxchg4_##sem((uint32_t*)ptr,n,_o); break;	\
+		case 8:							\
+		_r = ia64_cmpxchg8_##sem((uint64_t*)ptr,n,_o); break;	\
+		default:						\
+		_r = ia64_cmpxchg_called_with_bad_pointer(); break;	\
+	}								\
+	(__typeof__(o)) _r;						\
+})
+
+#define cmpxchg_acq(ptr,o,n) ia64_cmpxchg(acq,ptr,o,n,sizeof(*ptr))
+#define cmpxchg_rel(ptr,o,n) ia64_cmpxchg(rel,ptr,o,n,sizeof(*ptr))
+
+#ifdef __INTEL_COMPILER
+void  __fc(uint64_t *addr);
+void  __synci(void);
+void __isrlz(void);
+void __dsrlz(void);
+uint64_t __getReg(const int whichReg);
+uint64_t _InterlockedCompareExchange8_rel(volatile uint8_t *dest, uint64_t xchg, uint64_t comp);
+uint64_t _InterlockedCompareExchange8_acq(volatile uint8_t *dest, uint64_t xchg, uint64_t comp);
+uint64_t _InterlockedCompareExchange16_rel(volatile uint16_t *dest, uint64_t xchg, uint64_t comp);
+uint64_t _InterlockedCompareExchange16_acq(volatile uint16_t *dest, uint64_t xchg, uint64_t comp);
+uint64_t _InterlockedCompareExchange_rel(volatile uint32_t *dest, uint64_t xchg, uint64_t comp);
+uint64_t _InterlockedCompareExchange_acq(volatile uint32_t *dest, uint64_t xchg, uint64_t comp);
+uint64_t _InterlockedCompareExchange64_rel(volatile uint64_t *dest, uint64_t xchg, uint64_t comp);
+u64_t _InterlockedCompareExchange64_acq(volatile uint64_t *dest, uint64_t xchg, uint64_t comp);
+
+#define ia64_cmpxchg1_rel	_InterlockedCompareExchange8_rel
+#define ia64_cmpxchg1_acq	_InterlockedCompareExchange8_acq
+#define ia64_cmpxchg2_rel	_InterlockedCompareExchange16_rel
+#define ia64_cmpxchg2_acq	_InterlockedCompareExchange16_acq
+#define ia64_cmpxchg4_rel	_InterlockedCompareExchange_rel
+#define ia64_cmpxchg4_acq	_InterlockedCompareExchange_acq
+#define ia64_cmpxchg8_rel	_InterlockedCompareExchange64_rel
+#define ia64_cmpxchg8_acq	_InterlockedCompareExchange64_acq
+
+#define ia64_srlz_d		__dsrlz
+#define ia64_srlz_i		__isrlz
+#define __ia64_fc 		__fc
+#define ia64_sync_i		__synci
+#define __ia64_getreg		__getReg
+#else /* __INTEL_COMPILER */
+#define ia64_cmpxchg1_acq(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+	asm volatile ("cmpxchg1.acq %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg1_rel(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+	asm volatile ("cmpxchg1.rel %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg2_acq(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+	asm volatile ("cmpxchg2.acq %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg2_rel(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+											\
+	asm volatile ("cmpxchg2.rel %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg4_acq(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+	asm volatile ("cmpxchg4.acq %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg4_rel(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+	asm volatile ("cmpxchg4.rel %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg8_acq(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+	asm volatile ("cmpxchg8.acq %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_cmpxchg8_rel(ptr, new, old)						\
+({											\
+	uint64_t ia64_intri_res;							\
+	asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));					\
+											\
+	asm volatile ("cmpxchg8.rel %0=[%1],%2,ar.ccv":					\
+			      "=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");	\
+	ia64_intri_res;									\
+})
+
+#define ia64_srlz_i()	asm volatile (";; srlz.i ;;" ::: "memory")
+#define ia64_srlz_d()	asm volatile (";; srlz.d" ::: "memory");
+#define __ia64_fc(addr)	asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i()	asm volatile (";; sync.i" ::: "memory")
+
+#endif /* __INTEL_COMPILER */
+#endif /* IA64_INTRINSIC_H */
diff --git a/kvm-all.c b/kvm-all.c
index 15ec38e..0423fff 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -26,6 +26,7 @@
 #include "gdbstub.h"
 #include "kvm.h"
 
+#ifdef KVM_UPSTREAM
 /* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
 #define PAGE_SIZE TARGET_PAGE_SIZE
 
@@ -57,7 +58,6 @@
     KVMSlot slots[32];
     int fd;
     int vmfd;
-    int regs_modified;
     int coalesced_mmio;
     int broken_set_mem_region;
     int migration_log;
@@ -157,12 +157,14 @@
         abort();
     }
 }
+#endif
 
 int kvm_irqchip_in_kernel(void)
 {
     return kvm_state->irqchip_in_kernel;
 }
 
+#ifdef KVM_UPSTREAM
 int kvm_pit_in_kernel(void)
 {
     return kvm_state->pit_in_kernel;
@@ -343,6 +345,7 @@
 
     return ret;
 }
+#endif
 
 int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
 {
@@ -393,6 +396,7 @@
 
     return ret;
 }
+#ifdef KVM_UPSTREAM
 
 int kvm_init(int smp_cpus)
 {
@@ -504,6 +508,7 @@
 
     return ret;
 }
+#endif
 
 static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
                          uint32_t count)
@@ -544,6 +549,7 @@
     return 1;
 }
 
+#ifdef KVM_UPSTREAM
 static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run)
 {
 #ifdef KVM_CAP_COALESCED_MMIO
@@ -812,6 +818,7 @@
     }
 }
 
+#endif
 int kvm_ioctl(KVMState *s, int type, ...)
 {
     int ret;
@@ -879,6 +886,7 @@
     return kvm_state->vcpu_events;
 }
 
+#ifdef KVM_UPSTREAM
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
@@ -897,7 +905,11 @@
     }
 }
 
+#endif /* KVM_UPSTREAM */
+
 #ifdef KVM_CAP_SET_GUEST_DEBUG
+
+#ifdef KVM_UPSTREAM
 static void on_vcpu(CPUState *env, void (*func)(void *data), void *data)
 {
 #ifdef CONFIG_IOTHREAD
@@ -910,6 +922,7 @@
     func(data);
 #endif
 }
+#endif /* KVM_UPSTREAM */
 
 struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
                                                  target_ulong pc)
@@ -928,6 +941,8 @@
     return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
 }
 
+#ifdef KVM_UPSTREAM
+
 struct kvm_set_guest_debug_data {
     struct kvm_guest_debug dbg;
     CPUState *env;
@@ -961,6 +976,7 @@
     on_vcpu(env, kvm_invoke_set_guest_debug, &data);
     return data.err;
 }
+#endif
 
 int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
                           target_ulong len, int type)
@@ -1085,3 +1101,5 @@
 {
 }
 #endif /* !KVM_CAP_SET_GUEST_DEBUG */
+
+#include "qemu-kvm.c"
diff --git a/kvm-tpr-opt.c b/kvm-tpr-opt.c
new file mode 100644
index 0000000..bf9c9a0
--- /dev/null
+++ b/kvm-tpr-opt.c
@@ -0,0 +1,410 @@
+/*
+ * tpr optimization for qemu/kvm
+ *
+ * Copyright (C) 2007-2008 Qumranet Technologies
+ *
+ * Licensed under the terms of the GNU GPL version 2 or higher.
+ */
+
+#include "config.h"
+#include "config-host.h"
+
+#include <string.h>
+
+#include "hw/hw.h"
+#include "hw/isa.h"
+#include "sysemu.h"
+#include "qemu-kvm.h"
+#include "cpu.h"
+
+#include <stdio.h>
+
+static uint64_t map_addr(struct kvm_sregs *sregs, target_ulong virt, unsigned *perms)
+{
+    uint64_t mask = ((1ull << 48) - 1) & ~4095ull;
+    uint64_t p, pp = 7;
+
+    p = sregs->cr3;
+    if (sregs->cr4 & 0x20) {
+	p &= ~31ull;
+	p = ldq_phys(p + 8 * (virt >> 30));
+	if (!(p & 1))
+	    return -1ull;
+	p &= mask;
+	p = ldq_phys(p + 8 * ((virt >> 21) & 511));
+	if (!(p & 1))
+	    return -1ull;
+	pp &= p;
+	if (p & 128) {
+	    p += ((virt >> 12) & 511) << 12;
+	} else {
+	    p &= mask;
+	    p = ldq_phys(p + 8 * ((virt >> 12) & 511));
+	    if (!(p & 1))
+		return -1ull;
+	    pp &= p;
+	}
+    } else {
+	p &= mask;
+	p = ldl_phys(p + 4 * ((virt >> 22) & 1023));
+	if (!(p & 1))
+	    return -1ull;
+	pp &= p;
+	if (p & 128) {
+	    p += ((virt >> 12) & 1023) << 12;
+	} else {
+	    p &= mask;
+	    p = ldl_phys(p + 4 * ((virt >> 12) & 1023));
+	    pp &= p;
+	    if (!(p & 1))
+		return -1ull;
+	}
+    }
+    if (perms)
+	*perms = pp >> 1;
+    p &= mask;
+    return p + (virt & 4095);
+}
+
+static uint8_t read_byte_virt(CPUState *env, target_ulong virt)
+{
+    struct kvm_sregs sregs;
+
+    kvm_get_sregs(env, &sregs);
+    return ldub_phys(map_addr(&sregs, virt, NULL));
+}
+
+static void write_byte_virt(CPUState *env, target_ulong virt, uint8_t b)
+{
+    struct kvm_sregs sregs;
+
+    kvm_get_sregs(env, &sregs);
+    stb_phys(map_addr(&sregs, virt, NULL), b);
+}
+
+static __u64 kvm_rsp_read(CPUState *env)
+{
+    struct kvm_regs regs;
+
+    kvm_get_regs(env, &regs);
+    return regs.rsp;
+}
+
+struct vapic_bios {
+    char signature[8];
+    uint32_t virt_base;
+    uint32_t fixup_start;
+    uint32_t fixup_end;
+    uint32_t vapic;
+    uint32_t vapic_size;
+    uint32_t vcpu_shift;
+    uint32_t real_tpr;
+    struct vapic_patches {
+	uint32_t set_tpr;
+	uint32_t set_tpr_eax;
+	uint32_t get_tpr[8];
+        uint32_t get_tpr_stack;
+    } __attribute__((packed)) up, mp;
+} __attribute__((packed));
+
+static struct vapic_bios vapic_bios;
+
+static uint32_t real_tpr;
+static uint32_t bios_addr;
+static uint32_t vapic_phys;
+static uint32_t bios_enabled;
+static uint32_t vbios_desc_phys;
+static uint32_t vapic_bios_addr;
+
+static void update_vbios_real_tpr(void)
+{
+    cpu_physical_memory_rw(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios, 0);
+    vapic_bios.real_tpr = real_tpr;
+    vapic_bios.vcpu_shift = 7;
+    cpu_physical_memory_rw(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios, 1);
+}
+
+static unsigned modrm_reg(uint8_t modrm)
+{
+    return (modrm >> 3) & 7;
+}
+
+static int is_abs_modrm(uint8_t modrm)
+{
+    return (modrm & 0xc7) == 0x05;
+}
+
+static int instruction_is_ok(CPUState *env, uint64_t rip, int is_write)
+{
+    uint8_t b1, b2;
+    unsigned addr_offset;
+    uint32_t addr;
+    uint64_t p;
+
+    if ((rip & 0xf0000000) != 0x80000000 && (rip & 0xf0000000) != 0xe0000000)
+	return 0;
+    if (kvm_rsp_read(env) == 0)
+        return 0;
+    b1 = read_byte_virt(env, rip);
+    b2 = read_byte_virt(env, rip + 1);
+    switch (b1) {
+    case 0xc7: /* mov imm32, r/m32 (c7/0) */
+	if (modrm_reg(b2) != 0)
+	    return 0;
+	/* fall through */
+    case 0x89: /* mov r32 to r/m32 */
+    case 0x8b: /* mov r/m32 to r32 */
+	if (!is_abs_modrm(b2))
+	    return 0;
+	addr_offset = 2;
+	break;
+    case 0xa1: /* mov abs to eax */
+    case 0xa3: /* mov eax to abs */
+	addr_offset = 1;
+	break;
+    case 0xff: /* push r/m32 */
+        if (modrm_reg(b2) != 6 || !is_abs_modrm(b2))
+            return 0;
+        addr_offset = 2;
+    default:
+	return 0;
+    }
+    p = rip + addr_offset;
+    addr = read_byte_virt(env, p++);
+    addr |= read_byte_virt(env, p++) << 8;
+    addr |= read_byte_virt(env, p++) << 16;
+    addr |= read_byte_virt(env, p++) << 24;
+    if ((addr & 0xfff) != 0x80)
+	return 0;
+    real_tpr = addr;
+    update_vbios_real_tpr();
+    return 1;
+}
+
+static int bios_is_mapped(CPUState *env, uint64_t rip)
+{
+    uint32_t probe;
+    uint64_t phys;
+    struct kvm_sregs sregs;
+    unsigned perms;
+    uint32_t i;
+    uint32_t offset, fixup, start = vapic_bios_addr ? : 0xe0000;
+
+    if (bios_enabled)
+	return 1;
+
+    kvm_get_sregs(env, &sregs);
+
+    probe = (rip & 0xf0000000) + start;
+    phys = map_addr(&sregs, probe, &perms);
+    if (phys != start)
+	return 0;
+    bios_addr = probe;
+    for (i = 0; i < 64; ++i) {
+	cpu_physical_memory_read(phys, (void *)&vapic_bios, sizeof(vapic_bios));
+	if (memcmp(vapic_bios.signature, "kvm aPiC", 8) == 0)
+	    break;
+	phys += 1024;
+	bios_addr += 1024;
+    }
+    if (i == 64)
+	return 0;
+    if (bios_addr == vapic_bios.virt_base)
+	return 1;
+    vbios_desc_phys = phys;
+    for (i = vapic_bios.fixup_start; i < vapic_bios.fixup_end; i += 4) {
+	offset = ldl_phys(phys + i - vapic_bios.virt_base);
+	fixup = phys + offset;
+	stl_phys(fixup, ldl_phys(fixup) + bios_addr - vapic_bios.virt_base);
+    }
+    vapic_phys = vapic_bios.vapic - vapic_bios.virt_base + phys;
+    return 1;
+}
+
+static int get_pcr_cpu(CPUState *env)
+{
+    uint8_t b;
+
+    cpu_synchronize_state(env);
+
+    if (cpu_memory_rw_debug(env, env->segs[R_FS].base + 0x51, &b, 1, 0) < 0)
+	    return -1;
+
+    return (int)b;
+}
+
+int kvm_tpr_enable_vapic(CPUState *env)
+{
+    static uint8_t one = 1;
+    int pcr_cpu = get_pcr_cpu(env);
+
+    if (pcr_cpu < 0)
+	    return 0;
+
+    kvm_enable_vapic(env, vapic_phys + (pcr_cpu << 7));
+    cpu_physical_memory_rw(vapic_phys + (pcr_cpu << 7) + 4, &one, 1, 1);
+    env->update_vapic = 0;
+    bios_enabled = 1;
+    return 1;
+}
+
+static int enable_vapic(CPUState *env)
+{
+    bios_enabled = 1;
+    env->update_vapic = 1;
+    return 1;
+}
+
+static void patch_call(CPUState *env, uint64_t rip, uint32_t target)
+{
+    uint32_t offset;
+
+    offset = target - vapic_bios.virt_base + bios_addr - rip - 5;
+    write_byte_virt(env, rip, 0xe8); /* call near */
+    write_byte_virt(env, rip + 1, offset);
+    write_byte_virt(env, rip + 2, offset >> 8);
+    write_byte_virt(env, rip + 3, offset >> 16);
+    write_byte_virt(env, rip + 4, offset >> 24);
+}
+
+static void patch_instruction(CPUState *env, uint64_t rip)
+{
+    uint8_t b1, b2;
+    struct vapic_patches *vp;
+
+    vp = smp_cpus == 1 ? &vapic_bios.up : &vapic_bios.mp;
+    b1 = read_byte_virt(env, rip);
+    b2 = read_byte_virt(env, rip + 1);
+    switch (b1) {
+    case 0x89: /* mov r32 to r/m32 */
+	write_byte_virt(env, rip, 0x50 + modrm_reg(b2));  /* push reg */
+	patch_call(env, rip + 1, vp->set_tpr);
+	break;
+    case 0x8b: /* mov r/m32 to r32 */
+	write_byte_virt(env, rip, 0x90);
+	patch_call(env, rip + 1, vp->get_tpr[modrm_reg(b2)]);
+	break;
+    case 0xa1: /* mov abs to eax */
+	patch_call(env, rip, vp->get_tpr[0]);
+	break;
+    case 0xa3: /* mov eax to abs */
+	patch_call(env, rip, vp->set_tpr_eax);
+	break;
+    case 0xc7: /* mov imm32, r/m32 (c7/0) */
+	write_byte_virt(env, rip, 0x68);  /* push imm32 */
+	write_byte_virt(env, rip + 1, read_byte_virt(env, rip+6));
+	write_byte_virt(env, rip + 2, read_byte_virt(env, rip+7));
+	write_byte_virt(env, rip + 3, read_byte_virt(env, rip+8));
+	write_byte_virt(env, rip + 4, read_byte_virt(env, rip+9));
+	patch_call(env, rip + 5, vp->set_tpr);
+	break;
+    case 0xff: /* push r/m32 */
+        printf("patching push\n");
+        write_byte_virt(env, rip, 0x50); /* push eax */
+        patch_call(env, rip + 1, vp->get_tpr_stack);
+        break;
+    default:
+	printf("funny insn %02x %02x\n", b1, b2);
+    }
+}
+
+void kvm_tpr_access_report(CPUState *env, uint64_t rip, int is_write)
+{
+    if (!instruction_is_ok(env, rip, is_write))
+	return;
+    if (!bios_is_mapped(env, rip))
+	return;
+    if (!kvm_tpr_enable_vapic(env))
+	return;
+    patch_instruction(env, rip);
+}
+
+void kvm_tpr_vcpu_start(CPUState *env)
+{
+    kvm_enable_tpr_access_reporting(env);
+    if (bios_enabled)
+	kvm_tpr_enable_vapic(env);
+}
+
+static void tpr_save(QEMUFile *f, void *s)
+{
+    int i;
+
+    for (i = 0; i < (sizeof vapic_bios) / 4; ++i)
+	qemu_put_be32s(f, &((uint32_t *)&vapic_bios)[i]);
+    qemu_put_be32s(f, &bios_enabled);
+    qemu_put_be32s(f, &real_tpr);
+    qemu_put_be32s(f, &bios_addr);
+    qemu_put_be32s(f, &vapic_phys);
+    qemu_put_be32s(f, &vbios_desc_phys);
+}
+
+static int tpr_load(QEMUFile *f, void *s, int version_id)
+{
+    int i;
+
+    if (version_id != 1)
+	return -EINVAL;
+
+    for (i = 0; i < (sizeof vapic_bios) / 4; ++i)
+	qemu_get_be32s(f, &((uint32_t *)&vapic_bios)[i]);
+    qemu_get_be32s(f, &bios_enabled);
+    qemu_get_be32s(f, &real_tpr);
+    qemu_get_be32s(f, &bios_addr);
+    qemu_get_be32s(f, &vapic_phys);
+    qemu_get_be32s(f, &vbios_desc_phys);
+  
+    if (bios_enabled) {
+        CPUState *env = first_cpu->next_cpu;
+
+        for (env = first_cpu; env != NULL; env = env->next_cpu)
+            enable_vapic(env);
+    }
+
+    return 0;
+}
+
+static void vtpr_ioport_write16(void *opaque, uint32_t addr, uint32_t val)
+{
+    struct kvm_regs regs;
+    CPUState *env = cpu_single_env;
+    struct kvm_sregs sregs;
+    kvm_get_regs(env, &regs);
+    kvm_get_sregs(env, &sregs);
+    vapic_bios_addr = ((sregs.cs.base + regs.rip) & ~(512 - 1)) + val;
+    bios_enabled = 0;
+}
+
+static void vtpr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    CPUState *env = cpu_single_env;
+    struct kvm_regs regs;
+    struct kvm_sregs sregs;
+    uint32_t rip;
+
+    kvm_get_regs(env, &regs);
+    rip = regs.rip - 2;
+    write_byte_virt(env, rip, 0x66);
+    write_byte_virt(env, rip + 1, 0x90);
+    if (bios_enabled)
+	return;
+    if (!bios_is_mapped(env, rip))
+	printf("bios not mapped?\n");
+    kvm_get_sregs(env, &sregs);
+    for (addr = 0xfffff000u; addr >= 0x80000000u; addr -= 4096)
+	if (map_addr(&sregs, addr, NULL) == 0xfee00000u) {
+	    real_tpr = addr + 0x80;
+	    break;
+	}
+    bios_enabled = 1;
+    update_vbios_real_tpr();
+    kvm_tpr_enable_vapic(env);
+}
+
+void kvm_tpr_opt_setup(void)
+{
+    register_savevm("kvm-tpr-opt", 0, 1, tpr_save, tpr_load, NULL);
+    register_ioport_write(0x7e, 1, 1, vtpr_ioport_write, NULL);
+    register_ioport_write(0x7e, 2, 2, vtpr_ioport_write16, NULL);
+}
+
diff --git a/kvm.h b/kvm.h
index 1c93ac5..e2a945b 100644
--- a/kvm.h
+++ b/kvm.h
@@ -16,6 +16,9 @@
 
 #include "config.h"
 #include "qemu-queue.h"
+#include "qemu-kvm.h"
+
+#ifdef KVM_UPSTREAM
 
 #ifdef CONFIG_KVM
 extern int kvm_allowed;
@@ -47,7 +50,9 @@
 int kvm_set_migration_log(int enable);
 
 int kvm_has_sync_mmu(void);
+#endif /* KVM_UPSTREAM */
 int kvm_has_vcpu_events(void);
+#ifdef KVM_UPSTREAM
 
 void kvm_setup_guest_memory(void *start, size_t size);
 
@@ -140,3 +145,5 @@
 }
 
 #endif
+
+#endif
diff --git a/kvm/.gitignore b/kvm/.gitignore
new file mode 100644
index 0000000..22a8200
--- /dev/null
+++ b/kvm/.gitignore
@@ -0,0 +1,66 @@
+*.o
+*.d
+*~
+*.flat
+*.a
+config.mak
+.*.cmd
+qemu/config-host.h
+qemu/config-host.mak
+user/test/bootstrap
+user/kvmctl
+qemu/dyngen
+qemu/x86_64-softmmu
+qemu/qemu-img
+qemu/qemu-nbd
+*.ko
+*.mod.c
+bios/*.bin
+bios/*.sym
+bios/*.txt
+bios/acpi-dsdt.aml
+vgabios/*.bin
+vgabios/*.txt
+extboot/extboot.bin
+extboot/extboot.img
+extboot/signrom
+kernel/config.kbuild
+kernel/modules.order
+kernel/Module.symvers
+kernel/Modules.symvers
+kernel/Module.markers
+kernel/.tmp_versions
+kernel/include-compat/asm
+kernel/include-compat/asm-x86/asm-x86
+kernel/include
+kernel/x86/modules.order
+kernel/x86/i825[49].[ch]
+kernel/x86/kvm_main.c
+kernel/x86/kvm_svm.h
+kernel/x86/vmx.[ch]
+kernel/x86/svm.[ch]
+kernel/x86/mmu.[ch]
+kernel/x86/paging_tmpl.h
+kernel/x86/x86_emulate.[ch]
+kernel/x86/ioapic.[ch]
+kernel/x86/iodev.h
+kernel/x86/irq.[ch]
+kernel/x86/kvm_trace.c
+kernel/x86/lapic.[ch]
+kernel/x86/tss.h
+kernel/x86/x86.[ch]
+kernel/x86/coalesced_mmio.[ch]
+kernel/x86/kvm_cache_regs.h
+kernel/x86/vtd.c
+kernel/x86/irq_comm.c
+kernel/x86/timer.c
+kernel/x86/kvm_timer.h
+kernel/x86/iommu.c
+qemu/pc-bios/extboot.bin
+qemu/qemu-doc.html
+qemu/*.[18]
+qemu/*.pod
+qemu/qemu-tech.html
+qemu/qemu-options.texi
+user/kvmtrace
+user/test/x86/bootstrap
diff --git a/kvm/Makefile b/kvm/Makefile
new file mode 100644
index 0000000..617504c
--- /dev/null
+++ b/kvm/Makefile
@@ -0,0 +1,125 @@
+
+include config.mak
+
+DESTDIR=
+
+rpmrelease = devel
+
+sane-arch = $(subst i386,x86,$(subst x86_64,x86,$(subst s390x,s390,$(ARCH))))
+
+.PHONY: kernel user libkvm qemu bios vgabios extboot clean libfdt cscope
+
+all: libkvm qemu
+ifneq '$(filter $(ARCH), x86_64 i386 ia64)' ''
+    all: $(if $(WANT_MODULE), kernel) user
+endif
+
+kcmd = $(if $(WANT_MODULE),,@\#)
+
+qemu kernel user libkvm:
+	$(MAKE) -C $@
+
+qemu: libkvm
+ifneq '$(filter $(ARCH), i386 x86_64)' ''
+    qemu: extboot
+endif
+ifneq '$(filter $(ARCH), powerpc ia64)' ''
+    qemu: libfdt
+endif
+user: libkvm
+
+# sync if kernel/Makefile exists and if using --with-patched-kernel
+user libkvm qemu: header-sync-$(if $(wildcard kernel/Makefile),$(if $(WANT_MODULE),n,y),n)
+
+header-sync-n:
+
+header-sync-y:
+	make -C kernel \
+	LINUX=$(if $(KERNELSOURCEDIR),$(KERNELSOURCEDIR),$(KERNELDIR)) \
+	header-sync
+	rm -f kernel/include/asm
+	ln -sf asm-$(sane-arch) kernel/include/asm
+
+bios:
+	$(MAKE) -C $@
+	cp bios/BIOS-bochs-latest qemu/pc-bios/bios.bin
+
+vgabios:
+	$(MAKE) -C $@
+	cp vgabios/VGABIOS-lgpl-latest.bin qemu/pc-bios/vgabios.bin
+	cp vgabios/VGABIOS-lgpl-latest.cirrus.bin qemu/pc-bios/vgabios-cirrus.bin
+
+extboot:
+	$(MAKE) -C $@
+	if ! [ -f qemu/pc-bios/extboot.bin ] \
+           || ! cmp -s qemu/pc-bios/extboot.bin extboot/extboot.bin; then \
+		cp extboot/extboot.bin qemu/pc-bios/extboot.bin; \
+	fi
+libfdt:
+	$(MAKE) -C $@
+
+LINUX=linux-2.6
+
+sync:
+	make -C kernel sync LINUX=$(shell readlink -f "$(LINUX)")
+
+bindir = /usr/bin
+bin = $(bindir)/kvm
+initdir = /etc/init.d
+confdir = /etc/kvm
+utilsdir = /etc/kvm/utils
+
+install-rpm:
+	mkdir -p $(DESTDIR)/$(bindir)
+	mkdir -p $(DESTDIR)/$(confdir)
+	mkdir -p $(DESTDIR)/$(initdir)
+	mkdir -p $(DESTDIR)/$(utilsdir)
+	mkdir -p $(DESTDIR)/etc/udev/rules.d
+	make -C qemu DESTDIR=$(DESTDIR)/ install
+	ln -sf /usr/kvm/bin/qemu-system-x86_64 $(DESTDIR)/$(bin)
+	install -m 755 kvm_stat $(DESTDIR)/$(bindir)/kvm_stat
+	cp scripts/kvm $(DESTDIR)/$(initdir)/kvm
+	cp scripts/qemu-ifup $(DESTDIR)/$(confdir)/qemu-ifup
+	install -t $(DESTDIR)/etc/udev/rules.d scripts/*kvm*.rules
+
+install:
+	$(kcmd)make -C kernel DESTDIR="$(DESTDIR)" install
+	make -C libkvm DESTDIR="$(DESTDIR)" install
+	make -C qemu DESTDIR="$(DESTDIR)" install
+
+tmpspec = .tmp.kvm.spec
+RPMTOPDIR = $$(pwd)/rpmtop
+
+rpm:	srpm
+	rm -rf $(RPMTOPDIR)/BUILD
+	mkdir -p $(RPMTOPDIR)/{BUILD,RPMS/$$(uname -i)}
+	rpmbuild --rebuild \
+		 --define="_topdir $(RPMTOPDIR)" \
+		$(RPMTOPDIR)/SRPMS/kvm-0.0-$(rpmrelease).src.rpm
+
+srpm:
+	mkdir -p $(RPMTOPDIR)/{SOURCES,SRPMS}
+	sed 's/^Release:.*/Release: $(rpmrelease)/' kvm.spec > $(tmpspec)
+	tar czf $(RPMTOPDIR)/SOURCES/kvm.tar.gz qemu
+	tar czf $(RPMTOPDIR)/SOURCES/user.tar.gz user
+	tar czf $(RPMTOPDIR)/SOURCES/libkvm.tar.gz libkvm
+	tar czf $(RPMTOPDIR)/SOURCES/kernel.tar.gz kernel
+	tar czf $(RPMTOPDIR)/SOURCES/scripts.tar.gz scripts
+	tar czf $(RPMTOPDIR)/SOURCES/extboot.tar.gz extboot
+	cp Makefile configure kvm_stat $(RPMTOPDIR)/SOURCES
+	rpmbuild  --define="_topdir $(RPMTOPDIR)" -bs $(tmpspec)
+	$(RM) $(tmpspec)
+
+clean:
+	for i in $(if $(WANT_MODULE), kernel) user libkvm qemu libfdt; do \
+		make -C $$i clean; \
+	done
+	rm -f ./cscope.*
+
+distclean: clean
+	rm -f config.mak user/config.mak
+
+cscope:
+	rm -f ./cscope.*
+	find . -wholename './kernel' -prune -o -name "*.[ch]" -print > ./cscope.files
+	cscope -b
diff --git a/kvm/configure b/kvm/configure
new file mode 100755
index 0000000..249c743
--- /dev/null
+++ b/kvm/configure
@@ -0,0 +1,159 @@
+#!/bin/bash
+
+prefix=/usr/local
+kerneldir=/lib/modules/$(uname -r)/build
+cc=gcc
+ld=ld
+objcopy=objcopy
+ar=ar
+want_module=1
+qemu_cflags=
+qemu_ldflags=
+kvm_trace=
+qemu_opts=()
+cross_prefix=
+arch=`uname -m`
+target_exec=
+# don't use uname if kerneldir is set
+no_uname=
+if [ -z "TMPDIR" ] ; then
+    TMPDIR=.
+fi
+
+if [ ! -e kernel/Makefile ]; then
+    want_module=
+fi
+
+usage() {
+    cat <<-EOF
+	Usage: $0 [options]
+
+	Options include:
+	    --arch=ARCH            architecture to compile for ($arch)
+	    --cross-prefix=PREFIX  prefix for cross compile
+	    --prefix=PREFIX        where to install things ($prefix)
+	    --with-patched-kernel  don't use external module
+	    --with-kvm-trace       Enable kvm_trace
+	    --kerneldir=DIR        kernel build directory ($kerneldir)
+	    --qemu-cflags=CFLAGS   CFLAGS to add to qemu configuration
+	    --qemu-ldflags=LDFLAGS LDFLAGS to add to qemu configuration
+
+	Any additional option is given to qemu's configure verbatim; including:
+
+EOF
+    cd qemu
+    ./configure --help | egrep "enable-|disable-" \
+	| grep -v user | grep -v system | grep -v kqemu | grep -v kvm \
+	| sed -e "s/^  /    /g" \
+	| sed -e"s/  enable/enable/g" | sed -e "s/  disable/disable/g"
+    exit 1
+}
+
+while [[ "$1" = -* ]]; do
+    opt="$1"; shift
+    arg=
+    hasarg=
+    if [[ "$opt" = *=* ]]; then
+	arg="${opt#*=}"
+	opt="${opt%%=*}"
+	hasarg=1
+    fi
+    case "$opt" in
+	--prefix)
+	    prefix="$arg"
+	    ;;
+	--kerneldir)
+	    kerneldir="$arg"
+            no_uname=1
+	    ;;
+	--with-patched-kernel)
+	    want_module=
+	    ;;
+	--with-kvm-trace)
+	    kvm_trace=y
+	    ;;
+	--qemu-cflags)
+	    qemu_cflags="$arg"
+	    ;;
+	--qemu-ldflags)
+	    qemu_ldflags="$arg"
+	    ;;
+	--arch)
+	    arch="$arg"
+	    ;;
+	--cross-prefix)
+	    cross_prefix="$arg"
+            ;;
+	--help)
+	    usage
+	    ;;
+	*)
+	    qemu_opts=("${qemu_opts[@]}" "$opt${hasarg:+=$arg}")
+	    ;;
+    esac
+done
+
+
+#set kenel directory
+libkvm_kerneldir=$(readlink -f kernel)
+
+case $arch in
+    i?86*|x86_64*)
+        arch=${arch/#i?86/i386}
+        target_exec="x86_64-softmmu"
+        qemu_cflags="$qemu_cflags -DCONFIG_X86"
+        ;;
+    ia64*)
+        target_exec="ia64-softmmu"
+        ;;
+    powerpc*)
+        target_exec="ppcemb-softmmu"
+        qemu_cflags="$qemu_cflags -I $PWD/libfdt"
+        qemu_ldflags="$qemu_ldflags -L $PWD/libfdt"
+        ;;
+esac
+
+processor=${arch#*-}
+arch=${arch%%-*}
+
+#configure kernel module
+[ -e kernel/Makefile ] && (cd kernel;
+    ./configure \
+	--kerneldir="$kerneldir" \
+	--arch="$arch" \
+	$([ -z ${want_module} ] && echo "--with-patched-kernel") \
+	${cross_prefix:+"--cross-prefix=$cross_prefix"} \
+	${kvm_trace:+"--with-kvm-trace"}
+)
+
+#configure user dir
+(cd user; ./configure --prefix="$prefix" --kerneldir="$libkvm_kerneldir" \
+          --arch="$arch" --processor="$processor" \
+          ${cross_prefix:+"--cross-prefix=$cross_prefix"})
+
+#configure qemu
+(cd qemu; ./configure --target-list=$target_exec \
+    --disable-kqemu \
+    --extra-cflags="-I $PWD/../libkvm $qemu_cflags" \
+    --extra-ldflags="-L $PWD/../libkvm $qemu_ldflags" \
+    --kerneldir="$libkvm_kerneldir" \
+    --prefix="$prefix" \
+    ${cross_prefix:+"--cross-prefix=$cross_prefix"} \
+    ${cross_prefix:+"--cpu=$arch"} "${qemu_opts[@]}"
+) || usage
+
+
+cat <<EOF > config.mak
+ARCH=$arch
+PROCESSOR=$processor
+PREFIX=$prefix
+KERNELDIR=$kerneldir
+KERNELSOURCEDIR=$kernelsourcedir
+LIBKVM_KERNELDIR=$libkvm_kerneldir
+WANT_MODULE=$want_module
+CROSS_COMPILE=$cross_prefix
+CC=$cross_prefix$cc
+LD=$cross_prefix$ld
+OBJCOPY=$cross_prefix$objcopy
+AR=$cross_prefix$ar
+EOF
diff --git a/kvm/doxygen.conf b/kvm/doxygen.conf
new file mode 100644
index 0000000..21a04c0
--- /dev/null
+++ b/kvm/doxygen.conf
@@ -0,0 +1,1252 @@
+# Doxyfile 1.5.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = KVM
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = Release 7
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = NO
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = user/ kernel/
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable caller graphs for selected 
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that a graph may be further truncated if the graph's 
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH 
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), 
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/kvm/extboot/Makefile b/kvm/extboot/Makefile
new file mode 100644
index 0000000..ab2dae7
--- /dev/null
+++ b/kvm/extboot/Makefile
@@ -0,0 +1,41 @@
+OBJCOPY=objcopy
+
+# from kernel sources - scripts/Kbuild.include
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" is can be used as temporary file and
+# is automatically cleaned up.
+try-run = $(shell set -e;		\
+	TMP="$(TMPOUT).$$$$.tmp";	\
+	if ($(1)) >/dev/null 2>&1;	\
+	then echo "$(2)";		\
+	else echo "$(3)";		\
+	fi;				\
+	rm -f "$$TMP")
+
+# cc-option-yn
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+	$(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+
+CFLAGS = -Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin
+ifeq ($(call cc-option-yn,-fno-stack-protector),y)
+CFLAGS += -fno-stack-protector
+endif
+
+all: extboot.bin
+
+%.o: %.S
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+extboot.img: extboot.o
+	$(LD) --oformat binary -Ttext 0 -o $@ $<
+
+extboot.bin: extboot.img signrom
+	./signrom extboot.img extboot.bin
+
+signrom: signrom.c
+	$(CC) -o $@ -g -Wall $^
+
+clean:
+	$(RM) *.o *.img *.bin signrom *~
diff --git a/kvm/extboot/STATUS b/kvm/extboot/STATUS
new file mode 100644
index 0000000..687c6d6
--- /dev/null
+++ b/kvm/extboot/STATUS
@@ -0,0 +1,6 @@
+Working
+-------
+
+Ubuntu Server 7.04 (i386)
+Windows 2000 Professional (i386)
+Windows XP SP2 (i386)
diff --git a/kvm/extboot/signrom.c b/kvm/extboot/signrom.c
new file mode 100644
index 0000000..fe8d677
--- /dev/null
+++ b/kvm/extboot/signrom.c
@@ -0,0 +1,79 @@
+/*
+ * Extended Boot Option ROM
+ *
+ * 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 Corporation, 2007
+ *   Authors: Anthony Liguori <aliguori@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+	FILE *fin, *fout;
+	char buffer[512], oldbuffer[512];
+	int i, size, lag = 0;
+	uint8_t sum = 0;
+
+	if (argc != 3) {
+		printf("Usage: %s ROM OUTPUT\n", argv[0]);
+		return 1;
+	}
+
+	fin = fopen(argv[1], "rb");
+	fout = fopen(argv[2], "wb");
+
+	if (fin == NULL || fout == NULL) {
+		fprintf(stderr, "Could not open input/output files\n");
+		return 1;
+	}
+
+	do {
+		size = fread(buffer, 512, 1, fin);
+		if (size == 1) {
+			for (i = 0; i < 512; i++)
+				sum += buffer[i];
+
+			if (lag) {
+				if (fwrite(oldbuffer, 512, 1, fout) != 1) {
+					fprintf(stderr, "Write failed\n");
+					return 1;
+				}
+			}
+			lag = 1;
+			memcpy(oldbuffer, buffer, 512);
+		}
+	} while (size == 1);
+
+	if (size != 0) {
+		fprintf(stderr, "Failed to read from input file\n");
+		return 1;
+	}
+
+	oldbuffer[511] = -sum;
+
+	if (fwrite(oldbuffer, 512, 1, fout) != 1) {
+		fprintf(stderr, "Failed to write to output file\n");
+		return 1;
+	}
+
+	fclose(fin);
+	fclose(fout);
+
+	return 0;
+}
diff --git a/kvm/include/ia64/asm/kvm.h b/kvm/include/ia64/asm/kvm.h
new file mode 100644
index 0000000..bc90c75
--- /dev/null
+++ b/kvm/include/ia64/asm/kvm.h
@@ -0,0 +1,264 @@
+#ifndef __ASM_IA64_KVM_H
+#define __ASM_IA64_KVM_H
+
+/*
+ * kvm structure definitions  for ia64
+ *
+ * Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Select x86 specific features in <linux/kvm.h> */
+#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_DEVICE_ASSIGNMENT
+
+/* Architectural interrupt line count. */
+#define KVM_NR_INTERRUPTS 256
+
+#define KVM_IOAPIC_NUM_PINS  48
+
+struct kvm_ioapic_state {
+	__u64 base_address;
+	__u32 ioregsel;
+	__u32 id;
+	__u32 irr;
+	__u32 pad;
+	union {
+		__u64 bits;
+		struct {
+			__u8 vector;
+			__u8 delivery_mode:3;
+			__u8 dest_mode:1;
+			__u8 delivery_status:1;
+			__u8 polarity:1;
+			__u8 remote_irr:1;
+			__u8 trig_mode:1;
+			__u8 mask:1;
+			__u8 reserve:7;
+			__u8 reserved[4];
+			__u8 dest_id;
+		} fields;
+	} redirtbl[KVM_IOAPIC_NUM_PINS];
+};
+
+#define KVM_IRQCHIP_PIC_MASTER   0
+#define KVM_IRQCHIP_PIC_SLAVE    1
+#define KVM_IRQCHIP_IOAPIC       2
+#define KVM_NR_IRQCHIPS          3
+
+#define KVM_CONTEXT_SIZE	8*1024
+
+struct kvm_fpreg {
+	union {
+		unsigned long bits[2];
+		long double __dummy;	/* force 16-byte alignment */
+	} u;
+};
+
+union context {
+	/* 8K size */
+	char	dummy[KVM_CONTEXT_SIZE];
+	struct {
+		unsigned long       psr;
+		unsigned long       pr;
+		unsigned long       caller_unat;
+		unsigned long       pad;
+		unsigned long       gr[32];
+		unsigned long       ar[128];
+		unsigned long       br[8];
+		unsigned long       cr[128];
+		unsigned long       rr[8];
+		unsigned long       ibr[8];
+		unsigned long       dbr[8];
+		unsigned long       pkr[8];
+		struct kvm_fpreg   fr[128];
+	};
+};
+
+struct thash_data {
+	union {
+		struct {
+			unsigned long p    :  1; /* 0 */
+			unsigned long rv1  :  1; /* 1 */
+			unsigned long ma   :  3; /* 2-4 */
+			unsigned long a    :  1; /* 5 */
+			unsigned long d    :  1; /* 6 */
+			unsigned long pl   :  2; /* 7-8 */
+			unsigned long ar   :  3; /* 9-11 */
+			unsigned long ppn  : 38; /* 12-49 */
+			unsigned long rv2  :  2; /* 50-51 */
+			unsigned long ed   :  1; /* 52 */
+			unsigned long ig1  : 11; /* 53-63 */
+		};
+		struct {
+			unsigned long __rv1 : 53;     /* 0-52 */
+			unsigned long contiguous : 1; /*53 */
+			unsigned long tc : 1;         /* 54 TR or TC */
+			unsigned long cl : 1;
+			/* 55 I side or D side cache line */
+			unsigned long len  :  4;      /* 56-59 */
+			unsigned long io  : 1;	/* 60 entry is for io or not */
+			unsigned long nomap : 1;
+			/* 61 entry cann't be inserted into machine TLB.*/
+			unsigned long checked : 1;
+			/* 62 for VTLB/VHPT sanity check */
+			unsigned long invalid : 1;
+			/* 63 invalid entry */
+		};
+		unsigned long page_flags;
+	};                  /* same for VHPT and TLB */
+
+	union {
+		struct {
+			unsigned long rv3  :  2;
+			unsigned long ps   :  6;
+			unsigned long key  : 24;
+			unsigned long rv4  : 32;
+		};
+		unsigned long itir;
+	};
+	union {
+		struct {
+			unsigned long ig2  :  12;
+			unsigned long vpn  :  49;
+			unsigned long vrn  :   3;
+		};
+		unsigned long ifa;
+		unsigned long vadr;
+		struct {
+			unsigned long tag  :  63;
+			unsigned long ti   :  1;
+		};
+		unsigned long etag;
+	};
+	union {
+		struct thash_data *next;
+		unsigned long rid;
+		unsigned long gpaddr;
+	};
+};
+
+#define	NITRS	8
+#define NDTRS	8
+
+struct saved_vpd {
+	unsigned long  vhpi;
+	unsigned long  vgr[16];
+	unsigned long  vbgr[16];
+	unsigned long  vnat;
+	unsigned long  vbnat;
+	unsigned long  vcpuid[5];
+	unsigned long  vpsr;
+	unsigned long  vpr;
+	union {
+		unsigned long  vcr[128];
+		struct {
+			unsigned long dcr;
+			unsigned long itm;
+			unsigned long iva;
+			unsigned long rsv1[5];
+			unsigned long pta;
+			unsigned long rsv2[7];
+			unsigned long ipsr;
+			unsigned long isr;
+			unsigned long rsv3;
+			unsigned long iip;
+			unsigned long ifa;
+			unsigned long itir;
+			unsigned long iipa;
+			unsigned long ifs;
+			unsigned long iim;
+			unsigned long iha;
+			unsigned long rsv4[38];
+			unsigned long lid;
+			unsigned long ivr;
+			unsigned long tpr;
+			unsigned long eoi;
+			unsigned long irr[4];
+			unsigned long itv;
+			unsigned long pmv;
+			unsigned long cmcv;
+			unsigned long rsv5[5];
+			unsigned long lrr0;
+			unsigned long lrr1;
+			unsigned long rsv6[46];
+		};
+	};
+};
+
+struct kvm_regs {
+	struct saved_vpd vpd;
+	/*Arch-regs*/
+	int mp_state;
+	unsigned long vmm_rr;
+	/* TR and TC.  */
+	struct thash_data itrs[NITRS];
+	struct thash_data dtrs[NDTRS];
+	/* Bit is set if there is a tr/tc for the region.  */
+	unsigned char itr_regions;
+	unsigned char dtr_regions;
+	unsigned char tc_regions;
+
+	char irq_check;
+	unsigned long saved_itc;
+	unsigned long itc_check;
+	unsigned long timer_check;
+	unsigned long timer_pending;
+	unsigned long last_itc;
+
+	unsigned long vrr[8];
+	unsigned long ibr[8];
+	unsigned long dbr[8];
+	unsigned long insvc[4];		/* Interrupt in service.  */
+	unsigned long xtp;
+
+	unsigned long metaphysical_rr0; /* from kvm_arch (so is pinned) */
+	unsigned long metaphysical_rr4;	/* from kvm_arch (so is pinned) */
+	unsigned long metaphysical_saved_rr0; /* from kvm_arch          */
+	unsigned long metaphysical_saved_rr4; /* from kvm_arch          */
+	unsigned long fp_psr;       /*used for lazy float register */
+	unsigned long saved_gp;
+	/*for phycial  emulation */
+
+	union context saved_guest;
+
+	unsigned long reserved[64];	/* for future use */
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+#define KVM_IA64_VCPU_STACK_SHIFT	16
+#define KVM_IA64_VCPU_STACK_SIZE	(1UL << KVM_IA64_VCPU_STACK_SHIFT)
+
+struct kvm_ia64_vcpu_stack {
+	unsigned char stack[KVM_IA64_VCPU_STACK_SIZE];
+};
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+#endif
diff --git a/kvm/include/ia64/asm/kvm_para.h b/kvm/include/ia64/asm/kvm_para.h
new file mode 100644
index 0000000..1588aee
--- /dev/null
+++ b/kvm/include/ia64/asm/kvm_para.h
@@ -0,0 +1,31 @@
+#ifndef __IA64_KVM_PARA_H
+#define __IA64_KVM_PARA_H
+
+/*
+ * Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+	return 0;
+}
+
+#endif
+
+#endif
diff --git a/kvm/include/linux/compiler.h b/kvm/include/linux/compiler.h
new file mode 100644
index 0000000..f70c49f
--- /dev/null
+++ b/kvm/include/linux/compiler.h
@@ -0,0 +1,2 @@
+/* dummy file */
+
diff --git a/kvm/include/linux/config.h b/kvm/include/linux/config.h
new file mode 100644
index 0000000..a421f31
--- /dev/null
+++ b/kvm/include/linux/config.h
@@ -0,0 +1,43 @@
+#ifndef KVM_UNIFDEF_H
+#define KVM_UNIFDEF_H
+
+#ifdef __i386__
+#ifndef CONFIG_X86_32
+#define CONFIG_X86_32 1
+#endif
+#endif
+
+#ifdef __x86_64__
+#ifndef CONFIG_X86_64
+#define CONFIG_X86_64 1
+#endif
+#endif
+
+#if defined(__i386__) || defined (__x86_64__)
+#ifndef CONFIG_X86
+#define CONFIG_X86 1
+#endif
+#endif
+
+#ifdef __ia64__
+#ifndef CONFIG_IA64
+#define CONFIG_IA64 1
+#endif
+#endif
+
+#ifdef __PPC__
+#ifndef CONFIG_PPC
+#define CONFIG_PPC 1
+#endif
+#endif
+
+#ifdef __s390__
+#ifndef CONFIG_S390
+#define CONFIG_S390 1
+#endif
+#endif
+
+#endif
+
+
+#define __user
diff --git a/kvm/include/linux/kvm.h b/kvm/include/linux/kvm.h
new file mode 100644
index 0000000..db10887
--- /dev/null
+++ b/kvm/include/linux/kvm.h
@@ -0,0 +1,735 @@
+#ifndef __LINUX_KVM_H
+#define __LINUX_KVM_H
+
+/*
+ * Userspace interface for /dev/kvm - kernel based virtual machine
+ *
+ * Note: you must update KVM_API_VERSION if you change this interface.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <asm/kvm.h>
+
+#define KVM_API_VERSION 12
+
+/* *** Deprecated interfaces *** */
+
+#define KVM_TRC_SHIFT           16
+
+#define KVM_TRC_ENTRYEXIT       (1 << KVM_TRC_SHIFT)
+#define KVM_TRC_HANDLER         (1 << (KVM_TRC_SHIFT + 1))
+
+#define KVM_TRC_VMENTRY         (KVM_TRC_ENTRYEXIT + 0x01)
+#define KVM_TRC_VMEXIT          (KVM_TRC_ENTRYEXIT + 0x02)
+#define KVM_TRC_PAGE_FAULT      (KVM_TRC_HANDLER + 0x01)
+
+#define KVM_TRC_HEAD_SIZE       12
+#define KVM_TRC_CYCLE_SIZE      8
+#define KVM_TRC_EXTRA_MAX       7
+
+#define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
+#define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
+#define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
+#define KVM_TRC_IO_READ          (KVM_TRC_HANDLER + 0x05)
+#define KVM_TRC_IO_WRITE         (KVM_TRC_HANDLER + 0x06)
+#define KVM_TRC_CR_READ          (KVM_TRC_HANDLER + 0x07)
+#define KVM_TRC_CR_WRITE         (KVM_TRC_HANDLER + 0x08)
+#define KVM_TRC_DR_READ          (KVM_TRC_HANDLER + 0x09)
+#define KVM_TRC_DR_WRITE         (KVM_TRC_HANDLER + 0x0A)
+#define KVM_TRC_MSR_READ         (KVM_TRC_HANDLER + 0x0B)
+#define KVM_TRC_MSR_WRITE        (KVM_TRC_HANDLER + 0x0C)
+#define KVM_TRC_CPUID            (KVM_TRC_HANDLER + 0x0D)
+#define KVM_TRC_INTR             (KVM_TRC_HANDLER + 0x0E)
+#define KVM_TRC_NMI              (KVM_TRC_HANDLER + 0x0F)
+#define KVM_TRC_VMMCALL          (KVM_TRC_HANDLER + 0x10)
+#define KVM_TRC_HLT              (KVM_TRC_HANDLER + 0x11)
+#define KVM_TRC_CLTS             (KVM_TRC_HANDLER + 0x12)
+#define KVM_TRC_LMSW             (KVM_TRC_HANDLER + 0x13)
+#define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
+#define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
+#define KVM_TRC_GTLB_WRITE       (KVM_TRC_HANDLER + 0x16)
+#define KVM_TRC_STLB_WRITE       (KVM_TRC_HANDLER + 0x17)
+#define KVM_TRC_STLB_INVAL       (KVM_TRC_HANDLER + 0x18)
+#define KVM_TRC_PPC_INSTR        (KVM_TRC_HANDLER + 0x19)
+
+struct kvm_user_trace_setup {
+	__u32 buf_size;
+	__u32 buf_nr;
+};
+
+#define __KVM_DEPRECATED_MAIN_W_0x06 \
+	_IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
+#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
+#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
+
+#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
+
+struct kvm_breakpoint {
+	__u32 enabled;
+	__u32 padding;
+	__u64 address;
+};
+
+struct kvm_debug_guest {
+	__u32 enabled;
+	__u32 pad;
+	struct kvm_breakpoint breakpoints[4];
+	__u32 singlestep;
+};
+
+#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
+
+/* *** End of deprecated interfaces *** */
+
+
+/* for KVM_CREATE_MEMORY_REGION */
+struct kvm_memory_region {
+	__u32 slot;
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size; /* bytes */
+};
+
+/* for KVM_SET_USER_MEMORY_REGION */
+struct kvm_userspace_memory_region {
+	__u32 slot;
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size; /* bytes */
+	__u64 userspace_addr; /* start of the userspace allocated memory */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES  1UL
+
+
+/* for KVM_IRQ_LINE */
+struct kvm_irq_level {
+	/*
+	 * ACPI gsi notion of irq.
+	 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
+	 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+	 */
+	union {
+		__u32 irq;
+		__s32 status;
+	};
+	__u32 level;
+};
+
+
+struct kvm_irqchip {
+	__u32 chip_id;
+	__u32 pad;
+        union {
+		char dummy[512];  /* reserving space */
+#ifdef __KVM_HAVE_PIT
+		struct kvm_pic_state pic;
+#endif
+#ifdef __KVM_HAVE_IOAPIC
+		struct kvm_ioapic_state ioapic;
+#endif
+	} chip;
+};
+
+/* for KVM_CREATE_PIT2 */
+struct kvm_pit_config {
+	__u32 flags;
+	__u32 pad[15];
+};
+
+#define KVM_PIT_SPEAKER_DUMMY     1
+
+#define KVM_EXIT_UNKNOWN          0
+#define KVM_EXIT_EXCEPTION        1
+#define KVM_EXIT_IO               2
+#define KVM_EXIT_HYPERCALL        3
+#define KVM_EXIT_DEBUG            4
+#define KVM_EXIT_HLT              5
+#define KVM_EXIT_MMIO             6
+#define KVM_EXIT_IRQ_WINDOW_OPEN  7
+#define KVM_EXIT_SHUTDOWN         8
+#define KVM_EXIT_FAIL_ENTRY       9
+#define KVM_EXIT_INTR             10
+#define KVM_EXIT_SET_TPR          11
+#define KVM_EXIT_TPR_ACCESS       12
+#define KVM_EXIT_S390_SIEIC       13
+#define KVM_EXIT_S390_RESET       14
+#define KVM_EXIT_DCR              15
+#define KVM_EXIT_NMI              16
+#define KVM_EXIT_INTERNAL_ERROR   17
+
+/* For KVM_EXIT_INTERNAL_ERROR */
+#define KVM_INTERNAL_ERROR_EMULATION 1
+#define KVM_INTERNAL_ERROR_SIMUL_EX 2
+
+/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
+struct kvm_run {
+	/* in */
+	__u8 request_interrupt_window;
+	__u8 padding1[7];
+
+	/* out */
+	__u32 exit_reason;
+	__u8 ready_for_interrupt_injection;
+	__u8 if_flag;
+	__u8 padding2[2];
+
+	/* in (pre_kvm_run), out (post_kvm_run) */
+	__u64 cr8;
+	__u64 apic_base;
+
+	union {
+		/* KVM_EXIT_UNKNOWN */
+		struct {
+			__u64 hardware_exit_reason;
+		} hw;
+		/* KVM_EXIT_FAIL_ENTRY */
+		struct {
+			__u64 hardware_entry_failure_reason;
+		} fail_entry;
+		/* KVM_EXIT_EXCEPTION */
+		struct {
+			__u32 exception;
+			__u32 error_code;
+		} ex;
+		/* KVM_EXIT_IO */
+		struct {
+#define KVM_EXIT_IO_IN  0
+#define KVM_EXIT_IO_OUT 1
+			__u8 direction;
+			__u8 size; /* bytes */
+			__u16 port;
+			__u32 count;
+			__u64 data_offset; /* relative to kvm_run start */
+		} io;
+		struct {
+			struct kvm_debug_exit_arch arch;
+		} debug;
+		/* KVM_EXIT_MMIO */
+		struct {
+			__u64 phys_addr;
+			__u8  data[8];
+			__u32 len;
+			__u8  is_write;
+		} mmio;
+		/* KVM_EXIT_HYPERCALL */
+		struct {
+			__u64 nr;
+			__u64 args[6];
+			__u64 ret;
+			__u32 longmode;
+			__u32 pad;
+		} hypercall;
+		/* KVM_EXIT_TPR_ACCESS */
+		struct {
+			__u64 rip;
+			__u32 is_write;
+			__u32 pad;
+		} tpr_access;
+		/* KVM_EXIT_S390_SIEIC */
+		struct {
+			__u8 icptcode;
+			__u64 mask; /* psw upper half */
+			__u64 addr; /* psw lower half */
+			__u16 ipa;
+			__u32 ipb;
+		} s390_sieic;
+		/* KVM_EXIT_S390_RESET */
+#define KVM_S390_RESET_POR       1
+#define KVM_S390_RESET_CLEAR     2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT  8
+#define KVM_S390_RESET_IPL       16
+		__u64 s390_reset_flags;
+		/* KVM_EXIT_DCR */
+		struct {
+			__u32 dcrn;
+			__u32 data;
+			__u8  is_write;
+		} dcr;
+		struct {
+			__u32 suberror;
+			/* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
+			__u32 ndata;
+			__u64 data[16];
+		} internal;
+		/* Fix the size of the union. */
+		char padding[256];
+	};
+};
+
+/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
+
+struct kvm_coalesced_mmio_zone {
+	__u64 addr;
+	__u32 size;
+	__u32 pad;
+};
+
+struct kvm_coalesced_mmio {
+	__u64 phys_addr;
+	__u32 len;
+	__u32 pad;
+	__u8  data[8];
+};
+
+struct kvm_coalesced_mmio_ring {
+	__u32 first, last;
+	struct kvm_coalesced_mmio coalesced_mmio[0];
+};
+
+#define KVM_COALESCED_MMIO_MAX \
+	((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
+	 sizeof(struct kvm_coalesced_mmio))
+
+/* for KVM_TRANSLATE */
+struct kvm_translation {
+	/* in */
+	__u64 linear_address;
+
+	/* out */
+	__u64 physical_address;
+	__u8  valid;
+	__u8  writeable;
+	__u8  usermode;
+	__u8  pad[5];
+};
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+	/* in */
+	__u32 irq;
+};
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+	__u32 slot;
+	__u32 padding1;
+	union {
+		void *dirty_bitmap; /* one bit per page */
+		__u64 padding2;
+	};
+};
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+	__u32 len;
+	__u8  sigset[0];
+};
+
+/* for KVM_TPR_ACCESS_REPORTING */
+struct kvm_tpr_access_ctl {
+	__u32 enabled;
+	__u32 flags;
+	__u32 reserved[8];
+};
+
+/* for KVM_SET_VAPIC_ADDR */
+struct kvm_vapic_addr {
+	__u64 vapic_addr;
+};
+
+/* for KVM_SET_MPSTATE */
+
+#define KVM_MP_STATE_RUNNABLE          0
+#define KVM_MP_STATE_UNINITIALIZED     1
+#define KVM_MP_STATE_INIT_RECEIVED     2
+#define KVM_MP_STATE_HALTED            3
+#define KVM_MP_STATE_SIPI_RECEIVED     4
+
+struct kvm_mp_state {
+	__u32 mp_state;
+};
+
+struct kvm_s390_psw {
+	__u64 mask;
+	__u64 addr;
+};
+
+/* valid values for type in kvm_s390_interrupt */
+#define KVM_S390_SIGP_STOP		0xfffe0000u
+#define KVM_S390_PROGRAM_INT		0xfffe0001u
+#define KVM_S390_SIGP_SET_PREFIX	0xfffe0002u
+#define KVM_S390_RESTART		0xfffe0003u
+#define KVM_S390_INT_VIRTIO		0xffff2603u
+#define KVM_S390_INT_SERVICE		0xffff2401u
+#define KVM_S390_INT_EMERGENCY		0xffff1201u
+
+struct kvm_s390_interrupt {
+	__u32 type;
+	__u32 parm;
+	__u64 parm64;
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+
+#define KVM_GUESTDBG_ENABLE		0x00000001
+#define KVM_GUESTDBG_SINGLESTEP		0x00000002
+
+struct kvm_guest_debug {
+	__u32 control;
+	__u32 pad;
+	struct kvm_guest_debug_arch arch;
+};
+
+enum {
+	kvm_ioeventfd_flag_nr_datamatch,
+	kvm_ioeventfd_flag_nr_pio,
+	kvm_ioeventfd_flag_nr_deassign,
+	kvm_ioeventfd_flag_nr_max,
+};
+
+#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
+#define KVM_IOEVENTFD_FLAG_PIO       (1 << kvm_ioeventfd_flag_nr_pio)
+#define KVM_IOEVENTFD_FLAG_DEASSIGN  (1 << kvm_ioeventfd_flag_nr_deassign)
+
+#define KVM_IOEVENTFD_VALID_FLAG_MASK  ((1 << kvm_ioeventfd_flag_nr_max) - 1)
+
+struct kvm_ioeventfd {
+	__u64 datamatch;
+	__u64 addr;        /* legal pio/mmio address */
+	__u32 len;         /* 1, 2, 4, or 8 bytes    */
+	__s32 fd;
+	__u32 flags;
+	__u8  pad[36];
+};
+
+#define KVMIO 0xAE
+
+/*
+ * ioctls for /dev/kvm fds:
+ */
+#define KVM_GET_API_VERSION       _IO(KVMIO,   0x00)
+#define KVM_CREATE_VM             _IO(KVMIO,   0x01) /* returns a VM fd */
+#define KVM_GET_MSR_INDEX_LIST    _IOWR(KVMIO, 0x02, struct kvm_msr_list)
+
+#define KVM_S390_ENABLE_SIE       _IO(KVMIO,   0x06)
+/*
+ * Check if a kvm extension is available.  Argument is extension number,
+ * return is 1 (yes) or 0 (no, sorry).
+ */
+#define KVM_CHECK_EXTENSION       _IO(KVMIO,   0x03)
+/*
+ * Get size for mmap(vcpu_fd)
+ */
+#define KVM_GET_VCPU_MMAP_SIZE    _IO(KVMIO,   0x04) /* in bytes */
+#define KVM_GET_SUPPORTED_CPUID   _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
+#define KVM_TRACE_ENABLE          __KVM_DEPRECATED_MAIN_W_0x06
+#define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
+#define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
+
+/*
+ * Extension capability list.
+ */
+#define KVM_CAP_IRQCHIP	  0
+#define KVM_CAP_HLT	  1
+#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
+#define KVM_CAP_USER_MEMORY 3
+#define KVM_CAP_SET_TSS_ADDR 4
+#define KVM_CAP_VAPIC 6
+#define KVM_CAP_EXT_CPUID 7
+#define KVM_CAP_CLOCKSOURCE 8
+#define KVM_CAP_NR_VCPUS 9       /* returns max vcpus per vm */
+#define KVM_CAP_NR_MEMSLOTS 10   /* returns max memory slots per vm */
+#define KVM_CAP_PIT 11
+#define KVM_CAP_NOP_IO_DELAY 12
+#define KVM_CAP_PV_MMU 13
+#define KVM_CAP_MP_STATE 14
+#define KVM_CAP_COALESCED_MMIO 15
+#define KVM_CAP_SYNC_MMU 16  /* Changes to host mmap are reflected in guest */
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+#define KVM_CAP_DEVICE_ASSIGNMENT 17
+#endif
+#define KVM_CAP_IOMMU 18
+#ifdef __KVM_HAVE_MSI
+#define KVM_CAP_DEVICE_MSI 20
+#endif
+/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
+#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
+#ifdef __KVM_HAVE_USER_NMI
+#define KVM_CAP_USER_NMI 22
+#endif
+#ifdef __KVM_HAVE_GUEST_DEBUG
+#define KVM_CAP_SET_GUEST_DEBUG 23
+#endif
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_REINJECT_CONTROL 24
+#endif
+#ifdef __KVM_HAVE_IOAPIC
+#define KVM_CAP_IRQ_ROUTING 25
+#endif
+#define KVM_CAP_IRQ_INJECT_STATUS 26
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+#define KVM_CAP_DEVICE_DEASSIGNMENT 27
+#endif
+#ifdef __KVM_HAVE_MSIX
+#define KVM_CAP_DEVICE_MSIX 28
+#endif
+#define KVM_CAP_ASSIGN_DEV_IRQ 29
+/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
+#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
+#ifdef __KVM_HAVE_MCE
+#define KVM_CAP_MCE 31
+#endif
+#define KVM_CAP_IRQFD 32
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_PIT2 33
+#endif
+#define KVM_CAP_SET_BOOT_CPU_ID 34
+#ifdef __KVM_HAVE_PIT_STATE2
+#define KVM_CAP_PIT_STATE2 35
+#endif
+#define KVM_CAP_IOEVENTFD 36
+#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
+#ifdef __KVM_HAVE_XEN_HVM
+#define KVM_CAP_XEN_HVM 38
+#endif
+#define KVM_CAP_ADJUST_CLOCK 39
+#define KVM_CAP_INTERNAL_ERROR_DATA 40
+#ifdef __KVM_HAVE_VCPU_EVENTS
+#define KVM_CAP_VCPU_EVENTS 41
+#endif
+
+#ifdef KVM_CAP_IRQ_ROUTING
+
+struct kvm_irq_routing_irqchip {
+	__u32 irqchip;
+	__u32 pin;
+};
+
+struct kvm_irq_routing_msi {
+	__u32 address_lo;
+	__u32 address_hi;
+	__u32 data;
+	__u32 pad;
+};
+
+/* gsi routing entry types */
+#define KVM_IRQ_ROUTING_IRQCHIP 1
+#define KVM_IRQ_ROUTING_MSI 2
+
+struct kvm_irq_routing_entry {
+	__u32 gsi;
+	__u32 type;
+	__u32 flags;
+	__u32 pad;
+	union {
+		struct kvm_irq_routing_irqchip irqchip;
+		struct kvm_irq_routing_msi msi;
+		__u32 pad[8];
+	} u;
+};
+
+struct kvm_irq_routing {
+	__u32 nr;
+	__u32 flags;
+	struct kvm_irq_routing_entry entries[0];
+};
+
+#endif
+
+#ifdef KVM_CAP_MCE
+/* x86 MCE */
+struct kvm_x86_mce {
+	__u64 status;
+	__u64 addr;
+	__u64 misc;
+	__u64 mcg_status;
+	__u8 bank;
+	__u8 pad1[7];
+	__u64 pad2[3];
+};
+#endif
+
+#ifdef KVM_CAP_XEN_HVM
+struct kvm_xen_hvm_config {
+	__u32 flags;
+	__u32 msr;
+	__u64 blob_addr_32;
+	__u64 blob_addr_64;
+	__u8 blob_size_32;
+	__u8 blob_size_64;
+	__u8 pad2[30];
+};
+#endif
+
+#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
+
+struct kvm_irqfd {
+	__u32 fd;
+	__u32 gsi;
+	__u32 flags;
+	__u8  pad[20];
+};
+
+struct kvm_clock_data {
+	__u64 clock;
+	__u32 flags;
+	__u32 pad[9];
+};
+
+/*
+ * ioctls for VM fds
+ */
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO,  0x40, struct kvm_memory_region)
+/*
+ * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
+ * a vcpu fd.
+ */
+#define KVM_CREATE_VCPU           _IO(KVMIO,   0x41)
+#define KVM_GET_DIRTY_LOG         _IOW(KVMIO,  0x42, struct kvm_dirty_log)
+#define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO,  0x43, struct kvm_memory_alias)
+#define KVM_SET_NR_MMU_PAGES      _IO(KVMIO,   0x44)
+#define KVM_GET_NR_MMU_PAGES      _IO(KVMIO,   0x45)
+#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
+					struct kvm_userspace_memory_region)
+#define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
+#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+/* Device model IOC */
+#define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
+#define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
+#define KVM_GET_IRQCHIP           _IOWR(KVMIO, 0x62, struct kvm_irqchip)
+#define KVM_SET_IRQCHIP           _IOR(KVMIO,  0x63, struct kvm_irqchip)
+#define KVM_CREATE_PIT            _IO(KVMIO,   0x64)
+#define KVM_GET_PIT               _IOWR(KVMIO, 0x65, struct kvm_pit_state)
+#define KVM_SET_PIT               _IOR(KVMIO,  0x66, struct kvm_pit_state)
+#define KVM_IRQ_LINE_STATUS       _IOWR(KVMIO, 0x67, struct kvm_irq_level)
+#define KVM_REGISTER_COALESCED_MMIO \
+			_IOW(KVMIO,  0x67, struct kvm_coalesced_mmio_zone)
+#define KVM_UNREGISTER_COALESCED_MMIO \
+			_IOW(KVMIO,  0x68, struct kvm_coalesced_mmio_zone)
+#define KVM_ASSIGN_PCI_DEVICE     _IOR(KVMIO,  0x69, \
+				       struct kvm_assigned_pci_dev)
+#define KVM_SET_GSI_ROUTING       _IOW(KVMIO,  0x6a, struct kvm_irq_routing)
+/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
+#define KVM_ASSIGN_IRQ            __KVM_DEPRECATED_VM_R_0x70
+#define KVM_ASSIGN_DEV_IRQ        _IOW(KVMIO,  0x70, struct kvm_assigned_irq)
+#define KVM_REINJECT_CONTROL      _IO(KVMIO,   0x71)
+#define KVM_DEASSIGN_PCI_DEVICE   _IOW(KVMIO,  0x72, \
+				       struct kvm_assigned_pci_dev)
+#define KVM_ASSIGN_SET_MSIX_NR    _IOW(KVMIO,  0x73, \
+				       struct kvm_assigned_msix_nr)
+#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO,  0x74, \
+				       struct kvm_assigned_msix_entry)
+#define KVM_DEASSIGN_DEV_IRQ      _IOW(KVMIO,  0x75, struct kvm_assigned_irq)
+#define KVM_IRQFD                 _IOW(KVMIO,  0x76, struct kvm_irqfd)
+#define KVM_CREATE_PIT2		  _IOW(KVMIO,  0x77, struct kvm_pit_config)
+#define KVM_SET_BOOT_CPU_ID       _IO(KVMIO,   0x78)
+#define KVM_IOEVENTFD             _IOW(KVMIO,  0x79, struct kvm_ioeventfd)
+#define KVM_XEN_HVM_CONFIG        _IOW(KVMIO,  0x7a, struct kvm_xen_hvm_config)
+#define KVM_SET_CLOCK             _IOW(KVMIO,  0x7b, struct kvm_clock_data)
+#define KVM_GET_CLOCK             _IOR(KVMIO,  0x7c, struct kvm_clock_data)
+/* Available with KVM_CAP_PIT_STATE2 */
+#define KVM_GET_PIT2              _IOR(KVMIO,  0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2              _IOW(KVMIO,  0xa0, struct kvm_pit_state2)
+
+/*
+ * ioctls for vcpu fds
+ */
+#define KVM_RUN                   _IO(KVMIO,   0x80)
+#define KVM_GET_REGS              _IOR(KVMIO,  0x81, struct kvm_regs)
+#define KVM_SET_REGS              _IOW(KVMIO,  0x82, struct kvm_regs)
+#define KVM_GET_SREGS             _IOR(KVMIO,  0x83, struct kvm_sregs)
+#define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
+#define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
+#define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
+/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
+#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_VCPU_W_0x87
+#define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
+#define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
+#define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
+#define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)
+#define KVM_GET_FPU               _IOR(KVMIO,  0x8c, struct kvm_fpu)
+#define KVM_SET_FPU               _IOW(KVMIO,  0x8d, struct kvm_fpu)
+#define KVM_GET_LAPIC             _IOR(KVMIO,  0x8e, struct kvm_lapic_state)
+#define KVM_SET_LAPIC             _IOW(KVMIO,  0x8f, struct kvm_lapic_state)
+#define KVM_SET_CPUID2            _IOW(KVMIO,  0x90, struct kvm_cpuid2)
+#define KVM_GET_CPUID2            _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
+/* Available with KVM_CAP_VAPIC */
+#define KVM_TPR_ACCESS_REPORTING  _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
+/* Available with KVM_CAP_VAPIC */
+#define KVM_SET_VAPIC_ADDR        _IOW(KVMIO,  0x93, struct kvm_vapic_addr)
+/* valid for virtual machine (for floating interrupt)_and_ vcpu */
+#define KVM_S390_INTERRUPT        _IOW(KVMIO,  0x94, struct kvm_s390_interrupt)
+/* store status for s390 */
+#define KVM_S390_STORE_STATUS_NOADDR    (-1ul)
+#define KVM_S390_STORE_STATUS_PREFIXED  (-2ul)
+#define KVM_S390_STORE_STATUS	  _IOW(KVMIO,  0x95, unsigned long)
+/* initial ipl psw for s390 */
+#define KVM_S390_SET_INITIAL_PSW  _IOW(KVMIO,  0x96, struct kvm_s390_psw)
+/* initial reset for s390 */
+#define KVM_S390_INITIAL_RESET    _IO(KVMIO,   0x97)
+#define KVM_GET_MP_STATE          _IOR(KVMIO,  0x98, struct kvm_mp_state)
+#define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct kvm_mp_state)
+/* Available with KVM_CAP_NMI */
+#define KVM_NMI                   _IO(KVMIO,   0x9a)
+/* Available with KVM_CAP_SET_GUEST_DEBUG */
+#define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9b, struct kvm_guest_debug)
+/* MCE for x86 */
+#define KVM_X86_SETUP_MCE         _IOW(KVMIO,  0x9c, __u64)
+#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO,  0x9d, __u64)
+#define KVM_X86_SET_MCE           _IOW(KVMIO,  0x9e, struct kvm_x86_mce)
+/* IA64 stack access */
+#define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
+#define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
+/* Available with KVM_CAP_VCPU_EVENTS */
+#define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events)
+#define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events)
+
+#define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
+
+struct kvm_assigned_pci_dev {
+	__u32 assigned_dev_id;
+	__u32 busnr;
+	__u32 devfn;
+	__u32 flags;
+	union {
+		__u32 reserved[12];
+	};
+};
+
+#define KVM_DEV_IRQ_HOST_INTX    (1 << 0)
+#define KVM_DEV_IRQ_HOST_MSI     (1 << 1)
+#define KVM_DEV_IRQ_HOST_MSIX    (1 << 2)
+
+#define KVM_DEV_IRQ_GUEST_INTX   (1 << 8)
+#define KVM_DEV_IRQ_GUEST_MSI    (1 << 9)
+#define KVM_DEV_IRQ_GUEST_MSIX   (1 << 10)
+
+#define KVM_DEV_IRQ_HOST_MASK	 0x00ff
+#define KVM_DEV_IRQ_GUEST_MASK   0xff00
+
+struct kvm_assigned_irq {
+	__u32 assigned_dev_id;
+	__u32 host_irq;
+	__u32 guest_irq;
+	__u32 flags;
+	union {
+		struct {
+			__u32 addr_lo;
+			__u32 addr_hi;
+			__u32 data;
+		} guest_msi;
+		__u32 reserved[12];
+	};
+};
+
+
+struct kvm_assigned_msix_nr {
+	__u32 assigned_dev_id;
+	__u16 entry_nr;
+	__u16 padding;
+};
+
+#define KVM_MAX_MSIX_PER_DEV		256
+struct kvm_assigned_msix_entry {
+	__u32 assigned_dev_id;
+	__u32 gsi;
+	__u16 entry; /* The index of entry in the MSI-X table */
+	__u16 padding[3];
+};
+
+#endif /* __LINUX_KVM_H */
diff --git a/kvm/include/linux/kvm_para.h b/kvm/include/linux/kvm_para.h
new file mode 100644
index 0000000..d731092
--- /dev/null
+++ b/kvm/include/linux/kvm_para.h
@@ -0,0 +1,41 @@
+#ifndef __LINUX_KVM_PARA_H
+#define __LINUX_KVM_PARA_H
+
+/*
+ * This header file provides a method for making a hypercall to the host
+ * Architectures should define:
+ * - kvm_hypercall0, kvm_hypercall1...
+ * - kvm_arch_para_features
+ * - kvm_para_available
+ */
+
+/* Return values for hypercalls */
+#define KVM_ENOSYS		1000
+#define KVM_EFAULT		EFAULT
+#define KVM_E2BIG		E2BIG
+#define KVM_EPERM		EPERM
+
+#define KVM_HC_VAPIC_POLL_IRQ		1
+#define KVM_HC_MMU_OP			2
+
+/*
+ * hypercalls use architecture specific
+ */
+#include <asm/kvm_para.h>
+
+#ifdef __KERNEL__
+#ifdef CONFIG_KVM_GUEST
+void __init kvm_guest_init(void);
+#else
+#define kvm_guest_init() do { } while (0)
+#endif
+
+static inline int kvm_para_has_feature(unsigned int feature)
+{
+	if (kvm_arch_para_features() & (1UL << feature))
+		return 1;
+	return 0;
+}
+#endif /* __KERNEL__ */
+#endif /* __LINUX_KVM_PARA_H */
+
diff --git a/kvm/include/powerpc/asm/kvm.h b/kvm/include/powerpc/asm/kvm.h
new file mode 100644
index 0000000..bb2de6a
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm.h
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __LINUX_KVM_POWERPC_H
+#define __LINUX_KVM_POWERPC_H
+
+#include <linux/types.h>
+
+struct kvm_regs {
+	__u64 pc;
+	__u64 cr;
+	__u64 ctr;
+	__u64 lr;
+	__u64 xer;
+	__u64 msr;
+	__u64 srr0;
+	__u64 srr1;
+	__u64 pid;
+
+	__u64 sprg0;
+	__u64 sprg1;
+	__u64 sprg2;
+	__u64 sprg3;
+	__u64 sprg4;
+	__u64 sprg5;
+	__u64 sprg6;
+	__u64 sprg7;
+
+	__u64 gpr[32];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+	__u64 fpr[32];
+};
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/kvm/include/powerpc/asm/kvm_para.h b/kvm/include/powerpc/asm/kvm_para.h
new file mode 100644
index 0000000..2d48f6a
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_para.h
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PARA_H__
+#define __POWERPC_KVM_PARA_H__
+
+#ifdef __KERNEL__
+
+static inline int kvm_para_available(void)
+{
+	return 0;
+}
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+	return 0;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/kvm/include/x86/asm/kvm.h b/kvm/include/x86/asm/kvm.h
new file mode 100644
index 0000000..950df43
--- /dev/null
+++ b/kvm/include/x86/asm/kvm.h
@@ -0,0 +1,283 @@
+#ifndef _ASM_X86_KVM_H
+#define _ASM_X86_KVM_H
+
+/*
+ * KVM x86 specific structures and definitions
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Select x86 specific features in <linux/kvm.h> */
+#define __KVM_HAVE_PIT
+#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_DEVICE_ASSIGNMENT
+#define __KVM_HAVE_MSI
+#define __KVM_HAVE_USER_NMI
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_MSIX
+#define __KVM_HAVE_MCE
+#define __KVM_HAVE_PIT_STATE2
+#define __KVM_HAVE_XEN_HVM
+#define __KVM_HAVE_VCPU_EVENTS
+
+/* Architectural interrupt line count. */
+#define KVM_NR_INTERRUPTS 256
+
+struct kvm_memory_alias {
+	__u32 slot;  /* this has a different namespace than memory slots */
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size;
+	__u64 target_phys_addr;
+};
+
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
+struct kvm_pic_state {
+	__u8 last_irr;	/* edge detection */
+	__u8 irr;		/* interrupt request register */
+	__u8 imr;		/* interrupt mask register */
+	__u8 isr;		/* interrupt service register */
+	__u8 priority_add;	/* highest irq priority */
+	__u8 irq_base;
+	__u8 read_reg_select;
+	__u8 poll;
+	__u8 special_mask;
+	__u8 init_state;
+	__u8 auto_eoi;
+	__u8 rotate_on_auto_eoi;
+	__u8 special_fully_nested_mode;
+	__u8 init4;		/* true if 4 byte init */
+	__u8 elcr;		/* PIIX edge/trigger selection */
+	__u8 elcr_mask;
+};
+
+#define KVM_IOAPIC_NUM_PINS  24
+struct kvm_ioapic_state {
+	__u64 base_address;
+	__u32 ioregsel;
+	__u32 id;
+	__u32 irr;
+	__u32 pad;
+	union {
+		__u64 bits;
+		struct {
+			__u8 vector;
+			__u8 delivery_mode:3;
+			__u8 dest_mode:1;
+			__u8 delivery_status:1;
+			__u8 polarity:1;
+			__u8 remote_irr:1;
+			__u8 trig_mode:1;
+			__u8 mask:1;
+			__u8 reserve:7;
+			__u8 reserved[4];
+			__u8 dest_id;
+		} fields;
+	} redirtbl[KVM_IOAPIC_NUM_PINS];
+};
+
+#define KVM_IRQCHIP_PIC_MASTER   0
+#define KVM_IRQCHIP_PIC_SLAVE    1
+#define KVM_IRQCHIP_IOAPIC       2
+#define KVM_NR_IRQCHIPS          3
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+	/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+	__u64 rax, rbx, rcx, rdx;
+	__u64 rsi, rdi, rsp, rbp;
+	__u64 r8,  r9,  r10, r11;
+	__u64 r12, r13, r14, r15;
+	__u64 rip, rflags;
+};
+
+/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+	char regs[KVM_APIC_REG_SIZE];
+};
+
+struct kvm_segment {
+	__u64 base;
+	__u32 limit;
+	__u16 selector;
+	__u8  type;
+	__u8  present, dpl, db, s, l, g, avl;
+	__u8  unusable;
+	__u8  padding;
+};
+
+struct kvm_dtable {
+	__u64 base;
+	__u16 limit;
+	__u16 padding[3];
+};
+
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+	/* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
+	struct kvm_segment cs, ds, es, fs, gs, ss;
+	struct kvm_segment tr, ldt;
+	struct kvm_dtable gdt, idt;
+	__u64 cr0, cr2, cr3, cr4, cr8;
+	__u64 efer;
+	__u64 apic_base;
+	__u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
+};
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+	__u8  fpr[8][16];
+	__u16 fcw;
+	__u16 fsw;
+	__u8  ftwx;  /* in fxsave format */
+	__u8  pad1;
+	__u16 last_opcode;
+	__u64 last_ip;
+	__u64 last_dp;
+	__u8  xmm[16][16];
+	__u32 mxcsr;
+	__u32 pad2;
+};
+
+struct kvm_msr_entry {
+	__u32 index;
+	__u32 reserved;
+	__u64 data;
+};
+
+/* for KVM_GET_MSRS and KVM_SET_MSRS */
+struct kvm_msrs {
+	__u32 nmsrs; /* number of msrs in entries */
+	__u32 pad;
+
+	struct kvm_msr_entry entries[0];
+};
+
+/* for KVM_GET_MSR_INDEX_LIST */
+struct kvm_msr_list {
+	__u32 nmsrs; /* number of msrs in entries */
+	__u32 indices[0];
+};
+
+
+struct kvm_cpuid_entry {
+	__u32 function;
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+	__u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+	__u32 nent;
+	__u32 padding;
+	struct kvm_cpuid_entry entries[0];
+};
+
+struct kvm_cpuid_entry2 {
+	__u32 function;
+	__u32 index;
+	__u32 flags;
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+	__u32 padding[3];
+};
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
+#define KVM_CPUID_FLAG_STATEFUL_FUNC    2
+#define KVM_CPUID_FLAG_STATE_READ_NEXT  4
+
+/* for KVM_SET_CPUID2 */
+struct kvm_cpuid2 {
+	__u32 nent;
+	__u32 padding;
+	struct kvm_cpuid_entry2 entries[0];
+};
+
+/* for KVM_GET_PIT and KVM_SET_PIT */
+struct kvm_pit_channel_state {
+	__u32 count; /* can be 65536 */
+	__u16 latched_count;
+	__u8 count_latched;
+	__u8 status_latched;
+	__u8 status;
+	__u8 read_state;
+	__u8 write_state;
+	__u8 write_latch;
+	__u8 rw_mode;
+	__u8 mode;
+	__u8 bcd;
+	__u8 gate;
+	__s64 count_load_time;
+};
+
+struct kvm_debug_exit_arch {
+	__u32 exception;
+	__u32 pad;
+	__u64 pc;
+	__u64 dr6;
+	__u64 dr7;
+};
+
+#define KVM_GUESTDBG_USE_SW_BP		0x00010000
+#define KVM_GUESTDBG_USE_HW_BP		0x00020000
+#define KVM_GUESTDBG_INJECT_DB		0x00040000
+#define KVM_GUESTDBG_INJECT_BP		0x00080000
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+	__u64 debugreg[8];
+};
+
+struct kvm_pit_state {
+	struct kvm_pit_channel_state channels[3];
+};
+
+#define KVM_PIT_FLAGS_HPET_LEGACY  0x00000001
+
+struct kvm_pit_state2 {
+	struct kvm_pit_channel_state channels[3];
+	__u32 flags;
+	__u32 reserved[9];
+};
+
+struct kvm_reinject_control {
+	__u8 pit_reinject;
+	__u8 reserved[31];
+};
+
+/* for KVM_GET/SET_VCPU_EVENTS */
+struct kvm_vcpu_events {
+	struct {
+		__u8 injected;
+		__u8 nr;
+		__u8 has_error_code;
+		__u8 pad;
+		__u32 error_code;
+	} exception;
+	struct {
+		__u8 injected;
+		__u8 nr;
+		__u8 soft;
+		__u8 pad;
+	} interrupt;
+	struct {
+		__u8 injected;
+		__u8 pending;
+		__u8 masked;
+		__u8 pad;
+	} nmi;
+	__u32 sipi_vector;
+	__u32 flags;
+	__u32 reserved[10];
+};
+
+#endif /* _ASM_X86_KVM_H */
diff --git a/kvm/include/x86/asm/kvm_para.h b/kvm/include/x86/asm/kvm_para.h
new file mode 100644
index 0000000..c584076
--- /dev/null
+++ b/kvm/include/x86/asm/kvm_para.h
@@ -0,0 +1,149 @@
+#ifndef _ASM_X86_KVM_PARA_H
+#define _ASM_X86_KVM_PARA_H
+
+#include <linux/types.h>
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx.  It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE	0x40000000
+
+/* This CPUID returns a feature bitmap in eax.  Before enabling a particular
+ * paravirtualization, the appropriate feature bit should be checked.
+ */
+#define KVM_CPUID_FEATURES	0x40000001
+#define KVM_FEATURE_CLOCKSOURCE		0
+#define KVM_FEATURE_NOP_IO_DELAY	1
+#define KVM_FEATURE_MMU_OP		2
+
+#define MSR_KVM_WALL_CLOCK  0x11
+#define MSR_KVM_SYSTEM_TIME 0x12
+
+#define KVM_MAX_MMU_OP_BATCH           32
+
+/* Operations for KVM_HC_MMU_OP */
+#define KVM_MMU_OP_WRITE_PTE            1
+#define KVM_MMU_OP_FLUSH_TLB	        2
+#define KVM_MMU_OP_RELEASE_PT	        3
+
+/* Payload for KVM_HC_MMU_OP */
+struct kvm_mmu_op_header {
+	__u32 op;
+	__u32 pad;
+};
+
+struct kvm_mmu_op_write_pte {
+	struct kvm_mmu_op_header header;
+	__u64 pte_phys;
+	__u64 pte_val;
+};
+
+struct kvm_mmu_op_flush_tlb {
+	struct kvm_mmu_op_header header;
+};
+
+struct kvm_mmu_op_release_pt {
+	struct kvm_mmu_op_header header;
+	__u64 pt_phys;
+};
+
+#ifdef __KERNEL__
+#include <asm/processor.h>
+
+extern void kvmclock_init(void);
+
+
+/* This instruction is vmcall.  On non-VT architectures, it will generate a
+ * trap that we will then rewrite to the appropriate instruction.
+ */
+#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
+
+/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun
+ * instruction.  The hypervisor may replace it with something else but only the
+ * instructions are guaranteed to be supported.
+ *
+ * Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
+ * The hypercall number should be placed in rax and the return value will be
+ * placed in rax.  No other registers will be clobbered unless explicited
+ * noted by the particular hypercall.
+ */
+
+static inline long kvm_hypercall0(unsigned int nr)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL
+		     : "=a"(ret)
+		     : "a"(nr)
+		     : "memory");
+	return ret;
+}
+
+static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL
+		     : "=a"(ret)
+		     : "a"(nr), "b"(p1)
+		     : "memory");
+	return ret;
+}
+
+static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
+				  unsigned long p2)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL
+		     : "=a"(ret)
+		     : "a"(nr), "b"(p1), "c"(p2)
+		     : "memory");
+	return ret;
+}
+
+static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
+				  unsigned long p2, unsigned long p3)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL
+		     : "=a"(ret)
+		     : "a"(nr), "b"(p1), "c"(p2), "d"(p3)
+		     : "memory");
+	return ret;
+}
+
+static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
+				  unsigned long p2, unsigned long p3,
+				  unsigned long p4)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL
+		     : "=a"(ret)
+		     : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
+		     : "memory");
+	return ret;
+}
+
+static inline int kvm_para_available(void)
+{
+	unsigned int eax, ebx, ecx, edx;
+	char signature[13];
+
+	cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
+	memcpy(signature + 0, &ebx, 4);
+	memcpy(signature + 4, &ecx, 4);
+	memcpy(signature + 8, &edx, 4);
+	signature[12] = 0;
+
+	if (strcmp(signature, "KVMKVMKVM") == 0)
+		return 1;
+
+	return 0;
+}
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+	return cpuid_eax(KVM_CPUID_FEATURES);
+}
+
+#endif
+
+#endif /* _ASM_X86_KVM_PARA_H */
diff --git a/kvm/kvm.spec b/kvm/kvm.spec
new file mode 100644
index 0000000..92acb0e
--- /dev/null
+++ b/kvm/kvm.spec
@@ -0,0 +1,139 @@
+Name:           kvm
+Version:        0.0
+Release:        0
+Summary:        Kernel Virtual Machine virtualization environment
+
+Group:          System Environment/Kernel
+License:        GPL
+URL:            http://www.qumranet.com
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}
+
+ExclusiveArch:  i386 x86_64 ia64
+
+Requires:	kvm-kmod bridge-utils
+
+%define Distribution %(rpm -q -qf /etc/redhat-release --qf '%%{name}' | cut -d"-"  -f 1)
+%define os_version %(rpm -q --qf '%%{version}' %{Distribution}-release)
+%define os_release %(rpm -q --qf '%%{release}' %{Distribution}-release | cut -d"." -f 1)
+
+%if %([ x"%{Distribution}" = x"fedora" -a x"%{os_version}" = x"5" ] && echo 1 || echo 0)
+%define require_gccver 32
+%endif
+
+%if %([ x"%{Distribution}" = x"fedora" -a 0"%{os_version}" -ge "8" ] && echo 1 || echo 0)
+%define qemuldflags --qemu-ldflags=-Wl,--build-id
+%else
+%define qemuldflags ""
+%endif
+
+%if %([ x"%{Distribution}" = x"centos" -a x"%{os_version}" = x"4" ] && echo 1 || echo 0)
+%define require_gccver 32
+%endif
+
+%if %([ x"%{Distribution}" = x"redhat" -a x"%{os_release}" = x"5" ] && echo 1 || echo 0)
+%define require_gccver 34
+%endif
+
+%if %( [ x"%{require_gccver}" = x"32" ] && echo 1 || echo 0)
+BuildRequires: compat-gcc-32
+%else
+BuildRequires: compat-gcc-34
+%endif
+
+BuildRequires:  SDL-devel zlib-devel alsa-lib-devel
+
+%define _prebuilt %{?prebuilt:1}%{!?prebuilt:0}
+
+%if !%{_prebuilt}
+Source0: kvm.tar.gz
+Source1: user.tar.gz
+Source2: kernel.tar.gz
+Source3: scripts.tar.gz
+Source4: Makefile
+Source5: configure
+Source6: kvm_stat
+Source7: libkvm.tar.gz
+Source8: extboot.tar.gz
+%endif
+
+%description
+The Kernel Virtual Machine provides a virtualization enviroment for processors
+with hardware support for virtualization: Intel's VT-x&VT-i and AMD's AMD-V.
+
+%prep
+
+%if !%{_prebuilt}
+%setup -T -b 0 -n qemu
+%setup -T -b 1 -n user -D
+%setup -T -b 2 -n kernel -D
+%setup -T -b 7 -n libkvm -D
+%setup -T -b 3 -n scripts -D
+%setup -T -b 8 -n extboot -D
+cd ..
+cp %{_sourcedir}/Makefile %{_sourcedir}/configure %{_sourcedir}/kvm_stat .
+%endif
+
+%build
+
+rm -rf %{buildroot}
+
+%if !%{_prebuilt}
+cd ..
+./configure --prefix=/usr/kvm %{qemuldflags}
+make -C libkvm
+make -C user
+%ifarch i386 x86_64
+make extboot
+%endif
+#(cd qemu;
+#    ./co
+#   kpath="$(readlink -f ../kernel/include)"
+#   upath="$(readlink -f ../user)"
+#   ./configure --target-list=$(uname -i)-softmmu \
+#	    --extra-cflags="-I$kpath -I$upath" \
+#	    --extra-ldflags="-L$upath" \
+#	    --disable-kqemu --enable-kvm --prefix=/usr/kvm
+#)
+make -C qemu
+%endif
+
+%install
+
+%if !%{_prebuilt}
+cd ..
+%else
+cd %{objdir}
+%endif
+
+make DESTDIR=%{buildroot} install-rpm
+
+%define bindir /usr/bin
+%define bin %{bindir}/kvm
+%define initdir /etc/init.d
+%define confdir /etc/kvm
+%define utilsdir /etc/kvm/utils
+
+%post 
+/sbin/chkconfig --add kvm
+/sbin/chkconfig --level 2345 kvm on
+/sbin/chkconfig --level 16 kvm off
+/usr/sbin/groupadd -fg 444 kvm
+
+%preun
+if [ "$1" != 0 ]; then
+	/sbin/service kvm stop
+	/sbin/chkconfig --level 2345 kvm off
+	/sbin/chkconfig --del kvm
+fi
+
+%clean
+%{__rm} -rf %{buildroot}
+
+%files
+/usr/bin/kvm
+/usr/bin/kvm_stat
+%{confdir}/qemu-ifup
+%{initdir}/kvm  
+/etc/udev/rules.d/*kvm*.rules
+/usr/kvm
+%changelog
diff --git a/kvm/kvm_stat b/kvm/kvm_stat
new file mode 100755
index 0000000..21aff5b
--- /dev/null
+++ b/kvm/kvm_stat
@@ -0,0 +1,129 @@
+#!/usr/bin/python
+
+import curses
+import sys, os, time, optparse
+
+class Stats:
+    def __init__(self, fields = None):
+        def wanted(key):
+            import re
+            if not fields:
+                return True
+            return re.match(fields, key) != None
+        self.base = '/sys/kernel/debug/kvm'
+        self.values = {}
+        for key in os.listdir(self.base):
+            if wanted(key):
+                self.values[key] = None
+    def get(self):
+        for key, oldval in self.values.iteritems():
+            newval = int(file(self.base + '/' + key).read())
+            newdelta = None
+            if oldval is not None:
+                newdelta = newval - oldval[0]
+            self.values[key] = (newval, newdelta)
+        return self.values
+
+if not os.access('/sys/kernel/debug', os.F_OK):
+    print 'Please enable CONFIG_DEBUG_FS in your kernel'
+    sys.exit(1)
+if not os.access('/sys/kernel/debug/kvm', os.F_OK):
+    print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
+    print "and ensure the kvm modules are loaded"
+    sys.exit(1)
+
+label_width = 20
+number_width = 10
+
+def tui(screen, stats):
+    curses.use_default_colors()
+    curses.noecho()
+    def refresh():
+        screen.erase()
+        screen.addstr(0, 0, 'kvm statistics')
+        row = 2
+        s = stats.get()
+        for key in sorted(s.keys()):
+            if row >= screen.getmaxyx()[0]:
+                break
+            values = s[key]
+            col = 1
+            screen.addstr(row, col, key)
+            col += label_width
+            screen.addstr(row, col, '%10d' % (values[0],))
+            col += number_width
+            if values[1] is not None:
+                screen.addstr(row, col, '%8d' % (values[1],))
+            row += 1
+        screen.refresh()
+
+    while True:
+        refresh()
+        curses.halfdelay(10)
+        try:
+            c = screen.getkey()
+            if c == 'q':
+                break
+        except KeyboardInterrupt:
+            break
+        except curses.error:
+            continue
+
+def batch(stats):
+    s = stats.get()
+    time.sleep(1)
+    s = stats.get()
+    for key in sorted(s.keys()):
+        values = s[key]
+        print '%-22s%10d%10d' % (key, values[0], values[1])
+
+def log(stats):
+    keys = sorted(stats.get().iterkeys())
+    def banner():
+        for k in keys:
+            print '%10s' % k[0:9],
+        print
+    def statline():
+        s = stats.get()
+        for k in keys:
+            print ' %9d' % s[k][1],
+        print
+    line = 0
+    banner_repeat = 20
+    while True:
+        time.sleep(1)
+        if line % banner_repeat == 0:
+            banner()
+        statline()
+        line += 1
+
+options = optparse.OptionParser()
+options.add_option('-1', '--once', '--batch',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'once',
+                   help = 'run in batch mode for one second',
+                   )
+options.add_option('-l', '--log',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'log',
+                   help = 'run in logging mode (like vmstat)',
+                   )
+options.add_option('-f', '--fields',
+                   action = 'store',
+                   default = None,
+                   dest = 'fields',
+                   help = 'fields to display (regex)',
+                   )
+(options, args) = options.parse_args(sys.argv)
+
+stats = Stats(fields = options.fields)
+
+if options.log:
+    log(stats)
+elif not options.once:
+    import curses.wrapper
+    curses.wrapper(tui, stats)
+else:
+    batch(stats)
diff --git a/kvm/libfdt/Makefile b/kvm/libfdt/Makefile
new file mode 100644
index 0000000..db80e47
--- /dev/null
+++ b/kvm/libfdt/Makefile
@@ -0,0 +1,19 @@
+include ../config.mak
+include ../user/config.mak
+
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
+LIBFDT_INCLUDES = fdt.h libfdt.h
+LIBFDT_EXTRA = libfdt_internal.h
+LIBFDT_LIB = libfdt.a
+
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+
+CFLAGS += -I .
+
+$(LIBFDT_LIB): $(LIBFDT_OBJS)
+	$(AR) rcs $@ $^
+
+all: $(LIBFDT_LIB)
+
+clean:
+	rm -rf *.o *.a
diff --git a/kvm/libfdt/README b/kvm/libfdt/README
new file mode 100644
index 0000000..491bc76
--- /dev/null
+++ b/kvm/libfdt/README
@@ -0,0 +1,3 @@
+libfdt was grabbed from dtc source. This is the upstream source for libfdt.
+It can be found here:
+http://www.jdl.com/software/
diff --git a/kvm/libfdt/fdt.c b/kvm/libfdt/fdt.c
new file mode 100644
index 0000000..bd91712
--- /dev/null
+++ b/kvm/libfdt/fdt.c
@@ -0,0 +1,194 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		/* Complete tree */
+		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+	} else if (fdt_magic(fdt) == SW_MAGIC) {
+		/* Unfinished sequential-write blob */
+		if (fdt_size_dt_struct(fdt) == 0)
+			return -FDT_ERR_BADSTATE;
+	} else {
+		return -FDT_ERR_BADMAGIC;
+	}
+
+	return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int len)
+{
+	const void *p;
+
+	if (fdt_version(fdt) >= 0x11)
+		if (((offset + len) < offset)
+		    || ((offset + len) > fdt_size_dt_struct(fdt)))
+			return NULL;
+
+	p = _fdt_offset_ptr(fdt, offset);
+
+	if (p + len < p)
+		return NULL;
+	return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
+{
+	const uint32_t *tagp, *lenp;
+	uint32_t tag;
+	const char *p;
+
+	if (offset % FDT_TAGSIZE)
+		return -1;
+
+	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+	if (! tagp)
+		return FDT_END; /* premature end */
+	tag = fdt32_to_cpu(*tagp);
+	offset += FDT_TAGSIZE;
+
+	switch (tag) {
+	case FDT_BEGIN_NODE:
+		/* skip name */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (! p)
+			return FDT_END;
+		break;
+	case FDT_PROP:
+		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+		if (! lenp)
+			return FDT_END;
+		/* skip name offset, length and value */
+		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
+		break;
+	}
+
+	if (nextoffset)
+		*nextoffset = ALIGN(offset, FDT_TAGSIZE);
+
+	return tag;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+	int nextoffset = 0;
+	uint32_t tag;
+
+	if (offset >= 0) {
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		if (tag != FDT_BEGIN_NODE)
+			return -FDT_ERR_BADOFFSET;
+	}
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		case FDT_BEGIN_NODE:
+			if (depth)
+				(*depth)++;
+			break;
+
+		case FDT_END_NODE:
+			if (depth)
+				(*depth)--;
+			break;
+
+		case FDT_END:
+			return -FDT_ERR_NOTFOUND;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (tag != FDT_BEGIN_NODE);
+
+	return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+	int len = strlen(s) + 1;
+	const char *last = strtab + tabsize - len;
+	const char *p;
+
+	for (p = strtab; p <= last; p++)
+		if (memeq(p, s, len))
+			return p;
+	return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+	CHECK_HEADER(fdt);
+
+	if (fdt_totalsize(fdt) > bufsize)
+		return -FDT_ERR_NOSPACE;
+
+	memmove(buf, fdt, fdt_totalsize(fdt));
+	return 0;
+}
diff --git a/kvm/libfdt/fdt.h b/kvm/libfdt/fdt.h
new file mode 100644
index 0000000..48ccfd9
--- /dev/null
+++ b/kvm/libfdt/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+	uint32_t magic;			 /* magic word FDT_MAGIC */
+	uint32_t totalsize;		 /* total size of DT block */
+	uint32_t off_dt_struct;		 /* offset to structure */
+	uint32_t off_dt_strings;	 /* offset to strings */
+	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */
+	uint32_t version;		 /* format version */
+	uint32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	uint32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	uint32_t size_dt_struct;	 /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+	uint64_t address;
+	uint64_t size;
+};
+
+struct fdt_node_header {
+	uint32_t tag;
+	char name[0];
+};
+
+struct fdt_property {
+	uint32_t tag;
+	uint32_t len;
+	uint32_t nameoff;
+	char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE	0x1		/* Start node: full name */
+#define FDT_END_NODE	0x2		/* End node */
+#define FDT_PROP	0x3		/* Property: name off,
+					   size, content */
+#define FDT_NOP		0x4		/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(uint32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/kvm/libfdt/fdt_ro.c b/kvm/libfdt/fdt_ro.c
new file mode 100644
index 0000000..63fa129
--- /dev/null
+++ b/kvm/libfdt/fdt_ro.c
@@ -0,0 +1,476 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int nodename_eq(const void *fdt, int offset,
+		       const char *s, int len)
+{
+	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+	if (! p)
+		/* short match */
+		return 0;
+
+	if (memcmp(p, s, len) != 0)
+		return 0;
+
+	if (p[len] == '\0')
+		return 1;
+	else if (!memchr(s, '@', len) && (p[len] == '@'))
+		return 1;
+	else
+		return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+	return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+	CHECK_HEADER(fdt);
+	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+	return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+	int i = 0;
+
+	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+		i++;
+	return i;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+			       const char *name, int namelen)
+{
+	int depth;
+
+	CHECK_HEADER(fdt);
+
+	for (depth = 0;
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth < 0)
+			return -FDT_ERR_NOTFOUND;
+		else if ((depth == 1)
+			 && nodename_eq(fdt, offset, name, namelen))
+			return offset;
+	}
+
+	return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+		       const char *name)
+{
+	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+	const char *end = path + strlen(path);
+	const char *p = path;
+	int offset = 0;
+
+	CHECK_HEADER(fdt);
+
+	if (*path != '/')
+		return -FDT_ERR_BADPATH;
+
+	while (*p) {
+		const char *q;
+
+		while (*p == '/')
+			p++;
+		if (! *p)
+			return offset;
+		q = strchr(p, '/');
+		if (! q)
+			q = end;
+
+		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+		if (offset < 0)
+			return offset;
+
+		p = q;
+	}
+
+	return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+	const struct fdt_node_header *nh;
+	int err;
+
+	if ((err = fdt_check_header(fdt)) != 0)
+		goto fail;
+
+	err = -FDT_ERR_BADOFFSET;
+	nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
+	if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
+		goto fail;
+
+	if (len)
+		*len = strlen(nh->name);
+
+	return nh->name;
+
+ fail:
+	if (len)
+		*len = err;
+	return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+					    int nodeoffset,
+					    const char *name, int *lenp)
+{
+	uint32_t tag;
+	const struct fdt_property *prop;
+	int namestroff;
+	int offset, nextoffset;
+	int err;
+
+	if ((err = fdt_check_header(fdt)) != 0)
+		goto fail;
+
+	err = -FDT_ERR_BADOFFSET;
+	if (nodeoffset % FDT_TAGSIZE)
+		goto fail;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		goto fail;
+
+	do {
+		offset = nextoffset;
+
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		switch (tag) {
+		case FDT_END:
+			err = -FDT_ERR_TRUNCATED;
+			goto fail;
+
+		case FDT_BEGIN_NODE:
+		case FDT_END_NODE:
+		case FDT_NOP:
+			break;
+
+		case FDT_PROP:
+			err = -FDT_ERR_BADSTRUCTURE;
+			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
+			if (! prop)
+				goto fail;
+			namestroff = fdt32_to_cpu(prop->nameoff);
+			if (streq(fdt_string(fdt, namestroff), name)) {
+				/* Found it! */
+				int len = fdt32_to_cpu(prop->len);
+				prop = fdt_offset_ptr(fdt, offset,
+						      sizeof(*prop)+len);
+				if (! prop)
+					goto fail;
+
+				if (lenp)
+					*lenp = len;
+
+				return prop;
+			}
+			break;
+
+		default:
+			err = -FDT_ERR_BADSTRUCTURE;
+			goto fail;
+		}
+	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+
+	err = -FDT_ERR_NOTFOUND;
+ fail:
+	if (lenp)
+		*lenp = err;
+	return NULL;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+		  const char *name, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property(fdt, nodeoffset, name, lenp);
+	if (! prop)
+		return NULL;
+
+	return prop->data;
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+	const uint32_t *php;
+	int len;
+
+	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+	if (!php || (len != sizeof(*php)))
+		return 0;
+
+	return fdt32_to_cpu(*php);
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+	int pdepth = 0, p = 0;
+	int offset, depth, namelen;
+	const char *name;
+
+	CHECK_HEADER(fdt);
+
+	if (buflen < 2)
+		return -FDT_ERR_NOSPACE;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (pdepth < depth)
+			continue; /* overflowed buffer */
+
+		while (pdepth > depth) {
+			do {
+				p--;
+			} while (buf[p-1] != '/');
+			pdepth--;
+		}
+
+		name = fdt_get_name(fdt, offset, &namelen);
+		if (!name)
+			return namelen;
+		if ((p + namelen + 1) <= buflen) {
+			memcpy(buf + p, name, namelen);
+			p += namelen;
+			buf[p++] = '/';
+			pdepth++;
+		}
+
+		if (offset == nodeoffset) {
+			if (pdepth < (depth + 1))
+				return -FDT_ERR_NOSPACE;
+
+			if (p > 1) /* special case so that root path is "/", not "" */
+				p--;
+			buf[p] = '\0';
+			return p;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth)
+{
+	int offset, depth;
+	int supernodeoffset = -FDT_ERR_INTERNAL;
+
+	CHECK_HEADER(fdt);
+
+	if (supernodedepth < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth == supernodedepth)
+			supernodeoffset = offset;
+
+		if (offset == nodeoffset) {
+			if (nodedepth)
+				*nodedepth = depth;
+
+			if (supernodedepth > depth)
+				return -FDT_ERR_NOTFOUND;
+			else
+				return supernodeoffset;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+	int nodedepth;
+	int err;
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+	if (err)
+		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+	return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+	int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+	if (nodedepth < 0)
+		return nodedepth;
+	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+					    nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen)
+{
+	int offset;
+	const void *val;
+	int len;
+
+	CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_getprop(), then if that didn't
+	 * find what we want, we scan over them again making our way
+	 * to the next node.  Still it's the easiest to implement
+	 * approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		val = fdt_getprop(fdt, offset, propname, &len);
+		if (val && (len == proplen)
+		    && (memcmp(val, propval, len) == 0))
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+	if ((phandle == 0) || (phandle == -1))
+		return -FDT_ERR_BADPHANDLE;
+	phandle = cpu_to_fdt32(phandle);
+	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
+					     &phandle, sizeof(phandle));
+}
+
+int _stringlist_contains(const void *strlist, int listlen, const char *str)
+{
+	int len = strlen(str);
+	const void *p;
+
+	while (listlen >= len) {
+		if (memcmp(str, strlist, len+1) == 0)
+			return 1;
+		p = memchr(strlist, '\0', listlen);
+		if (!p)
+			return 0; /* malformed strlist.. */
+		listlen -= (p-strlist) + 1;
+		strlist = p + 1;
+	}
+	return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible)
+{
+	const void *prop;
+	int len;
+
+	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+	if (!prop)
+		return len;
+	if (_stringlist_contains(prop, len, compatible))
+		return 0;
+	else
+		return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible)
+{
+	int offset, err;
+
+	CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_node_check_compatible(), then if
+	 * that didn't find what we want, we scan over them again
+	 * making our way to the next node.  Still it's the easiest to
+	 * implement approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		err = fdt_node_check_compatible(fdt, offset, compatible);
+		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+			return err;
+		else if (err == 0)
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
diff --git a/kvm/libfdt/fdt_rw.c b/kvm/libfdt/fdt_rw.c
new file mode 100644
index 0000000..0df472b
--- /dev/null
+++ b/kvm/libfdt/fdt_rw.c
@@ -0,0 +1,467 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _blocks_misordered(const void *fdt,
+			      int mem_rsv_size, int struct_size)
+{
+	return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
+		|| (fdt_off_dt_struct(fdt) <
+		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+		|| (fdt_off_dt_strings(fdt) <
+		    (fdt_off_dt_struct(fdt) + struct_size))
+		|| (fdt_totalsize(fdt) <
+		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int rw_check_header(void *fdt)
+{
+	CHECK_HEADER(fdt);
+
+	if (fdt_version(fdt) < 17)
+		return -FDT_ERR_BADVERSION;
+	if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+			       fdt_size_dt_struct(fdt)))
+		return -FDT_ERR_BADLAYOUT;
+	if (fdt_version(fdt) > 17)
+		fdt_set_version(fdt, 17);
+
+	return 0;
+}
+
+#define RW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = rw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static inline int _blob_data_size(void *fdt)
+{
+	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
+{
+	void *end = fdt + _blob_data_size(fdt);
+
+	if (((p + oldlen) < p) || ((p + oldlen) > end))
+		return -FDT_ERR_BADOFFSET;
+	if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
+		return -FDT_ERR_NOSPACE;
+	memmove(p + newlen, p + oldlen, end - p - oldlen);
+	return 0;
+}
+
+static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+				int oldn, int newn)
+{
+	int delta = (newn - oldn) * sizeof(*p);
+	int err;
+	err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+	if (err)
+		return err;
+	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _blob_splice_struct(void *fdt, void *p,
+			       int oldlen, int newlen)
+{
+	int delta = newlen - oldlen;
+	int err;
+
+	if ((err = _blob_splice(fdt, p, oldlen, newlen)))
+		return err;
+
+	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _blob_splice_string(void *fdt, int newlen)
+{
+	void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+	int err;
+
+	if ((err = _blob_splice(fdt, p, 0, newlen)))
+		return err;
+
+	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+	return 0;
+}
+
+static int _find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+	const char *p;
+	char *new;
+	int len = strlen(s) + 1;
+	int err;
+
+	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+	if (p)
+		/* found it */
+		return (p - strtab);
+
+	new = strtab + fdt_size_dt_strings(fdt);
+	err = _blob_splice_string(fdt, len);
+	if (err)
+		return err;
+
+	memcpy(new, s, len);
+	return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+	err = _blob_splice_mem_rsv(fdt, re, 0, 1);
+	if (err)
+		return err;
+
+	re->address = cpu_to_fdt64(address);
+	re->size = cpu_to_fdt64(size);
+	return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+	if (n >= fdt_num_mem_rsv(fdt))
+		return -FDT_ERR_NOTFOUND;
+
+	err = _blob_splice_mem_rsv(fdt, re, 1, 0);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
+			    struct fdt_property **prop)
+{
+	int oldlen;
+	int err;
+
+	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (! (*prop))
+		return oldlen;
+
+	if ((err = _blob_splice_struct(fdt, (*prop)->data,
+				       ALIGN(oldlen, FDT_TAGSIZE),
+				       ALIGN(len, FDT_TAGSIZE))))
+		return err;
+
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
+			 struct fdt_property **prop)
+{
+	uint32_t tag;
+	int proplen;
+	int nextoffset;
+	int namestroff;
+	int err;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADOFFSET;
+
+	namestroff = _find_add_string(fdt, name);
+	if (namestroff < 0)
+		return namestroff;
+
+	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
+	proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
+
+	err = _blob_splice_struct(fdt, *prop, 0, proplen);
+	if (err)
+		return err;
+
+	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
+	(*prop)->nameoff = cpu_to_fdt32(namestroff);
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE),
+				  ALIGN(newlen+1, FDT_TAGSIZE));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	err = _resize_property(fdt, nodeoffset, name, len, &prop);
+	if (err == -FDT_ERR_NOTFOUND)
+		err = _add_property(fdt, nodeoffset, name, len, &prop);
+	if (err)
+		return err;
+
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len, proplen;
+
+	RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
+	return _blob_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen)
+{
+	struct fdt_node_header *nh;
+	int offset, nextoffset;
+	int nodelen;
+	int err;
+	uint32_t tag;
+	uint32_t *endtag;
+
+	RW_CHECK_HEADER(fdt);
+
+	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+	if (offset >= 0)
+		return -FDT_ERR_EXISTS;
+	else if (offset != -FDT_ERR_NOTFOUND)
+		return offset;
+
+	/* Try to place the new node after the parent's properties */
+	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+	nh = _fdt_offset_ptr_w(fdt, offset);
+	nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
+
+	err = _blob_splice_struct(fdt, nh, 0, nodelen);
+	if (err)
+		return err;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
+	memcpy(nh->name, name, namelen);
+	endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
+	*endtag = cpu_to_fdt32(FDT_END_NODE);
+
+	return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	RW_CHECK_HEADER(fdt);
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+				   endoffset - nodeoffset, 0);
+}
+
+static void _packblocks(const void *fdt, void *buf,
+		       int mem_rsv_size, int struct_size)
+{
+	int mem_rsv_off, struct_off, strings_off;
+
+	mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
+	struct_off = mem_rsv_off + mem_rsv_size;
+	strings_off = struct_off + struct_size;
+
+	memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
+	fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
+
+	memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
+	fdt_set_off_dt_struct(buf, struct_off);
+	fdt_set_size_dt_struct(buf, struct_size);
+
+	memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
+		fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(buf, strings_off);
+	fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+	int err;
+	int mem_rsv_size, struct_size;
+	int newsize;
+	void *tmp;
+
+	CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+
+	if (fdt_version(fdt) >= 17) {
+		struct_size = fdt_size_dt_struct(fdt);
+	} else {
+		struct_size = 0;
+		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+			;
+	}
+
+	if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+		/* no further work necessary */
+		err = fdt_move(fdt, buf, bufsize);
+		if (err)
+			return err;
+		fdt_set_version(buf, 17);
+		fdt_set_size_dt_struct(buf, struct_size);
+		fdt_set_totalsize(buf, bufsize);
+		return 0;
+	}
+
+	/* Need to reorder */
+	newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+		+ struct_size + fdt_size_dt_strings(fdt);
+
+	if (bufsize < newsize)
+		return -FDT_ERR_NOSPACE;
+
+	if (((buf + newsize) <= fdt)
+	    || (buf >= (fdt + fdt_totalsize(fdt)))) {
+		tmp = buf;
+	} else {
+		tmp = (void *)fdt + fdt_totalsize(fdt);
+		if ((tmp + newsize) > (buf + bufsize))
+			return -FDT_ERR_NOSPACE;
+	}
+
+	_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+	memmove(buf, tmp, newsize);
+
+	fdt_set_magic(buf, FDT_MAGIC);
+	fdt_set_totalsize(buf, bufsize);
+	fdt_set_version(buf, 17);
+	fdt_set_last_comp_version(buf, 16);
+	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+	return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+	int mem_rsv_size;
+	int err;
+
+	err = rw_check_header(fdt);
+	if (err)
+		return err;
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+	_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+	fdt_set_totalsize(fdt, _blob_data_size(fdt));
+
+	return 0;
+}
diff --git a/kvm/libfdt/fdt_strerror.c b/kvm/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..f9d32ef
--- /dev/null
+++ b/kvm/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct errtabent {
+	const char *str;
+};
+
+#define ERRTABENT(val) \
+	[(val)] = { .str = #val, }
+
+static struct errtabent errtable[] = {
+	ERRTABENT(FDT_ERR_NOTFOUND),
+	ERRTABENT(FDT_ERR_EXISTS),
+	ERRTABENT(FDT_ERR_NOSPACE),
+
+	ERRTABENT(FDT_ERR_BADOFFSET),
+	ERRTABENT(FDT_ERR_BADPATH),
+	ERRTABENT(FDT_ERR_BADSTATE),
+
+	ERRTABENT(FDT_ERR_TRUNCATED),
+	ERRTABENT(FDT_ERR_BADMAGIC),
+	ERRTABENT(FDT_ERR_BADVERSION),
+	ERRTABENT(FDT_ERR_BADSTRUCTURE),
+	ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define ERRTABSIZE	(sizeof(errtable) / sizeof(errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+	if (errval > 0)
+		return "<valid offset/length>";
+	else if (errval == 0)
+		return "<no error>";
+	else if (errval > -ERRTABSIZE) {
+		const char *s = errtable[-errval].str;
+
+		if (s)
+			return s;
+	}
+
+	return "<unknown error>";
+}
diff --git a/kvm/libfdt/fdt_sw.c b/kvm/libfdt/fdt_sw.c
new file mode 100644
index 0000000..dda2de3
--- /dev/null
+++ b/kvm/libfdt/fdt_sw.c
@@ -0,0 +1,258 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int check_header_sw(void *fdt)
+{
+	if (fdt_magic(fdt) != SW_MAGIC)
+		return -FDT_ERR_BADMAGIC;
+	return 0;
+}
+
+static void *grab_space(void *fdt, int len)
+{
+	int offset = fdt_size_dt_struct(fdt);
+	int spaceleft;
+
+	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+		- fdt_size_dt_strings(fdt);
+
+	if ((offset + len < offset) || (offset + len > spaceleft))
+		return NULL;
+
+	fdt_set_size_dt_struct(fdt, offset + len);
+	return fdt_offset_ptr_w(fdt, offset, len);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+	void *fdt = buf;
+
+	if (bufsize < sizeof(struct fdt_header))
+		return -FDT_ERR_NOSPACE;
+
+	memset(buf, 0, bufsize);
+
+	fdt_set_magic(fdt, SW_MAGIC);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+	fdt_set_totalsize(fdt,  bufsize);
+
+	fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
+					  sizeof(struct fdt_reserve_entry)));
+	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+	fdt_set_off_dt_strings(fdt, bufsize);
+
+	return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err = check_header_sw(fdt);
+	int offset;
+
+	if (err)
+		return err;
+	if (fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADSTATE;
+
+	offset = fdt_off_dt_struct(fdt);
+	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+		return -FDT_ERR_NOSPACE;
+
+	re = (struct fdt_reserve_entry *)(fdt + offset);
+	re->address = cpu_to_fdt64(addr);
+	re->size = cpu_to_fdt64(size);
+
+	fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+	return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+	return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+	struct fdt_node_header *nh;
+	int err = check_header_sw(fdt);
+	int namelen = strlen(name) + 1;
+
+	if (err)
+		return err;
+
+	nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
+	if (! nh)
+		return -FDT_ERR_NOSPACE;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memcpy(nh->name, name, namelen);
+	return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+	uint32_t *en;
+	int err = check_header_sw(fdt);
+
+	if (err)
+		return err;
+
+	en = grab_space(fdt, FDT_TAGSIZE);
+	if (! en)
+		return -FDT_ERR_NOSPACE;
+
+	*en = cpu_to_fdt32(FDT_END_NODE);
+	return 0;
+}
+
+static int find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_totalsize(fdt);
+	const char *p;
+	int strtabsize = fdt_size_dt_strings(fdt);
+	int len = strlen(s) + 1;
+	int struct_top, offset;
+
+	p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+	if (p)
+		return p - strtab;
+
+	/* Add it */
+	offset = -strtabsize - len;
+	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	if (fdt_totalsize(fdt) + offset < struct_top)
+		return 0; /* no more room :( */
+
+	memcpy(strtab + offset, s, len);
+	fdt_set_size_dt_strings(fdt, strtabsize + len);
+	return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err = check_header_sw(fdt);
+	int nameoff;
+
+	if (err)
+		return err;
+
+	nameoff = find_add_string(fdt, name);
+	if (nameoff == 0)
+		return -FDT_ERR_NOSPACE;
+
+	prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
+	if (! prop)
+		return -FDT_ERR_NOSPACE;
+
+	prop->tag = cpu_to_fdt32(FDT_PROP);
+	prop->nameoff = cpu_to_fdt32(nameoff);
+	prop->len = cpu_to_fdt32(len);
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+	int err = check_header_sw(fdt);
+	char *p = (char *)fdt;
+	uint32_t *end;
+	int oldstroffset, newstroffset;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	if (err)
+		return err;
+
+	/* Add terminator */
+	end = grab_space(fdt, sizeof(*end));
+	if (! end)
+		return -FDT_ERR_NOSPACE;
+	*end = cpu_to_fdt32(FDT_END);
+
+	/* Relocate the string table */
+	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(fdt, newstroffset);
+
+	/* Walk the structure, correcting string offsets */
+	offset = 0;
+	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+		if (tag == FDT_PROP) {
+			struct fdt_property *prop =
+				fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
+			int nameoff;
+
+			if (! prop)
+				return -FDT_ERR_BADSTRUCTURE;
+
+			nameoff = fdt32_to_cpu(prop->nameoff);
+			nameoff += fdt_size_dt_strings(fdt);
+			prop->nameoff = cpu_to_fdt32(nameoff);
+		}
+		offset = nextoffset;
+	}
+
+	/* Finally, adjust the header */
+	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	return 0;
+}
diff --git a/kvm/libfdt/fdt_wip.c b/kvm/libfdt/fdt_wip.c
new file mode 100644
index 0000000..88e24b8
--- /dev/null
+++ b/kvm/libfdt/fdt_wip.c
@@ -0,0 +1,144 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len)
+{
+	void *propval;
+	int proplen;
+
+	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+	if (! propval)
+		return proplen;
+
+	if (proplen != len)
+		return -FDT_ERR_NOSPACE;
+
+	memcpy(propval, val, len);
+	return 0;
+}
+
+static void nop_region(void *start, int len)
+{
+	uint32_t *p;
+
+	for (p = start; (void *)p < (start + len); p++)
+		*p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len;
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	nop_region(prop, len + sizeof(*prop));
+
+	return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int nodeoffset)
+{
+	int level = 0;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADOFFSET;
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_END:
+			return offset;
+
+		case FDT_BEGIN_NODE:
+			level++;
+			break;
+
+		case FDT_END_NODE:
+			level--;
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (level >= 0);
+
+	return nextoffset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
+	return 0;
+}
diff --git a/kvm/libfdt/libfdt.h b/kvm/libfdt/libfdt.h
new file mode 100644
index 0000000..8645de0
--- /dev/null
+++ b/kvm/libfdt/libfdt.h
@@ -0,0 +1,1076 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attemped to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+	 * value.  phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+#define FDT_ERR_MAX		13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+	return (void *)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retreive a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retreive the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retreive one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retreive the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+					    const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+						      const char *name,
+						      int *lenp)
+{
+	return (struct fdt_property *)fdt_get_property(fdt, nodeoffset,
+						       name, lenp);
+}
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+				  const char *name, int *lenp)
+{
+	return (void *)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retreive the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on succes (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	stucture block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary.  This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+  *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+					   const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_property(fdt, name, &val, sizeof(val));
+}
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @addres, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therfore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therfore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creeating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+				   uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/kvm/libfdt/libfdt_env.h b/kvm/libfdt/libfdt_env.h
new file mode 100644
index 0000000..59f2536
--- /dev/null
+++ b/kvm/libfdt/libfdt_env.h
@@ -0,0 +1,22 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define fdt32_to_cpu(x)		(x)
+#define cpu_to_fdt32(x)		(x)
+#define fdt64_to_cpu(x)		(x)
+#define cpu_to_fdt64(x)		(x)
+#else
+#define fdt32_to_cpu(x)		(bswap_32((x)))
+#define cpu_to_fdt32(x)		(bswap_32((x)))
+#define fdt64_to_cpu(x)		(bswap_64((x)))
+#define cpu_to_fdt64(x)		(bswap_64((x)))
+#endif
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/kvm/libfdt/libfdt_internal.h b/kvm/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..52e1b8d
--- /dev/null
+++ b/kvm/libfdt/libfdt_internal.h
@@ -0,0 +1,96 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <fdt.h>
+
+#define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1))
+#define PALIGN(p, a)	((void *)ALIGN((unsigned long)(p), (a)))
+
+#define memeq(p, q, n)	(memcmp((p), (q), (n)) == 0)
+#define streq(p, q)	(strcmp((p), (q)) == 0)
+
+#define CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+	return fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+	return (void *)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+	const struct fdt_reserve_entry *rsv_table =
+		fdt + fdt_off_mem_rsvmap(fdt);
+
+	return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+	return (void *)_fdt_mem_rsv(fdt, n);
+}
+
+#define SW_MAGIC		(~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/kvm/libkvm/Makefile b/kvm/libkvm/Makefile
new file mode 100644
index 0000000..4db773d
--- /dev/null
+++ b/kvm/libkvm/Makefile
@@ -0,0 +1,54 @@
+all: libkvm.a
+
+include ../../config-host.mak
+ifneq ($(VPATH),)
+srcdir=$(VPATH)/kvm/libkvm
+else
+srcdir=.
+endif
+
+include $(srcdir)/config-$(ARCH).mak
+
+
+# libkvm is not -Wredundant-decls friendly yet
+CFLAGS += -Wno-redundant-decls
+
+# cc-option
+# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
+cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
+              > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+
+CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
+CFLAGS += $(call cc-option, -fno-stack-protector, "")
+CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
+CFLAGS += $(KVM_CFLAGS)
+
+LDFLAGS += $(CFLAGS)
+
+CXXFLAGS = $(autodepend-flags)
+
+VPATH:=$(VPATH)/kvm/libkvm
+
+autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
+
+
+libkvm.a: libkvm.o $(libkvm-$(ARCH)-objs)
+	$(AR) rcs $@ $^
+
+install:
+	@echo skipping libkvm install
+
+install-libkvm:
+	install -D libkvm.h $(DESTDIR)/$(PREFIX)/include/libkvm.h
+	install -D libkvm.a $(DESTDIR)/$(PREFIX)/$(LIBDIR)/libkvm.a
+
+install-kernel-headers:
+	install -D $(LIBKVM_KERNELDIR)/include/linux/kvm.h \
+		$(DESTDIR)/$(PREFIX)/include/linux/kvm.h
+	install -D $(LIBKVM_KERNELDIR)/include/linux/kvm_para.h \
+		$(DESTDIR)/$(PREFIX)/include/linux/kvm_para.h
+
+-include .*.d
+
+clean:
+	$(RM) *.o *.a .*.d
diff --git a/kvm/libkvm/config-i386.mak b/kvm/libkvm/config-i386.mak
new file mode 100644
index 0000000..2706b70
--- /dev/null
+++ b/kvm/libkvm/config-i386.mak
@@ -0,0 +1,6 @@
+
+LIBDIR := /lib
+CFLAGS += -m32
+CFLAGS += -D__i386__
+
+libkvm-$(ARCH)-objs := libkvm-x86.o
diff --git a/kvm/libkvm/config-ia64.mak b/kvm/libkvm/config-ia64.mak
new file mode 100644
index 0000000..568c397
--- /dev/null
+++ b/kvm/libkvm/config-ia64.mak
@@ -0,0 +1,5 @@
+
+LIBDIR := /lib
+CFLAGS += -D__ia64__
+
+libkvm-$(ARCH)-objs := libkvm-ia64.o
diff --git a/kvm/libkvm/config-ppc.mak b/kvm/libkvm/config-ppc.mak
new file mode 100644
index 0000000..091da37
--- /dev/null
+++ b/kvm/libkvm/config-ppc.mak
@@ -0,0 +1,4 @@
+
+LIBDIR := /lib
+
+libkvm-$(ARCH)-objs := libkvm-powerpc.o
diff --git a/kvm/libkvm/config-s390.mak b/kvm/libkvm/config-s390.mak
new file mode 100644
index 0000000..8177e4a
--- /dev/null
+++ b/kvm/libkvm/config-s390.mak
@@ -0,0 +1,3 @@
+# s390 31bit mode
+LIBDIR := /lib
+libkvm-$(ARCH)-objs := libkvm-s390.o
diff --git a/kvm/libkvm/config-s390x.mak b/kvm/libkvm/config-s390x.mak
new file mode 100644
index 0000000..f08ed3d
--- /dev/null
+++ b/kvm/libkvm/config-s390x.mak
@@ -0,0 +1,3 @@
+# s390 64 bit mode (arch=s390x)
+LIBDIR := /lib64
+libkvm-$(ARCH)-objs := libkvm-s390.o
diff --git a/kvm/libkvm/config-x86_64.mak b/kvm/libkvm/config-x86_64.mak
new file mode 100644
index 0000000..e638977
--- /dev/null
+++ b/kvm/libkvm/config-x86_64.mak
@@ -0,0 +1,6 @@
+
+LIBDIR := /lib64
+CFLAGS += -m64
+CFLAGS += -D__x86_64__
+
+libkvm-$(ARCH)-objs := libkvm-x86.o
diff --git a/kvm/libkvm/kvm-common.h b/kvm/libkvm/kvm-common.h
new file mode 100644
index 0000000..c95c591
--- /dev/null
+++ b/kvm/libkvm/kvm-common.h
@@ -0,0 +1,94 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm.
+ *
+ * derived from libkvm.c
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ *   This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_COMMON_H
+#define KVM_COMMON_H
+
+/* FIXME: share this number with kvm */
+/* FIXME: or dynamically alloc/realloc regions */
+#ifdef __s390__
+#define KVM_MAX_NUM_MEM_REGIONS 1u
+#define MAX_VCPUS 64
+#define LIBKVM_S390_ORIGIN (0UL)
+#elif defined(__ia64__)
+#define KVM_MAX_NUM_MEM_REGIONS 32u
+#define MAX_VCPUS 256
+#else
+#define KVM_MAX_NUM_MEM_REGIONS 32u
+#define MAX_VCPUS 16
+#endif
+
+
+/* kvm abi verison variable */
+extern int kvm_abi;
+
+/**
+ * \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;
+	/// is dirty pages logging enabled for all regions or not
+	int dirty_pages_log_all;
+	/// do not create in-kernel irqchip if set
+	int no_irqchip_creation;
+	/// in-kernel irqchip status
+	int irqchip_in_kernel;
+	/// ioctl to use to inject interrupts
+	int irqchip_inject_ioctl;
+	/// do not create in-kernel pit if set
+	int no_pit_creation;
+	/// in-kernel pit status
+	int pit_in_kernel;
+	/// in-kernel coalesced mmio
+	int coalesced_mmio;
+#ifdef KVM_CAP_IRQ_ROUTING
+	struct kvm_irq_routing *irq_routes;
+	int nr_allocated_irq_routes;
+#endif
+	void *used_gsi_bitmap;
+	int max_gsi;
+};
+
+int kvm_alloc_kernel_memory(kvm_context_t kvm, unsigned long memory,
+								void **vm_mem);
+int kvm_alloc_userspace_memory(kvm_context_t kvm, unsigned long memory,
+								void **vm_mem);
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+                        void **vm_mem);
+int kvm_arch_run(struct kvm_run *run, kvm_context_t kvm, int vcpu);
+
+
+void kvm_show_code(kvm_context_t kvm, int vcpu);
+
+int handle_halt(kvm_context_t kvm, int vcpu);
+int handle_shutdown(kvm_context_t kvm, void *env);
+void post_kvm_run(kvm_context_t kvm, void *env);
+int pre_kvm_run(kvm_context_t kvm, void *env);
+int handle_io_window(kvm_context_t kvm);
+int handle_debug(kvm_context_t kvm, int vcpu, void *env);
+int try_push_interrupts(kvm_context_t kvm);
+
+#endif
diff --git a/kvm/libkvm/kvm-ia64.h b/kvm/libkvm/kvm-ia64.h
new file mode 100644
index 0000000..ad87ae7
--- /dev/null
+++ b/kvm/libkvm/kvm-ia64.h
@@ -0,0 +1,31 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for x86.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * derived from libkvm.c
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_IA64_H
+#define KVM_IA64_H
+
+#include "kvm-common.h"
+
+extern int kvm_page_size;
+
+#define PAGE_SIZE kvm_page_size
+#define PAGE_MASK (~(kvm_page_size - 1))
+
+#define ia64_mf()	asm volatile ("mf" ::: "memory")
+#define smp_wmb()	ia64_mf()
+
+#endif
diff --git a/kvm/libkvm/kvm-powerpc.h b/kvm/libkvm/kvm-powerpc.h
new file mode 100644
index 0000000..b09511c
--- /dev/null
+++ b/kvm/libkvm/kvm-powerpc.h
@@ -0,0 +1,36 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for powerpc.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * Copyright 2007 IBM Corporation.
+ * Added by: Jerone Young <jyoung5@us.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_POWERPC_H
+#define KVM_POWERPC_H
+
+#include "kvm-common.h"
+
+extern int kvm_page_size;
+
+#define PAGE_SIZE kvm_page_size
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+static inline void eieio(void)
+{
+	asm volatile("eieio" : : : "memory");
+}
+
+#define smp_wmb()	eieio()
+
+#endif
diff --git a/kvm/libkvm/kvm-s390.h b/kvm/libkvm/kvm-s390.h
new file mode 100644
index 0000000..9edd9a3
--- /dev/null
+++ b/kvm/libkvm/kvm-s390.h
@@ -0,0 +1,31 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for s390.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors:
+ *	Carsten Otte <cotte@de.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_S390_H
+#define KVM_S390_H
+
+#include <asm/ptrace.h>
+#include "kvm-common.h"
+
+#define PAGE_SIZE 4096ul
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+#define smp_wmb()   asm volatile("" ::: "memory")
+
+#endif
diff --git a/kvm/libkvm/kvm-x86.h b/kvm/libkvm/kvm-x86.h
new file mode 100644
index 0000000..e988cb7
--- /dev/null
+++ b/kvm/libkvm/kvm-x86.h
@@ -0,0 +1,55 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for x86.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * derived from libkvm.c
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_X86_H
+#define KVM_X86_H
+
+#include "kvm-common.h"
+
+#define PAGE_SIZE 4096ul
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr);
+
+#ifdef KVM_CAP_VAPIC
+
+/*!
+ * \brief Enable kernel tpr access reporting
+ *
+ * When tpr access reporting is enabled, the kernel will call the
+ * ->tpr_access() callback every time the guest vcpu accesses the tpr.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu vcpu to enable tpr access reporting on
+ */
+int kvm_enable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
+
+/*!
+ * \brief Disable kernel tpr access reporting
+ *
+ * Undoes the effect of kvm_enable_tpr_access_reporting().
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu vcpu to disable tpr access reporting on
+ */
+int kvm_disable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
+
+#endif
+
+#define smp_wmb()   asm volatile("" ::: "memory")
+
+#endif
diff --git a/kvm/libkvm/libkvm-ia64.c b/kvm/libkvm/libkvm-ia64.c
new file mode 100644
index 0000000..2f15675
--- /dev/null
+++ b/kvm/libkvm/libkvm-ia64.c
@@ -0,0 +1,82 @@
+/*
+ * libkvm-ia64.c :Kernel-based Virtual Machine control library for ia64.
+ *
+ * This library provides an API to control the kvm hardware virtualization
+ * module.
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ * Authors:
+ *
+ *  Avi Kivity <avi@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * Copyright (C) 2007 Intel
+ * Added by : Zhang Xiantao <xiantao.zhang@intel.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ *
+ */
+
+#include "libkvm.h"
+#include "kvm-ia64.h"
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+			void **vm_mem)
+{
+	int r;
+
+	r = kvm_init_coalesced_mmio(kvm);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+int kvm_arch_run(struct kvm_run *run,kvm_context_t kvm, int vcpu)
+{
+	int r = 0;
+
+	switch (run->exit_reason) {
+		default:
+			r = 1;
+			break;
+	}
+
+	return r;
+}
+
+void kvm_show_code(kvm_context_t kvm, int vcpu)
+{
+	fprintf(stderr, "kvm_show_code not supported yet!\n");
+}
+
+void kvm_show_regs(kvm_context_t kvm, int vcpu)
+{
+	fprintf(stderr,"kvm_show_regs not supportted today!\n");
+}
+
+int kvm_create_memory_alias(kvm_context_t kvm,
+			    uint64_t phys_start,
+			    uint64_t len,
+			    uint64_t target_phys)
+{
+    return 0;
+}
+
+int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start)
+{
+	return 0;
+}
diff --git a/kvm/libkvm/libkvm-powerpc.c b/kvm/libkvm/libkvm-powerpc.c
new file mode 100644
index 0000000..f2cd8dc
--- /dev/null
+++ b/kvm/libkvm/libkvm-powerpc.c
@@ -0,0 +1,100 @@
+/*
+ * This file contains the powerpc specific implementation for the
+ * architecture dependent functions defined in kvm-common.h and
+ * libkvm.h
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *      Avi Kivity   <avi@qumranet.com>
+ *      Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * Copyright IBM Corp. 2007,2008
+ * Authors:
+ * 	Jerone Young <jyoung5@us.ibm.com>
+ * 	Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#include "libkvm.h"
+#include "kvm-powerpc.h"
+#include <errno.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+int handle_dcr(struct kvm_run *run,  kvm_context_t kvm, int vcpu)
+{
+	int ret = 0;
+
+	if (run->dcr.is_write)
+		ret = kvm->callbacks->powerpc_dcr_write(vcpu,
+							run->dcr.dcrn,
+							run->dcr.data);
+	else
+		ret = kvm->callbacks->powerpc_dcr_read(vcpu,
+							run->dcr.dcrn,
+							&(run->dcr.data));
+
+	return ret;
+}
+
+void kvm_show_code(kvm_context_t kvm, int vcpu)
+{
+	fprintf(stderr, "%s: Operation not supported\n", __FUNCTION__);
+}
+
+void kvm_show_regs(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_regs regs;
+	int i;
+
+	if (kvm_get_regs(kvm, vcpu, &regs))
+		return;
+
+	fprintf(stderr,"guest vcpu #%d\n", vcpu);
+	fprintf(stderr,"pc:   %016"PRIx64" msr:  %016"PRIx64"\n",
+	        regs.pc, regs.msr);
+	fprintf(stderr,"lr:   %016"PRIx64" ctr:  %016"PRIx64"\n",
+	        regs.lr, regs.ctr);
+	fprintf(stderr,"srr0: %016"PRIx64" srr1: %016"PRIx64"\n",
+	        regs.srr0, regs.srr1);
+	for (i=0; i<32; i+=4)
+	{
+		fprintf(stderr, "gpr%02d: %016"PRIx64" %016"PRIx64" %016"PRIx64
+		        " %016"PRIx64"\n", i,
+			regs.gpr[i],
+			regs.gpr[i+1],
+			regs.gpr[i+2],
+			regs.gpr[i+3]);
+	}
+
+	fflush(stdout);
+}
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+			 void **vm_mem)
+{
+	int r;
+
+	r = kvm_init_coalesced_mmio(kvm);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+int kvm_arch_run(struct kvm_run *run, kvm_context_t kvm, int vcpu)
+{
+	int ret = 0;
+
+	switch (run->exit_reason){
+	case KVM_EXIT_DCR:
+		ret = handle_dcr(run, kvm, vcpu);
+		break;
+	default:
+		ret = 1;
+		break;
+	}
+	return ret;
+}
diff --git a/kvm/libkvm/libkvm-s390.c b/kvm/libkvm/libkvm-s390.c
new file mode 100644
index 0000000..041c0ce
--- /dev/null
+++ b/kvm/libkvm/libkvm-s390.c
@@ -0,0 +1,110 @@
+/*
+ * This file contains the s390 specific implementation for the
+ * architecture dependent functions defined in kvm-common.h and
+ * libkvm.h
+ *
+ * Copyright (C) 2006 Qumranet
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ *	Carsten Otte <cotte@de.ibm.com>
+ *	Christian Borntraeger <borntraeger@de.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#include <sys/ioctl.h>
+#include <asm/ptrace.h>
+
+#include "libkvm.h"
+#include "kvm-common.h"
+#include <errno.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+void kvm_show_code(kvm_context_t kvm, int vcpu)
+{
+	fprintf(stderr, "%s: Operation not supported\n", __FUNCTION__);
+}
+
+void kvm_show_regs(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int i;
+
+	if (kvm_get_regs(kvm, vcpu, &regs))
+		return;
+
+	if (kvm_get_sregs(kvm, vcpu, &sregs))
+		return;
+
+	fprintf(stderr, "guest vcpu #%d\n", vcpu);
+	fprintf(stderr, "PSW:\t%16.16lx %16.16lx\n",
+					kvm->run[vcpu]->s390_sieic.mask,
+					kvm->run[vcpu]->s390_sieic.addr);
+	fprintf(stderr,"GPRS:");
+	for (i=0; i<15; i+=4)
+		fprintf(stderr, "\t%16.16lx %16.16lx %16.16lx %16.16lx\n",
+							regs.gprs[i],
+							regs.gprs[i+1],
+							regs.gprs[i+2],
+							regs.gprs[i+3]);
+	fprintf(stderr,"ACRS:");
+	for (i=0; i<15; i+=4)
+		fprintf(stderr, "\t%8.8x %8.8x %8.8x %8.8x\n",
+							sregs.acrs[i],
+							sregs.acrs[i+1],
+							sregs.acrs[i+2],
+							sregs.acrs[i+3]);
+
+	fprintf(stderr,"CRS:");
+	for (i=0; i<15; i+=4)
+		fprintf(stderr, "\t%16.16lx %16.16lx %16.16lx %16.16lx\n",
+							sregs.crs[i],
+							sregs.crs[i+1],
+							sregs.crs[i+2],
+							sregs.crs[i+3]);
+}
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+			 void **vm_mem)
+{
+	return 0;
+}
+
+int kvm_arch_run(struct kvm_run *run, kvm_context_t kvm, int vcpu)
+{
+	int ret = 0;
+
+	switch (run->exit_reason){
+	default:
+		ret = 1;
+		break;
+	}
+	return ret;
+}
+
+int kvm_s390_initial_reset(kvm_context_t kvm, int slot)
+{
+	return ioctl(kvm->vcpu_fd[slot], KVM_S390_INITIAL_RESET, NULL);
+}
+
+int kvm_s390_interrupt(kvm_context_t kvm, int slot,
+	struct kvm_s390_interrupt *kvmint)
+{
+	if (slot>=0)
+		return ioctl(kvm->vcpu_fd[slot], KVM_S390_INTERRUPT, kvmint);
+	else
+		return ioctl(kvm->vm_fd, KVM_S390_INTERRUPT, kvmint);
+}
+
+int kvm_s390_set_initial_psw(kvm_context_t kvm, int slot, psw_t psw)
+{
+	return ioctl(kvm->vcpu_fd[slot], KVM_S390_SET_INITIAL_PSW, &psw);
+}
+
+int kvm_s390_store_status(kvm_context_t kvm, int slot, unsigned long addr)
+{
+	return ioctl(kvm->vcpu_fd[slot], KVM_S390_STORE_STATUS, addr);
+}
diff --git a/kvm/libkvm/libkvm-x86.c b/kvm/libkvm/libkvm-x86.c
new file mode 100644
index 0000000..f1aef76
--- /dev/null
+++ b/kvm/libkvm/libkvm-x86.c
@@ -0,0 +1,676 @@
+#include "libkvm.h"
+#include "kvm-x86.h"
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr)
+{
+#ifdef KVM_CAP_SET_TSS_ADDR
+	int r;
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
+	if (r > 0) {
+		r = ioctl(kvm->vm_fd, KVM_SET_TSS_ADDR, addr);
+		if (r == -1) {
+			fprintf(stderr, "kvm_set_tss_addr: %m\n");
+			return -errno;
+		}
+		return 0;
+	}
+#endif
+	return -ENOSYS;
+}
+
+static int kvm_init_tss(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_SET_TSS_ADDR
+	int r;
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
+	if (r > 0) {
+		/*
+		 * this address is 3 pages before the bios, and the bios should present
+		 * as unavaible memory
+		 */
+		r = kvm_set_tss_addr(kvm, 0xfffbd000);
+		if (r < 0) {
+			fprintf(stderr, "kvm_init_tss: unable to set tss addr\n");
+			return r;
+		}
+
+	}
+#endif
+	return 0;
+}
+
+static int kvm_create_pit(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_PIT
+	int r;
+
+	kvm->pit_in_kernel = 0;
+	if (!kvm->no_pit_creation) {
+#ifdef KVM_CAP_PIT2
+		struct kvm_pit_config config = { .flags = 0 };
+
+		r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT2);
+		if (r > 0)
+			r = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &config);
+		else
+#endif
+		{
+			r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT);
+			if (r <= 0)
+				return 0;
+
+			r = ioctl(kvm->vm_fd, KVM_CREATE_PIT);
+		}
+		if (r < 0) {
+			fprintf(stderr, "Create kernel PIC irqchip failed\n");
+			return r;
+		}
+		kvm->pit_in_kernel = 1;
+	}
+#endif
+	return 0;
+}
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+ 			void **vm_mem)
+{
+	int r = 0;
+
+	r = kvm_init_tss(kvm);
+	if (r < 0)
+		return r;
+
+	r = kvm_create_pit(kvm);
+	if (r < 0)
+		return r;
+
+	r = kvm_init_coalesced_mmio(kvm);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+#ifdef KVM_EXIT_TPR_ACCESS
+
+static int handle_tpr_access(kvm_context_t kvm, struct kvm_run *run, int vcpu)
+{
+	return kvm->callbacks->tpr_access(kvm->opaque, vcpu,
+					  run->tpr_access.rip,
+					  run->tpr_access.is_write);
+}
+
+
+int kvm_enable_vapic(kvm_context_t kvm, int vcpu, uint64_t vapic)
+{
+	int r;
+	struct kvm_vapic_addr va = {
+		.vapic_addr = vapic,
+	};
+
+	r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_VAPIC_ADDR, &va);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_enable_vapic");
+		return r;
+	}
+	return 0;
+}
+
+#endif
+
+int kvm_arch_run(struct kvm_run *run,kvm_context_t kvm, int vcpu)
+{
+	int r = 0;
+
+	switch (run->exit_reason) {
+#ifdef KVM_EXIT_SET_TPR
+		case KVM_EXIT_SET_TPR:
+			break;
+#endif
+#ifdef KVM_EXIT_TPR_ACCESS
+		case KVM_EXIT_TPR_ACCESS:
+			r = handle_tpr_access(kvm, run, vcpu);
+			break;
+#endif
+		default:
+			r = 1;
+			break;
+	}
+
+	return r;
+}
+
+#define MAX_ALIAS_SLOTS 4
+static struct {
+	uint64_t start;
+	uint64_t len;
+} kvm_aliases[MAX_ALIAS_SLOTS];
+
+static int get_alias_slot(uint64_t start)
+{
+	int i;
+
+	for (i=0; i<MAX_ALIAS_SLOTS; i++)
+		if (kvm_aliases[i].start == start)
+			return i;
+	return -1;
+}
+static int get_free_alias_slot(void)
+{
+        int i;
+
+        for (i=0; i<MAX_ALIAS_SLOTS; i++)
+                if (kvm_aliases[i].len == 0)
+                        return i;
+        return -1;
+}
+
+static void register_alias(int slot, uint64_t start, uint64_t len)
+{
+	kvm_aliases[slot].start = start;
+	kvm_aliases[slot].len   = len;
+}
+
+int kvm_create_memory_alias(kvm_context_t kvm,
+			    uint64_t phys_start,
+			    uint64_t len,
+			    uint64_t target_phys)
+{
+	struct kvm_memory_alias alias = {
+		.flags = 0,
+		.guest_phys_addr = phys_start,
+		.memory_size = len,
+		.target_phys_addr = target_phys,
+	};
+	int fd = kvm->vm_fd;
+	int r;
+	int slot;
+
+	slot = get_alias_slot(phys_start);
+	if (slot < 0)
+		slot = get_free_alias_slot();
+	if (slot < 0)
+		return -EBUSY;
+	alias.slot = slot;
+
+	r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias);
+	if (r == -1)
+	    return -errno;
+
+	register_alias(slot, phys_start, len);
+	return 0;
+}
+
+int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start)
+{
+	return kvm_create_memory_alias(kvm, phys_start, 0, 0);
+}
+
+#ifdef KVM_CAP_IRQCHIP
+
+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
+
+#ifdef KVM_CAP_PIT
+
+int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s)
+{
+	int r;
+	if (!kvm->pit_in_kernel)
+		return 0;
+	r = ioctl(kvm->vm_fd, KVM_GET_PIT, s);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_get_pit");
+	}
+	return r;
+}
+
+int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s)
+{
+	int r;
+	if (!kvm->pit_in_kernel)
+		return 0;
+	r = ioctl(kvm->vm_fd, KVM_SET_PIT, s);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_set_pit");
+	}
+	return r;
+}
+
+#endif
+
+void kvm_show_code(kvm_context_t kvm, int vcpu)
+{
+#define SHOW_CODE_LEN 50
+	int fd = kvm->vcpu_fd[vcpu];
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int r, n;
+	int back_offset;
+	unsigned char code;
+	char code_str[SHOW_CODE_LEN * 3 + 1];
+	unsigned long rip;
+
+	r = ioctl(fd, KVM_GET_SREGS, &sregs);
+	if (r == -1) {
+		perror("KVM_GET_SREGS");
+		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;
+	*code_str = 0;
+	for (n = -back_offset; n < SHOW_CODE_LEN-back_offset; ++n) {
+		if (n == 0)
+			strcat(code_str, " -->");
+		r = kvm->callbacks->mmio_read(kvm->opaque, rip + n, &code, 1);
+		if (r < 0) {
+			strcat(code_str, " xx");
+			continue;
+		}
+		sprintf(code_str + strlen(code_str), " %02x", code);
+	}
+	fprintf(stderr, "code:%s\n", code_str);
+}
+
+
+/*
+ * 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);
+}
+
+uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	return run->apic_base;
+}
+
+void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	run->cr8 = cr8;
+}
+
+__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu)
+{
+	return kvm->run[vcpu]->cr8;
+}
+
+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_setup_cpuid2(kvm_context_t kvm, int vcpu, int nent,
+		     struct kvm_cpuid_entry2 *entries)
+{
+	struct kvm_cpuid2 *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_CPUID2, cpuid);
+	if (r == -1) {
+		fprintf(stderr, "kvm_setup_cpuid2: %m\n");
+		r = -errno;
+	}
+	free(cpuid);
+	return r;
+}
+
+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;
+}
+
+#ifdef KVM_CAP_VAPIC
+
+static int tpr_access_reporting(kvm_context_t kvm, int vcpu, int enabled)
+{
+	int r;
+	struct kvm_tpr_access_ctl tac = {
+		.enabled = enabled,
+	};
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_VAPIC);
+	if (r == -1 || r == 0)
+		return -ENOSYS;
+	r = ioctl(kvm->vcpu_fd[vcpu], KVM_TPR_ACCESS_REPORTING, &tac);
+	if (r == -1) {
+		r = -errno;
+		perror("KVM_TPR_ACCESS_REPORTING");
+		return r;
+	}
+	return 0;
+}
+
+int kvm_enable_tpr_access_reporting(kvm_context_t kvm, int vcpu)
+{
+	return tpr_access_reporting(kvm, vcpu, 1);
+}
+
+int kvm_disable_tpr_access_reporting(kvm_context_t kvm, int vcpu)
+{
+	return tpr_access_reporting(kvm, vcpu, 0);
+}
+
+#endif
+
+#ifdef KVM_CAP_EXT_CPUID
+
+static struct kvm_cpuid2 *try_get_cpuid(kvm_context_t kvm, int max)
+{
+	struct kvm_cpuid2 *cpuid;
+	int r, size;
+
+	size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
+	cpuid = (struct kvm_cpuid2 *)malloc(size);
+	cpuid->nent = max;
+	r = ioctl(kvm->fd, KVM_GET_SUPPORTED_CPUID, cpuid);
+	if (r == -1)
+		r = -errno;
+	else if (r == 0 && cpuid->nent >= max)
+		r = -E2BIG;
+	if (r < 0) {
+		if (r == -E2BIG) {
+			free(cpuid);
+			return NULL;
+		} else {
+			fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
+				strerror(-r));
+			exit(1);
+		}
+	}
+	return cpuid;
+}
+
+#define R_EAX 0
+#define R_ECX 1
+#define R_EDX 2
+#define R_EBX 3
+#define R_ESP 4
+#define R_EBP 5
+#define R_ESI 6
+#define R_EDI 7
+
+uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg)
+{
+	struct kvm_cpuid2 *cpuid;
+	int i, max;
+	uint32_t ret = 0;
+	uint32_t cpuid_1_edx;
+
+	if (!kvm_check_extension(kvm, KVM_CAP_EXT_CPUID)) {
+		return -1U;
+	}
+
+	max = 1;
+	while ((cpuid = try_get_cpuid(kvm, max)) == NULL) {
+		max *= 2;
+	}
+
+	for (i = 0; i < cpuid->nent; ++i) {
+		if (cpuid->entries[i].function == function) {
+			switch (reg) {
+			case R_EAX:
+				ret = cpuid->entries[i].eax;
+				break;
+			case R_EBX:
+				ret = cpuid->entries[i].ebx;
+				break;
+			case R_ECX:
+				ret = cpuid->entries[i].ecx;
+				break;
+			case R_EDX:
+				ret = cpuid->entries[i].edx;
+                                if (function == 1) {
+                                    /* kvm misreports the following features
+                                     */
+                                    ret |= 1 << 12; /* MTRR */
+                                    ret |= 1 << 16; /* PAT */
+                                    ret |= 1 << 7;  /* MCE */
+                                    ret |= 1 << 14; /* MCA */
+                                }
+
+				/* On Intel, kvm returns cpuid according to
+				 * the Intel spec, so add missing bits
+				 * according to the AMD spec:
+				 */
+				if (function == 0x80000001) {
+					cpuid_1_edx = kvm_get_supported_cpuid(kvm, 1, R_EDX);
+					ret |= cpuid_1_edx & 0xdfeff7ff;
+				}
+				break;
+			}
+		}
+	}
+
+	free(cpuid);
+
+	return ret;
+}
+
+#else
+
+uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg)
+{
+	return -1U;
+}
+
+#endif
diff --git a/kvm/libkvm/libkvm.c b/kvm/libkvm/libkvm.c
new file mode 100644
index 0000000..c5d6a7f
--- /dev/null
+++ b/kvm/libkvm/libkvm.c
@@ -0,0 +1,1497 @@
+/*
+ * 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@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * 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 <inttypes.h>
+#include "libkvm.h"
+
+#if defined(__x86_64__) || defined(__i386__)
+#include "kvm-x86.h"
+#endif
+
+#if defined(__ia64__)
+#include "kvm-ia64.h"
+#endif
+
+#if defined(__powerpc__)
+#include "kvm-powerpc.h"
+#endif
+
+#if defined(__s390__)
+#include "kvm-s390.h"
+#endif
+
+//#define DEBUG_MEMREG
+#ifdef	DEBUG_MEMREG
+#define DPRINTF(fmt, args...) \
+	do { fprintf(stderr, "%s:%d " fmt , __func__, __LINE__, ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1))
+
+int kvm_abi = EXPECTED_KVM_API_VERSION;
+int kvm_page_size;
+
+static inline void set_gsi(kvm_context_t kvm, unsigned int gsi)
+{
+	uint32_t *bitmap = kvm->used_gsi_bitmap;
+
+	if (gsi < kvm->max_gsi)
+		bitmap[gsi / 32] |= 1U << (gsi % 32);
+	else
+		DPRINTF("Invalid GSI %d\n");
+}
+
+static inline void clear_gsi(kvm_context_t kvm, unsigned int gsi)
+{
+	uint32_t *bitmap = kvm->used_gsi_bitmap;
+
+	if (gsi < kvm->max_gsi)
+		bitmap[gsi / 32] &= ~(1U << (gsi % 32));
+	else
+		DPRINTF("Invalid GSI %d\n");
+}
+
+struct slot_info {
+	unsigned long phys_addr;
+	unsigned long len;
+	unsigned long userspace_addr;
+	unsigned flags;
+	int logging_count;
+};
+
+struct slot_info slots[KVM_MAX_NUM_MEM_REGIONS];
+
+static void init_slots(void)
+{
+	int i;
+
+	for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i)
+		slots[i].len = 0;
+}
+
+static int get_free_slot(kvm_context_t kvm)
+{
+	int i;
+	int tss_ext;
+
+#if defined(KVM_CAP_SET_TSS_ADDR) && !defined(__s390__)
+	tss_ext = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
+#else
+	tss_ext = 0;
+#endif
+
+	/*
+	 * on older kernels where the set tss ioctl is not supprted we must save
+	 * slot 0 to hold the extended memory, as the vmx will use the last 3
+	 * pages of this slot.
+	 */
+	if (tss_ext > 0)
+		i = 0;
+	else
+		i = 1;
+
+	for (; i < KVM_MAX_NUM_MEM_REGIONS; ++i)
+		if (!slots[i].len)
+			return i;
+	return -1;
+}
+
+static void register_slot(int slot, unsigned long phys_addr, unsigned long len,
+		   unsigned long userspace_addr, unsigned flags)
+{
+	slots[slot].phys_addr = phys_addr;
+	slots[slot].len = len;
+	slots[slot].userspace_addr = userspace_addr;
+        slots[slot].flags = flags;
+}
+
+static void free_slot(int slot)
+{
+	slots[slot].len = 0;
+	slots[slot].logging_count = 0;
+}
+
+static int get_slot(unsigned long phys_addr)
+{
+	int i;
+
+	for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS ; ++i) {
+		if (slots[i].len && slots[i].phys_addr <= phys_addr &&
+	 	    (slots[i].phys_addr + slots[i].len-1) >= phys_addr)
+			return i;
+	}
+	return -1;
+}
+
+/* Returns -1 if this slot is not totally contained on any other,
+ * and the number of the slot otherwise */
+static int get_container_slot(uint64_t phys_addr, unsigned long size)
+{
+	int i;
+
+	for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS ; ++i)
+		if (slots[i].len && slots[i].phys_addr <= phys_addr &&
+		    (slots[i].phys_addr + slots[i].len) >= phys_addr + size)
+			return i;
+	return -1;
+}
+
+int kvm_is_containing_region(kvm_context_t kvm, unsigned long phys_addr, unsigned long size)
+{
+	int slot = get_container_slot(phys_addr, size);
+	if (slot == -1)
+		return 0;
+	return 1;
+}
+
+/* 
+ * dirty pages logging control 
+ */
+static int kvm_dirty_pages_log_change(kvm_context_t kvm,
+				      unsigned long phys_addr,
+				      unsigned flags,
+				      unsigned mask)
+{
+	int r = -1;
+	int slot = get_slot(phys_addr);
+
+	if (slot == -1) {
+		fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
+		return 1;
+	}
+
+	flags = (slots[slot].flags & ~mask) | flags;
+	if (flags == slots[slot].flags)
+		return 0;
+	slots[slot].flags = flags;
+
+	{
+		struct kvm_userspace_memory_region mem = {
+			.slot = slot,
+			.memory_size = slots[slot].len,
+			.guest_phys_addr = slots[slot].phys_addr,
+			.userspace_addr = slots[slot].userspace_addr,
+			.flags = slots[slot].flags,
+		};
+
+
+		DPRINTF("slot %d start %llx len %llx flags %x\n",
+			mem.slot,
+			mem.guest_phys_addr,
+			mem.memory_size,
+			mem.flags);
+		r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem);
+		if (r == -1)
+			fprintf(stderr, "%s: %m\n", __FUNCTION__);
+	}
+	return r;
+}
+
+static int kvm_dirty_pages_log_change_all(kvm_context_t kvm,
+					  int (*change)(kvm_context_t kvm,
+							uint64_t start,
+							uint64_t len))
+{
+	int i, r;
+
+	for (i=r=0; i<KVM_MAX_NUM_MEM_REGIONS && r==0; i++) {
+		if (slots[i].len)
+			r = change(kvm, slots[i].phys_addr, slots[i].len);
+	}
+	return r;
+}
+
+int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm,
+				    uint64_t phys_addr,
+				    uint64_t len)
+{
+	int slot = get_slot(phys_addr);
+
+	DPRINTF("start %"PRIx64" len %"PRIx64"\n", phys_addr, len);
+	if (slot == -1) {
+		fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (slots[slot].logging_count++)
+		return 0;
+
+	return kvm_dirty_pages_log_change(kvm, slots[slot].phys_addr,
+					  KVM_MEM_LOG_DIRTY_PAGES,
+					  KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+int kvm_dirty_pages_log_disable_slot(kvm_context_t kvm,
+				     uint64_t phys_addr,
+				     uint64_t len)
+{
+	int slot = get_slot(phys_addr);
+
+	if (slot == -1) {
+		fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (--slots[slot].logging_count)
+		return 0;
+
+	return kvm_dirty_pages_log_change(kvm, slots[slot].phys_addr,
+					  0,
+					  KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+/**
+ * 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_dirty_pages_log_enable_slot);
+}
+
+/**
+ * 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,
+					      kvm_dirty_pages_log_disable_slot);
+}
+
+
+kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
+		       void *opaque)
+{
+	int fd;
+	kvm_context_t kvm;
+	int r, gsi_count;
+
+	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) {
+		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_page_size = getpagesize();
+	kvm = malloc(sizeof(*kvm));
+	if (kvm == NULL)
+		goto out_close;
+	memset(kvm, 0, 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;
+	kvm->no_pit_creation = 0;
+
+	gsi_count = kvm_get_gsi_count(kvm);
+	if (gsi_count > 0) {
+		int gsi_bits, i;
+
+		/* Round up so we can search ints using ffs */
+		gsi_bits = ALIGN(gsi_count, 32);
+		kvm->used_gsi_bitmap = malloc(gsi_bits / 8);
+		if (!kvm->used_gsi_bitmap)
+			goto out_close;
+		memset(kvm->used_gsi_bitmap, 0, gsi_bits / 8);
+		kvm->max_gsi = gsi_bits;
+
+		/* Mark any over-allocated bits as already in use */
+		for (i = gsi_count; i < gsi_bits; i++)
+			set_gsi(kvm, i);
+	}
+
+	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;
+}
+
+void kvm_disable_pit_creation(kvm_context_t kvm)
+{
+	kvm->no_pit_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_create_vm(kvm_context_t kvm)
+{
+	int fd = kvm->fd;
+
+#ifdef KVM_CAP_IRQ_ROUTING
+	kvm->irq_routes = malloc(sizeof(*kvm->irq_routes));
+	if (!kvm->irq_routes)
+		return -ENOMEM;
+	memset(kvm->irq_routes, 0, sizeof(*kvm->irq_routes));
+	kvm->nr_allocated_irq_routes = 0;
+#endif
+
+	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;
+	return 0;
+}
+
+static int kvm_create_default_phys_mem(kvm_context_t kvm,
+				       unsigned long phys_mem_bytes,
+				       void **vm_mem)
+{
+#ifdef KVM_CAP_USER_MEMORY
+	int r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
+	if (r > 0)
+		return 0;
+	fprintf(stderr, "Hypervisor too old: KVM_CAP_USER_MEMORY extension not supported\n");
+#else
+#error Hypervisor too old: KVM_CAP_USER_MEMORY extension not supported
+#endif
+	return -1;
+}
+
+int kvm_check_extension(kvm_context_t kvm, int ext)
+{
+	int ret;
+
+	ret = ioctl(kvm->fd, KVM_CHECK_EXTENSION, ext);
+	if (ret > 0)
+		return ret;
+	return 0;
+}
+
+void kvm_create_irqchip(kvm_context_t kvm)
+{
+	int r;
+
+	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(kvm->vm_fd, KVM_CREATE_IRQCHIP);
+			if (r >= 0) {
+				kvm->irqchip_inject_ioctl = KVM_IRQ_LINE;
+#if defined(KVM_CAP_IRQ_INJECT_STATUS) && defined(KVM_IRQ_LINE_STATUS)
+				r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
+			  KVM_CAP_IRQ_INJECT_STATUS);
+				if (r > 0)
+					kvm->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+#endif
+				kvm->irqchip_in_kernel = 1;
+			}
+			else
+				fprintf(stderr, "Create kernel PIC irqchip failed\n");
+		}
+	}
+#endif
+}
+
+int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, void **vm_mem)
+{
+	int r;
+	
+	r = kvm_create_vm(kvm);
+	if (r < 0)
+	        return r;
+	r = kvm_arch_create(kvm, phys_mem_bytes, vm_mem);
+	if (r < 0)
+		return r;
+	init_slots();
+	r = kvm_create_default_phys_mem(kvm, phys_mem_bytes, vm_mem);
+	if (r < 0)
+	        return r;
+	kvm_create_irqchip(kvm);
+
+	return 0;
+}
+
+
+void *kvm_create_phys_mem(kvm_context_t kvm, unsigned long phys_start,
+			  unsigned long len, int log, int writable)
+{
+	int r;
+	int prot = PROT_READ;
+	void *ptr;
+	struct kvm_userspace_memory_region memory = {
+		.memory_size = len,
+		.guest_phys_addr = phys_start,
+		.flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
+	};
+
+	if (writable)
+		prot |= PROT_WRITE;
+
+#if !defined(__s390__)
+	ptr = mmap(NULL, len, prot, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+#else
+	ptr = mmap(LIBKVM_S390_ORIGIN, len, prot | PROT_EXEC,
+		MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+#endif
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "%s: %s", __func__, strerror(errno));
+		return 0;
+	}
+
+	memset(ptr, 0, len);
+
+	memory.userspace_addr = (unsigned long)ptr;
+	memory.slot = get_free_slot(kvm);
+	DPRINTF("slot %d start %llx len %llx flags %x\n",
+		memory.slot,
+		memory.guest_phys_addr,
+		memory.memory_size,
+		memory.flags);
+	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &memory);
+	if (r == -1) {
+		fprintf(stderr, "%s: %s", __func__, strerror(errno));
+		return 0;
+	}
+	register_slot(memory.slot, memory.guest_phys_addr, memory.memory_size,
+		      memory.userspace_addr, memory.flags);
+
+        return ptr;
+}
+
+int kvm_register_phys_mem(kvm_context_t kvm,
+			  unsigned long phys_start, void *userspace_addr,
+			  unsigned long len, int log)
+{
+
+	struct kvm_userspace_memory_region memory = {
+		.memory_size = len,
+		.guest_phys_addr = phys_start,
+		.userspace_addr = (unsigned long)(intptr_t)userspace_addr,
+		.flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
+	};
+	int r;
+
+	memory.slot = get_free_slot(kvm);
+	DPRINTF("memory: gpa: %llx, size: %llx, uaddr: %llx, slot: %x, flags: %lx\n",
+		memory.guest_phys_addr, memory.memory_size,
+		memory.userspace_addr, memory.slot, memory.flags);
+	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &memory);
+	if (r == -1) {
+		fprintf(stderr, "create_userspace_phys_mem: %s\n", strerror(errno));
+		return -1;
+	}
+	register_slot(memory.slot, memory.guest_phys_addr, memory.memory_size,
+		      memory.userspace_addr, memory.flags);
+        return 0;
+}
+
+
+/* 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;
+	int r;
+	struct kvm_userspace_memory_region memory = {
+		.memory_size = 0,
+		.guest_phys_addr = phys_start,
+		.userspace_addr = 0,
+		.flags = 0,
+	};
+
+	slot = get_slot(phys_start);
+
+	if ((slot >= KVM_MAX_NUM_MEM_REGIONS) || (slot == -1)) {
+		fprintf(stderr, "BUG: %s: invalid parameters (slot=%d)\n",
+			__FUNCTION__, slot);
+		return;
+	}
+	if (phys_start != slots[slot].phys_addr) {
+		fprintf(stderr,
+			"WARNING: %s: phys_start is 0x%lx expecting 0x%lx\n",
+			__FUNCTION__, phys_start, slots[slot].phys_addr);
+		phys_start = slots[slot].phys_addr;
+	}
+
+	memory.slot = slot;
+	DPRINTF("slot %d start %llx len %llx flags %x\n",
+		memory.slot,
+		memory.guest_phys_addr,
+		memory.memory_size,
+		memory.flags);
+	r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &memory);
+	if (r == -1) {
+		fprintf(stderr, "destroy_userspace_phys_mem: %s",
+			strerror(errno));
+		return;
+	}
+
+	free_slot(memory.slot);
+}
+
+void kvm_unregister_memory_area(kvm_context_t kvm, uint64_t phys_addr, unsigned long size)
+{
+
+	int slot = get_container_slot(phys_addr, size);
+
+	if (slot != -1) {
+		DPRINTF("Unregistering memory region %llx (%lx)\n", phys_addr, size);
+		kvm_destroy_phys_mem(kvm, phys_addr, size);
+		return;
+	}
+}
+
+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, unsigned long phys_addr, void *buf)
+{
+	int slot;
+
+	slot = get_slot(phys_addr);
+	return kvm_get_map(kvm, KVM_GET_DIRTY_LOG, slot, buf);
+}
+
+int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
+			      unsigned long len, void *buf, void *opaque,
+			      int (*cb)(unsigned long start, unsigned long len,
+					void*bitmap, void *opaque))
+{
+	int i;
+	int r;
+	unsigned long end_addr = phys_addr + len;
+
+	for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i) {
+		if ((slots[i].len && (uint64_t)slots[i].phys_addr >= phys_addr)
+		    && ((uint64_t)slots[i].phys_addr + slots[i].len  <= end_addr)) {
+			r = kvm_get_map(kvm, KVM_GET_DIRTY_LOG, i, buf);
+			if (r)
+				return r;
+			r = cb(slots[i].phys_addr, slots[i].len, buf, opaque);
+			if (r)
+				return r;
+		}
+	}
+	return 0;
+}
+
+#ifdef KVM_CAP_IRQCHIP
+
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status)
+{
+	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->irqchip_inject_ioctl, &event);
+	if (r == -1)
+		perror("kvm_set_irq_level");
+
+	if (status) {
+#ifdef KVM_CAP_IRQ_INJECT_STATUS
+		*status = (kvm->irqchip_inject_ioctl == KVM_IRQ_LINE) ?
+			1 : event.status;
+#else
+		*status = 1;
+#endif
+	}
+
+	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;
+}
+
+#endif
+
+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;
+}
+
+int handle_debug(kvm_context_t kvm, int vcpu, void *env)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    struct kvm_run *run = kvm->run[vcpu];
+
+    return kvm->callbacks->debug(kvm->opaque, env, &run->debug.arch);
+#else
+    return 0;
+#endif
+}
+
+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);
+}
+
+#ifdef KVM_CAP_MP_STATE
+int kvm_get_mpstate(kvm_context_t kvm, int vcpu, struct kvm_mp_state *mp_state)
+{
+    int r;
+
+    r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_MP_STATE);
+    if (r > 0)
+        return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_MP_STATE, mp_state);
+    return -ENOSYS;
+}
+
+int kvm_set_mpstate(kvm_context_t kvm, int vcpu, struct kvm_mp_state *mp_state)
+{
+    int r;
+
+    r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_MP_STATE);
+    if (r > 0)
+        return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_MP_STATE, mp_state);
+    return -ENOSYS;
+}
+#endif
+
+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;
+
+	/* hack: Red Hat 7.1 generates these weird accesses. */
+	if ((addr > 0xa0000-4 && addr <= 0xa0000) && kvm_run->mmio.len == 3)
+	    return 0;
+
+	if (kvm_run->mmio.is_write)
+		return kvm->callbacks->mmio_write(kvm->opaque, addr, data,
+					kvm_run->mmio.len);
+	else
+		return kvm->callbacks->mmio_read(kvm->opaque, addr, data,
+					kvm_run->mmio.len);
+}
+
+int handle_io_window(kvm_context_t kvm)
+{
+	return kvm->callbacks->io_window(kvm->opaque);
+}
+
+int handle_halt(kvm_context_t kvm, int vcpu)
+{
+	return kvm->callbacks->halt(kvm->opaque, vcpu);
+}
+
+int handle_shutdown(kvm_context_t kvm, void *env)
+{
+	return kvm->callbacks->shutdown(kvm->opaque, env);
+}
+
+int try_push_interrupts(kvm_context_t kvm)
+{
+	return kvm->callbacks->try_push_interrupts(kvm->opaque);
+}
+
+static inline void push_nmi(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_USER_NMI
+	kvm->callbacks->push_nmi(kvm->opaque);
+#endif /* KVM_CAP_USER_NMI */
+}
+
+void post_kvm_run(kvm_context_t kvm, void *env)
+{
+	kvm->callbacks->post_kvm_run(kvm->opaque, env);
+}
+
+int pre_kvm_run(kvm_context_t kvm, void *env)
+{
+	return kvm->callbacks->pre_kvm_run(kvm->opaque, env);
+}
+
+int kvm_get_interrupt_flag(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	return run->if_flag;
+}
+
+int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu)
+{
+	struct kvm_run *run = kvm->run[vcpu];
+
+	return run->ready_for_interrupt_injection;
+}
+
+int kvm_run(kvm_context_t kvm, int vcpu, void *env)
+{
+	int r;
+	int fd = kvm->vcpu_fd[vcpu];
+	struct kvm_run *run = kvm->run[vcpu];
+
+again:
+	push_nmi(kvm);
+#if !defined(__s390__)
+	if (!kvm->irqchip_in_kernel)
+		run->request_interrupt_window = try_push_interrupts(kvm);
+#endif
+	r = pre_kvm_run(kvm, env);
+	if (r)
+	    return r;
+	r = ioctl(fd, KVM_RUN, 0);
+
+	if (r == -1 && errno != EINTR && errno != EAGAIN) {
+		r = -errno;
+		post_kvm_run(kvm, env);
+		fprintf(stderr, "kvm_run: %s\n", strerror(-r));
+		return r;
+	}
+
+	post_kvm_run(kvm, env);
+
+#if defined(KVM_CAP_COALESCED_MMIO)
+	if (kvm->coalesced_mmio) {
+	        struct kvm_coalesced_mmio_ring *ring = (void *)run +
+						kvm->coalesced_mmio * PAGE_SIZE;
+		while (ring->first != ring->last) {
+			kvm->callbacks->mmio_write(kvm->opaque,
+				 ring->coalesced_mmio[ring->first].phys_addr,
+				&ring->coalesced_mmio[ring->first].data[0],
+				 ring->coalesced_mmio[ring->first].len);
+			smp_wmb();
+			ring->first = (ring->first + 1) %
+							KVM_COALESCED_MMIO_MAX;
+		}
+	}
+#endif
+
+#if !defined(__s390__)
+	if (r == -1) {
+		r = handle_io_window(kvm);
+		goto more;
+	}
+#endif
+	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);
+			kvm_show_regs(kvm, vcpu);
+			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, env);
+			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, env);
+			break;
+#if defined(__s390__)
+		case KVM_EXIT_S390_SIEIC:
+			r = kvm->callbacks->s390_handle_intercept(kvm, vcpu,
+				run);
+			break;
+		case KVM_EXIT_S390_RESET:
+			r = kvm->callbacks->s390_handle_reset(kvm, vcpu, run);
+			break;
+#endif
+		default:
+			if (kvm_arch_run(run, kvm, vcpu)) {
+				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);
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_guest_debug *dbg)
+{
+	return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_GUEST_DEBUG, dbg);
+}
+#endif
+
+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;
+}
+
+int kvm_pit_in_kernel(kvm_context_t kvm)
+{
+	return kvm->pit_in_kernel;
+}
+
+int kvm_has_sync_mmu(kvm_context_t kvm)
+{
+        int r = 0;
+#ifdef KVM_CAP_SYNC_MMU
+        r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SYNC_MMU);
+#endif
+        return r;
+}
+
+int kvm_inject_nmi(kvm_context_t kvm, int vcpu)
+{
+#ifdef KVM_CAP_USER_NMI
+	return ioctl(kvm->vcpu_fd[vcpu], KVM_NMI);
+#else
+	return -ENOSYS;
+#endif
+}
+
+int kvm_init_coalesced_mmio(kvm_context_t kvm)
+{
+	int r = 0;
+	kvm->coalesced_mmio = 0;
+#ifdef KVM_CAP_COALESCED_MMIO
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+	if (r > 0) {
+		kvm->coalesced_mmio = r;
+		return 0;
+	}
+#endif
+	return r;
+}
+
+int kvm_register_coalesced_mmio(kvm_context_t kvm, uint64_t addr, uint32_t size)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+	struct kvm_coalesced_mmio_zone zone;
+	int r;
+
+	if (kvm->coalesced_mmio) {
+
+		zone.addr = addr;
+		zone.size = size;
+
+		r = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone);
+		if (r == -1) {
+			perror("kvm_register_coalesced_mmio_zone");
+			return -errno;
+		}
+		return 0;
+	}
+#endif
+	return -ENOSYS;
+}
+
+int kvm_unregister_coalesced_mmio(kvm_context_t kvm, uint64_t addr, uint32_t size)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+	struct kvm_coalesced_mmio_zone zone;
+	int r;
+
+	if (kvm->coalesced_mmio) {
+
+		zone.addr = addr;
+		zone.size = size;
+
+		r = ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+		if (r == -1) {
+			perror("kvm_unregister_coalesced_mmio_zone");
+			return -errno;
+		}
+		DPRINTF("Unregistered coalesced mmio region for %llx (%lx)\n", addr, size);
+		return 0;
+	}
+#endif
+	return -ENOSYS;
+}
+
+#ifdef KVM_CAP_DEVICE_ASSIGNMENT
+int kvm_assign_pci_device(kvm_context_t kvm,
+			  struct kvm_assigned_pci_dev *assigned_dev)
+{
+	int ret;
+
+	ret = ioctl(kvm->vm_fd, KVM_ASSIGN_PCI_DEVICE, assigned_dev);
+	if (ret < 0)
+		return -errno;
+
+	return ret;
+}
+
+static int kvm_old_assign_irq(kvm_context_t kvm,
+		   struct kvm_assigned_irq *assigned_irq)
+{
+	int ret;
+
+	ret = ioctl(kvm->vm_fd, KVM_ASSIGN_IRQ, assigned_irq);
+	if (ret < 0)
+		return -errno;
+
+	return ret;
+}
+
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+int kvm_assign_irq(kvm_context_t kvm,
+		   struct kvm_assigned_irq *assigned_irq)
+{
+	int ret;
+
+	ret = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_ASSIGN_DEV_IRQ);
+	if (ret > 0) {
+		ret = ioctl(kvm->vm_fd, KVM_ASSIGN_DEV_IRQ, assigned_irq);
+		if (ret < 0)
+			return -errno;
+		return ret;
+	}
+
+	return kvm_old_assign_irq(kvm, assigned_irq);
+}
+
+int kvm_deassign_irq(kvm_context_t kvm,
+		     struct kvm_assigned_irq *assigned_irq)
+{
+	int ret;
+
+	ret = ioctl(kvm->vm_fd, KVM_DEASSIGN_DEV_IRQ, assigned_irq);
+	if (ret < 0)
+            return -errno;
+
+	return ret;
+}
+#else
+int kvm_assign_irq(kvm_context_t kvm,
+		   struct kvm_assigned_irq *assigned_irq)
+{
+	return kvm_old_assign_irq(kvm, assigned_irq);
+}
+#endif
+#endif
+
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+int kvm_deassign_pci_device(kvm_context_t kvm,
+			    struct kvm_assigned_pci_dev *assigned_dev)
+{
+	int ret;
+
+	ret = ioctl(kvm->vm_fd, KVM_DEASSIGN_PCI_DEVICE, assigned_dev);
+	if (ret < 0)
+		return -errno;
+
+	return ret;
+}
+#endif
+
+int kvm_destroy_memory_region_works(kvm_context_t kvm)
+{
+	int ret = 0;
+
+#ifdef KVM_CAP_DESTROY_MEMORY_REGION_WORKS
+	ret = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
+		    KVM_CAP_DESTROY_MEMORY_REGION_WORKS);
+	if (ret <= 0)
+		ret = 0;
+#endif
+	return ret;
+}
+
+int kvm_reinject_control(kvm_context_t kvm, int pit_reinject)
+{
+#ifdef KVM_CAP_REINJECT_CONTROL
+	int r;
+	struct kvm_reinject_control control;
+
+	control.pit_reinject = pit_reinject;
+
+	r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_REINJECT_CONTROL);
+	if (r > 0) {
+		r = ioctl(kvm->vm_fd, KVM_REINJECT_CONTROL, &control);
+		if (r == -1)
+			return -errno;
+		return r;
+	}
+#endif
+	return -ENOSYS;
+}
+
+int kvm_has_gsi_routing(kvm_context_t kvm)
+{
+    int r = 0;
+
+#ifdef KVM_CAP_IRQ_ROUTING
+    r = kvm_check_extension(kvm, KVM_CAP_IRQ_ROUTING);
+#endif
+    return r;
+}
+
+int kvm_get_gsi_count(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	return kvm_check_extension(kvm, KVM_CAP_IRQ_ROUTING);
+#else
+	return -EINVAL;
+#endif
+}
+
+int kvm_clear_gsi_routes(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	kvm->irq_routes->nr = 0;
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+int kvm_add_routing_entry(kvm_context_t kvm,
+		          struct kvm_irq_routing_entry* entry)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	struct kvm_irq_routing *z;
+	struct kvm_irq_routing_entry *new;
+	int n, size;
+
+	if (kvm->irq_routes->nr == kvm->nr_allocated_irq_routes) {
+		n = kvm->nr_allocated_irq_routes * 2;
+		if (n < 64)
+			n = 64;
+		size = sizeof(struct kvm_irq_routing);
+		size += n * sizeof(*new);
+		z = realloc(kvm->irq_routes, size);
+		if (!z)
+			return -ENOMEM;
+		kvm->nr_allocated_irq_routes = n;
+		kvm->irq_routes = z;
+	}
+	n = kvm->irq_routes->nr++;
+	new = &kvm->irq_routes->entries[n];
+	memset(new, 0, sizeof(*new));
+	new->gsi = entry->gsi;
+	new->type = entry->type;
+	new->flags = entry->flags;
+	new->u = entry->u;
+
+	set_gsi(kvm, entry->gsi);
+
+	return 0;
+#else
+	return -ENOSYS;
+#endif
+}
+
+int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	struct kvm_irq_routing_entry e;
+
+	e.gsi = gsi;
+	e.type = KVM_IRQ_ROUTING_IRQCHIP;
+	e.flags = 0;
+	e.u.irqchip.irqchip = irqchip;
+	e.u.irqchip.pin = pin;
+	return kvm_add_routing_entry(kvm, &e);
+#else
+	return -ENOSYS;
+#endif
+}
+
+int kvm_del_routing_entry(kvm_context_t kvm,
+	                  struct kvm_irq_routing_entry* entry)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	struct kvm_irq_routing_entry *e, *p;
+	int i, gsi, found = 0;
+
+	gsi = entry->gsi;
+
+	for (i = 0; i < kvm->irq_routes->nr; ++i) {
+		e = &kvm->irq_routes->entries[i];
+		if (e->type == entry->type
+		    && e->gsi == gsi) {
+			switch (e->type)
+			{
+			case KVM_IRQ_ROUTING_IRQCHIP: {
+				if (e->u.irqchip.irqchip ==
+				    entry->u.irqchip.irqchip
+				    && e->u.irqchip.pin ==
+				    entry->u.irqchip.pin) {
+					p = &kvm->irq_routes->
+					    entries[--kvm->irq_routes->nr];
+					*e = *p;
+					found = 1;
+				}
+				break;
+			}
+			case KVM_IRQ_ROUTING_MSI: {
+				if (e->u.msi.address_lo ==
+				    entry->u.msi.address_lo
+				    && e->u.msi.address_hi ==
+				    entry->u.msi.address_hi
+				    && e->u.msi.data == entry->u.msi.data) {
+					p = &kvm->irq_routes->
+					    entries[--kvm->irq_routes->nr];
+					*e = *p;
+					found = 1;
+				}
+				break;
+			}
+			default:
+				break;
+			}
+			if (found) {
+				/* If there are no other users of this GSI
+				 * mark it available in the bitmap */
+				for (i = 0; i < kvm->irq_routes->nr; i++) {
+					e = &kvm->irq_routes->entries[i];
+					if (e->gsi == gsi)
+						break;
+				}
+				if (i == kvm->irq_routes->nr)
+					clear_gsi(kvm, gsi);
+
+				return 0;
+			}
+		}
+	}
+	return -ESRCH;
+#else
+	return -ENOSYS;
+#endif
+}
+
+int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	struct kvm_irq_routing_entry e;
+
+	e.gsi = gsi;
+	e.type = KVM_IRQ_ROUTING_IRQCHIP;
+	e.flags = 0;
+	e.u.irqchip.irqchip = irqchip;
+	e.u.irqchip.pin = pin;
+	return kvm_del_routing_entry(kvm, &e);
+#else
+	return -ENOSYS;
+#endif
+}
+
+int kvm_commit_irq_routes(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+	int r;
+
+	kvm->irq_routes->flags = 0;
+	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, kvm->irq_routes);
+	if (r == -1)
+		r = -errno;
+	return r;
+#else
+	return -ENOSYS;
+#endif
+}
+
+int kvm_get_irq_route_gsi(kvm_context_t kvm)
+{
+	int i, bit;
+	uint32_t *buf = kvm->used_gsi_bitmap;
+
+	/* Return the lowest unused GSI in the bitmap */
+	for (i = 0; i < kvm->max_gsi / 32; i++) {
+		bit = ffs(~buf[i]);
+		if (!bit)
+			continue;
+
+		return bit - 1 + i * 32;
+	}
+
+	return -ENOSPC;
+}
+
+#ifdef KVM_CAP_DEVICE_MSIX
+int kvm_assign_set_msix_nr(kvm_context_t kvm,
+                           struct kvm_assigned_msix_nr *msix_nr)
+{
+        int ret;
+
+        ret = ioctl(kvm->vm_fd, KVM_ASSIGN_SET_MSIX_NR, msix_nr);
+        if (ret < 0)
+                return -errno;
+
+        return ret;
+}
+
+int kvm_assign_set_msix_entry(kvm_context_t kvm,
+                              struct kvm_assigned_msix_entry *entry)
+{
+        int ret;
+
+        ret = ioctl(kvm->vm_fd, KVM_ASSIGN_SET_MSIX_ENTRY, entry);
+        if (ret < 0)
+                return -errno;
+
+        return ret;
+}
+#endif
diff --git a/kvm/libkvm/libkvm.h b/kvm/libkvm/libkvm.h
new file mode 100644
index 0000000..4821a1e
--- /dev/null
+++ b/kvm/libkvm/libkvm.h
@@ -0,0 +1,868 @@
+/** \file libkvm.h
+ * libkvm API
+ */
+
+#ifndef LIBKVM_H
+#define LIBKVM_H
+
+#if defined(__s390__)
+#include <asm/ptrace.h>
+#endif
+
+#include <stdint.h>
+
+#ifndef __user
+#define __user /* temporary, until installed via make headers_install */
+#endif
+
+#include <linux/kvm.h>
+
+#include <signal.h>
+
+struct kvm_context;
+
+typedef struct kvm_context *kvm_context_t;
+
+#if defined(__x86_64__) || defined(__i386__)
+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);
+#endif
+
+/*!
+ * \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);
+	/// generic memory reads to unmapped memory (For MMIO devices)
+    int (*mmio_read)(void *opaque, uint64_t addr, uint8_t *data,
+					int len);
+	/// generic memory writes to unmapped memory (For MMIO devices)
+    int (*mmio_write)(void *opaque, uint64_t addr, uint8_t *data,
+					int len);
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    int (*debug)(void *opaque, void *env,
+		 struct kvm_debug_exit_arch *arch_info);
+#endif
+	/*!
+	 * \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, void *env);
+    int (*io_window)(void *opaque);
+    int (*try_push_interrupts)(void *opaque);
+#ifdef KVM_CAP_USER_NMI
+    void (*push_nmi)(void *opaque);
+#endif
+    void (*post_kvm_run)(void *opaque, void *env);
+    int (*pre_kvm_run)(void *opaque, void *env);
+    int (*tpr_access)(void *opaque, int vcpu, uint64_t rip, int is_write);
+#if defined(__powerpc__)
+    int (*powerpc_dcr_read)(int vcpu, uint32_t dcrn, uint32_t *data);
+    int (*powerpc_dcr_write)(int vcpu, uint32_t dcrn, uint32_t data);
+#endif
+#if defined(__s390__)
+    int (*s390_handle_intercept)(kvm_context_t context, int vcpu,
+	struct kvm_run *run);
+    int (*s390_handle_reset)(kvm_context_t context, int vcpu,
+	 struct kvm_run *run);
+#endif
+};
+
+/*!
+ * \brief Create new KVM context
+ *
+ * This creates a new kvm_context. A KVM context is a small area of data that
+ * holds information about the KVM instance that gets created by this call.\n
+ * This should always be your first call to KVM.
+ *
+ * \param callbacks Pointer to a valid kvm_callbacks structure
+ * \param opaque Not used
+ * \return NULL on failure
+ */
+kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
+		       void *opaque);
+
+/*!
+ * \brief Cleanup the KVM context
+ *
+ * Should always be called when closing down KVM.\n
+ * Exception: If kvm_init() fails, this function should not be called, as the
+ * context would be invalid
+ *
+ * \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 Disable the in-kernel PIT creation
+ *
+ * In-kernel pit is enabled by default. If userspace pit is to be used,
+ * this should be called prior to kvm_create().
+ *
+ *  \param kvm Pointer to the kvm_context
+ */
+void kvm_disable_pit_creation(kvm_context_t kvm);
+
+/*!
+ * \brief Create new virtual machine
+ *
+ * This creates a new virtual machine, maps physical RAM to it, and creates a
+ * virtual CPU for it.\n
+ * \n
+ * Memory gets mapped for addresses 0->0xA0000, 0xC0000->phys_mem_bytes
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param phys_mem_bytes The amount of physical ram you want the VM to have
+ * \param phys_mem This pointer will be set to point to the memory that
+ * kvm_create allocates for physical RAM
+ * \return 0 on success
+ */
+int kvm_create(kvm_context_t kvm,
+	       unsigned long phys_mem_bytes,
+	       void **phys_mem);
+int kvm_create_vm(kvm_context_t kvm);
+int kvm_check_extension(kvm_context_t kvm, int ext);
+void kvm_create_irqchip(kvm_context_t kvm);
+
+/*!
+ * \brief Create a new virtual cpu
+ *
+ * This creates a new virtual cpu (the first vcpu is created by kvm_create()).
+ * Should be called from a thread dedicated to the vcpu.
+ *
+ * \param kvm kvm context
+ * \param slot vcpu number (> 0)
+ * \return 0 on success, -errno on failure
+ */
+int kvm_create_vcpu(kvm_context_t kvm, int slot);
+
+/*!
+ * \brief Start the VCPU
+ *
+ * This starts the VCPU and virtualization is started.\n
+ * \n
+ * This function will not return until any of these conditions are met:
+ * - An IO/MMIO handler does not return "0"
+ * - An exception that neither the guest OS, nor KVM can handle occurs
+ *
+ * \note This function will call the callbacks registered in kvm_init()
+ * to emulate those functions
+ * \note If you at any point want to interrupt the VCPU, kvm_run() will
+ * listen to the EINTR signal. This allows you to simulate external interrupts
+ * and asyncronous IO.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should be started
+ * \return 0 on success, but you really shouldn't expect this function to
+ * return except for when an error has occured, or when you have sent it
+ * an EINTR signal.
+ */
+int kvm_run(kvm_context_t kvm, int vcpu, void *env);
+
+/*!
+ * \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 Read VCPU registers
+ *
+ * This gets the GP registers from the VCPU and outputs them
+ * into a kvm_regs structure
+ *
+ * \note This function returns a \b copy of the VCPUs registers.\n
+ * If you wish to modify the VCPUs GP registers, you should call kvm_set_regs()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_regs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs);
+
+/*!
+ * \brief Write VCPU registers
+ *
+ * This sets the GP registers on the VCPU from a kvm_regs structure
+ *
+ * \note When this function returns, the regs pointer and the data it points to
+ * can be discarded
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_regs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_set_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs);
+/*!
+ * \brief Read VCPU fpu registers
+ *
+ * This gets the FPU registers from the VCPU and outputs them
+ * into a kvm_fpu structure
+ *
+ * \note This function returns a \b copy of the VCPUs registers.\n
+ * If you wish to modify the VCPU FPU registers, you should call kvm_set_fpu()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param fpu Pointer to a kvm_fpu which will be populated with the VCPUs
+ * fpu registers values
+ * \return 0 on success
+ */
+int kvm_get_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu);
+
+/*!
+ * \brief Write VCPU fpu registers
+ *
+ * This sets the FPU registers on the VCPU from a kvm_fpu structure
+ *
+ * \note When this function returns, the fpu pointer and the data it points to
+ * can be discarded
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param fpu Pointer to a kvm_fpu which holds the new vcpu fpu state
+ * \return 0 on success
+ */
+int kvm_set_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu);
+
+/*!
+ * \brief Read VCPU system registers
+ *
+ * This gets the non-GP registers from the VCPU and outputs them
+ * into a kvm_sregs structure
+ *
+ * \note This function returns a \b copy of the VCPUs registers.\n
+ * If you wish to modify the VCPUs non-GP registers, you should call
+ * kvm_set_sregs()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_sregs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_get_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *regs);
+
+/*!
+ * \brief Write VCPU system registers
+ *
+ * This sets the non-GP registers on the VCPU from a kvm_sregs structure
+ *
+ * \note When this function returns, the regs pointer and the data it points to
+ * can be discarded
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_sregs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_set_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *regs);
+
+#ifdef KVM_CAP_MP_STATE
+/*!
+ *  * \brief Read VCPU MP state
+ *
+ */
+int kvm_get_mpstate(kvm_context_t kvm, int vcpu,
+                    struct kvm_mp_state *mp_state);
+
+/*!
+ *  * \brief Write VCPU MP state
+ *
+ */
+int kvm_set_mpstate(kvm_context_t kvm, int vcpu,
+                    struct kvm_mp_state *mp_state);
+/*!
+ *  * \brief Reset VCPU MP state
+ *
+ */
+static inline int kvm_reset_mpstate(kvm_context_t kvm, int vcpu)
+{
+    struct kvm_mp_state mp_state = {.mp_state = KVM_MP_STATE_UNINITIALIZED};
+    return kvm_set_mpstate(kvm, vcpu, &mp_state);
+}
+#endif
+
+/*!
+ * \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);
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(kvm_context_t, int vcpu, struct kvm_guest_debug *dbg);
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * \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 Setup a vcpu's cpuid instruction emulation
+ *
+ * Set up a table of cpuid function to cpuid outputs.
+ * This call replaces the older kvm_setup_cpuid interface by adding a few
+ * parameters to support cpuid functions that have sub-leaf values.
+ *
+ * \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_cpuid2(kvm_context_t kvm, int vcpu, int nent,
+		     struct kvm_cpuid_entry2 *entries);
+
+/*!
+ * \brief Setting the number of shadow pages to be allocated to the vm
+ *
+ * \param kvm pointer to kvm_context
+ * \param nrshadow_pages number of pages to be allocated
+ */
+int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages);
+
+/*!
+ * \brief Getting the number of shadow pages that are allocated to the vm
+ *
+ * \param kvm pointer to kvm_context
+ * \param nrshadow_pages number of pages to be allocated
+ */
+int kvm_get_shadow_pages(kvm_context_t kvm , unsigned int *nrshadow_pages);
+
+/*!
+ * \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);
+#endif
+
+/*!
+ * \brief Set a vcpu's signal mask for guest mode
+ *
+ * A vcpu can have different signals blocked in guest mode and user mode.
+ * This allows guest execution to be interrupted on a signal, without requiring
+ * that the signal be delivered to a signal handler (the signal can be
+ * dequeued using sigwait(2).
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should be initialized
+ * \param sigset signal mask for guest mode
+ * \return 0 on success, or -errno on error
+ */
+int kvm_set_signal_mask(kvm_context_t kvm, int vcpu, const sigset_t *sigset);
+
+/*!
+ * \brief Dump all VCPU information
+ *
+ * This dumps \b all the information that KVM has about a virtual CPU, namely:
+ * - GP Registers
+ * - System registers (selectors, descriptors, etc)
+ * - VMCS Data
+ * - MSRS
+ * - Pending interrupts
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return 0 on success
+ */
+int kvm_dump_vcpu(kvm_context_t kvm, int vcpu);
+
+/*!
+ * \brief Dump VCPU registers
+ *
+ * This dumps some of the information that KVM has about a virtual CPU, namely:
+ * - GP Registers
+ *
+ * A much more verbose version of this is available as kvm_dump_vcpu()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return 0 on success
+ */
+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 log, int writable);
+void kvm_destroy_phys_mem(kvm_context_t, unsigned long phys_start, 
+			  unsigned long len);
+void kvm_unregister_memory_area(kvm_context_t, uint64_t phys_start,
+                                unsigned long len);
+
+int kvm_is_containing_region(kvm_context_t kvm, unsigned long phys_start, unsigned long size);
+int kvm_register_phys_mem(kvm_context_t kvm,
+			unsigned long phys_start, void *userspace_addr,
+			unsigned long len, int log);
+int kvm_get_dirty_pages(kvm_context_t, unsigned long phys_addr, void *buf);
+int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
+			      unsigned long end_addr, void *buf, void*opaque,
+			      int (*cb)(unsigned long start, unsigned long len,
+					void*bitmap, void *opaque));
+int kvm_register_coalesced_mmio(kvm_context_t kvm,
+				uint64_t addr, uint32_t size);
+int kvm_unregister_coalesced_mmio(kvm_context_t kvm,
+				  uint64_t addr, uint32_t size);
+
+/*!
+ * \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,
+			    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, uint64_t phys_start);
+
+/*!
+ * \brief Get a bitmap of guest ram pages which are allocated to the guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param phys_addr Memory slot phys addr
+ * \param bitmap Long aligned address of a big enough bitmap (one bit per page)
+ */
+int kvm_get_mem_map(kvm_context_t kvm, unsigned long phys_addr, void *bitmap);
+int kvm_get_mem_map_range(kvm_context_t kvm, unsigned long phys_addr,
+			   unsigned long len, void *buf, void *opaque,
+			   int (*cb)(unsigned long start,unsigned long len,
+				     void* bitmap, void* opaque));
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status);
+
+int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm,
+				    uint64_t phys_start,
+				    uint64_t len);
+int kvm_dirty_pages_log_disable_slot(kvm_context_t kvm,
+				     uint64_t phys_start,
+				     uint64_t len);
+/*!
+ * \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);
+
+int kvm_has_sync_mmu(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);
+
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * \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
+
+/*!
+ * \brief Simulate an NMI
+ *
+ * This allows you to simulate a non-maskable interrupt.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return 0 on success
+ */
+int kvm_inject_nmi(kvm_context_t kvm, int vcpu);
+
+#endif
+
+/*!
+ * \brief Query wheather in kernel pit is used
+ *
+ *  \param kvm Pointer to the current kvm_context
+ */
+int kvm_pit_in_kernel(kvm_context_t kvm);
+
+/*!
+ * \brief Initialize coalesced MMIO
+ *
+ * Check for coalesced MMIO capability and store in context
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_init_coalesced_mmio(kvm_context_t kvm);
+
+#ifdef KVM_CAP_PIT
+
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * \brief Get in kernel PIT of the virtual domain
+ *
+ * Save the PIT state.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param s PIT state of the virtual domain
+ */
+int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s);
+
+/*!
+ * \brief Set in kernel PIT of the virtual domain
+ *
+ * Restore the PIT state.
+ * Timer would be retriggerred after restored.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param s PIT state of the virtual domain
+ */
+int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s);
+#endif
+
+int kvm_reinject_control(kvm_context_t kvm, int pit_reinject);
+
+#endif
+
+#ifdef KVM_CAP_VAPIC
+
+/*!
+ * \brief Enable kernel tpr access reporting
+ *
+ * When tpr access reporting is enabled, the kernel will call the
+ * ->tpr_access() callback every time the guest vcpu accesses the tpr.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu vcpu to enable tpr access reporting on
+ */
+int kvm_enable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
+
+/*!
+ * \brief Disable kernel tpr access reporting
+ *
+ * Undoes the effect of kvm_enable_tpr_access_reporting().
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu vcpu to disable tpr access reporting on
+ */
+int kvm_disable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
+
+int kvm_enable_vapic(kvm_context_t kvm, int vcpu, uint64_t vapic);
+
+#endif
+
+#if defined(__s390__)
+int kvm_s390_initial_reset(kvm_context_t kvm, int slot);
+int kvm_s390_interrupt(kvm_context_t kvm, int slot,
+	struct kvm_s390_interrupt *kvmint);
+int kvm_s390_set_initial_psw(kvm_context_t kvm, int slot, psw_t psw);
+int kvm_s390_store_status(kvm_context_t kvm, int slot, unsigned long addr);
+#endif
+
+#ifdef KVM_CAP_DEVICE_ASSIGNMENT
+/*!
+ * \brief Notifies host kernel about a PCI device to be assigned to a guest
+ *
+ * Used for PCI device assignment, this function notifies the host
+ * kernel about the assigning of the physical PCI device to a guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_dev Parameters, like bus, devfn number, etc
+ */
+int kvm_assign_pci_device(kvm_context_t kvm,
+			  struct kvm_assigned_pci_dev *assigned_dev);
+
+/*!
+ * \brief Assign IRQ for an assigned device
+ *
+ * Used for PCI device assignment, this function assigns IRQ numbers for
+ * an physical device and guest IRQ handling.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_irq Parameters, like dev id, host irq, guest irq, etc
+ */
+int kvm_assign_irq(kvm_context_t kvm,
+		   struct kvm_assigned_irq *assigned_irq);
+
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+/*!
+ * \brief Deassign IRQ for an assigned device
+ *
+ * Used for PCI device assignment, this function deassigns IRQ numbers
+ * for an assigned device.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_irq Parameters, like dev id, host irq, guest irq, etc
+ */
+int kvm_deassign_irq(kvm_context_t kvm,
+                   struct kvm_assigned_irq *assigned_irq);
+#endif
+#endif
+
+/*!
+ * \brief Determines whether destroying memory regions is allowed
+ *
+ * KVM before 2.6.29 had a bug when destroying memory regions.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_destroy_memory_region_works(kvm_context_t kvm);
+
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+/*!
+ * \brief Notifies host kernel about a PCI device to be deassigned from a guest
+ *
+ * Used for hot remove PCI device, this function notifies the host
+ * kernel about the deassigning of the physical PCI device from a guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_dev Parameters, like bus, devfn number, etc
+ */
+int kvm_deassign_pci_device(kvm_context_t kvm,
+			    struct kvm_assigned_pci_dev *assigned_dev);
+#endif
+
+/*!
+ * \brief Checks whether the generic irq routing capability is present
+ *
+ * Checks whether kvm can reroute interrupts among the various interrupt
+ * controllers.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_has_gsi_routing(kvm_context_t kvm);
+
+/*!
+ * \brief Determines the number of gsis that can be routed
+ *
+ * Returns the number of distinct gsis that can be routed by kvm.  This is
+ * also the number of distinct routes (if a gsi has two routes, than another
+ * gsi cannot be used...)
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_get_gsi_count(kvm_context_t kvm);
+
+/*!
+ * \brief Clears the temporary irq routing table
+ *
+ * Clears the temporary irq routing table.  Nothing is committed to the
+ * running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_clear_gsi_routes(kvm_context_t kvm);
+
+/*!
+ * \brief Adds an irq route to the temporary irq routing table
+ *
+ * Adds an irq route to the temporary irq routing table.  Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
+
+/*!
+ * \brief Removes an irq route from the temporary irq routing table
+ *
+ * Adds an irq route to the temporary irq routing table.  Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
+
+struct kvm_irq_routing_entry;
+/*!
+ * \brief Adds a routing entry to the temporary irq routing table
+ *
+ * Adds a filled routing entry to the temporary irq routing table. Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_add_routing_entry(kvm_context_t kvm,
+                          struct kvm_irq_routing_entry* entry);
+
+/*!
+ * \brief Removes a routing from the temporary irq routing table
+ *
+ * Remove a routing to the temporary irq routing table.  Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_del_routing_entry(kvm_context_t kvm,
+		          struct kvm_irq_routing_entry* entry);
+
+/*!
+ * \brief Commit the temporary irq routing table
+ *
+ * Commit the temporary irq routing table to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_commit_irq_routes(kvm_context_t kvm);
+
+/*!
+ * \brief Get unused GSI number for irq routing table
+ *
+ * Get unused GSI number for irq routing table
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_get_irq_route_gsi(kvm_context_t kvm);
+
+#ifdef KVM_CAP_DEVICE_MSIX
+int kvm_assign_set_msix_nr(kvm_context_t kvm,
+			   struct kvm_assigned_msix_nr *msix_nr);
+int kvm_assign_set_msix_entry(kvm_context_t kvm,
+                              struct kvm_assigned_msix_entry *entry);
+#endif
+
+uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg);
+
+#endif
diff --git a/kvm/scripts/65-kvm.rules b/kvm/scripts/65-kvm.rules
new file mode 100644
index 0000000..481cfcf
--- /dev/null
+++ b/kvm/scripts/65-kvm.rules
@@ -0,0 +1 @@
+KERNEL=="kvm", NAME="%k", GROUP="kvm", MODE="0660"
diff --git a/kvm/scripts/kvm b/kvm/scripts/kvm
new file mode 100755
index 0000000..cddc931
--- /dev/null
+++ b/kvm/scripts/kvm
@@ -0,0 +1,226 @@
+#!/bin/sh
+# kvm init script              Takes care for all VMM tasks
+#
+# chkconfig: - 99 01
+# description: The KVM is a kernel level Virtual Machine Monitor.  \
+#              Currently it starts a bridge and attached eth0 for it
+
+dir=$(dirname "$0")
+
+ifnum=${ifnum:-$(ip route list | awk '/^default / { print $NF }' | sed 's/^[^0-9]*//')}
+ifnum=${ifnum:-0}
+switch=${sw0:-sw${ifnum}}
+pif=${pif:-eth${ifnum}}
+antispoof=${antispoof:-no}
+command=$1
+
+if [ -f /etc/sysconfig/network-scripts/network-functions ]; then
+    . /etc/sysconfig/network-scripts/network-functions
+fi
+
+#check for bonding link aggregation
+bond_int=$(awk < /etc/sysconfig/network-scripts/ifcfg-${pif} '/^MASTER=/ { print $BF }' | sed 's/MASTER=//')
+if [ ${bond_int}"0" != "0" ]; then
+	pif=${bond_int}
+fi
+
+if [ -f /etc/sysconfig/network-scripts/ifcfg-${pif} ]; then
+    . /etc/sysconfig/network-scripts/ifcfg-${pif}
+fi
+
+get_ip_info() {
+    addr=`ip addr show dev $1 | egrep '^ *inet' | sed -e 's/ *inet //' -e 's/ .*//'`
+    gateway=$(ip route list | awk '/^default / { print $3 }')
+    broadcast=$(/sbin/ip addr show dev $1 | grep inet | awk '/brd / { print $4 }')
+}
+
+#When a bonding device link goes down, its slave interfaces
+#are getting detached so they should be re-added
+bond_link_up () {
+    dev=$1
+    is_bonding=$(echo ${dev} | awk '/^bond/ { print $NF }')
+    if [ ${is_bonding}"0" != "0" ]; then
+	for slave in `awk < /proc/net/bonding/bond0 '/Slave Interface: / {print $3 }'`; do
+		ifenslave $dev $slave
+	done
+    fi
+}
+
+
+do_ifup() {
+     if [ ${addr} ] ; then
+        ip addr flush $1 
+        bond_link_up $1
+        ip addr add ${addr} broadcast ${broadcast} dev $1 
+        ip link set dev $1 up
+     fi
+}
+
+link_exists()
+{
+    if ip link show "$1" >/dev/null 2>/dev/null
+    then
+        return 0
+    else
+        return 1
+    fi
+}
+
+create_switch () {
+    local switch=$1
+
+    if [ ! -e "/sys/class/net/${switch}/bridge" ]; then
+	brctl addbr ${switch} >/dev/null 2>&1
+	brctl stp ${switch} off >/dev/null 2>&1
+	brctl setfd ${switch} 0.1 >/dev/null 2>&1
+    fi
+    ip link set ${switch} up >/dev/null 2>&1
+}
+
+
+add_to_switch () {
+    local switch=$1
+    local dev=$2
+
+    if [ ! -e "/sys/class/net/${switch}/brif/${dev}" ]; then
+    	brctl addif ${switch} ${dev} >/dev/null 2>&1
+    fi
+
+    ip link set ${dev} up >/dev/null 2>&1
+}
+
+#taken from Xen
+transfer_routes () {
+    local src=$1
+    local dst=$2
+    # List all routes and grep the ones with $src in.
+    # Stick 'ip route del' on the front to delete.
+    # Change $src to $dst and use 'ip route add' to add.
+    ip route list | sed -ne "
+/dev ${src}\( \|$\)/ {
+  h
+  s/^/ip route del /
+  P
+  g
+  s/${src}/${dst}/
+  s/^/ip route add /
+  P
+  d
+}" | sh -e
+}
+
+
+change_ips() {
+    local src=$1
+    local dst=$2
+
+    #take care also for case we do not have /etc/sysconfig data (the switch as a src case)
+    if [ -x $BOOTPROTO ]; then
+        if [ -x $(pgrep dhclient) ];then
+           BOOTPROTO="null"
+        else
+            BOOTPROTO="dhcp"
+        fi
+    fi
+
+    if [ $BOOTPROTO = "dhcp" ]; then
+        ifdown ${src} >/dev/null 2>&1 || true
+        ip link set ${src} up >/dev/null 2>&1
+        bond_link_up ${src}
+        pkill dhclient >/dev/null 2>&1
+	for ((i=0;i<3;i++)); do
+	    pgrep dhclient >/dev/null 2>&1 || i=4	
+   	    sleep 1
+	done
+        dhclient ${dst} >/dev/null 2>&1
+    else
+        get_ip_info ${src}
+        ifconfig ${src} 0.0.0.0
+        do_ifup ${dst}
+        transfer_routes ${src} ${dst}
+        ip route add default via ${gateway} dev ${dst}
+    fi
+}
+               
+antispoofing () {
+    iptables -P FORWARD DROP >/dev/null 2>&1
+    iptables -F FORWARD >/dev/null 2>&1
+    iptables -A FORWARD -m physdev --physdev-in ${dev} -j ACCEPT >/dev/null 2>&1
+}
+
+status () {
+    local dev=$1
+    local sw=$2
+    
+    echo '============================================================'
+    ip addr show ${dev}
+    ip addr show ${sw}
+    echo ' '
+    brctl show ${sw}
+    echo ' '
+    ip route list
+    echo ' '
+    route -n
+    echo '============================================================'
+    gateway=$(ip route list | awk '/^default / { print $3 }')
+    ping -c 1 ${gateway} || true
+    echo '============================================================'
+}
+
+start () {
+    if [ "${switch}" = "null" ] ; then
+	return
+    fi
+
+    create_switch ${switch}
+    add_to_switch ${switch} ${pif}
+    change_ips ${pif} ${switch}
+
+    if [ ${antispoof} = 'yes' ] ; then
+	antispoofing
+    fi
+
+    grep -q GenuineIntel /proc/cpuinfo && /sbin/modprobe kvm-intel
+    grep -q AuthenticAMD /proc/cpuinfo && /sbin/modprobe kvm-amd
+}
+
+stop () {
+    if [ "${switch}" = "null" ]; then
+	return
+    fi
+    if ! link_exists "$switch"; then
+	return
+    fi
+
+    change_ips ${switch} ${pif}
+    ip link set ${switch} down
+    brctl delbr ${switch}
+
+    grep -q GenuineIntel /proc/cpuinfo && /sbin/modprobe -r kvm-intel
+    grep -q AuthenticAMD /proc/cpuinfo && /sbin/modprobe -r kvm-amd
+    /sbin/modprobe -r kvm
+}
+
+
+case "$command" in
+    start)
+	echo -n $"Starting KVM: "
+	start
+	echo
+	;;
+    
+    stop)
+	echo -n $"Shutting down KVM: "
+	stop
+	echo
+	;;
+
+    status)
+	status ${pif} ${switch}
+	;;
+
+    *)
+	echo "Unknown command: $command" >&2
+	echo 'Valid commands are: start, stop, status' >&2
+	exit 1
+esac
diff --git a/kvm/scripts/make-combined-release b/kvm/scripts/make-combined-release
new file mode 100755
index 0000000..adef8f6
--- /dev/null
+++ b/kvm/scripts/make-combined-release
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+
+import sys, tarfile, os.path
+
+# usage: $0 combined.tar.gz qemu.tar.gz kvm-kmod.tar.gz
+
+outname, qemuname, kmodname = sys.argv[1:4]
+
+out = tarfile.open(name = outname, mode = 'w:gz')
+
+def tarcopy(dst, src, transform):
+    for member in src:
+        f = src.extractfile(member)
+        member.name = transform(member.name)
+        dst.addfile(member, f)
+
+def stem(fname):
+    fname = os.path.basename(fname)
+    if fname.endswith('.tar.gz'):
+        fname = fname[:-7]
+    return fname
+
+def transformer(old, new):
+    def transform(fname):
+        if fname.startswith(old + '/'):
+            fname = new + fname[len(old):]
+        return fname
+    return transform
+
+tarcopy(out, tarfile.open(name = qemuname),
+        transformer(stem(qemuname), stem(outname)))
+
+tarcopy(out, tarfile.open(name = kmodname),
+        transformer(stem(kmodname), stem(outname) + '/kvm/kernel'))
+
+
diff --git a/kvm/scripts/make-release b/kvm/scripts/make-release
new file mode 100755
index 0000000..11d9c27
--- /dev/null
+++ b/kvm/scripts/make-release
@@ -0,0 +1,67 @@
+#!/bin/bash -e
+
+usage() {
+    echo "usage: $0 [--upload] [--formal] commit [name]"
+    exit 1
+}
+
+[[ -f ~/.kvmreleaserc ]] && . ~/.kvmreleaserc
+
+upload=
+formal=
+
+releasedir=~/sf-release
+[[ -z "$TMP" ]] && TMP="/tmp"
+tmpdir="$TMP/qemu-kvm-make-release.$$"
+while [[ "$1" = -* ]]; do
+    opt="$1"
+    shift
+    case "$opt" in
+	--upload)
+	    upload="yes"
+	    ;;
+	--formal)
+	    formal="yes"
+	    ;;
+	*)
+	    usage
+	    ;;
+    esac
+done
+
+commit="$1"
+name="$2"
+
+if [[ -z "$commit" ]]; then
+    usage
+fi
+
+if [[ -z "$name" ]]; then
+    name="$commit"
+fi
+
+tarball="$releasedir/$name.tar"
+
+cd "$(dirname "$0")"/../..
+git archive --prefix="$name/" --format=tar "$commit" > "$tarball"
+
+mkdir -p "$tmpdir"
+git cat-file -p "${commit}:roms" | awk ' { print $4, $3 } ' \
+    > "$tmpdir/EXTERNAL_DEPENDENCIES"
+tar -rf "$tarball" --transform "s,^,$name/," -C "$tmpdir" \
+    "EXTERNAL_DEPENDENCIES"
+rm -rf "$tmpdir"
+
+if [[ -n "$formal" ]]; then
+    mkdir -p "$tmpdir"
+    echo "$name" > "$tmpdir/KVM_VERSION"
+    tar -rf "$tarball" --transform "s,^,$name/," -C "$tmpdir" "KVM_VERSION"
+    rm -rf "$tmpdir"
+fi
+
+gzip -9 "$tarball"
+tarball="$tarball.gz"
+
+if [[ -n "$upload" ]]; then
+    rsync --progress -h "$tarball" avik@frs.sourceforge.net:uploads/
+fi
diff --git a/kvm/scripts/mkbootdisk b/kvm/scripts/mkbootdisk
new file mode 100755
index 0000000..3b7f7c0
--- /dev/null
+++ b/kvm/scripts/mkbootdisk
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+set -e
+
+kernel="$1"
+mnt_dir="/tmp/mkbootdisk/mnt"
+img_file="/tmp/mkbootdisk/boot.img"
+
+[[ -f "$kernel" ]] || { echo need kernel; exit 1; }
+
+mkdir -p $mnt_dir
+
+[[ -d "$mnt_dir" ]] || { echo mount dir err; exit 1; }
+
+dd < /dev/zero > $img_file bs=1M count=10
+mkfs -t vfat $img_file
+
+mount -o loop $img_file $mnt_dir
+
+cp "$kernel" $mnt_dir/kernel
+
+cat <<EOF > $mnt_dir/SYSLINUX.CFG
+DEFAULT kernel
+APPEND console=ttyS0
+EOF
+
+umount $mnt_dir
+
+syslinux $img_file
+
diff --git a/kvm/scripts/qemu-ifup b/kvm/scripts/qemu-ifup
new file mode 100755
index 0000000..284b176
--- /dev/null
+++ b/kvm/scripts/qemu-ifup
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+switch=$(/sbin/ip route list | awk '/^default / { print $5 }')
+/sbin/ifconfig $1 0.0.0.0 up
+/usr/sbin/brctl addif ${switch} $1
diff --git a/kvm/scripts/run_img b/kvm/scripts/run_img
new file mode 100755
index 0000000..10c7497
--- /dev/null
+++ b/kvm/scripts/run_img
@@ -0,0 +1,4 @@
+sudo /sbin/rmmod kvm
+sudo /sbin/insmod ../kernel/kvm.ko
+sudo chmod a+rw /dev/hvm
+../qemu/x86_64-softmmu/qemu-system-x86_64 -boot c -L /usr/share/qemu -hda /tmp/mkbootdisk/boot.img -m 384 -serial file:/tmp/qemu_serial.out
diff --git a/kvm/scripts/vmxcap b/kvm/scripts/vmxcap
new file mode 100755
index 0000000..b7f58ac
--- /dev/null
+++ b/kvm/scripts/vmxcap
@@ -0,0 +1,215 @@
+#!/usr/bin/python
+
+MSR_IA32_VMX_BASIC = 0x480
+MSR_IA32_VMX_PINBASED_CTLS = 0x481
+MSR_IA32_VMX_PROCBASED_CTLS = 0x482
+MSR_IA32_VMX_EXIT_CTLS = 0x483
+MSR_IA32_VMX_ENTRY_CTLS = 0x484
+MSR_IA32_VMX_MISC_CTLS = 0x485
+MSR_IA32_VMX_PROCBASED_CTLS2 = 0x48B
+MSR_IA32_VMX_EPT_VPID_CAP = 0x48C
+MSR_IA32_VMX_TRUE_PINBASED_CTLS = 0x48D
+MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E
+MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F
+MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490
+
+class msr(object):
+    def __init__(self):
+        try:
+            self.f = file('/dev/cpu/0/msr')
+        except:
+            self.f = file('/dev/msr0')
+    def read(self, index, default = None):
+        import struct
+        self.f.seek(index)
+        try:
+            return struct.unpack('Q', self.f.read(8))[0]
+        except:
+            return default
+
+class Control(object):
+    def __init__(self, name, bits, cap_msr, true_cap_msr = None):
+        self.name = name
+        self.bits = bits
+        self.cap_msr = cap_msr
+        self.true_cap_msr = true_cap_msr
+    def read2(self, nr):
+        m = msr()
+        val = m.read(nr, 0)
+        return (val & 0xffffffff, val >> 32)
+    def show(self):
+        print self.name
+        mbz, mb1 = self.read2(self.cap_msr)
+        tmbz, tmb1 = 0, 0
+        if self.true_cap_msr:
+            tmbz, tmb1 = self.read2(self.true_cap_msr)
+        for bit in sorted(self.bits.keys()):
+            zero = not (mbz & (1 << bit))
+            one = mb1 & (1 << bit)
+            true_zero = not (tmbz & (1 << bit))
+            true_one = tmb1 & (1 << bit)
+            s= '?'
+            if (self.true_cap_msr and true_zero and true_one
+                and one and not zero):
+                s = 'default'
+            elif zero and not one:
+                s = 'no'
+            elif one and not zero:
+                s = 'forced'
+            elif one and zero:
+                s = 'yes'
+            print '  %-40s %s' % (self.bits[bit], s)
+
+class Misc(object):
+    def __init__(self, name, bits, msr):
+        self.name = name
+        self.bits = bits
+        self.msr = msr
+    def show(self):
+        print self.name
+        value = msr().read(self.msr, 0)
+        def first_bit(key):
+            if type(key) is tuple:
+                return key[0]
+            else:
+                return key
+        for bits in sorted(self.bits.keys(), key = first_bit):
+            if type(bits) is tuple:
+                lo, hi = bits
+                fmt = int
+            else:
+                lo = hi = bits
+                def fmt(x):
+                    return { True: 'yes', False: 'no' }[x]
+            v = (value >> lo) & ((1 << (hi - lo + 1)) - 1)
+            print '  %-40s %s' % (self.bits[bits], fmt(v))
+
+controls = [
+    Control(
+        name = 'pin-based controls',
+        bits = {
+            0: 'External interrupt exiting',
+            3: 'NMI exiting',
+            5: 'Virtual NMIs',
+            6: 'Activate VMX-preemption timer',
+            },
+        cap_msr = MSR_IA32_VMX_PINBASED_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+        ),
+
+    Control(
+        name = 'primary processor-based controls',
+        bits = {
+            2: 'Interrupt window exiting',
+            3: 'Use TSC offsetting',
+            7: 'HLT exiting',
+            9: 'INVLPG exiting',
+            10: 'MWAIT exiting',
+            11: 'RDPMC exiting',
+            12: 'RDTSC exiting',
+            15: 'CR3-load exiting',
+            16: 'CR3-store exiting',
+            19: 'CR8-load exiting',
+            20: 'CR8-store exiting',
+            21: 'Use TPR shadow',
+            22: 'NMI-window exiting',
+            23: 'MOV-DR exiting',
+            24: 'Unconditional I/O exiting',
+            25: 'Use I/O bitmaps',
+            27: 'Monitor trap flag',
+            28: 'Use MSR bitmaps',
+            29: 'MONITOR exiting',
+            30: 'PAUSE exiting',
+            31: 'Activate secondary control',
+            },
+        cap_msr = MSR_IA32_VMX_PROCBASED_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+        ),
+
+    Control(
+        name = 'secondary processor-based controls',
+        bits = {
+            0: 'Virtualize APIC accesses',
+            1: 'Enable EPT',
+            2: 'Descriptor-table exiting',
+            4: 'Virtualize x2APIC mode',
+            5: 'Enable VPID',
+            6: 'WBINVD exiting',
+            7: 'Unrestricted guest',
+            10: 'PAUSE-loop exiting',
+            },
+        cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2,
+        ),
+
+    Control(
+        name = 'VM-Exit controls',
+        bits = {
+            2: 'Save debug controls',
+            9: 'Host address-space size',
+            12: 'Load IA32_PERF_GLOBAL_CTRL',
+            15: 'Acknowledge interrupt on exit',
+            18: 'Save IA32_PAT',
+            19: 'Load IA32_PAT',
+            20: 'Save IA32_EFER',
+            21: 'Load IA32_EFER',
+            22: 'Save VMX-preemption timer value',
+            },
+        cap_msr = MSR_IA32_VMX_EXIT_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS,
+        ),
+
+    Control(
+        name = 'VM-Entry controls',
+        bits = {
+            2: 'Load debug controls',
+            9: 'IA-64 mode guest',
+            10: 'Entry to SMM',
+            11: 'Deactivate dual-monitor treatment',
+            13: 'Load IA32_PERF_GLOBAL_CTRL',
+            14: 'Load IA32_PAT',
+            15: 'Load IA32_EFER',
+            },
+        cap_msr = MSR_IA32_VMX_ENTRY_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+        ),
+
+    Misc(
+        name = 'Miscellaneous data',
+        bits = {
+            (0,4): 'VMX-preemption timer scale (log2)',
+            5: 'Store EFER.LMA into IA-32e mode guest control',
+            6: 'HLT activity state',
+            7: 'Shutdown activity state',
+            8: 'Wait-for-SIPI activity state',
+            (16,24): 'Number of CR3-target values',
+            (25,27): 'MSR-load/store count recommenation',
+            (32,62): 'MSEG revision identifier',
+            },
+        msr = MSR_IA32_VMX_MISC_CTLS,
+        ),
+
+    Misc(
+        name = 'VPID and EPT capabilities',
+        bits = {
+            0: 'Execute-only EPT translations',
+            6: 'Page-walk length 4',
+            8: 'Paging-structure memory type UC',
+            14: 'Paging-structure memory type WB',
+            16: '2MB EPT pages',
+            20: 'INVEPT supported',
+            25: 'Single-context INVEPT',
+            26: 'All-context INVEPT',
+            32: 'INVVPID supported',
+            40: 'Individual-address INVVPID',
+            41: 'Single-context INVVPID',
+            42: 'All-context INVVPID',
+            43: 'Single-context-retaining-globals INVVPID',
+            },
+        msr = MSR_IA32_VMX_EPT_VPID_CAP,
+        ),
+    ]
+
+for c in controls:
+    c.show()
+
+
diff --git a/kvm/user/COPYRIGHT b/kvm/user/COPYRIGHT
new file mode 100644
index 0000000..d35649c
--- /dev/null
+++ b/kvm/user/COPYRIGHT
@@ -0,0 +1,4 @@
+Copyright (C) 2006 Qumranet.
+
+The files in this directory and its subdirectories are licensed under the
+GNU LGPL, version 2.
diff --git a/kvm/user/Makefile b/kvm/user/Makefile
new file mode 100644
index 0000000..ed462bb
--- /dev/null
+++ b/kvm/user/Makefile
@@ -0,0 +1,60 @@
+
+include config.mak
+
+DESTDIR :=
+
+.PHONY: arch_clean clean
+
+#make sure env CFLAGS variable is not used
+CFLAGS =
+
+libgcc := $(shell $(CC) --print-libgcc-file-name)
+
+libcflat := test/lib/libcflat.a
+cflatobjs := \
+	test/lib/panic.o \
+	test/lib/printf.o \
+	test/lib/string.o
+
+#include architecure specific make rules
+include config-$(ARCH).mak
+
+# cc-option
+# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
+
+cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
+              > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+
+CFLAGS += -O1
+CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
+CFLAGS += $(call cc-option, -fno-stack-protector, "")
+CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
+CFLAGS += -I../include
+CFLAGS += -I ../libkvm
+
+LDFLAGS += $(CFLAGS) -L ../libkvm
+
+CXXFLAGS = $(autodepend-flags)
+
+autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
+
+LDFLAGS += -pthread -lrt
+
+kvmtrace_objs= kvmtrace.o
+
+kvmctl: $(kvmctl_objs)
+	$(CC) $(LDFLAGS) $^ -o $@
+
+kvmtrace: $(kvmtrace_objs)
+	$(CC) $(LDFLAGS) $^ -o $@
+
+$(libcflat): $(cflatobjs)
+	$(AR) rcs $@ $^
+
+%.o: %.S
+	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
+
+-include .*.d
+
+clean: arch_clean
+	$(RM) kvmctl kvmtrace *.o *.a .*.d $(libcflat) $(cflatobjs)
diff --git a/kvm/user/balloon_ctl.c b/kvm/user/balloon_ctl.c
new file mode 100755
index 0000000..e65b08d
--- /dev/null
+++ b/kvm/user/balloon_ctl.c
@@ -0,0 +1,92 @@
+/*
+ * This binary provides access to the guest's balloon driver
+ * module.
+ *
+ * Copyright (C) 2007 Qumranet
+ *
+ * Author:
+ *
+ *  Dor Laor <dor.laor@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#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>
+
+#define __user
+#include <linux/kvm.h>
+
+#define PAGE_SIZE 4096ul
+
+
+static int balloon_op(int *fd, int bytes)
+{
+	struct kvm_balloon_op bop;
+        int r;
+
+	bop.npages = bytes/PAGE_SIZE;
+	r = ioctl(*fd, KVM_BALLOON_OP, &bop);
+	if (r == -1)
+		return -errno;
+	printf("Ballon handled %d pages successfully\n", bop.npages);
+
+	return 0;
+}
+
+static int balloon_init(int *fd)
+{
+	*fd = open("/dev/kvm_balloon", O_RDWR);
+	if (*fd == -1) {
+		perror("open /dev/kvm_balloon");
+		return -1;
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int r;
+	int bytes;
+
+	if (argc != 3) {
+		perror("Please provide op=[i|d], bytes\n");
+		return 1;
+	}
+	bytes = atoi(argv[2]);
+
+	switch (*argv[1]) {
+	case 'i':
+		break;
+	case 'd':
+		bytes = -bytes;
+		break;
+	default:
+		perror("Wrong op param\n");
+		return 1;
+	}
+
+	if (balloon_init(&fd)) {
+		perror("balloon_init failed\n");
+		return 1;
+	}
+
+	if ((r = balloon_op(&fd, bytes))) {
+		perror("balloon_op failed\n");
+		goto out;
+	}
+
+out:
+	close(fd);
+        
+	return r;
+}
+
diff --git a/kvm/user/bootstrap.lds b/kvm/user/bootstrap.lds
new file mode 100644
index 0000000..fd0a4f8
--- /dev/null
+++ b/kvm/user/bootstrap.lds
@@ -0,0 +1,15 @@
+OUTPUT_FORMAT(binary)
+
+SECTIONS
+{
+    . = 0;
+    stext = .;
+    .text : { *(.init) *(.text) }
+    . = ALIGN(4K);
+    .data : { *(.data) }
+    . = ALIGN(16);
+    .bss : { *(.bss) }
+    . = ALIGN(4K);
+    edata = .;
+}
+
diff --git a/kvm/user/config-i386.mak b/kvm/user/config-i386.mak
new file mode 100644
index 0000000..09175d5
--- /dev/null
+++ b/kvm/user/config-i386.mak
@@ -0,0 +1,10 @@
+TEST_DIR=test/x86
+cstart.o = $(TEST_DIR)/cstart.o
+bits = 32
+ldarch = elf32-i386
+CFLAGS += -D__i386__
+CFLAGS += -I $(KERNELDIR)/include
+
+tests=
+
+include config-x86-common.mak
diff --git a/kvm/user/config-ia64.mak b/kvm/user/config-ia64.mak
new file mode 100644
index 0000000..d9350fc
--- /dev/null
+++ b/kvm/user/config-ia64.mak
@@ -0,0 +1,7 @@
+bits = 64
+CFLAGS += -m64
+CFLAGS += -D__ia64__
+CFLAGS += -I../include/ia64
+
+all:
+
diff --git a/kvm/user/config-powerpc-440.mak b/kvm/user/config-powerpc-440.mak
new file mode 100644
index 0000000..12698e6
--- /dev/null
+++ b/kvm/user/config-powerpc-440.mak
@@ -0,0 +1,15 @@
+
+
+# for some reason binutils hates tlbsx unless we say we're 405  :(
+CFLAGS += -Wa,-m405 -I test/lib/powerpc/44x
+
+cflatobjs += \
+	test/lib/powerpc/44x/map.o \
+	test/lib/powerpc/44x/tlbwe.o \
+	test/lib/powerpc/44x/timebase.o
+
+simpletests += \
+	test/powerpc/44x/tlbsx.bin \
+	test/powerpc/44x/tlbwe_16KB.bin \
+	test/powerpc/44x/tlbwe_hole.bin \
+	test/powerpc/44x/tlbwe.bin
diff --git a/kvm/user/config-powerpc.mak b/kvm/user/config-powerpc.mak
new file mode 100644
index 0000000..ec6086b
--- /dev/null
+++ b/kvm/user/config-powerpc.mak
@@ -0,0 +1,39 @@
+CFLAGS += -I../include/powerpc
+CFLAGS += -Wa,-mregnames -I test/lib
+CFLAGS += -ffreestanding
+
+cstart := test/powerpc/cstart.o
+
+cflatobjs += \
+	test/lib/powerpc/io.o
+
+$(libcflat): LDFLAGS += -nostdlib
+
+# these tests do not use libcflat
+simpletests := \
+	test/powerpc/spin.bin \
+	test/powerpc/io.bin \
+	test/powerpc/sprg.bin
+
+# theses tests use cstart.o, libcflat, and libgcc
+tests := \
+	test/powerpc/exit.bin \
+	test/powerpc/helloworld.bin
+
+include config-powerpc-$(PROCESSOR).mak
+
+
+all: kvmtrace kvmctl $(libcflat) $(simpletests) $(tests)
+
+$(simpletests): %.bin: %.o
+	$(CC) -nostdlib $^ -Wl,-T,flat.lds -o $@
+
+$(tests): %.bin: $(cstart) %.o $(libcflat)
+	$(CC) -nostdlib $^ $(libgcc) -Wl,-T,flat.lds -o $@
+
+kvmctl_objs = main-ppc.o iotable.o ../libkvm/libkvm.a
+
+arch_clean:
+	$(RM) $(simpletests) $(tests) $(cstart)
+	$(RM) $(patsubst %.bin, %.elf, $(simpletests) $(tests))
+	$(RM) $(patsubst %.bin, %.o, $(simpletests) $(tests))
diff --git a/kvm/user/config-x86-common.mak b/kvm/user/config-x86-common.mak
new file mode 100644
index 0000000..63cca42
--- /dev/null
+++ b/kvm/user/config-x86-common.mak
@@ -0,0 +1,77 @@
+#This is a make file with common rules for both x86 & x86-64
+
+CFLAGS += -I../include/x86
+
+all: kvmtrace test_cases
+
+balloon_ctl: balloon_ctl.o
+
+cflatobjs += \
+	test/lib/x86/io.o \
+	test/lib/x86/smp.o
+
+cflatobjs += test/lib/x86/fwcfg.o
+cflatobjs += test/lib/x86/apic.o
+
+$(libcflat): LDFLAGS += -nostdlib
+$(libcflat): CFLAGS += -ffreestanding -I test/lib
+
+CFLAGS += -m$(bits)
+
+FLATLIBS = test/lib/libcflat.a $(libgcc)
+%.flat: %.o $(FLATLIBS)
+	$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,flat.lds $^ $(FLATLIBS)
+
+tests-common = $(TEST_DIR)/bootstrap \
+			$(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
+			$(TEST_DIR)/smptest.flat  $(TEST_DIR)/port80.flat \
+			$(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat
+
+test_cases: $(tests-common) $(tests)
+
+$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I test/lib -I test/lib/x86
+ 
+$(TEST_DIR)/bootstrap: $(TEST_DIR)/bootstrap.o
+	$(CC) -nostdlib -o $@ -Wl,-T,bootstrap.lds $^
+ 
+$(TEST_DIR)/access.flat: $(cstart.o) $(TEST_DIR)/access.o $(TEST_DIR)/print.o
+ 
+$(TEST_DIR)/hypercall.flat: $(cstart.o) $(TEST_DIR)/hypercall.o $(TEST_DIR)/print.o
+ 
+$(TEST_DIR)/sieve.flat: $(cstart.o) $(TEST_DIR)/sieve.o \
+		$(TEST_DIR)/print.o $(TEST_DIR)/vm.o
+ 
+$(TEST_DIR)/vmexit.flat: $(cstart.o) $(TEST_DIR)/vmexit.o
+ 
+$(TEST_DIR)/test32.flat: $(TEST_DIR)/test32.o
+
+$(TEST_DIR)/smptest.flat: $(cstart.o) $(TEST_DIR)/smptest.o
+ 
+$(TEST_DIR)/emulator.flat: $(cstart.o) $(TEST_DIR)/emulator.o \
+			   $(TEST_DIR)/vm.o $(TEST_DIR)/print.o
+
+$(TEST_DIR)/port80.flat: $(cstart.o) $(TEST_DIR)/port80.o
+
+$(TEST_DIR)/tsc.flat: $(cstart.o) $(TEST_DIR)/tsc.o
+
+$(TEST_DIR)/apic.flat: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/vm.o \
+		       $(TEST_DIR)/print.o 
+
+$(TEST_DIR)/realmode.flat: $(TEST_DIR)/realmode.o
+	$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
+
+$(TEST_DIR)/realmode.o: bits = 32
+
+$(TEST_DIR)/memtest1.flat: $(TEST_DIR)/memtest1.o
+
+$(TEST_DIR)/stringio.flat: $(TEST_DIR)/stringio.o
+
+$(TEST_DIR)/simple.flat: $(TEST_DIR)/simple.o
+
+$(TEST_DIR)/msr.flat: $(cstart.o) $(TEST_DIR)/msr.o
+
+arch_clean:
+	$(RM) $(TEST_DIR)/bootstrap $(TEST_DIR)/*.o $(TEST_DIR)/*.flat \
+	$(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
+
+-include $(TEST_DIR)/.*.d test/lib/.*.d test/lib/x86/.*.d
diff --git a/kvm/user/config-x86_64.mak b/kvm/user/config-x86_64.mak
new file mode 100644
index 0000000..97990bb
--- /dev/null
+++ b/kvm/user/config-x86_64.mak
@@ -0,0 +1,12 @@
+TEST_DIR=test/x86
+cstart.o = $(TEST_DIR)/cstart64.o
+bits = 64
+ldarch = elf64-x86-64
+CFLAGS += -D__x86_64__
+
+tests = $(TEST_DIR)/access.flat $(TEST_DIR)/sieve.flat \
+      $(TEST_DIR)/simple.flat $(TEST_DIR)/stringio.flat \
+      $(TEST_DIR)/memtest1.flat $(TEST_DIR)/emulator.flat \
+      $(TEST_DIR)/hypercall.flat $(TEST_DIR)/apic.flat
+
+include config-x86-common.mak
diff --git a/kvm/user/configure b/kvm/user/configure
new file mode 100755
index 0000000..efb8705
--- /dev/null
+++ b/kvm/user/configure
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+prefix=/usr/local
+kerneldir=/lib/modules/$(uname -r)/build
+cc=gcc
+ld=ld
+objcopy=objcopy
+ar=ar
+arch=`uname -m | sed -e s/i.86/i386/`
+processor="$arch"
+cross_prefix=
+
+usage() {
+    cat <<-EOF
+	Usage: $0 [options]
+
+	Options include:
+	    --arch=ARCH            architecture to compile for ($arch)
+	    --cross-prefix=PREFIX  cross compiler prefix
+	    --cc=CC		   c compiler to use ($cc)
+	    --ld=LD		   ld linker to use ($ld)
+	    --prefix=PREFIX        where to install things ($prefix)
+	    --kerneldir=DIR        kernel build directory for kvm.h ($kerneldir)
+EOF
+    exit 1
+}
+
+while [[ "$1" = -* ]]; do
+    opt="$1"; shift
+    arg=
+    if [[ "$opt" = *=* ]]; then
+	arg="${opt#*=}"
+	opt="${opt%%=*}"
+    fi
+    case "$opt" in
+	--prefix)
+	    prefix="$arg"
+	    ;;
+	--kerneldir)
+	    kerneldir="$arg"
+	    ;;
+        --arch)
+	    arch="$arg"
+	    ;;
+        --processor)
+	    processor="$arg"
+	    ;;
+	--cross-prefix)
+	    cross_prefix="$arg"
+	    ;;
+	--cc)
+	    cc="$arg"
+	    ;;
+	--ld)
+	    ld="$arg"
+	    ;;
+	--help)
+	    usage
+	    ;;
+	*)
+	    usage
+	    ;;
+    esac
+done
+
+cat <<EOF > config.mak
+PREFIX=$prefix
+KERNELDIR=$(readlink -f $kerneldir)
+ARCH=$arch
+PROCESSOR=$processor
+CC=$cross_prefix$cc
+LD=$cross_prefix$ld
+OBJCOPY=$cross_prefix$objcopy
+AR=$cross_prefix$ar
+EOF
diff --git a/kvm/user/flat.lds b/kvm/user/flat.lds
new file mode 100644
index 0000000..4120595
--- /dev/null
+++ b/kvm/user/flat.lds
@@ -0,0 +1,15 @@
+SECTIONS
+{
+    . = 4M + SIZEOF_HEADERS;
+    stext = .;
+    .text : { *(.init) *(.text) *(.text.*) }
+    . = ALIGN(4K);
+    .data : { *(.data) }
+    . = ALIGN(16);
+    .rodata : { *(.rodata) }
+    . = ALIGN(16);
+    .bss : { *(.bss) }
+    . = ALIGN(4K);
+    edata = .;
+}
+
diff --git a/kvm/user/formats b/kvm/user/formats
new file mode 100644
index 0000000..7f4ebdb
--- /dev/null
+++ b/kvm/user/formats
@@ -0,0 +1,31 @@
+0x00000000  %(ts)d (+%(relts)12d)  unknown (0x%(event)016x) vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x ]
+
+0x00010001  %(ts)d (+%(relts)12d)  VMENTRY       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
+0x00010002  %(ts)d (+%(relts)12d)  VMEXIT        vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ exitcode = 0x%(1)08x, rip = 0x%(3)08x %(2)08x ]
+0x00020001  %(ts)d (+%(relts)12d)  PAGE_FAULT    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ errorcode = 0x%(1)08x, virt = 0x%(3)08x %(2)08x ]
+0x00020002  %(ts)d (+%(relts)12d)  INJ_VIRQ      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
+0x00020003  %(ts)d (+%(relts)12d)  REDELIVER_EVT vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
+0x00020004  %(ts)d (+%(relts)12d)  PEND_INTR     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
+0x00020005  %(ts)d (+%(relts)12d)  IO_READ       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ port = 0x%(1)04x, size = %(2)d ]
+0x00020006  %(ts)d (+%(relts)12d)  IO_WRITE      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ port = 0x%(1)04x, size = %(2)d ]
+0x00020007  %(ts)d (+%(relts)12d)  CR_READ       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ CR# = %(1)d, value = 0x%(3)08x %(2)08x ]
+0x00020008  %(ts)d (+%(relts)12d)  CR_WRITE      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ CR# = %(1)d, value = 0x%(3)08x %(2)08x ]
+0x00020009  %(ts)d (+%(relts)12d)  DR_READ       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ DR# = %(1)d, value = 0x%(2)08x ]
+0x0002000A  %(ts)d (+%(relts)12d)  DR_WRITE      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ DR# = %(1)d, value = 0x%(2)08x ]
+0x0002000B  %(ts)d (+%(relts)12d)  MSR_READ      vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ MSR# = 0x%(1)08x, data = 0x%(3)08x %(2)08x ]
+0x0002000C  %(ts)d (+%(relts)12d)  MSR_WRITE     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ MSR# = 0x%(1)08x, data = 0x%(3)08x %(2)08x ]
+0x0002000D  %(ts)d (+%(relts)12d)  CPUID         vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ func = 0x%(1)08x, eax = 0x%(2)08x, ebx = 0x%(3)08x, ecx = 0x%(4)08x edx = 0x%(5)08x]
+0x0002000E  %(ts)d (+%(relts)12d)  INTR          vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ vector = 0x%(1)02x ]
+0x0002000F  %(ts)d (+%(relts)12d)  NMI           vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
+0x00020010  %(ts)d (+%(relts)12d)  VMMCALL       vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ func = 0x%(1)08x ]
+0x00020011  %(ts)d (+%(relts)12d)  HLT           vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
+0x00020012  %(ts)d (+%(relts)12d)  CLTS          vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x
+0x00020013  %(ts)d (+%(relts)12d)  LMSW          vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ value = 0x%(1)08x ]
+0x00020014  %(ts)d (+%(relts)12d)  APIC_ACCESS   vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ offset = 0x%(1)08x ]
+0x00020015  %(ts)d (+%(relts)12d)  TDP_FAULT     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ errorcode = 0x%(1)08x, virt = 0x%(3)08x %(2)08x ]
+# ppc: tlb traces
+0x00020016  GTLB_WRITE    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ index = 0x%(1)08x, tid = 0x%(2)08x, word1=0x%(3)08x, word2=0x%(4)08x, word3=0x%(5)08x ]
+0x00020017  STLB_WRITE    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ index = 0x%(1)08x, tid = 0x%(2)08x, word1=0x%(3)08x, word2=0x%(4)08x, word3=0x%(5)08x ]
+0x00020018  STLB_INVAL    vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ index = 0x%(1)08x, tid = 0x%(2)08x, word1=0x%(3)08x, word2=0x%(4)08x, word3=0x%(5)08x ]
+# ppc: instruction emulation - this type is handled more complex in kvmtrace_format, but listed to show the eventid and transported data
+#0x00020019  %(ts)d (+%(relts)12d)  PPC_INSTR     vcpu = 0x%(vcpu)08x  pid = 0x%(pid)08x [ instr = 0x%(1)08x, pc = 0x%(2)08x, emul = 0x%(3)08x, nsec = %(4)08d ]
diff --git a/kvm/user/iotable.c b/kvm/user/iotable.c
new file mode 100644
index 0000000..91a5016
--- /dev/null
+++ b/kvm/user/iotable.c
@@ -0,0 +1,53 @@
+/*
+ * 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@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "iotable.h"
+
+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;
+}
diff --git a/kvm/user/iotable.h b/kvm/user/iotable.h
new file mode 100644
index 0000000..cb18f23
--- /dev/null
+++ b/kvm/user/iotable.h
@@ -0,0 +1,40 @@
+/*
+ * 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@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#include <stdint.h>
+
+#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];
+};
+
+struct io_table_entry *io_table_lookup(struct io_table *io_table,
+                                       uint64_t addr);
+int io_table_register(struct io_table *io_table, uint64_t start, uint64_t size,
+                      io_table_handler_t *handler, void *opaque);
diff --git a/kvm/user/kvmtrace.c b/kvm/user/kvmtrace.c
new file mode 100644
index 0000000..de3c189
--- /dev/null
+++ b/kvm/user/kvmtrace.c
@@ -0,0 +1,706 @@
+/*
+ * kvm tracing application
+ *
+ * This tool is used for collecting trace buffer data
+ * for kvm trace.
+ *
+ * Based on blktrace 0.99.3
+ *
+ * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
+ * Copyright (C) 2008 Eric Liu <eric.e.liu@intel.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/statfs.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sched.h>
+
+#ifndef __user
+#define __user
+#endif
+#include <linux/kvm.h>
+
+static char kvmtrace_version[] = "0.1";
+
+/*
+ * You may want to increase this even more, if you are logging at a high
+ * rate and see skipped/missed events
+ */
+#define BUF_SIZE	(512 * 1024)
+#define BUF_NR		(8)
+
+#define OFILE_BUF	(128 * 1024)
+
+#define DEBUGFS_TYPE	0x64626720
+
+#define max(a, b)	((a) > (b) ? (a) : (b))
+
+#define S_OPTS	"r:o:w:?Vb:n:D:"
+static struct option l_opts[] = {
+	{
+		.name = "relay",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'r'
+	},
+	{
+		.name = "output",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'o'
+	},
+	{
+		.name = "stopwatch",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'w'
+	},
+	{
+		.name = "version",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'V'
+	},
+	{
+		.name = "buffer-size",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'b'
+	},
+	{
+		.name = "num-sub-buffers",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'n'
+	},
+	{
+		.name = "output-dir",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'D'
+	},
+	{
+		.name = NULL,
+	}
+};
+
+struct thread_information {
+	int cpu;
+	pthread_t thread;
+
+	int fd;
+	char fn[MAXPATHLEN + 64];
+
+	FILE *ofile;
+	char *ofile_buffer;
+
+	int (*get_subbuf)(struct thread_information *, unsigned int);
+	int (*read_data)(struct thread_information *, void *, unsigned int);
+
+	unsigned long long data_read;
+
+	struct kvm_trace_information *trace_info;
+
+	int exited;
+
+	/*
+	 * mmap controlled output files
+	 */
+	unsigned long long fs_size;
+	unsigned long long fs_max_size;
+	unsigned long fs_off;
+	void *fs_buf;
+	unsigned long fs_buf_len;
+
+};
+
+struct kvm_trace_information {
+	int fd;
+	volatile int trace_started;
+	unsigned long lost_records;
+	struct thread_information *threads;
+	unsigned long buf_size;
+	unsigned long buf_nr;
+};
+
+static struct kvm_trace_information trace_information;
+
+static int ncpus;
+static char default_debugfs_path[] = "/sys/kernel/debug";
+
+/* command line option globals */
+static char *debugfs_path;
+static char *output_name;
+static char *output_dir;
+static int stop_watch;
+static unsigned long buf_size = BUF_SIZE;
+static unsigned long buf_nr = BUF_NR;
+static unsigned int page_size;
+
+#define for_each_cpu_online(cpu) \
+	for (cpu = 0; cpu < ncpus; cpu++)
+#define for_each_tip(tip, i) \
+	for (i = 0, tip = trace_information.threads; i < ncpus; i++, tip++)
+
+#define is_done()	(*(volatile int *)(&done))
+static volatile int done;
+
+#define is_trace_stopped()	(*(volatile int *)(&trace_stopped))
+static volatile int trace_stopped;
+
+static void exit_trace(int status);
+
+static void handle_sigint(__attribute__((__unused__)) int sig)
+{
+	ioctl(trace_information.fd, KVM_TRACE_PAUSE);
+	done = 1;
+}
+
+static int get_lost_records()
+{
+	int fd;
+	char tmp[MAXPATHLEN + 64];
+
+	snprintf(tmp, sizeof(tmp), "%s/kvm/lost_records", debugfs_path);
+	fd = open(tmp, O_RDONLY);
+	if (fd < 0) {
+		/*
+		 * this may be ok, if the kernel doesn't support dropped counts
+		 */
+		if (errno == ENOENT)
+			return 0;
+
+		fprintf(stderr, "Couldn't open dropped file %s\n", tmp);
+		return -1;
+	}
+
+	if (read(fd, tmp, sizeof(tmp)) < 0) {
+		perror(tmp);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	return atoi(tmp);
+}
+
+static void wait_for_data(struct thread_information *tip, int timeout)
+{
+	struct pollfd pfd = { .fd = tip->fd, .events = POLLIN };
+
+	while (!is_done()) {
+		if (poll(&pfd, 1, timeout) < 0) {
+			perror("poll");
+			break;
+		}
+		if (pfd.revents & POLLIN)
+			break;
+	}
+}
+
+static int read_data(struct thread_information *tip, void *buf,
+			  unsigned int len)
+{
+	int ret = 0;
+
+	do {
+		wait_for_data(tip, 100);
+
+		ret = read(tip->fd, buf, len);
+
+		if (!ret)
+			continue;
+		else if (ret > 0)
+			return ret;
+		else {
+			if (errno != EAGAIN) {
+				perror(tip->fn);
+				fprintf(stderr, "Thread %d failed read of %s\n",
+					tip->cpu, tip->fn);
+				break;
+			}
+			continue;
+		}
+	} while (!is_done());
+
+	return ret;
+
+}
+
+/*
+ * For file output, truncate and mmap the file appropriately
+ */
+static int mmap_subbuf(struct thread_information *tip, unsigned int maxlen)
+{
+	int ofd = fileno(tip->ofile);
+	int ret;
+	unsigned long nr;
+	unsigned long size;
+
+	/*
+	 * extend file, if we have to. use chunks of 16 subbuffers.
+	 */
+	if (tip->fs_off + maxlen > tip->fs_buf_len) {
+		if (tip->fs_buf) {
+			munlock(tip->fs_buf, tip->fs_buf_len);
+			munmap(tip->fs_buf, tip->fs_buf_len);
+			tip->fs_buf = NULL;
+		}
+
+		tip->fs_off = tip->fs_size & (page_size - 1);
+		nr = max(16, tip->trace_info->buf_nr);
+		size = tip->trace_info->buf_size;
+		tip->fs_buf_len = (nr * size) - tip->fs_off;
+		tip->fs_max_size += tip->fs_buf_len;
+
+		if (ftruncate(ofd, tip->fs_max_size) < 0) {
+			perror("ftruncate");
+			return -1;
+		}
+
+		tip->fs_buf = mmap(NULL, tip->fs_buf_len, PROT_WRITE,
+				   MAP_SHARED, ofd, tip->fs_size - tip->fs_off);
+		if (tip->fs_buf == MAP_FAILED) {
+			perror("mmap");
+			return -1;
+		}
+		mlock(tip->fs_buf, tip->fs_buf_len);
+	}
+
+	ret = tip->read_data(tip, tip->fs_buf + tip->fs_off, maxlen);
+	if (ret >= 0) {
+		tip->data_read += ret;
+		tip->fs_size += ret;
+		tip->fs_off += ret;
+		return 0;
+	}
+
+	return -1;
+}
+
+static void tip_ftrunc_final(struct thread_information *tip)
+{
+	/*
+	 * truncate to right size and cleanup mmap
+	 */
+	if (tip->ofile) {
+		int ofd = fileno(tip->ofile);
+
+		if (tip->fs_buf)
+			munmap(tip->fs_buf, tip->fs_buf_len);
+
+		ftruncate(ofd, tip->fs_size);
+	}
+}
+
+static void *thread_main(void *arg)
+{
+	struct thread_information *tip = arg;
+	pid_t pid = getpid();
+	cpu_set_t cpu_mask;
+
+	CPU_ZERO(&cpu_mask);
+	CPU_SET((tip->cpu), &cpu_mask);
+
+	if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
+		perror("sched_setaffinity");
+		exit_trace(1);
+	}
+
+	snprintf(tip->fn, sizeof(tip->fn), "%s/kvm/trace%d",
+			debugfs_path, tip->cpu);
+	tip->fd = open(tip->fn, O_RDONLY);
+	if (tip->fd < 0) {
+		perror(tip->fn);
+		fprintf(stderr, "Thread %d failed open of %s\n", tip->cpu,
+			tip->fn);
+		exit_trace(1);
+	}
+	while (!is_done()) {
+		if (tip->get_subbuf(tip, tip->trace_info->buf_size) < 0)
+			break;
+	}
+
+	/*
+	 * trace is stopped, pull data until we get a short read
+	 */
+	while (tip->get_subbuf(tip, tip->trace_info->buf_size) > 0)
+		;
+
+	tip_ftrunc_final(tip);
+	tip->exited = 1;
+	return NULL;
+}
+
+static int fill_ofname(struct thread_information *tip, char *dst)
+{
+	struct stat sb;
+	int len = 0;
+
+	if (output_dir)
+		len = sprintf(dst, "%s/", output_dir);
+	else
+		len = sprintf(dst, "./");
+
+	if (stat(dst, &sb) < 0) {
+		if (errno != ENOENT) {
+			perror("stat");
+			return 1;
+		}
+		if (mkdir(dst, 0755) < 0) {
+			perror(dst);
+			fprintf(stderr, "Can't make output dir\n");
+			return 1;
+		}
+	}
+
+	sprintf(dst + len, "%s.kvmtrace.%d", output_name, tip->cpu);
+
+	return 0;
+}
+
+static void fill_ops(struct thread_information *tip)
+{
+	tip->get_subbuf = mmap_subbuf;
+	tip->read_data = read_data;
+}
+
+static void close_thread(struct thread_information *tip)
+{
+	if (tip->fd != -1)
+		close(tip->fd);
+	if (tip->ofile)
+		fclose(tip->ofile);
+	if (tip->ofile_buffer)
+		free(tip->ofile_buffer);
+
+	tip->fd = -1;
+	tip->ofile = NULL;
+	tip->ofile_buffer = NULL;
+}
+
+static int tip_open_output(struct thread_information *tip)
+{
+	int mode, vbuf_size;
+	char op[NAME_MAX];
+
+	if (fill_ofname(tip, op))
+		return 1;
+
+	tip->ofile = fopen(op, "w+");
+	mode = _IOFBF;
+	vbuf_size = OFILE_BUF;
+
+	if (tip->ofile == NULL) {
+		perror(op);
+		return 1;
+	}
+
+	tip->ofile_buffer = malloc(vbuf_size);
+	if (setvbuf(tip->ofile, tip->ofile_buffer, mode, vbuf_size)) {
+		perror("setvbuf");
+		close_thread(tip);
+		return 1;
+	}
+
+	fill_ops(tip);
+	return 0;
+}
+
+static int start_threads(int cpu)
+{
+	struct thread_information *tip;
+
+	tip = trace_information.threads + cpu;
+	tip->cpu = cpu;
+	tip->trace_info = &trace_information;
+	tip->fd = -1;
+
+	if (tip_open_output(tip))
+	    return 1;
+
+	if (pthread_create(&tip->thread, NULL, thread_main, tip)) {
+		perror("pthread_create");
+		close_thread(tip);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void stop_threads()
+{
+	struct thread_information *tip;
+	unsigned long ret;
+	int i;
+
+	for_each_tip(tip, i) {
+		if (tip->thread)
+			(void) pthread_join(tip->thread, (void *) &ret);
+		close_thread(tip);
+	}
+}
+
+static int start_trace(void)
+{
+	int fd;
+	struct kvm_user_trace_setup kuts;
+
+	fd = trace_information.fd = open("/dev/kvm", O_RDWR);
+	if (fd == -1) {
+		perror("/dev/kvm");
+		return 1;
+	}
+
+	memset(&kuts, 0, sizeof(kuts));
+	kuts.buf_size = trace_information.buf_size = buf_size;
+	kuts.buf_nr = trace_information.buf_nr = buf_nr;
+
+	if (ioctl(trace_information.fd , KVM_TRACE_ENABLE, &kuts) < 0) {
+		perror("KVM_TRACE_ENABLE");
+		close(fd);
+		return 1;
+	}
+	trace_information.trace_started = 1;
+
+	return 0;
+}
+
+static void cleanup_trace(void)
+{
+	if (trace_information.fd == -1)
+		return;
+
+	trace_information.lost_records = get_lost_records();
+
+	if (trace_information.trace_started) {
+		trace_information.trace_started = 0;
+		if (ioctl(trace_information.fd, KVM_TRACE_DISABLE) < 0)
+			perror("KVM_TRACE_DISABLE");
+	}
+
+	close(trace_information.fd);
+	trace_information.fd  = -1;
+}
+
+static void stop_all_traces(void)
+{
+	if (!is_trace_stopped()) {
+		trace_stopped = 1;
+		stop_threads();
+		cleanup_trace();
+	}
+}
+
+static void exit_trace(int status)
+{
+	stop_all_traces();
+	exit(status);
+}
+
+static int start_kvm_trace(void)
+{
+	int i, size;
+	struct thread_information *tip;
+
+	size = ncpus * sizeof(struct thread_information);
+	tip = malloc(size);
+	if (!tip) {
+		fprintf(stderr, "Out of memory, threads (%d)\n", size);
+		return 1;
+	}
+	memset(tip, 0, size);
+	trace_information.threads = tip;
+
+	if (start_trace())
+		return 1;
+
+	for_each_cpu_online(i) {
+		if (start_threads(i)) {
+			fprintf(stderr, "Failed to start worker threads\n");
+			break;
+		}
+	}
+
+	if (i != ncpus) {
+		stop_threads();
+		cleanup_trace();
+		return 1;
+	}
+
+	return 0;
+}
+
+static void wait_for_threads(void)
+{
+	struct thread_information *tip;
+	int i, tips_running;
+
+	do {
+		tips_running = 0;
+		usleep(100000);
+
+		for_each_tip(tip, i)
+			tips_running += !tip->exited;
+
+	} while (tips_running);
+}
+
+static void show_stats(void)
+{
+	struct thread_information *tip;
+	unsigned long long data_read;
+	int i;
+
+	data_read = 0;
+	for_each_tip(tip, i) {
+		printf("  CPU%3d: %8llu KiB data\n",
+			tip->cpu, (tip->data_read + 1023) >> 10);
+		data_read += tip->data_read;
+	}
+
+	printf("  Total:  lost %lu, %8llu KiB data\n",
+		trace_information.lost_records, (data_read + 1023) >> 10);
+
+	if (trace_information.lost_records)
+		fprintf(stderr, "You have lost records, "
+				"consider using a larger buffer size (-b)\n");
+}
+
+static char usage_str[] = \
+	"[ -r debugfs path ] [ -D output dir ] [ -b buffer size ]\n" \
+	"[ -n number of buffers] [ -o <output file> ] [ -w time  ] [ -V ]\n\n" \
+	"\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
+	"\t-o File(s) to send output to\n" \
+	"\t-D Directory to prepend to output file names\n" \
+	"\t-w Stop after defined time, in seconds\n" \
+	"\t-b Sub buffer size in KiB\n" \
+	"\t-n Number of sub buffers\n" \
+	"\t-V Print program version info\n\n";
+
+static void show_usage(char *prog)
+{
+	fprintf(stderr, "Usage: %s %s %s", prog, kvmtrace_version, usage_str);
+	exit(EXIT_FAILURE);
+}
+
+void parse_args(int argc, char **argv)
+{
+	int c;
+
+	while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
+		switch (c) {
+		case 'r':
+			debugfs_path = optarg;
+			break;
+		case 'o':
+			output_name = optarg;
+			break;
+		case 'w':
+			stop_watch = atoi(optarg);
+			if (stop_watch <= 0) {
+				fprintf(stderr,
+					"Invalid stopwatch value (%d secs)\n",
+					stop_watch);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'V':
+			printf("%s version %s\n", argv[0], kvmtrace_version);
+			exit(EXIT_SUCCESS);
+		case 'b':
+			buf_size = strtoul(optarg, NULL, 10);
+			if (buf_size <= 0 || buf_size > 16*1024) {
+				fprintf(stderr,
+					"Invalid buffer size (%lu)\n",
+					buf_size);
+				exit(EXIT_FAILURE);
+			}
+			buf_size <<= 10;
+			break;
+		case 'n':
+			buf_nr = strtoul(optarg, NULL, 10);
+			if (buf_nr <= 0) {
+				fprintf(stderr,
+					"Invalid buffer nr (%lu)\n", buf_nr);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'D':
+			output_dir = optarg;
+			break;
+		default:
+			show_usage(argv[0]);
+		}
+	}
+
+	if (optind < argc || output_name == NULL)
+		show_usage(argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+	struct statfs st;
+
+	parse_args(argc, argv);
+
+	if (!debugfs_path)
+		debugfs_path = default_debugfs_path;
+
+	if (statfs(debugfs_path, &st) < 0) {
+		perror("statfs");
+		fprintf(stderr, "%s does not appear to be a valid path\n",
+			debugfs_path);
+		return 1;
+	} else if (st.f_type != (long) DEBUGFS_TYPE) {
+		fprintf(stderr, "%s does not appear to be a debug filesystem,"
+			" please mount debugfs.\n",
+			debugfs_path);
+		return 1;
+	}
+
+	page_size = getpagesize();
+
+	ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+	if (ncpus < 0) {
+		fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
+		return 1;
+	}
+
+	signal(SIGINT, handle_sigint);
+	signal(SIGHUP, handle_sigint);
+	signal(SIGTERM, handle_sigint);
+	signal(SIGALRM, handle_sigint);
+	signal(SIGPIPE, SIG_IGN);
+
+	if (start_kvm_trace() != 0)
+		return 1;
+
+	if (stop_watch)
+		alarm(stop_watch);
+
+	wait_for_threads();
+	stop_all_traces();
+	show_stats();
+
+	return 0;
+}
diff --git a/kvm/user/kvmtrace_format b/kvm/user/kvmtrace_format
new file mode 100755
index 0000000..6556475
--- /dev/null
+++ b/kvm/user/kvmtrace_format
@@ -0,0 +1,532 @@
+#!/usr/bin/env python
+
+# by Mark Williamson, (C) 2004 Intel Research Cambridge
+
+# Program for reformatting trace buffer output according to user-supplied rules
+
+import re, sys, string, signal, struct, os, getopt, operator
+
+PREFIX = '/usr'
+DATADIR = os.path.join(PREFIX, 'share')
+KVMDIR = os.path.join(DATADIR, 'kvm')
+FORMATS_FILE = os.path.join(KVMDIR, 'formats')
+
+def usage():
+    print >> sys.stderr, \
+          "Usage: " + sys.argv[0] + """ defs-file
+          Parses trace data in binary format, as output by kvmtrace and
+          reformats it according to the rules in a file of definitions.  The
+          rules in this file should have the format ({ and } show grouping
+          and are not part of the syntax):
+
+          {event_id}{whitespace}{text format string}
+
+          The textual format string may include format specifiers, such as:
+            %(ts)d, %(event)d, %(pid)d %(vcpu)d %(1)d, %(2)d,
+	    %(3)d, %(4)d, %(5)d
+          [ the 'd' format specifier outputs in decimal, alternatively 'x'
+            will output in hexadecimal and 'o' will output in octal ]
+
+          Which correspond to the event ID, timestamp counter, pid
+	  , vcpu and the 5 data fields from the trace record.  There should be
+	  one such rule for each type of event.
+          Depending on your system and the volume of trace buffer data,
+          this script may not be able to keep up with the output of kvmtrace
+          if it is piped directly.  In these circumstances you should have
+          kvmtrace output to a file for processing off-line.
+
+          kvmtrace_format has the following additional switches
+          -s     - if this switch is set additional trace statistics are
+                   created and printed at the end of the output
+          """
+    sys.exit(1)
+
+def read_defs(defs_file):
+    defs = {}
+
+    fd = open(defs_file)
+
+    reg = re.compile('(\S+)\s+(\S.*)')
+
+    while True:
+        line = fd.readline()
+        if not line:
+            break
+
+        if line[0] == '#' or line[0] == '\n':
+            continue
+
+        m = reg.match(line)
+
+        if not m: print >> sys.stderr, "Bad format file" ; sys.exit(1)
+
+        defs[str(eval(m.group(1)))] = m.group(2)
+
+    return defs
+
+def sighand(x,y):
+    global interrupted
+    interrupted = 1
+
+# ppc instruction decoding for event type 0x00020019 (PPC_INSTR)
+# some globals for statistic summaries
+stat_ppc_instr_mnemonic = {};
+stat_ppc_instr_spr = {};
+stat_ppc_instr_dcr = {};
+stat_ppc_instr_tlb = {};
+
+def ppc_instr_print_summary(sortedlist, colname):
+	print "\n\n%14s + %10s" % (colname, "count")
+	print "%s" % (15*"-"+"+"+11*"-")
+	sum = 0
+	for value, key in sortedlist:
+		sum += key
+		print "%14s | %10d" % (value, key)
+	print "%14s = %10d" % ("sum", sum)
+
+
+def ppc_instr_summary():
+	# don't print empty statistics
+        if stat_ppc_instr_mnemonic:
+		ppc_instr_print_summary(sorted(stat_ppc_instr_mnemonic.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic")
+        if stat_ppc_instr_spr:
+		ppc_instr_print_summary(sorted(stat_ppc_instr_spr.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic-spr")
+        if stat_ppc_instr_dcr:
+		ppc_instr_print_summary(sorted(stat_ppc_instr_dcr.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic-dcr")
+        if stat_ppc_instr_tlb:
+		ppc_instr_print_summary(sorted(stat_ppc_instr_tlb.iteritems(), key=operator.itemgetter(1), reverse=True), "mnemonic-tlb")
+
+def get_op(instr):
+        return (instr >> 26);
+
+def get_xop(instr):
+        return (instr >> 1) & 0x3ff;
+
+def get_sprn(instr):
+	return ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0)
+
+def get_dcrn(instr):
+	return ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
+
+def get_tlbwe_type(instr):
+	ws = (instr >> 11) & 0x1f;
+	if ws == 0:
+		return "PAGEID"
+	elif ws == 1:
+		return "XLAT"
+	elif ws == 2:
+		return "ATTRIB"
+	else:
+		return "UNKNOWN"
+
+def get_name(instr):
+	if get_op(instr)==3:
+		return "trap"
+	elif get_op(instr)==19:
+		if get_xop(instr) == 50:
+			return "rfi"
+		else:
+			return "unknown"
+	elif get_op(instr)==31:
+		if get_xop(instr) == 83:
+			return "mfmsr"
+
+		elif get_xop(instr) == 87:
+			return "lbzx"
+
+		elif get_xop(instr) == 131:
+			return "wrtee"
+
+		elif get_xop(instr) == 146:
+			return "mtmsr"
+
+		elif get_xop(instr) == 163:
+			return "wrteei"
+
+		elif get_xop(instr) == 215:
+			return "stbx"
+
+		elif get_xop(instr) == 247:
+			return "stbux"
+
+		elif get_xop(instr) == 279:
+			return "lhzx"
+
+		elif get_xop(instr) == 311:
+			return "lhzux"
+
+		elif get_xop(instr) == 323:
+			return "mfdcr"
+
+		elif get_xop(instr) == 339:
+			return "mfspr"
+
+		elif get_xop(instr) == 407:
+			return "sthx"
+
+		elif get_xop(instr) == 439:
+			return "sthux"
+
+		elif get_xop(instr) == 451:
+			return "mtdcr"
+
+		elif get_xop(instr) == 467:
+			return "mtspr"
+
+		elif get_xop(instr) == 470:
+			return "dcbi"
+
+		elif get_xop(instr) == 534:
+			return "lwbrx"
+
+		elif get_xop(instr) == 566:
+			return "tlbsync"
+
+		elif get_xop(instr) == 662:
+			return "stwbrx"
+
+		elif get_xop(instr) == 978:
+			return "tlbwe"
+
+		elif get_xop(instr) == 914:
+			return "tlbsx"
+
+		elif get_xop(instr) == 790:
+			return "lhbrx"
+
+		elif get_xop(instr) == 918:
+			return "sthbrx"
+
+		elif get_xop(instr) == 966:
+			return "iccci"
+
+		else:
+			return "unknown"
+
+	elif get_op(instr) == 32:
+		return "lwz"
+
+	elif get_op(instr) == 33:
+		return "lwzu"
+
+	elif get_op(instr) == 34:
+		return "lbz"
+
+	elif get_op(instr) == 35:
+		return "lbzu"
+
+	elif get_op(instr) == 36:
+		return "stw"
+
+	elif get_op(instr) == 37:
+		return "stwu"
+
+	elif get_op(instr) == 38:
+		return "stb"
+
+	elif get_op(instr) == 39:
+		return "stbu"
+
+	elif get_op(instr) == 40:
+		return "lhz"
+
+	elif get_op(instr) == 41:
+		return "lhzu"
+
+	elif get_op(instr) == 44:
+		return "sth"
+
+	elif get_op(instr) == 45:
+		return "sthu"
+
+	else:
+		return "unknown"
+
+def get_sprn_name(sprn):
+		if sprn == 0x01a:
+			return "SRR0"
+		elif sprn == 0x01b:
+			return "SRR1"
+		elif sprn == 0x3b2:
+			return "MMUCR"
+		elif sprn == 0x030:
+			return "PID"
+		elif sprn == 0x03f:
+			return "IVPR"
+		elif sprn == 0x3b3:
+			return "CCR0"
+		elif sprn == 0x378:
+			return "CCR1"
+		elif sprn == 0x11f:
+			return "PVR"
+		elif sprn == 0x03d:
+			return "DEAR"
+		elif sprn == 0x03e:
+			return "ESR"
+		elif sprn == 0x134:
+			return "DBCR0"
+		elif sprn == 0x135:
+			return "DBCR1"
+		elif sprn == 0x11c:
+			return "TBWL"
+		elif sprn == 0x11d:
+			return "TBWU"
+		elif sprn == 0x016:
+			return "DEC"
+		elif sprn == 0x150:
+			return "TSR"
+		elif sprn == 0x154:
+			return "TCR"
+		elif sprn == 0x110:
+			return "SPRG0"
+		elif sprn == 0x111:
+			return "SPRG1"
+		elif sprn == 0x112:
+			return "SPRG2"
+		elif sprn == 0x113:
+			return "SPRG3"
+		elif sprn == 0x114:
+			return "SPRG4"
+		elif sprn == 0x115:
+			return "SPRG5"
+		elif sprn == 0x116:
+			return "SPRG6"
+		elif sprn == 0x117:
+			return "SPRG7"
+		elif sprn == 0x190:
+			return "IVOR0"
+		elif sprn == 0x191:
+			return "IVOR1"
+		elif sprn == 0x192:
+			return "IVOR2"
+		elif sprn == 0x193:
+			return "IVOR3"
+		elif sprn == 0x194:
+			return "IVOR4"
+		elif sprn == 0x195:
+			return "IVOR5"
+		elif sprn == 0x196:
+			return "IVOR6"
+		elif sprn == 0x197:
+			return "IVOR7"
+		elif sprn == 0x198:
+			return "IVOR8"
+		elif sprn == 0x199:
+			return "IVOR9"
+		elif sprn == 0x19a:
+			return "IVOR10"
+		elif sprn == 0x19b:
+			return "IVOR11"
+		elif sprn == 0x19c:
+			return "IVOR12"
+		elif sprn == 0x19d:
+			return "IVOR13"
+		elif sprn == 0x19e:
+			return "IVOR14"
+		elif sprn == 0x19f:
+			return "IVOR15"
+		else:
+			return "UNKNOWN"
+
+def get_special(instr):
+	name = get_name(instr);
+	if stat_ppc_instr_mnemonic.has_key(name):
+		stat_ppc_instr_mnemonic[name] += 1
+	else:
+		stat_ppc_instr_mnemonic[name] = 1
+
+	if get_op(instr) == 31:
+		if (get_xop(instr) == 339) or (get_xop(instr) == 467):
+			sprn = get_sprn(instr);
+			sprn_name = get_sprn_name(sprn);
+			stat_idx = name+"-"+sprn_name
+			if stat_ppc_instr_spr.has_key(stat_idx):
+				stat_ppc_instr_spr[stat_idx] += 1
+			else:
+				stat_ppc_instr_spr[stat_idx] = 1
+			return ("- sprn 0x%03x %8s" % (sprn, sprn_name))
+		elif (get_xop(instr) == 323 ) or (get_xop(instr) == 451):
+			dcrn = get_dcrn(instr);
+			stat_idx = name+"-"+("%04X"%dcrn)
+			if stat_ppc_instr_dcr.has_key(stat_idx):
+				stat_ppc_instr_dcr[stat_idx] += 1
+			else:
+				stat_ppc_instr_dcr[stat_idx] = 1
+			return ("- dcrn 0x%03x" % dcrn)
+		elif (get_xop(instr) == 978 ) or (get_xop(instr) == 451):
+			tlbwe_type = get_tlbwe_type(instr)
+			stat_idx = name+"-"+tlbwe_type
+			if stat_ppc_instr_tlb.has_key(stat_idx):
+				stat_ppc_instr_tlb[stat_idx] += 1
+			else:
+				stat_ppc_instr_tlb[stat_idx] = 1
+			return ("- ws -> %8s" % tlbwe_type)
+	return ""
+
+##### Main code
+
+summary = False
+
+try:
+    opts, arg = getopt.getopt(sys.argv[1:], "sc:" )
+    for opt in opts:
+        if opt[0] == '-s' : summary = True
+
+except getopt.GetoptError:
+    usage()
+
+signal.signal(signal.SIGTERM, sighand)
+signal.signal(signal.SIGHUP,  sighand)
+signal.signal(signal.SIGINT,  sighand)
+
+interrupted = 0
+
+if len(arg) > 0:
+    defs = read_defs(arg[0])
+else:
+    defs = read_defs(FORMATS_FILE)
+
+# structure of trace record (as output by kvmtrace):
+# HDR(I) {TSC(Q)} D1(I) D2(I) D3(I) D4(I) D5(I)
+#
+# HDR consists of EVENT:28:, n_data:3:, ts_in:1:
+# pid:32, vcpu_id:32
+# EVENT means Event ID
+# n_data means number of data (like D1, D2, ...)
+# ts_in means Timestamp data exists(1) or not(0).
+# if ts_in == 0, TSC(Q) does not exists.
+#
+HDRREC = "<III"
+TSCREC = "<Q"
+D1REC  = "<I"
+D2REC  = "<II"
+D3REC  = "<III"
+D4REC  = "<IIII"
+D5REC  = "<IIIII"
+KMAGIC  = "<I"
+
+last_ts = 0
+
+i=0
+
+while not interrupted:
+    try:
+        i=i+1
+
+        if i == 1:
+            line = sys.stdin.read(struct.calcsize(KMAGIC))
+            if not line:
+                break
+            kmgc = struct.unpack(KMAGIC, line)[0]
+
+            #firstly try to parse data file as little endian
+            # if "kvmtrace-metadata".kmagic != kmagic
+            # then data file must be big endian"
+            if kmgc != 0x12345678:
+                if kmgc != 0x78563412:
+                    print >> sys.stderr, "Bad data file: magic number error."
+                    break;
+                else:
+                    HDRREC = ">III"
+                    TSCREC = ">Q"
+                    D1REC  = ">I"
+                    D2REC  = ">II"
+                    D3REC  = ">III"
+                    D4REC  = ">IIII"
+                    D5REC  = ">IIIII"
+            continue
+
+        line = sys.stdin.read(struct.calcsize(HDRREC))
+        if not line:
+            break
+	(event, pid, vcpu_id) = struct.unpack(HDRREC, line)
+
+        n_data = event >> 28 & 0x7
+        ts_in = event >> 31
+
+        d1 = 0
+        d2 = 0
+        d3 = 0
+        d4 = 0
+        d5 = 0
+
+        ts = 0
+
+        if ts_in == 1:
+            line = sys.stdin.read(struct.calcsize(TSCREC))
+            if not line:
+                break
+            ts = struct.unpack(TSCREC, line)[0]
+        if n_data == 1:
+            line = sys.stdin.read(struct.calcsize(D1REC))
+            if not line:
+                break
+            d1 = struct.unpack(D1REC, line)[0]
+        if n_data == 2:
+            line = sys.stdin.read(struct.calcsize(D2REC))
+            if not line:
+                break
+            (d1, d2) = struct.unpack(D2REC, line)
+        if n_data == 3:
+            line = sys.stdin.read(struct.calcsize(D3REC))
+            if not line:
+                break
+            (d1, d2, d3) = struct.unpack(D3REC, line)
+        if n_data == 4:
+            line = sys.stdin.read(struct.calcsize(D4REC))
+            if not line:
+                break
+            (d1, d2, d3, d4) = struct.unpack(D4REC, line)
+        if n_data == 5:
+            line = sys.stdin.read(struct.calcsize(D5REC))
+            if not line:
+                break
+            (d1, d2, d3, d4, d5) = struct.unpack(D5REC, line)
+
+	event &= 0x0fffffff
+
+        # provide relative TSC
+
+        if last_ts > 0 and ts_in == 1:
+            relts = ts - last_ts
+        else:
+            relts = 0
+
+        if ts_in == 1:
+            last_ts = ts
+
+        args = {'ts'   : ts,
+                'event' : event,
+                'relts': relts,
+		'pid'   : pid,
+		'vcpu'  : vcpu_id,
+                '1'     : d1,
+                '2'     : d2,
+                '3'     : d3,
+                '4'     : d4,
+                '5'     : d5    }
+
+        # some event types need more than just formats mapping they are if/elif
+        # chained here and the last default else is the mapping via formats
+        if event == 0x00020019:
+            pdata = (ts, relts, vcpu_id, pid, d1, d2, d3, get_name(d1), get_special(d1))
+            print "%d (+%12d)  PPC_INSTR vcpu = 0x%08x  pid = 0x%08x [ instr = 0x%08x, pc = 0x%08x, emul = %01d, mnemonic = %8s %s" % pdata
+        else:
+            try:
+                if defs.has_key(str(event)):
+                    print defs[str(event)] % args
+                else:
+                    if defs.has_key(str(0)): print defs[str(0)] % args
+            except TypeError:
+                if defs.has_key(str(event)):
+                    print defs[str(event)]
+                    print args
+                else:
+                    if defs.has_key(str(0)):
+                        print defs[str(0)]
+                        print args
+
+    except IOError, struct.error: sys.exit()
+
+if summary:
+	ppc_instr_summary()
diff --git a/kvm/user/main-ppc.c b/kvm/user/main-ppc.c
new file mode 100644
index 0000000..5af59f8
--- /dev/null
+++ b/kvm/user/main-ppc.c
@@ -0,0 +1,383 @@
+/*
+ * 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
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ *
+ *  Avi Kivity <avi@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *  Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#define _GNU_SOURCE
+
+#include <libkvm.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>
+#include <inttypes.h>
+
+#include "iotable.h"
+
+static int gettid(void)
+{
+	return syscall(__NR_gettid);
+}
+
+kvm_context_t kvm;
+
+#define IPI_SIGNAL (SIGRTMIN + 4)
+
+struct io_table mmio_table;
+
+static int ncpus = 1;
+static sem_t exited_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;
+};
+
+struct vcpu_info *vcpus;
+
+/* Must match flat.lds linker script */
+#define VM_TEST_LOAD_ADDRESS 0x100000
+
+static int test_debug(void *opaque, void *vcpu)
+{
+	printf("test_debug\n");
+	return 0;
+}
+
+static int test_halt(void *opaque, int vcpu)
+{
+	int n;
+
+	sigwait(&ipi_sigmask, &n);
+	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, void *vcpu)
+{
+}
+
+static int test_pre_kvm_run(void *opaque, void *vcpu)
+{
+	return 0;
+}
+
+static int mmio_handler(void *opaque, int len, int is_write, uint64_t offset,
+                        uint64_t *data)
+{
+	int r = 0;
+
+	switch (offset) {
+	case 0: /* putc */
+		putc(*(char *)data, stdout);
+		fflush(stdout);
+		break;
+	case 1: /* exit */
+		r = *(char *)data;
+		break;
+	default:
+		printf("%s: offset %"PRIx64" len %d data %"PRIx64"\n",
+		       __func__, offset, len, *(uint64_t *)data);
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
+{
+	struct io_table_entry *iodev;
+
+#if 0
+	printf("%s: addr %"PRIx64" len %d\n", __func__, addr, len);
+#endif
+
+	iodev = io_table_lookup(&mmio_table, addr);
+	if (!iodev) {
+		printf("couldn't find device\n");
+		return -ENODEV;
+	}
+
+	return iodev->handler(iodev->opaque, len, 0, addr - iodev->start,
+	                      (uint64_t *)data);
+}
+
+static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
+{
+	struct io_table_entry *iodev;
+
+#if 0
+	printf("%s: addr %"PRIx64" len %d data %"PRIx64"\n",
+	       __func__, addr, len, *(uint64_t *)data);
+#endif
+
+	iodev = io_table_lookup(&mmio_table, addr);
+	if (!iodev) {
+		printf("couldn't find device\n");
+		return -ENODEV;
+	}
+
+	return iodev->handler(iodev->opaque, len, 1, addr - iodev->start,
+	                      (uint64_t *)data);
+}
+
+static int test_dcr_read(int vcpu, uint32_t dcrn, uint32_t *data)
+{
+	printf("%s: dcrn %04X\n", __func__, dcrn);
+	*data = 0;
+	return 0;
+}
+
+static int test_dcr_write(int vcpu, uint32_t dcrn, uint32_t data)
+{
+	printf("%s: dcrn %04X data %04X\n", __func__, dcrn, data);
+	return 0;
+}
+
+static struct kvm_callbacks test_callbacks = {
+	.mmio_read   = test_mem_read,
+	.mmio_write  = test_mem_write,
+	.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,
+	.powerpc_dcr_read = test_dcr_read,
+	.powerpc_dcr_write = test_dcr_write,
+};
+
+static unsigned long load_file(void *mem, const char *fname, int inval_icache)
+{
+	ssize_t r;
+	int fd;
+	unsigned long bytes = 0;
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1) {
+		perror("open");
+		exit(1);
+	}
+
+	while ((r = read(fd, mem, 4096)) != -1 && r != 0) {
+		mem += r;
+		bytes += r;
+	}
+
+	if (r == -1) {
+		perror("read");
+		printf("read %d bytes\n", bytes);
+		exit(1);
+	}
+
+	return bytes;
+}
+
+#define ICACHE_LINE_SIZE 32
+
+void sync_caches(void *mem, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 0; i < len; i += ICACHE_LINE_SIZE)
+		asm volatile ("dcbst %0, %1" : : "g"(mem), "r"(i));
+	asm volatile ("sync");
+	for (i = 0; i < len; i += ICACHE_LINE_SIZE)
+		asm volatile ("icbi %0, %1" : : "g"(mem), "r"(i));
+	asm volatile ("sync; isync");
+}
+
+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);
+}
+
+static void *do_create_vcpu(void *_n)
+{
+	struct kvm_regs regs;
+	int n = (long)_n;
+
+	kvm_create_vcpu(kvm, n);
+	init_vcpu(n);
+
+	kvm_get_regs(kvm, n, &regs);
+	regs.pc = VM_TEST_LOAD_ADDRESS;
+	kvm_set_regs(kvm, n, &regs);
+
+	kvm_run(kvm, n, &vcpus[n]);
+	sem_post(&exited_sem);
+	return NULL;
+}
+
+static void start_vcpu(int n)
+{
+	pthread_t thread;
+
+	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"
+"  -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-ppc@vger.kernel.org>.\n"
+		, progname);
+}
+
+static void sig_ignore(int sig)
+{
+	write(1, "boo\n", 4);
+}
+
+int main(int argc, char **argv)
+{
+	void *vm_mem;
+	unsigned long len;
+	int i;
+	const char *sopts = "s:phm:";
+	struct option lopts[] = {
+		{ "smp", 1, 0, 's' },
+		{ "memory", 1, 0, 'm' },
+		{ "help", 0, 0, 'h' },
+		{ 0 },
+	};
+	int opt_ind, ch;
+	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 '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;
+	}
+
+	vm_mem = kvm_create_phys_mem(kvm, 0, memory_size, 0, 1);
+
+	len = load_file(vm_mem + VM_TEST_LOAD_ADDRESS, argv[optind], 1);
+	sync_caches(vm_mem + VM_TEST_LOAD_ADDRESS, len);
+
+	io_table_register(&mmio_table, 0xf0000000, 64, mmio_handler, NULL);
+
+	sem_init(&exited_sem, 0, 0);
+	for (i = 0; i < ncpus; ++i)
+		start_vcpu(i);
+	/* Wait for all vcpus to exit. */
+	for (i = 0; i < ncpus; ++i)
+		sem_wait(&exited_sem);
+
+	return 0;
+}
diff --git a/kvm/user/main.c b/kvm/user/main.c
new file mode 100644
index 0000000..1530ae2
--- /dev/null
+++ b/kvm/user/main.c
@@ -0,0 +1,611 @@
+/*
+ * 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@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#define _GNU_SOURCE
+
+#include <libkvm.h>
+#include "test/lib/x86/fake-apic.h"
+#include "test/x86/ioram.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>
+
+#include "iotable.h"
+
+static uint8_t ioram[IORAM_LEN];
+
+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)
+
+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 {
+	int id;
+	pid_t tid;
+	sem_t sipi_sem;
+};
+
+struct vcpu_info *vcpus;
+
+static uint32_t apic_sipi_addr;
+
+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;
+	case 0xf4: // exit
+		if (is_write)
+			exit(*value);
+		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;
+
+	err = io_table_register(&pio_table, 0xf4, 1, misc_io, NULL);
+	if (err < 0)
+		return err;
+
+	return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL);
+}
+
+#define IRQCHIP_IO_BASE 0x2000
+
+static int irqchip_io(void *opaque, int size, int is_write,
+		      uint64_t addr, uint64_t *value)
+{
+	addr -= IRQCHIP_IO_BASE;
+
+	if (is_write) {
+		kvm_set_irq_level(kvm, addr, *value, NULL);
+	}
+	return 0;
+}
+
+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;
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+static int test_debug(void *opaque, void *vcpu,
+		      struct kvm_debug_exit_arch *arch_info)
+{
+	printf("test_debug\n");
+	return 0;
+}
+#endif
+
+static int test_halt(void *opaque, int vcpu)
+{
+	int n;
+
+	sigwait(&ipi_sigmask, &n);
+	kvm_inject_irq(kvm, vcpus[vcpu].id, apic_ipi_vector);
+	return 0;
+}
+
+static int test_io_window(void *opaque)
+{
+	return 0;
+}
+
+static int test_try_push_interrupts(void *opaque)
+{
+	return 0;
+}
+
+#ifdef KVM_CAP_USER_NMI
+static void test_push_nmi(void *opaque)
+{
+}
+#endif
+
+static void test_post_kvm_run(void *opaque, void *vcpu)
+{
+}
+
+static int test_pre_kvm_run(void *opaque, void *vcpu)
+{
+	return 0;
+}
+
+static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
+{
+	if (addr < IORAM_BASE_PHYS || addr + len > IORAM_BASE_PHYS + IORAM_LEN)
+		return 1;
+	memcpy(data, ioram + addr - IORAM_BASE_PHYS, len);
+	return 0;
+}
+
+static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
+{
+	if (addr < IORAM_BASE_PHYS || addr + len > IORAM_BASE_PHYS + IORAM_LEN)
+		return 1;
+	memcpy(ioram + addr - IORAM_BASE_PHYS, data, len);
+	return 0;
+}
+
+static int test_shutdown(void *opaque, void *env)
+{
+	printf("shutdown\n");
+	kvm_show_regs(kvm, 0);
+	exit(1);
+	return 1;
+}
+
+static struct kvm_callbacks test_callbacks = {
+	.inb         = test_inb,
+	.inw         = test_inw,
+	.inl         = test_inl,
+	.outb        = test_outb,
+	.outw        = test_outw,
+	.outl        = test_outl,
+	.mmio_read   = test_mem_read,
+	.mmio_write  = test_mem_write,
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+	.debug       = test_debug,
+#endif
+	.halt        = test_halt,
+	.io_window = test_io_window,
+	.try_push_interrupts = test_try_push_interrupts,
+#ifdef KVM_CAP_USER_NMI
+	.push_nmi = test_push_nmi,
+#endif
+	.post_kvm_run = test_post_kvm_run,
+	.pre_kvm_run = test_pre_kvm_run,
+	.shutdown = test_shutdown,
+};
+
+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].id = n;
+	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, &vcpus[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@vger.kernel.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;
+	}
+
+	vm_mem = kvm_create_phys_mem(kvm, 0, memory_size, 0, 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();
+
+	io_table_register(&pio_table, IRQCHIP_IO_BASE, 0x20, irqchip_io, NULL);
+
+	sem_init(&init_sem, 0, 0);
+	for (i = 0; i < ncpus; ++i)
+		start_vcpu(i);
+	for (i = 0; i < ncpus; ++i)
+		sem_wait(&init_sem);
+
+	kvm_run(kvm, 0, &vcpus[0]);
+
+	return 0;
+}
diff --git a/kvm/user/test/lib/libcflat.h b/kvm/user/test/lib/libcflat.h
new file mode 100644
index 0000000..1da4013
--- /dev/null
+++ b/kvm/user/test/lib/libcflat.h
@@ -0,0 +1,42 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __LIBCFLAT_H
+#define __LIBCFLAT_H
+
+#include <stdarg.h>
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned u32;
+typedef unsigned long ulong;
+typedef unsigned long long u64;
+
+extern void exit(int code);
+extern void panic(char *fmt, ...);
+
+extern unsigned long strlen(const char *buf);
+extern char *strcat(char *dest, const char *src);
+
+extern int printf(const char *fmt, ...);
+extern int vsnprintf(char *buf, int size, const char *fmt, va_list va);
+
+extern void puts(const char *s);
+
+#endif
diff --git a/kvm/user/test/lib/panic.c b/kvm/user/test/lib/panic.c
new file mode 100644
index 0000000..6e0b29e
--- /dev/null
+++ b/kvm/user/test/lib/panic.c
@@ -0,0 +1,13 @@
+#include "libcflat.h"
+
+void panic(char *fmt, ...)
+{
+	va_list va;
+	char buf[2000];
+
+	va_start(va, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, va);
+	va_end(va);
+	puts(buf);
+	exit(-1);
+}
diff --git a/kvm/user/test/lib/powerpc/44x/map.c b/kvm/user/test/lib/powerpc/44x/map.c
new file mode 100644
index 0000000..113434d
--- /dev/null
+++ b/kvm/user/test/lib/powerpc/44x/map.c
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include "libcflat.h"
+
+#define TLB_SIZE 64
+
+extern void tlbwe(unsigned int index,
+		  unsigned char tid,
+		  unsigned int word0,
+		  unsigned int word1,
+		  unsigned int word2);
+
+unsigned int next_free_index;
+
+#define PAGE_SHIFT 12
+#define PAGE_MASK (~((1<<PAGE_SHIFT)-1))
+
+#define V (1<<9)
+
+void map(unsigned long vaddr, unsigned long paddr)
+{
+	unsigned int w0, w1, w2;
+
+	/* We don't install exception handlers, so we can't handle TLB misses,
+	 * so we can't loop around and overwrite entry 0. */
+	if (next_free_index++ >= TLB_SIZE)
+		panic("TLB overflow");
+
+	w0 = (vaddr & PAGE_MASK) | V;
+	w1 = paddr & PAGE_MASK;
+	w2 = 0x3;
+
+	tlbwe(next_free_index, 0, w0, w1, w2);
+}
diff --git a/kvm/user/test/lib/powerpc/44x/timebase.S b/kvm/user/test/lib/powerpc/44x/timebase.S
new file mode 100644
index 0000000..385904d
--- /dev/null
+++ b/kvm/user/test/lib/powerpc/44x/timebase.S
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+/* unsigned long long mftb(void); */
+.global mftb
+mftb:
+	mftbu	r5
+	mftbl 	r4
+	mftbu 	r3
+	cmpw 	r3, r5
+	bne 	mftb
+	blr
diff --git a/kvm/user/test/lib/powerpc/44x/timebase.h b/kvm/user/test/lib/powerpc/44x/timebase.h
new file mode 100644
index 0000000..ce85347
--- /dev/null
+++ b/kvm/user/test/lib/powerpc/44x/timebase.h
@@ -0,0 +1,25 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __TIMEBASE_H__
+#define __TIMEBASE_H__
+
+unsigned long long mftb(void);
+
+#endif /* __TIMEBASE_H__ */
diff --git a/kvm/user/test/lib/powerpc/44x/tlbwe.S b/kvm/user/test/lib/powerpc/44x/tlbwe.S
new file mode 100644
index 0000000..3790374
--- /dev/null
+++ b/kvm/user/test/lib/powerpc/44x/tlbwe.S
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#define SPRN_MMUCR 0x3b2
+
+/* tlbwe(uint index, uint8_t tid, uint word0, uint word1, uint word2) */
+.global tlbwe
+tlbwe:
+	mtspr	SPRN_MMUCR, r4
+	tlbwe	r5, r3, 0
+	tlbwe	r6, r3, 1
+	tlbwe	r7, r3, 2
+	blr
diff --git a/kvm/user/test/lib/powerpc/io.c b/kvm/user/test/lib/powerpc/io.c
new file mode 100644
index 0000000..8bd2395
--- /dev/null
+++ b/kvm/user/test/lib/powerpc/io.c
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include "libcflat.h"
+
+#define BASE 0xf0000000
+#define _putc ((volatile char *)(BASE))
+#define _exit ((volatile char *)(BASE+1))
+
+void puts(const char *s)
+{
+	while (*s != '\0')
+		*_putc = *s++;
+}
+
+void exit(int code)
+{
+	*_exit = code;
+}
diff --git a/kvm/user/test/lib/printf.c b/kvm/user/test/lib/printf.c
new file mode 100644
index 0000000..3bb9e3d
--- /dev/null
+++ b/kvm/user/test/lib/printf.c
@@ -0,0 +1,179 @@
+#include "libcflat.h"
+
+typedef struct pstream {
+    char *buffer;
+    int remain;
+    int added;
+} pstream_t;
+
+static void addchar(pstream_t *p, char c)
+{
+    if (p->remain) {
+	*p->buffer++ = c;
+	--p->remain;
+    }
+    ++p->added;
+}
+
+void print_str(pstream_t *p, const char *s)
+{
+    while (*s)
+	addchar(p, *s++);
+}
+
+static char digits[16] = "0123456789abcdef";
+
+void print_int(pstream_t *ps, long long n, int base)
+{
+    char buf[sizeof(long) * 3 + 2], *p = buf;
+    int s = 0, i;
+
+    if (n < 0) {
+	n = -n;
+	s = 1;
+    }
+
+    while (n) {
+	*p++ = digits[n % base];
+	n /= base;
+    }
+
+    if (s)
+	*p++ = '-';
+
+    if (p == buf)
+	*p++ = '0';
+
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print_str(ps, buf);
+}
+
+void print_unsigned(pstream_t *ps, unsigned long long n, int base)
+{
+    char buf[sizeof(long) * 3 + 1], *p = buf;
+    int i;
+
+    while (n) {
+	*p++ = digits[n % base];
+	n /= base;
+    }
+
+    if (p == buf)
+	*p++ = '0';
+
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print_str(ps, buf);
+}
+
+int vsnprintf(char *buf, int size, const char *fmt, va_list va)
+{
+    pstream_t s;
+
+    s.buffer = buf;
+    s.remain = size - 1;
+    s.added = 0;
+    while (*fmt) {
+	char f = *fmt++;
+	int nlong = 0;
+
+	if (f != '%') {
+	    addchar(&s, f);
+	    continue;
+	}
+    morefmt:
+	f = *fmt++;
+	switch (f) {
+	case '%':
+	    addchar(&s, '%');
+	    break;
+	case '\0':
+	    --fmt;
+	    break;
+	case 'l':
+	    ++nlong;
+	    goto morefmt;
+	case 'd':
+	    switch (nlong) {
+	    case 0:
+		print_int(&s, va_arg(va, int), 10);
+		break;
+	    case 1:
+		print_int(&s, va_arg(va, long), 10);
+		break;
+	    default:
+		print_int(&s, va_arg(va, long long), 10);
+		break;
+	    }
+	    break;
+	case 'x':
+	    switch (nlong) {
+	    case 0:
+		print_unsigned(&s, va_arg(va, unsigned), 16);
+		break;
+	    case 1:
+		print_unsigned(&s, va_arg(va, unsigned long), 16);
+		break;
+	    default:
+		print_unsigned(&s, va_arg(va, unsigned long long), 16);
+		break;
+	    }
+	    break;
+	case 'p':
+	    print_str(&s, "0x");
+	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
+	    break;
+	case 's':
+	    print_str(&s, va_arg(va, const char *));
+	    break;
+	default:
+	    addchar(&s, f);
+	    break;
+	}
+    }
+    *s.buffer = 0;
+    ++s.added;
+    return s.added;
+}
+
+
+int snprintf(char *buf, int size, const char *fmt, ...)
+{
+    va_list va;
+    int r;
+
+    va_start(va, fmt);
+    r = vsnprintf(buf, size, fmt, va);
+    va_end(va);
+    return r;
+}
+
+int printf(const char *fmt, ...)
+{
+    va_list va;
+    char buf[2000];
+    int r;
+
+    va_start(va, fmt);
+    r = vsnprintf(buf, sizeof buf, fmt, va);
+    va_end(va);
+    puts(buf);
+    return r;
+}
diff --git a/kvm/user/test/lib/string.c b/kvm/user/test/lib/string.c
new file mode 100644
index 0000000..42be946
--- /dev/null
+++ b/kvm/user/test/lib/string.c
@@ -0,0 +1,21 @@
+#include "libcflat.h"
+
+unsigned long strlen(const char *buf)
+{
+    unsigned long len = 0;
+
+    while (*buf++)
+	++len;
+    return len;
+}
+
+char *strcat(char *dest, const char *src)
+{
+    char *p = dest;
+
+    while (*p)
+	++p;
+    while ((*p++ = *src++) != 0)
+	;
+    return dest;
+}
diff --git a/kvm/user/test/lib/x86/apic-defs.h b/kvm/user/test/lib/x86/apic-defs.h
new file mode 100644
index 0000000..c061e3d
--- /dev/null
+++ b/kvm/user/test/lib/x86/apic-defs.h
@@ -0,0 +1,133 @@
+#ifndef _ASM_X86_APICDEF_H
+#define _ASM_X86_APICDEF_H
+
+/*
+ * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
+ *
+ * Alan Cox <Alan.Cox@linux.org>, 1995.
+ * Ingo Molnar <mingo@redhat.com>, 1999, 2000
+ */
+
+#define	APIC_DEFAULT_PHYS_BASE	0xfee00000
+
+#define	APIC_ID		0x20
+
+#define	APIC_LVR	0x30
+#define		APIC_LVR_MASK		0xFF00FF
+#define		GET_APIC_VERSION(x)	((x) & 0xFFu)
+#define		GET_APIC_MAXLVT(x)	(((x) >> 16) & 0xFFu)
+#ifdef CONFIG_X86_32
+#  define	APIC_INTEGRATED(x)	((x) & 0xF0u)
+#else
+#  define	APIC_INTEGRATED(x)	(1)
+#endif
+#define		APIC_XAPIC(x)		((x) >= 0x14)
+#define	APIC_TASKPRI	0x80
+#define		APIC_TPRI_MASK		0xFFu
+#define	APIC_ARBPRI	0x90
+#define		APIC_ARBPRI_MASK	0xFFu
+#define	APIC_PROCPRI	0xA0
+#define	APIC_EOI	0xB0
+#define		APIC_EIO_ACK		0x0
+#define	APIC_RRR	0xC0
+#define	APIC_LDR	0xD0
+#define		APIC_LDR_MASK		(0xFFu << 24)
+#define		GET_APIC_LOGICAL_ID(x)	(((x) >> 24) & 0xFFu)
+#define		SET_APIC_LOGICAL_ID(x)	(((x) << 24))
+#define		APIC_ALL_CPUS		0xFFu
+#define	APIC_DFR	0xE0
+#define		APIC_DFR_CLUSTER		0x0FFFFFFFul
+#define		APIC_DFR_FLAT			0xFFFFFFFFul
+#define	APIC_SPIV	0xF0
+#define		APIC_SPIV_FOCUS_DISABLED	(1 << 9)
+#define		APIC_SPIV_APIC_ENABLED		(1 << 8)
+#define	APIC_ISR	0x100
+#define	APIC_ISR_NR     0x8     /* Number of 32 bit ISR registers. */
+#define	APIC_TMR	0x180
+#define	APIC_IRR	0x200
+#define	APIC_ESR	0x280
+#define		APIC_ESR_SEND_CS	0x00001
+#define		APIC_ESR_RECV_CS	0x00002
+#define		APIC_ESR_SEND_ACC	0x00004
+#define		APIC_ESR_RECV_ACC	0x00008
+#define		APIC_ESR_SENDILL	0x00020
+#define		APIC_ESR_RECVILL	0x00040
+#define		APIC_ESR_ILLREGA	0x00080
+#define	APIC_ICR	0x300
+#define		APIC_DEST_SELF		0x40000
+#define		APIC_DEST_ALLINC	0x80000
+#define		APIC_DEST_ALLBUT	0xC0000
+#define		APIC_ICR_RR_MASK	0x30000
+#define		APIC_ICR_RR_INVALID	0x00000
+#define		APIC_ICR_RR_INPROG	0x10000
+#define		APIC_ICR_RR_VALID	0x20000
+#define		APIC_INT_LEVELTRIG	0x08000
+#define		APIC_INT_ASSERT		0x04000
+#define		APIC_ICR_BUSY		0x01000
+#define		APIC_DEST_LOGICAL	0x00800
+#define		APIC_DEST_PHYSICAL	0x00000
+#define		APIC_DM_FIXED		0x00000
+#define		APIC_DM_LOWEST		0x00100
+#define		APIC_DM_SMI		0x00200
+#define		APIC_DM_REMRD		0x00300
+#define		APIC_DM_NMI		0x00400
+#define		APIC_DM_INIT		0x00500
+#define		APIC_DM_STARTUP		0x00600
+#define		APIC_DM_EXTINT		0x00700
+#define		APIC_VECTOR_MASK	0x000FF
+#define	APIC_ICR2	0x310
+#define		GET_APIC_DEST_FIELD(x)	(((x) >> 24) & 0xFF)
+#define		SET_APIC_DEST_FIELD(x)	((x) << 24)
+#define	APIC_LVTT	0x320
+#define	APIC_LVTTHMR	0x330
+#define	APIC_LVTPC	0x340
+#define	APIC_LVT0	0x350
+#define		APIC_LVT_TIMER_BASE_MASK	(0x3 << 18)
+#define		GET_APIC_TIMER_BASE(x)		(((x) >> 18) & 0x3)
+#define		SET_APIC_TIMER_BASE(x)		(((x) << 18))
+#define		APIC_TIMER_BASE_CLKIN		0x0
+#define		APIC_TIMER_BASE_TMBASE		0x1
+#define		APIC_TIMER_BASE_DIV		0x2
+#define		APIC_LVT_TIMER_PERIODIC		(1 << 17)
+#define		APIC_LVT_MASKED			(1 << 16)
+#define		APIC_LVT_LEVEL_TRIGGER		(1 << 15)
+#define		APIC_LVT_REMOTE_IRR		(1 << 14)
+#define		APIC_INPUT_POLARITY		(1 << 13)
+#define		APIC_SEND_PENDING		(1 << 12)
+#define		APIC_MODE_MASK			0x700
+#define		GET_APIC_DELIVERY_MODE(x)	(((x) >> 8) & 0x7)
+#define		SET_APIC_DELIVERY_MODE(x, y)	(((x) & ~0x700) | ((y) << 8))
+#define			APIC_MODE_FIXED		0x0
+#define			APIC_MODE_NMI		0x4
+#define			APIC_MODE_EXTINT	0x7
+#define	APIC_LVT1	0x360
+#define	APIC_LVTERR	0x370
+#define	APIC_TMICT	0x380
+#define	APIC_TMCCT	0x390
+#define	APIC_TDCR	0x3E0
+#define APIC_SELF_IPI	0x3F0
+#define		APIC_TDR_DIV_TMBASE	(1 << 2)
+#define		APIC_TDR_DIV_1		0xB
+#define		APIC_TDR_DIV_2		0x0
+#define		APIC_TDR_DIV_4		0x1
+#define		APIC_TDR_DIV_8		0x2
+#define		APIC_TDR_DIV_16		0x3
+#define		APIC_TDR_DIV_32		0x8
+#define		APIC_TDR_DIV_64		0x9
+#define		APIC_TDR_DIV_128	0xA
+#define	APIC_EILVT0     0x500
+#define		APIC_EILVT_NR_AMD_K8	1	/* # of extended interrupts */
+#define		APIC_EILVT_NR_AMD_10H	4
+#define		APIC_EILVT_LVTOFF(x)	(((x) >> 4) & 0xF)
+#define		APIC_EILVT_MSG_FIX	0x0
+#define		APIC_EILVT_MSG_SMI	0x2
+#define		APIC_EILVT_MSG_NMI	0x4
+#define		APIC_EILVT_MSG_EXT	0x7
+#define		APIC_EILVT_MASKED	(1 << 16)
+#define	APIC_EILVT1     0x510
+#define	APIC_EILVT2     0x520
+#define	APIC_EILVT3     0x530
+
+#define APIC_BASE_MSR	0x800
+
+#endif /* _ASM_X86_APICDEF_H */
diff --git a/kvm/user/test/lib/x86/apic.c b/kvm/user/test/lib/x86/apic.c
new file mode 100644
index 0000000..7bb98ed
--- /dev/null
+++ b/kvm/user/test/lib/x86/apic.c
@@ -0,0 +1,143 @@
+#include "libcflat.h"
+#include "apic.h"
+
+static void *g_apic = (void *)0xfee00000;
+static void *g_ioapic = (void *)0xfec00000;
+
+struct apic_ops {
+    u32 (*reg_read)(unsigned reg);
+    void (*reg_write)(unsigned reg, u32 val);
+    void (*icr_write)(u32 val, u32 dest);
+    u32 (*id)(void);
+};
+
+static void outb(unsigned char data, unsigned short port)
+{
+    asm volatile ("out %0, %1" : : "a"(data), "d"(port));
+}
+
+static u32 xapic_read(unsigned reg)
+{
+    return *(volatile u32 *)(g_apic + reg);
+}
+
+static void xapic_write(unsigned reg, u32 val)
+{
+    *(volatile u32 *)(g_apic + reg) = val;
+}
+
+static void xapic_icr_write(u32 val, u32 dest)
+{
+    while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
+        ;
+    xapic_write(APIC_ICR2, dest << 24);
+    xapic_write(APIC_ICR, val);
+}
+
+static uint32_t xapic_id(void)
+{
+    return xapic_read(APIC_ID) >> 24;
+}
+
+static const struct apic_ops xapic_ops = {
+    .reg_read = xapic_read,
+    .reg_write = xapic_write,
+    .icr_write = xapic_icr_write,
+    .id = xapic_id,
+};
+
+static const struct apic_ops *apic_ops = &xapic_ops;
+
+static u32 x2apic_read(unsigned reg)
+{
+    unsigned a, d;
+
+    asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
+    return a | (u64)d << 32;
+}
+
+static void x2apic_write(unsigned reg, u32 val)
+{
+    asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
+}
+
+static void x2apic_icr_write(u32 val, u32 dest)
+{
+    asm volatile ("wrmsr" : : "a"(val), "d"(dest),
+                  "c"(APIC_BASE_MSR + APIC_ICR/16));
+}
+
+static uint32_t x2apic_id(void)
+{
+    return xapic_read(APIC_ID);
+}
+
+static const struct apic_ops x2apic_ops = {
+    .reg_read = x2apic_read,
+    .reg_write = x2apic_write,
+    .icr_write = x2apic_icr_write,
+    .id = x2apic_id,
+};
+
+u32 apic_read(unsigned reg)
+{
+    return apic_ops->reg_read(reg);
+}
+
+void apic_write(unsigned reg, u32 val)
+{
+    apic_ops->reg_write(reg, val);
+}
+
+void apic_icr_write(u32 val, u32 dest)
+{
+    apic_ops->icr_write(val, dest);
+}
+
+uint32_t apic_id(void)
+{
+    return apic_ops->id();
+}
+
+#define MSR_APIC_BASE 0x0000001b
+
+int enable_x2apic(void)
+{
+    unsigned a, b, c, d;
+
+    asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
+
+    if (c & (1 << 21)) {
+        asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_APIC_BASE));
+        a |= 1 << 10;
+        asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_APIC_BASE));
+        apic_ops = &x2apic_ops;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+void ioapic_write_reg(unsigned reg, u32 value)
+{
+    *(volatile u32 *)g_ioapic = reg;
+    *(volatile u32 *)(g_ioapic + 0x10) = value;
+}
+
+void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
+{
+    ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
+    ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
+}
+
+void enable_apic(void)
+{
+    printf("enabling apic\n");
+    xapic_write(0xf0, 0x1ff); /* spurious vector register */
+}
+
+void mask_pic_interrupts(void)
+{
+    outb(0xff, 0x21);
+    outb(0xff, 0xa1);
+}
diff --git a/kvm/user/test/lib/x86/apic.h b/kvm/user/test/lib/x86/apic.h
new file mode 100644
index 0000000..e325e9a
--- /dev/null
+++ b/kvm/user/test/lib/x86/apic.h
@@ -0,0 +1,34 @@
+#ifndef CFLAT_APIC_H
+#define CFLAT_APIC_H
+
+#include <stdint.h>
+#include "apic-defs.h"
+
+typedef struct {
+    uint8_t vector;
+    uint8_t delivery_mode:3;
+    uint8_t dest_mode:1;
+    uint8_t delivery_status:1;
+    uint8_t polarity:1;
+    uint8_t remote_irr:1;
+    uint8_t trig_mode:1;
+    uint8_t mask:1;
+    uint8_t reserve:7;
+    uint8_t reserved[4];
+    uint8_t dest_id;
+} ioapic_redir_entry_t;
+
+void mask_pic_interrupts(void);
+
+void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e);
+void ioapic_write_reg(unsigned reg, uint32_t value);
+
+void enable_apic(void);
+uint32_t apic_read(unsigned reg);
+void apic_write(unsigned reg, uint32_t val);
+void apic_icr_write(uint32_t val, uint32_t dest);
+uint32_t apic_id(void);
+
+int enable_x2apic(void);
+
+#endif
diff --git a/kvm/user/test/lib/x86/fake-apic.h b/kvm/user/test/lib/x86/fake-apic.h
new file mode 100644
index 0000000..eed63ba
--- /dev/null
+++ b/kvm/user/test/lib/x86/fake-apic.h
@@ -0,0 +1,14 @@
+#ifndef SILLY_APIC_H
+#define SILLY_APIC_H
+
+#define APIC_BASE 0x1000
+#define APIC_SIZE 0x100
+
+#define APIC_REG_NCPU        0x00
+#define APIC_REG_ID          0x04
+#define APIC_REG_SIPI_ADDR   0x08
+#define APIC_REG_SEND_SIPI   0x0c
+#define APIC_REG_IPI_VECTOR  0x10
+#define APIC_REG_SEND_IPI    0x14
+
+#endif
diff --git a/kvm/user/test/lib/x86/fwcfg.c b/kvm/user/test/lib/x86/fwcfg.c
new file mode 100644
index 0000000..2cf7cec
--- /dev/null
+++ b/kvm/user/test/lib/x86/fwcfg.c
@@ -0,0 +1,40 @@
+#include "fwcfg.h"
+
+uint64_t fwcfg_get_u(uint16_t index, int bytes)
+{
+    uint64_t r = 0;
+    uint8_t b;
+    int i;
+
+    asm volatile ("out %0, %1" : : "a"(index), "d"((uint16_t)BIOS_CFG_IOPORT));
+    for (i = 0; i < bytes; ++i) {
+        asm volatile ("in %1, %0" : "=a"(b) : "d"((uint16_t)(BIOS_CFG_IOPORT + 1)));
+        r |= (uint64_t)b << (i * 8);
+    }
+    return r;
+}
+
+uint8_t fwcfg_get_u8(unsigned index)
+{
+    return fwcfg_get_u(index, 1);
+}
+
+uint16_t fwcfg_get_u16(unsigned index)
+{
+    return fwcfg_get_u(index, 2);
+}
+
+uint32_t fwcfg_get_u32(unsigned index)
+{
+    return fwcfg_get_u(index, 4);
+}
+
+uint64_t fwcfg_get_u64(unsigned index)
+{
+    return fwcfg_get_u(index, 8);
+}
+
+unsigned fwcfg_get_nb_cpus(void)
+{
+    return fwcfg_get_u16(FW_CFG_NB_CPUS);
+}
diff --git a/kvm/user/test/lib/x86/fwcfg.h b/kvm/user/test/lib/x86/fwcfg.h
new file mode 100644
index 0000000..e0836ca
--- /dev/null
+++ b/kvm/user/test/lib/x86/fwcfg.h
@@ -0,0 +1,44 @@
+#ifndef FWCFG_H
+#define FWCFG_H
+
+#include <stdint.h>
+
+#define FW_CFG_SIGNATURE        0x00
+#define FW_CFG_ID               0x01
+#define FW_CFG_UUID             0x02
+#define FW_CFG_RAM_SIZE         0x03
+#define FW_CFG_NOGRAPHIC        0x04
+#define FW_CFG_NB_CPUS          0x05
+#define FW_CFG_MACHINE_ID       0x06
+#define FW_CFG_KERNEL_ADDR      0x07
+#define FW_CFG_KERNEL_SIZE      0x08
+#define FW_CFG_KERNEL_CMDLINE   0x09
+#define FW_CFG_INITRD_ADDR      0x0a
+#define FW_CFG_INITRD_SIZE      0x0b
+#define FW_CFG_BOOT_DEVICE      0x0c
+#define FW_CFG_NUMA             0x0d
+#define FW_CFG_BOOT_MENU        0x0e
+#define FW_CFG_MAX_CPUS         0x0f
+#define FW_CFG_MAX_ENTRY        0x10
+
+#define FW_CFG_WRITE_CHANNEL    0x4000
+#define FW_CFG_ARCH_LOCAL       0x8000
+#define FW_CFG_ENTRY_MASK       ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
+
+#define FW_CFG_INVALID          0xffff
+
+#define BIOS_CFG_IOPORT 0x510
+
+#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
+#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
+
+uint8_t fwcfg_get_u8(unsigned index);
+uint16_t fwcfg_get_u16(unsigned index);
+uint32_t fwcfg_get_u32(unsigned index);
+uint64_t fwcfg_get_u64(unsigned index);
+
+unsigned fwcfg_get_nb_cpus(void);
+
+#endif
+
diff --git a/kvm/user/test/lib/x86/io.c b/kvm/user/test/lib/x86/io.c
new file mode 100644
index 0000000..894f398
--- /dev/null
+++ b/kvm/user/test/lib/x86/io.c
@@ -0,0 +1,23 @@
+#include "libcflat.h"
+#include "smp.h"
+
+static struct spinlock lock;
+
+static void print_serial(const char *buf)
+{
+	unsigned long len = strlen(buf);
+
+	asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
+}
+
+void puts(const char *s)
+{
+	spin_lock(&lock);
+	print_serial(s);
+	spin_unlock(&lock);
+}
+
+void exit(int code)
+{
+        asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
+}
diff --git a/kvm/user/test/lib/x86/smp.c b/kvm/user/test/lib/x86/smp.c
new file mode 100644
index 0000000..241f755
--- /dev/null
+++ b/kvm/user/test/lib/x86/smp.c
@@ -0,0 +1,128 @@
+
+#include <libcflat.h>
+#include "smp.h"
+#include "apic.h"
+#include "fwcfg.h"
+
+#define IPI_VECTOR 0x20
+
+static struct spinlock ipi_lock;
+static void (*ipi_function)(void *data);
+static void *ipi_data;
+static volatile int ipi_done;
+
+static __attribute__((used)) void ipi()
+{
+    ipi_function(ipi_data);
+    apic_write(APIC_EOI, 0);
+    ipi_done = 1;
+}
+
+asm (
+     "ipi_entry: \n"
+     "   call ipi \n"
+#ifndef __x86_64__
+     "   iret"
+#else
+     "   iretq"
+#endif
+     );
+
+
+static void set_ipi_descriptor(void (*ipi_entry)(void))
+{
+    unsigned short *desc = (void *)(IPI_VECTOR * sizeof(long) * 2);
+    unsigned short cs;
+    unsigned long ipi = (unsigned long)ipi_entry;
+
+    asm ("mov %%cs, %0" : "=r"(cs));
+    desc[0] = ipi;
+    desc[1] = cs;
+    desc[2] = 0x8e00;
+    desc[3] = ipi >> 16;
+#ifdef __x86_64__
+    desc[4] = ipi >> 32;
+    desc[5] = ipi >> 48;
+    desc[6] = 0;
+    desc[7] = 0;
+#endif
+}
+
+void spin_lock(struct spinlock *lock)
+{
+    int v = 1;
+
+    do {
+	asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
+    } while (v);
+    asm volatile ("" : : : "memory");
+}
+
+void spin_unlock(struct spinlock *lock)
+{
+    asm volatile ("" : : : "memory");
+    lock->v = 0;
+}
+
+int cpu_count(void)
+{
+    return fwcfg_get_nb_cpus();
+}
+
+int smp_id(void)
+{
+    unsigned id;
+
+    asm ("mov %%gs:0, %0" : "=r"(id));
+    return id;
+}
+
+static void setup_smp_id(void *data)
+{
+    asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory");
+}
+
+static void __on_cpu(int cpu, void (*function)(void *data), void *data,
+                     int wait)
+{
+    spin_lock(&ipi_lock);
+    if (cpu == smp_id())
+	function(data);
+    else {
+	ipi_done = 0;
+	ipi_function = function;
+	ipi_data = data;
+	apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED
+                       | IPI_VECTOR,
+                       cpu);
+	if (wait) {
+		while (!ipi_done)
+		    ;
+	}
+    }
+    spin_unlock(&ipi_lock);
+}
+
+void on_cpu(int cpu, void (*function)(void *data), void *data)
+{
+    __on_cpu(cpu, function, data, 1);
+}
+
+void on_cpu_async(int cpu, void (*function)(void *data), void *data)
+{
+    __on_cpu(cpu, function, data, 0);
+}
+
+
+void smp_init(void)
+{
+    int i;
+    void ipi_entry(void);
+
+    set_ipi_descriptor(ipi_entry);
+
+    setup_smp_id(0);
+    for (i = 1; i < cpu_count(); ++i)
+        on_cpu(i, setup_smp_id, 0);
+
+}
diff --git a/kvm/user/test/lib/x86/smp.h b/kvm/user/test/lib/x86/smp.h
new file mode 100644
index 0000000..c2e7350
--- /dev/null
+++ b/kvm/user/test/lib/x86/smp.h
@@ -0,0 +1,17 @@
+#ifndef __SMP_H
+#define __SMP_H
+
+struct spinlock {
+    int v;
+};
+
+void smp_init(void);
+
+int cpu_count(void);
+int smp_id(void);
+void on_cpu(int cpu, void (*function)(void *data), void *data);
+void on_cpu_async(int cpu, void (*function)(void *data), void *data);
+void spin_lock(struct spinlock *lock);
+void spin_unlock(struct spinlock *lock);
+
+#endif
diff --git a/kvm/user/test/powerpc/44x/tlbsx.S b/kvm/user/test/powerpc/44x/tlbsx.S
new file mode 100644
index 0000000..b15874b
--- /dev/null
+++ b/kvm/user/test/powerpc/44x/tlbsx.S
@@ -0,0 +1,33 @@
+#define SPRN_MMUCR 0x3b2
+
+#define TLBWORD0 0x10000210
+#define TLBWORD1 0x10000000
+#define TLBWORD2 0x00000003
+
+.global _start
+_start:
+	li	r4, 0
+	mtspr	SPRN_MMUCR, r4
+
+	li	r3, 23
+
+	lis	r4, TLBWORD0@h
+	ori	r4, r4, TLBWORD0@l
+	tlbwe	r4, r3, 0
+
+	lis	r4, TLBWORD1@h
+	ori	r4, r4, TLBWORD1@l
+	tlbwe	r4, r3, 1
+
+	lis	r4, TLBWORD2@h
+	ori	r4, r4, TLBWORD2@l
+	tlbwe	r4, r3, 2
+
+	lis	r4, 0x1000
+	tlbsx	r5, r4, r0
+	cmpwi	r5, 23
+	beq	good
+	trap
+
+good:
+	b	.
diff --git a/kvm/user/test/powerpc/44x/tlbwe.S b/kvm/user/test/powerpc/44x/tlbwe.S
new file mode 100644
index 0000000..ec6ef5c
--- /dev/null
+++ b/kvm/user/test/powerpc/44x/tlbwe.S
@@ -0,0 +1,27 @@
+#define SPRN_MMUCR 0x3b2
+
+/* Create a mapping at 4MB */
+#define TLBWORD0 0x00400210
+#define TLBWORD1 0x00400000
+#define TLBWORD2 0x00000003
+
+.global _start
+_start:
+	li	r4, 0
+	mtspr	SPRN_MMUCR, r4
+
+	li	r3, 23
+
+	lis	r4, TLBWORD0@h
+	ori	r4, r4, TLBWORD0@l
+	tlbwe	r4, r3, 0
+
+	lis	r4, TLBWORD1@h
+	ori	r4, r4, TLBWORD1@l
+	tlbwe	r4, r3, 1
+
+	lis	r4, TLBWORD2@h
+	ori	r4, r4, TLBWORD2@l
+	tlbwe	r4, r3, 2
+
+	b	.
diff --git a/kvm/user/test/powerpc/44x/tlbwe_16KB.S b/kvm/user/test/powerpc/44x/tlbwe_16KB.S
new file mode 100644
index 0000000..1bd10bf
--- /dev/null
+++ b/kvm/user/test/powerpc/44x/tlbwe_16KB.S
@@ -0,0 +1,35 @@
+#define SPRN_MMUCR 0x3b2
+
+/* 16KB mapping at 4MB */
+#define TLBWORD0 0x00400220
+#define TLBWORD1 0x00400000
+#define TLBWORD2 0x00000003
+
+.global _start
+_start:
+	li	r4, 0
+	mtspr	SPRN_MMUCR, r4
+
+	li	r3, 5
+
+	lis	r4, TLBWORD0@h
+	ori	r4, r4, TLBWORD0@l
+	tlbwe	r4, r3, 0
+
+	lis	r4, TLBWORD1@h
+	ori	r4, r4, TLBWORD1@l
+	tlbwe	r4, r3, 1
+
+	lis	r4, TLBWORD2@h
+	ori	r4, r4, TLBWORD2@l
+	tlbwe	r4, r3, 2
+
+	/* load from 4MB */
+	lis	r3, 0x0040
+	lwz	r4, 0(r3)
+
+	/* load from 4MB+8KB */
+	ori	r3, r3, 0x2000
+	lwz	r4, 0(r3)
+
+	b	.
diff --git a/kvm/user/test/powerpc/44x/tlbwe_hole.S b/kvm/user/test/powerpc/44x/tlbwe_hole.S
new file mode 100644
index 0000000..5efd303
--- /dev/null
+++ b/kvm/user/test/powerpc/44x/tlbwe_hole.S
@@ -0,0 +1,27 @@
+#define SPRN_MMUCR 0x3b2
+
+/* Try to map real address 1GB. */
+#define TLBWORD0 0x40000210
+#define TLBWORD1 0x40000000
+#define TLBWORD2 0x00000003
+
+.global _start
+_start:
+	li	r4, 0
+	mtspr	SPRN_MMUCR, r4
+
+	li	r3, 23
+
+	lis	r4, TLBWORD0@h
+	ori	r4, r4, TLBWORD0@l
+	tlbwe	r4, r3, 0
+
+	lis	r4, TLBWORD1@h
+	ori	r4, r4, TLBWORD1@l
+	tlbwe	r4, r3, 1
+
+	lis	r4, TLBWORD2@h
+	ori	r4, r4, TLBWORD2@l
+	tlbwe	r4, r3, 2
+
+	b	.
diff --git a/kvm/user/test/powerpc/cstart.S b/kvm/user/test/powerpc/cstart.S
new file mode 100644
index 0000000..70a0e9f
--- /dev/null
+++ b/kvm/user/test/powerpc/cstart.S
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation;
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#define OUTPUT_VADDR 0xf0000000
+#define OUTPUT_PADDR 0xf0000000
+
+.globl _start
+_start:
+	/* In the future we might need to assign a stack and zero BSS here. */
+
+	/* Map the debug page 1:1. */
+	lis	r3, OUTPUT_VADDR@h
+	ori	r3, r3, OUTPUT_VADDR@l
+	lis	r4, OUTPUT_PADDR@h
+	ori	r4, r4, OUTPUT_PADDR@l
+	bl	map
+
+	/* Call main() and pass return code to exit(). */
+	bl	main
+	bl	exit
+
+	b	.
diff --git a/kvm/user/test/powerpc/exit.c b/kvm/user/test/powerpc/exit.c
new file mode 100644
index 0000000..804ee04
--- /dev/null
+++ b/kvm/user/test/powerpc/exit.c
@@ -0,0 +1,23 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation;
+ *
+ * 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. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+int main(void)
+{
+	return 1;
+}
diff --git a/kvm/user/test/powerpc/helloworld.c b/kvm/user/test/powerpc/helloworld.c
new file mode 100644
index 0000000..f8630f7
--- /dev/null
+++ b/kvm/user/test/powerpc/helloworld.c
@@ -0,0 +1,27 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation;
+ *
+ * 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. 2008
+ *
+ * Authors: Deepa Srinivasan <deepas@us.ibm.com>
+ */
+
+#include "libcflat.h"
+
+int main()
+{
+	printf("Hello World\n");
+
+	return 1;
+}
diff --git a/kvm/user/test/powerpc/io.S b/kvm/user/test/powerpc/io.S
new file mode 100644
index 0000000..97567cb
--- /dev/null
+++ b/kvm/user/test/powerpc/io.S
@@ -0,0 +1,32 @@
+#define SPRN_MMUCR 0x3b2
+
+#define TLBWORD0 0xf0000210
+#define TLBWORD1 0xf0000000
+#define TLBWORD2 0x00000003
+
+.global _start
+_start:
+	li	r4, 0
+	mtspr	SPRN_MMUCR, r4
+
+	li	r3, 2
+
+	lis	r4, TLBWORD0@h
+	ori	r4, r4, TLBWORD0@l
+	tlbwe	r4, r3, 0
+
+	lis	r4, TLBWORD1@h
+	ori	r4, r4, TLBWORD1@l
+	tlbwe	r4, r3, 1
+
+	lis	r4, TLBWORD2@h
+	ori	r4, r4, TLBWORD2@l
+	tlbwe	r4, r3, 2
+
+	lis	r3, 0xf000
+	lis	r4, 0x1234
+	ori	r4, r4, 0x5678
+	stb	r4, 0(r3)
+	lbz	r5, 0(r3)
+
+	b	.
diff --git a/kvm/user/test/powerpc/spin.S b/kvm/user/test/powerpc/spin.S
new file mode 100644
index 0000000..4406641
--- /dev/null
+++ b/kvm/user/test/powerpc/spin.S
@@ -0,0 +1,4 @@
+
+.global _start
+_start:
+	b	.
diff --git a/kvm/user/test/powerpc/sprg.S b/kvm/user/test/powerpc/sprg.S
new file mode 100644
index 0000000..d0414a4
--- /dev/null
+++ b/kvm/user/test/powerpc/sprg.S
@@ -0,0 +1,7 @@
+
+.global _start
+_start:
+	li	r3, 42
+	mtsprg	0, r3
+	mfsprg	r4, 0
+	b	.
diff --git a/kvm/user/test/x86/access.c b/kvm/user/test/x86/access.c
new file mode 100644
index 0000000..5eadff8
--- /dev/null
+++ b/kvm/user/test/x86/access.c
@@ -0,0 +1,604 @@
+
+#include "libcflat.h"
+
+#define smp_id() 0
+
+#define true 1
+#define false 0
+
+typedef unsigned long pt_element_t;
+
+#define PAGE_SIZE ((pt_element_t)4096)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#define PT_BASE_ADDR_MASK ((pt_element_t)((((pt_element_t)1 << 40) - 1) & PAGE_MASK))
+#define PT_PSE_BASE_ADDR_MASK (PT_BASE_ADDR_MASK & ~(1ull << 21))
+
+#define PT_PRESENT_MASK    ((pt_element_t)1 << 0)
+#define PT_WRITABLE_MASK   ((pt_element_t)1 << 1)
+#define PT_USER_MASK       ((pt_element_t)1 << 2)
+#define PT_ACCESSED_MASK   ((pt_element_t)1 << 5)
+#define PT_DIRTY_MASK      ((pt_element_t)1 << 6)
+#define PT_PSE_MASK        ((pt_element_t)1 << 7)
+#define PT_NX_MASK         ((pt_element_t)1 << 63)
+
+#define CR0_WP_MASK (1UL << 16)
+
+#define PFERR_PRESENT_MASK (1U << 0)
+#define PFERR_WRITE_MASK (1U << 1)
+#define PFERR_USER_MASK (1U << 2)
+#define PFERR_RESERVED_MASK (1U << 3)
+#define PFERR_FETCH_MASK (1U << 4)
+
+#define MSR_EFER 0xc0000080
+#define EFER_NX_MASK		(1ull << 11)
+
+/*
+ * page table access check tests
+ */
+
+enum {
+    AC_PTE_PRESENT,
+    AC_PTE_WRITABLE,
+    AC_PTE_USER,
+    AC_PTE_ACCESSED,
+    AC_PTE_DIRTY,
+    AC_PTE_NX,
+    AC_PTE_BIT51,
+
+    AC_PDE_PRESENT,
+    AC_PDE_WRITABLE,
+    AC_PDE_USER,
+    AC_PDE_ACCESSED,
+    AC_PDE_DIRTY,
+    AC_PDE_PSE,
+    AC_PDE_NX,
+    AC_PDE_BIT51,
+
+    AC_ACCESS_USER,
+    AC_ACCESS_WRITE,
+    AC_ACCESS_FETCH,
+    AC_ACCESS_TWICE,
+    // AC_ACCESS_PTE,
+
+    AC_CPU_EFER_NX,
+    AC_CPU_CR0_WP,
+
+    NR_AC_FLAGS
+};
+
+const char *ac_names[] = {
+    [AC_PTE_PRESENT] = "pte.p",
+    [AC_PTE_ACCESSED] = "pte.a",
+    [AC_PTE_WRITABLE] = "pte.rw",
+    [AC_PTE_USER] = "pte.user",
+    [AC_PTE_DIRTY] = "pte.d",
+    [AC_PTE_NX] = "pte.nx",
+    [AC_PTE_BIT51] = "pte.51",
+    [AC_PDE_PRESENT] = "pde.p",
+    [AC_PDE_ACCESSED] = "pde.a",
+    [AC_PDE_WRITABLE] = "pde.rw",
+    [AC_PDE_USER] = "pde.user",
+    [AC_PDE_DIRTY] = "pde.d",
+    [AC_PDE_PSE] = "pde.pse",
+    [AC_PDE_NX] = "pde.nx",
+    [AC_PDE_BIT51] = "pde.51",
+    [AC_ACCESS_WRITE] = "write",
+    [AC_ACCESS_USER] = "user",
+    [AC_ACCESS_FETCH] = "fetch",
+    [AC_ACCESS_TWICE] = "twice",
+    [AC_CPU_EFER_NX] = "efer.nx",
+    [AC_CPU_CR0_WP] = "cr0.wp",
+};
+
+static inline void *va(pt_element_t phys)
+{
+    return (void *)phys;
+}
+
+static unsigned long read_cr0()
+{
+    unsigned long cr0;
+
+    asm volatile ("mov %%cr0, %0" : "=r"(cr0));
+
+    return cr0;
+}
+
+static void write_cr0(unsigned long cr0)
+{
+    asm volatile ("mov %0, %%cr0" : : "r"(cr0));
+}
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+    unsigned offset2;
+    unsigned reserved;
+} idt_entry_t;
+
+typedef struct {
+    unsigned flags[NR_AC_FLAGS];
+    void *virt;
+    pt_element_t phys;
+    pt_element_t pt_pool;
+    unsigned pt_pool_size;
+    unsigned pt_pool_current;
+    pt_element_t *ptep;
+    pt_element_t expected_pte;
+    pt_element_t *pdep;
+    pt_element_t expected_pde;
+    int expected_fault;
+    unsigned expected_error;
+    idt_entry_t idt[256];
+} ac_test_t;
+
+typedef struct {
+    unsigned short limit;
+    unsigned long linear_addr;
+} __attribute__((packed)) descriptor_table_t;
+
+void lidt(idt_entry_t *idt, int nentries)
+{
+    descriptor_table_t dt;
+    
+    dt.limit = nentries * sizeof(*idt) - 1;
+    dt.linear_addr = (unsigned long)idt;
+    asm volatile ("lidt %0" : : "m"(dt));
+}
+
+void memset(void *a, unsigned char v, int n)
+{
+    unsigned char *x = a;
+
+    while (n--)
+	*x++ = v;
+}
+
+unsigned short read_cs()
+{
+    unsigned short r;
+
+    asm volatile ("mov %%cs, %0" : "=r"(r));
+    return r;
+}
+
+unsigned long long rdmsr(unsigned index)
+{
+    unsigned a, d;
+
+    asm volatile("rdmsr" : "=a"(a), "=d"(d) : "c"(index));
+    return ((unsigned long long)d << 32) | a;
+}
+
+void wrmsr(unsigned index, unsigned long long val)
+{
+    unsigned a = val, d = val >> 32;
+
+    asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(index));
+}
+
+void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
+{
+    memset(e, 0, sizeof *e);
+    e->offset0 = (unsigned long)addr;
+    e->selector = read_cs();
+    e->ist = 0;
+    e->type = 14;
+    e->dpl = dpl;
+    e->p = 1;
+    e->offset1 = (unsigned long)addr >> 16;
+    e->offset2 = (unsigned long)addr >> 32;
+}
+
+void set_cr0_wp(int wp)
+{
+    unsigned long cr0 = read_cr0();
+
+    cr0 &= ~CR0_WP_MASK;
+    if (wp)
+	cr0 |= CR0_WP_MASK;
+    write_cr0(cr0);
+}
+
+void set_efer_nx(int nx)
+{
+    unsigned long long efer;
+
+    efer = rdmsr(MSR_EFER);
+    efer &= ~EFER_NX_MASK;
+    if (nx)
+	efer |= EFER_NX_MASK;
+    wrmsr(MSR_EFER, efer);
+}
+
+
+void ac_test_init(ac_test_t *at)
+{
+    wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
+    set_cr0_wp(1);
+    for (int i = 0; i < NR_AC_FLAGS; ++i)
+	at->flags[i] = 0;
+    at->virt = (void *)(0x123400000000 + 16 * smp_id());
+    at->phys = 32 * 1024 * 1024;
+    at->pt_pool = 33 * 1024 * 1024;
+    at->pt_pool_size = 120 * 1024 * 1024 - at->pt_pool;
+    at->pt_pool_current = 0;
+    memset(at->idt, 0, sizeof at->idt);
+    lidt(at->idt, 256);
+    extern char page_fault, kernel_entry;
+    set_idt_entry(&at->idt[14], &page_fault, 0);
+    set_idt_entry(&at->idt[0x20], &kernel_entry, 3);
+}
+
+int ac_test_bump_one(ac_test_t *at)
+{
+    for (int i = 0; i < NR_AC_FLAGS; ++i)
+	if (!at->flags[i]) {
+	    at->flags[i] = 1;
+	    return 1;
+	} else
+	    at->flags[i] = 0;
+    return 0;
+}
+
+_Bool ac_test_legal(ac_test_t *at)
+{
+    if (at->flags[AC_ACCESS_FETCH] && at->flags[AC_ACCESS_WRITE])
+	return false;
+    return true;
+}
+
+int ac_test_bump(ac_test_t *at)
+{
+    int ret;
+
+    ret = ac_test_bump_one(at);
+    while (ret && !ac_test_legal(at))
+	ret = ac_test_bump_one(at);
+    return ret;
+}
+
+unsigned long read_cr3()
+{
+    unsigned long cr3;
+
+    asm volatile ("mov %%cr3, %0" : "=r"(cr3));
+    return cr3;
+}
+
+void invlpg(void *addr)
+{
+    asm volatile ("invlpg (%0)" : : "r"(addr));
+}
+
+pt_element_t ac_test_alloc_pt(ac_test_t *at)
+{
+    pt_element_t ret = at->pt_pool + at->pt_pool_current;
+    at->pt_pool_current += PAGE_SIZE;
+    return ret;
+}
+
+_Bool ac_test_enough_room(ac_test_t *at)
+{
+    return at->pt_pool_current + 4 * PAGE_SIZE <= at->pt_pool_size;
+}
+
+void ac_test_reset_pt_pool(ac_test_t *at)
+{
+    at->pt_pool_current = 0;
+}
+
+void ac_test_setup_pte(ac_test_t *at)
+{
+    unsigned long root = read_cr3();
+    int pde_valid, pte_valid;
+
+    if (!ac_test_enough_room(at))
+	ac_test_reset_pt_pool(at);
+
+    at->ptep = 0;
+    for (int i = 4; i >= 1 && (i >= 2 || !at->flags[AC_PDE_PSE]); --i) {
+	pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK);
+	unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511;
+	pt_element_t pte = 0;
+	switch (i) {
+	case 4:
+	case 3:
+	    pte = vroot[index];
+	    pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;
+	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;
+	    break;
+	case 2:
+	    if (!at->flags[AC_PDE_PSE])
+		pte = ac_test_alloc_pt(at);
+	    else {
+		pte = at->phys & PT_PSE_BASE_ADDR_MASK;
+		pte |= PT_PSE_MASK;
+	    }
+	    if (at->flags[AC_PDE_PRESENT])
+		pte |= PT_PRESENT_MASK;
+	    if (at->flags[AC_PDE_WRITABLE])
+		pte |= PT_WRITABLE_MASK;
+	    if (at->flags[AC_PDE_USER])
+		pte |= PT_USER_MASK;
+	    if (at->flags[AC_PDE_ACCESSED])
+		pte |= PT_ACCESSED_MASK;
+	    if (at->flags[AC_PDE_DIRTY])
+		pte |= PT_DIRTY_MASK;
+	    if (at->flags[AC_PDE_NX])
+		pte |= PT_NX_MASK;
+	    if (at->flags[AC_PDE_BIT51])
+		pte |= 1ull << 51;
+	    at->pdep = &vroot[index];
+	    break;
+	case 1:
+	    pte = at->phys & PT_BASE_ADDR_MASK;
+	    if (at->flags[AC_PTE_PRESENT])
+		pte |= PT_PRESENT_MASK;
+	    if (at->flags[AC_PTE_WRITABLE])
+		pte |= PT_WRITABLE_MASK;
+	    if (at->flags[AC_PTE_USER])
+		pte |= PT_USER_MASK;
+	    if (at->flags[AC_PTE_ACCESSED])
+		pte |= PT_ACCESSED_MASK;
+	    if (at->flags[AC_PTE_DIRTY])
+		pte |= PT_DIRTY_MASK;
+	    if (at->flags[AC_PTE_NX])
+		pte |= PT_NX_MASK;
+	    if (at->flags[AC_PTE_BIT51])
+		pte |= 1ull << 51;
+	    at->ptep = &vroot[index];
+	    break;
+	}
+	vroot[index] = pte;
+	root = vroot[index];
+    }
+    invlpg(at->virt);
+    if (at->ptep)
+	at->expected_pte = *at->ptep;
+    at->expected_pde = *at->pdep;
+    at->expected_fault = 0;
+    at->expected_error = PFERR_PRESENT_MASK;
+
+    pde_valid = at->flags[AC_PDE_PRESENT]
+        && !at->flags[AC_PDE_BIT51]
+        && !(at->flags[AC_PDE_NX] && !at->flags[AC_CPU_EFER_NX]);
+    pte_valid = pde_valid
+        && at->flags[AC_PTE_PRESENT]
+        && !at->flags[AC_PTE_BIT51]
+        && !(at->flags[AC_PTE_NX] && !at->flags[AC_CPU_EFER_NX]);
+    if (at->flags[AC_ACCESS_TWICE]) {
+	if (pde_valid) {
+	    at->expected_pde |= PT_ACCESSED_MASK;
+	    if (pte_valid)
+		at->expected_pte |= PT_ACCESSED_MASK;
+	}
+    }
+
+    if (at->flags[AC_ACCESS_USER])
+	at->expected_error |= PFERR_USER_MASK;
+
+    if (at->flags[AC_ACCESS_WRITE])
+	at->expected_error |= PFERR_WRITE_MASK;
+
+    if (at->flags[AC_ACCESS_FETCH])
+	at->expected_error |= PFERR_FETCH_MASK;
+
+    if (!at->flags[AC_PDE_PRESENT]) {
+	at->expected_fault = 1;
+	at->expected_error &= ~PFERR_PRESENT_MASK;
+    } else if (!pde_valid) {
+        at->expected_fault = 1;
+        at->expected_error |= PFERR_RESERVED_MASK;
+    }
+
+    if (at->flags[AC_ACCESS_USER] && !at->flags[AC_PDE_USER])
+	at->expected_fault = 1;
+
+    if (at->flags[AC_ACCESS_WRITE]
+	&& !at->flags[AC_PDE_WRITABLE]
+	&& (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER]))
+	at->expected_fault = 1;
+
+    if (at->flags[AC_ACCESS_FETCH] && at->flags[AC_PDE_NX])
+	at->expected_fault = 1;
+
+    if (at->expected_fault)
+	goto fault;
+
+    at->expected_pde |= PT_ACCESSED_MASK;
+
+    if (at->flags[AC_PDE_PSE]) {
+	if (at->flags[AC_ACCESS_WRITE])
+	    at->expected_pde |= PT_DIRTY_MASK;
+	goto no_pte;
+    }
+
+    if (!at->flags[AC_PTE_PRESENT]) {
+	at->expected_fault = 1;
+	at->expected_error &= ~PFERR_PRESENT_MASK;
+    } else if (!pte_valid) {
+        at->expected_fault = 1;
+        at->expected_error |= PFERR_RESERVED_MASK;
+    }
+
+    if (at->flags[AC_ACCESS_USER] && !at->flags[AC_PTE_USER])
+	at->expected_fault = 1;
+
+    if (at->flags[AC_ACCESS_WRITE]
+	&& !at->flags[AC_PTE_WRITABLE]
+	&& (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER]))
+	at->expected_fault = 1;
+
+    if (at->flags[AC_ACCESS_FETCH] && at->flags[AC_PTE_NX])
+	at->expected_fault = 1;
+
+    if (at->expected_fault)
+	goto fault;
+
+    at->expected_pte |= PT_ACCESSED_MASK;
+    if (at->flags[AC_ACCESS_WRITE])
+	at->expected_pte |= PT_DIRTY_MASK;
+
+no_pte:
+fault:
+    ;
+}
+
+int ac_test_do_access(ac_test_t *at)
+{
+    static unsigned unique = 42;
+    int fault = 0;
+    unsigned e;
+    static unsigned char user_stack[4096];
+    unsigned long rsp;
+
+    ++unique;
+
+    *((unsigned char *)at->phys) = 0xc3; /* ret */
+
+    unsigned r = unique;
+    set_cr0_wp(at->flags[AC_CPU_CR0_WP]);
+    set_efer_nx(at->flags[AC_CPU_EFER_NX]);
+
+    if (at->flags[AC_ACCESS_TWICE]) {
+	asm volatile (
+	    "mov $fixed2, %%rsi \n\t"
+	    "mov (%[addr]), %[reg] \n\t"
+	    "fixed2:"
+	    : [reg]"=r"(r), [fault]"=a"(fault), "=b"(e)
+	    : [addr]"r"(at->virt)
+	    : "rsi"
+	    );
+	fault = 0;
+    }
+
+    asm volatile ("mov $fixed1, %%rsi \n\t"
+		  "mov %%rsp, %%rdx \n\t"
+		  "cmp $0, %[user] \n\t"
+		  "jz do_access \n\t"
+		  "push %%rax; mov %[user_ds], %%ax; mov %%ax, %%ds; pop %%rax  \n\t"
+		  "pushq %[user_ds] \n\t"
+		  "pushq %[user_stack_top] \n\t"
+		  "pushfq \n\t"
+		  "pushq %[user_cs] \n\t"
+		  "pushq $do_access \n\t"
+		  "iretq \n"
+		  "do_access: \n\t"
+		  "cmp $0, %[fetch] \n\t"
+		  "jnz 2f \n\t"
+		  "cmp $0, %[write] \n\t"
+		  "jnz 1f \n\t"
+		  "mov (%[addr]), %[reg] \n\t"
+		  "jmp done \n\t"
+		  "1: mov %[reg], (%[addr]) \n\t"
+		  "jmp done \n\t"
+		  "2: call *%[addr] \n\t"
+		  "done: \n"
+		  "fixed1: \n"
+		  "int %[kernel_entry_vector] \n\t"
+		  "back_to_kernel:"
+		  : [reg]"+r"(r), "+a"(fault), "=b"(e), "=&d"(rsp)
+		  : [addr]"r"(at->virt),
+		    [write]"r"(at->flags[AC_ACCESS_WRITE]),
+		    [user]"r"(at->flags[AC_ACCESS_USER]),
+		    [fetch]"r"(at->flags[AC_ACCESS_FETCH]),
+		    [user_ds]"i"(32+3),
+		    [user_cs]"i"(24+3),
+		    [user_stack_top]"r"(user_stack + sizeof user_stack),
+		    [kernel_entry_vector]"i"(0x20)
+		  : "rsi");
+
+    asm volatile (".section .text.pf \n\t"
+		  "page_fault: \n\t"
+		  "pop %rbx \n\t"
+		  "mov %rsi, (%rsp) \n\t"
+		  "movl $1, %eax \n\t"
+		  "iretq \n\t"
+		  ".section .text");
+
+    asm volatile (".section .text.entry \n\t"
+		  "kernel_entry: \n\t"
+		  "mov %rdx, %rsp \n\t"
+		  "jmp back_to_kernel \n\t"
+		  ".section .text");
+
+    if (fault && !at->expected_fault) {
+	printf("FAIL: unexpected fault\n");
+	return 0;
+    }
+    if (!fault && at->expected_fault) {
+	printf("FAIL: unexpected access\n");
+	return 0;
+    }
+    if (fault && e != at->expected_error) {
+	printf("FAIL: error code %x expected %x\n", e, at->expected_error);
+	return 0;
+    }
+    if (at->ptep && *at->ptep != at->expected_pte) {
+	printf("FAIL: pte %x expected %x\n", *at->ptep, at->expected_pte);
+	return 0;
+    }
+
+    if (*at->pdep != at->expected_pde) {
+	printf("FAIL: pde %x expected %x\n", *at->pdep, at->expected_pde);
+	return 0;
+    }
+
+    printf("PASS\n");
+    return 1;
+}
+
+int ac_test_exec(ac_test_t *at)
+{
+    int r;
+    char line[5000];
+
+    *line = 0;
+    strcat(line, "test");
+    for (int i = 0; i < NR_AC_FLAGS; ++i)
+	if (at->flags[i]) {
+	    strcat(line, " ");
+	    strcat(line, ac_names[i]);
+	}
+    strcat(line, ": ");
+    printf("%s", line);
+    ac_test_setup_pte(at);
+    r = ac_test_do_access(at);
+    return r;
+}
+
+int ac_test_run(void)
+{
+    static ac_test_t at;
+    int tests, successes;
+
+    printf("run\n");
+    tests = successes = 0;
+    ac_test_init(&at);
+    do {
+	++tests;
+	successes += ac_test_exec(&at);
+    } while (ac_test_bump(&at));
+
+    printf("\n%d tests, %d failures\n", tests, tests - successes);
+
+    return successes == tests;
+}
+
+int main()
+{
+    int r;
+
+    printf("starting test\n\n");
+    r = ac_test_run();
+    return r ? 0 : 1;
+}
diff --git a/kvm/user/test/x86/apic.c b/kvm/user/test/x86/apic.c
new file mode 100644
index 0000000..b6718ec
--- /dev/null
+++ b/kvm/user/test/x86/apic.c
@@ -0,0 +1,317 @@
+#include "libcflat.h"
+#include "apic.h"
+#include "vm.h"
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+#ifdef __x86_64__
+    unsigned offset2;
+    unsigned reserved;
+#endif
+} idt_entry_t;
+
+typedef struct {
+    ulong regs[sizeof(ulong)*2];
+    ulong func;
+    ulong rip;
+    ulong cs;
+    ulong rflags;
+} isr_regs_t;
+
+#ifdef __x86_64__
+#  define R "r"
+#else
+#  define R "e"
+#endif
+
+extern char isr_entry_point[];
+
+asm (
+    "isr_entry_point: \n"
+#ifdef __x86_64__
+    "push %r15 \n\t"
+    "push %r14 \n\t"
+    "push %r13 \n\t"
+    "push %r12 \n\t"
+    "push %r11 \n\t"
+    "push %r10 \n\t"
+    "push %r9  \n\t"
+    "push %r8  \n\t"
+#endif
+    "push %"R "di \n\t"
+    "push %"R "si \n\t"
+    "push %"R "bp \n\t"
+    "push %"R "sp \n\t"
+    "push %"R "bx \n\t"
+    "push %"R "dx \n\t"
+    "push %"R "cx \n\t"
+    "push %"R "ax \n\t"
+#ifdef __x86_64__
+    "mov %rsp, %rdi \n\t"
+    "callq *8*16(%rsp) \n\t"
+#else
+    "push %esp \n\t"
+    "calll *4+4*8(%esp) \n\t"
+    "add $4, %esp \n\t"
+#endif
+    "pop %"R "ax \n\t"
+    "pop %"R "cx \n\t"
+    "pop %"R "dx \n\t"
+    "pop %"R "bx \n\t"
+    "pop %"R "bp \n\t"
+    "pop %"R "bp \n\t"
+    "pop %"R "si \n\t"
+    "pop %"R "di \n\t"
+#ifdef __x86_64__
+    "pop %r8  \n\t"
+    "pop %r9  \n\t"
+    "pop %r10 \n\t"
+    "pop %r11 \n\t"
+    "pop %r12 \n\t"
+    "pop %r13 \n\t"
+    "pop %r14 \n\t"
+    "pop %r15 \n\t"
+#endif
+#ifdef __x86_64__
+    "add $8, %rsp \n\t"
+    "iretq \n\t"
+#else
+    "add $4, %esp \n\t"
+    "iretl \n\t"
+#endif
+    );
+
+static idt_entry_t idt[256];
+
+static int g_fail;
+static int g_tests;
+
+static void outb(unsigned char data, unsigned short port)
+{
+    asm volatile ("out %0, %1" : : "a"(data), "d"(port));
+}
+
+static void report(const char *msg, int pass)
+{
+    ++g_tests;
+    printf("%s: %s\n", msg, (pass ? "PASS" : "FAIL"));
+    if (!pass)
+        ++g_fail;
+}
+
+static void test_lapic_existence(void)
+{
+    u32 lvr;
+
+    lvr = apic_read(APIC_LVR);
+    printf("apic version: %x\n", lvr);
+    report("apic existence", (u16)lvr == 0x14);
+}
+
+#define MSR_APIC_BASE 0x0000001b
+
+void test_enable_x2apic(void)
+{
+    if (enable_x2apic()) {
+        printf("x2apic enabled\n");
+    } else {
+        printf("x2apic not detected\n");
+    }
+}
+
+static u16 read_cs(void)
+{
+    u16 v;
+
+    asm("mov %%cs, %0" : "=rm"(v));
+    return v;
+}
+
+static void init_idt(void)
+{
+    struct {
+        u16 limit;
+        ulong idt;
+    } __attribute__((packed)) idt_ptr = {
+        sizeof(idt_entry_t) * 256 - 1,
+        (ulong)&idt,
+    };
+
+    asm volatile("lidt %0" : : "m"(idt_ptr));
+}
+
+static void set_idt_entry(unsigned vec, void (*func)(isr_regs_t *regs))
+{
+    u8 *thunk = vmalloc(50);
+    ulong ptr = (ulong)thunk;
+    idt_entry_t ent = {
+        .offset0 = ptr,
+        .selector = read_cs(),
+        .ist = 0,
+        .type = 14,
+        .dpl = 0,
+        .p = 1,
+        .offset1 = ptr >> 16,
+#ifdef __x86_64__
+        .offset2 = ptr >> 32,
+#endif
+    };
+#ifdef __x86_64__
+    /* sub $8, %rsp */
+    *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
+    /* mov $func_low, %(rsp) */
+    *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24;
+    *(u32 *)thunk = (ulong)func; thunk += 4;
+    /* mov $func_high, %(rsp+4) */
+    *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04;
+    *(u32 *)thunk = (ulong)func >> 32; thunk += 4;
+    /* jmp isr_entry_point */
+    *thunk ++ = 0xe9;
+    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#else
+    /* push $func */
+    *thunk++ = 0x68;
+    *(u32 *)thunk = (ulong)func;
+    /* jmp isr_entry_point */
+    *thunk ++ = 0xe9;
+    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#endif
+    idt[vec] = ent;
+}
+
+static void irq_disable(void)
+{
+    asm volatile("cli");
+}
+
+static void irq_enable(void)
+{
+    asm volatile("sti");
+}
+
+static void eoi(void)
+{
+    apic_write(APIC_EOI, 0);
+}
+
+static int ipi_count;
+
+static void self_ipi_isr(isr_regs_t *regs)
+{
+    ++ipi_count;
+    eoi();
+}
+
+static void test_self_ipi(void)
+{
+    int vec = 0xf1;
+
+    set_idt_entry(vec, self_ipi_isr);
+    irq_enable();
+    apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
+                   0);
+    asm volatile ("nop");
+    report("self ipi", ipi_count == 1);
+}
+
+static void set_ioapic_redir(unsigned line, unsigned vec)
+{
+    ioapic_redir_entry_t e = {
+        .vector = vec,
+        .delivery_mode = 0,
+        .trig_mode = 0,
+    };
+
+    ioapic_write_redir(line, e);
+}
+
+static void set_irq_line(unsigned line, int val)
+{
+    asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line)));
+}
+
+static void toggle_irq_line(unsigned line)
+{
+    set_irq_line(line, 1);
+    set_irq_line(line, 0);
+}
+
+static int g_isr_77;
+
+static void ioapic_isr_77(isr_regs_t *regs)
+{
+    ++g_isr_77;
+    eoi();
+}
+
+static void test_ioapic_intr(void)
+{
+    set_idt_entry(0x77, ioapic_isr_77);
+    set_ioapic_redir(0x10, 0x77);
+    toggle_irq_line(0x10);
+    asm volatile ("nop");
+    report("ioapic interrupt", g_isr_77 == 1);
+}
+
+static int g_78, g_66, g_66_after_78;
+static ulong g_66_rip, g_78_rip;
+
+static void ioapic_isr_78(isr_regs_t *regs)
+{
+    ++g_78;
+    g_78_rip = regs->rip;
+    eoi();
+}
+
+static void ioapic_isr_66(isr_regs_t *regs)
+{
+    ++g_66;
+    if (g_78)
+        ++g_66_after_78;
+    g_66_rip = regs->rip;
+    eoi();
+}
+
+static void test_ioapic_simultaneous(void)
+{
+    set_idt_entry(0x78, ioapic_isr_78);
+    set_idt_entry(0x66, ioapic_isr_66);
+    set_ioapic_redir(0x10, 0x78);
+    set_ioapic_redir(0x11, 0x66);
+    irq_disable();
+    toggle_irq_line(0x11);
+    toggle_irq_line(0x10);
+    irq_enable();
+    asm volatile ("nop");
+    report("ioapic simultaneous interrupt",
+           g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip);
+}
+
+int main()
+{
+    setup_vm();
+
+    test_lapic_existence();
+
+    mask_pic_interrupts();
+    enable_apic();
+    test_enable_x2apic();
+    init_idt();
+
+    test_self_ipi();
+
+    test_ioapic_intr();
+    test_ioapic_simultaneous();
+
+    printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
+
+    return g_fail != 0;
+}
diff --git a/kvm/user/test/x86/bootstrap.S b/kvm/user/test/x86/bootstrap.S
new file mode 100644
index 0000000..e32fea9
--- /dev/null
+++ b/kvm/user/test/x86/bootstrap.S
@@ -0,0 +1,137 @@
+/*
+ * minimal bootstrap to set up flat 32-bit protected mode
+ */
+
+#include "fake-apic.h"
+	
+bstart = 0xf0000
+	
+.code16
+
+stack_top = 0x1000
+cpu_up = 0x1000
+cpu_up_pmode = 0x1004
+
+pmode_stack_start = 0x10000
+pmode_stack_shift = 16
+pmode_stack_size = (1 << pmode_stack_shift)
+
+ipi_vec = 0xf0
+	
+start:
+	mov $stack_top, %sp
+	call smp_init
+
+	cs lidtl idt_desc
+	cs lgdtl gdt_desc
+	mov %cr0, %eax
+	or $1, %eax
+	mov %eax, %cr0
+	ljmpl $8, $pmode + bstart
+
+smp_init:
+	mov $ipi_vec, %eax
+	mov $(APIC_BASE + APIC_REG_IPI_VECTOR), %dx
+	out %eax, %dx
+	movw $ap_switch_to_pmode, ipi_vec*4
+	movw %cs, %ax
+	mov %ax, ipi_vec*4+2
+	mov $sipi, %eax
+	mov $(APIC_BASE + APIC_REG_SIPI_ADDR), %dx
+	outl %eax, %dx
+	mov $(APIC_BASE + APIC_REG_NCPU), %dx
+	inl %dx, %eax
+	mov %eax, %ecx
+	mov $1, %esi
+smp_loop:
+	cmp %esi, %ecx
+	jbe smp_done
+	mov %esi, %eax
+	mov $(APIC_BASE + APIC_REG_SEND_SIPI), %dx
+	outl %eax, %dx
+wait_for_cpu:
+	cmp cpu_up, %esi
+	jne wait_for_cpu
+	mov %esi, %eax
+	mov $(APIC_BASE + APIC_REG_SEND_IPI), %dx
+	out %eax, %dx
+wait_for_cpu_pmode:
+	cmp cpu_up_pmode, %esi
+	jne wait_for_cpu_pmode
+	
+	inc %esi
+	jmp smp_loop
+smp_done:
+	ret
+
+sipi:
+	mov $(APIC_BASE + APIC_REG_ID), %dx
+	inl %dx, %eax
+	mov %eax, cpu_up
+	shl $12, %eax
+	addl $stack_top, %eax
+	movl %eax, %esp
+	sti
+	nop
+1:	hlt
+	jmp 1b
+
+ap_switch_to_pmode:
+	cs lidtl idt_desc
+	cs lgdtl gdt_desc
+	mov %cr0, %eax
+	or $1, %eax
+	mov %eax, %cr0
+	ljmpl $8, $ap_pmode + bstart
+
+.code32	
+ap_pmode:
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $(APIC_BASE + APIC_REG_ID), %dx
+	in %dx, %eax
+	mov %eax, cpu_up_pmode
+	shl $pmode_stack_shift, %eax
+	lea pmode_stack_start + pmode_stack_size(%eax), %esp
+	sti
+	nop
+ap_pmode_wait:
+	hlt
+	jmp ap_pmode_wait
+
+pmode:
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $pmode_stack_start + pmode_stack_size, %esp
+	ljmp $8, $0x100000
+
+.align 16
+	
+idt_desc:
+	.word 8*256-1
+	.long 0
+
+gdt_desc:
+	.word gdt_end - gdt - 1
+	.long gdt + bstart
+
+.align 16
+
+gdt:
+	.quad 0
+	.quad 0x00cf9b000000ffff // flat 32-bit code segment
+	.quad 0x00cf93000000ffff // flat 32-bit data segment
+gdt_end:
+	
+. = 0xfff0
+	.code16
+	ljmp $0xf000, $start
+.align 65536
diff --git a/kvm/user/test/x86/cstart.S b/kvm/user/test/x86/cstart.S
new file mode 100644
index 0000000..0471b92
--- /dev/null
+++ b/kvm/user/test/x86/cstart.S
@@ -0,0 +1,19 @@
+
+
+.bss
+
+.section .init
+
+mb_magic = 0x1BADB002
+mb_flags = 0x0
+
+	# multiboot header
+	.long mb_magic, mb_flags, 0 - (mb_magic + mb_flags)
+
+.globl start
+start:
+	call main
+	push %eax
+	call exit
+
+
diff --git a/kvm/user/test/x86/cstart64.S b/kvm/user/test/x86/cstart64.S
new file mode 100644
index 0000000..f1a9d09
--- /dev/null
+++ b/kvm/user/test/x86/cstart64.S
@@ -0,0 +1,225 @@
+
+#include "apic-defs.h"
+
+.globl boot_idt
+boot_idt = 0
+
+ipi_vector = 0x20
+
+max_cpus = 4
+
+.bss
+
+	. = . + 4096 * max_cpus
+	.align 16
+stacktop:
+
+	. = . + 4096
+	.align 16
+ring0stacktop:
+
+.data
+		
+.align 4096
+ptl2:
+i = 0
+	.rept 512 * 4
+	.quad 0x1e7 | (i << 21)
+	i = i + 1
+	.endr
+
+.align 4096
+ptl3:
+	.quad ptl2 + 7 + 0 * 4096
+	.quad ptl2 + 7 + 1 * 4096
+	.quad ptl2 + 7 + 2 * 4096
+	.quad ptl2 + 7 + 3 * 4096
+
+.align 4096
+ptl4:
+	.quad ptl3 + 7
+	
+.align 4096
+
+gdt64_desc:
+	.word gdt64_end - gdt64 - 1
+	.quad gdt64
+
+gdt64:
+	.quad 0
+	.quad 0x00af9b000000ffff // 64-bit code segment
+	.quad 0x00cf93000000ffff // 64-bit data segment
+	.quad 0x00affb000000ffff // 64-bit code segment (user)
+	.quad 0x00cff3000000ffff // 64-bit data segment (user)
+tss_descr:
+	.rept max_cpus
+	.quad 0x000089000000ffff // 64-bit avail tss
+	.quad 0                  // tss high addr
+	.endr
+gdt64_end:
+
+i = 0
+tss:
+	.rept max_cpus
+	.long 0
+	.quad ring0stacktop - i * 4096
+	.quad 0, 0, 0
+	.quad 0, 0, 0, 0, 0, 0, 0, 0
+	.long 0, 0, 0
+i = i + 1
+	.endr
+tss_end:
+
+.section .init
+
+.code32
+
+mb_magic = 0x1BADB002
+mb_flags = 0x0
+
+	# multiboot header
+	.long mb_magic, mb_flags, 0 - (mb_magic + mb_flags)
+
+MSR_GS_BASE = 0xc0000101
+
+.macro setup_percpu_area
+	lea -4096(%esp), %eax
+	mov $0, %edx
+	mov $MSR_GS_BASE, %ecx
+	wrmsr
+.endm
+
+.globl start
+start:
+	mov $stacktop, %esp
+	setup_percpu_area
+	call prepare_64
+	jmpl $8, $start64
+
+prepare_64:
+	lgdt gdt64_desc
+
+	mov %cr4, %eax
+	bts $5, %eax  // pae
+	mov %eax, %cr4
+
+	mov $ptl4, %eax
+	mov %eax, %cr3
+
+efer = 0xc0000080
+	mov $efer, %ecx
+	rdmsr
+	bts $8, %eax
+	wrmsr
+
+	mov %cr0, %eax
+	bts $0, %eax
+	bts $31, %eax
+	mov %eax, %cr0
+	ret
+
+smp_stacktop:	.long 0xa0000
+
+.align 16
+
+gdt32:
+	.quad 0
+	.quad 0x00cf9b000000ffff // flat 32-bit code segment
+	.quad 0x00cf93000000ffff // flat 32-bit data segment
+gdt32_end:
+
+.code16
+sipi_entry:
+	mov %cr0, %eax
+	or $1, %eax
+	mov %eax, %cr0
+	lgdtl gdt32_descr - sipi_entry
+	ljmpl $8, $ap_start32
+
+gdt32_descr:
+	.word gdt32_end - gdt32 - 1
+	.long gdt32
+
+sipi_end:
+
+.code32
+ap_start32:
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $-4096, %esp
+	lock/xaddl %esp, smp_stacktop
+	setup_percpu_area
+	call prepare_64
+	ljmpl $8, $ap_start64
+
+.code64
+ap_start64:
+	call load_tss
+	call enable_apic
+	call enable_x2apic
+	sti
+	nop
+	lock incw cpu_online_count
+
+1:	hlt
+	jmp 1b
+
+start64:
+	call load_tss
+	call mask_pic_interrupts
+	call enable_apic
+	call smp_init
+	call enable_x2apic
+	call main
+	mov %eax, %edi
+	call exit
+
+idt_descr:
+	.word 16 * 256 - 1
+	.quad boot_idt
+
+load_tss:
+	lidtq idt_descr
+	mov $0, %eax
+	mov %ax, %ss
+	mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax
+	mov (%rax), %eax
+	shr $24, %eax
+	mov %eax, %ebx
+	shl $4, %ebx
+	mov $((tss_end - tss) / max_cpus), %edx
+	imul %edx
+	add $tss, %rax
+	mov %ax, tss_descr+2(%rbx)
+	shr $16, %rax
+	mov %al, tss_descr+4(%rbx)
+	shr $8, %rax
+	mov %al, tss_descr+7(%rbx)
+	shr $8, %rax
+	mov %eax, tss_descr+8(%rbx)
+	lea tss_descr-gdt64(%rbx), %rax
+	ltr %ax
+	ret
+
+smp_init:
+	cld
+	lea sipi_entry, %rsi
+	xor %rdi, %rdi
+	mov $(sipi_end - sipi_entry), %rcx
+	rep/movsb
+	mov $APIC_DEFAULT_PHYS_BASE, %eax
+	movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT), APIC_ICR(%rax)
+	movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT), APIC_ICR(%rax)
+	movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_STARTUP), APIC_ICR(%rax)
+	call fwcfg_get_nb_cpus
+1:	pause
+	cmpw %ax, cpu_online_count
+	jne 1b
+smp_init_done:
+	ret
+
+cpu_online_count:	.word 1
diff --git a/kvm/user/test/x86/emulator.c b/kvm/user/test/x86/emulator.c
new file mode 100644
index 0000000..c6adbb5
--- /dev/null
+++ b/kvm/user/test/x86/emulator.c
@@ -0,0 +1,258 @@
+#include "ioram.h"
+#include "vm.h"
+#include "libcflat.h"
+
+#define memset __builtin_memset
+
+int fails, tests;
+
+void report(const char *name, int result)
+{
+	++tests;
+	if (result)
+		printf("PASS: %s\n", name);
+	else {
+		printf("FAIL: %s\n", name);
+		++fails;
+	}
+}
+
+void test_cmps(void *mem)
+{
+	unsigned char *m1 = mem, *m2 = mem + 1024;
+	unsigned char m3[1024];
+	void *rsi, *rdi;
+	long rcx, tmp;
+
+	for (int i = 0; i < 100; ++i)
+		m1[i] = m2[i] = m3[i] = i;
+	for (int i = 100; i < 200; ++i)
+		m1[i] = (m3[i] = m2[i] = i) + 1;
+
+	rsi = m1; rdi = m3; rcx = 30;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsb"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpsb (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
+
+	rsi = m1; rdi = m3; rcx = 15;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsw"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpsw (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
+
+	rsi = m1; rdi = m3; rcx = 7;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsl"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpll (1)", rcx == 0 && rsi == m1 + 28 && rdi == m3 + 28);
+
+	rsi = m1; rdi = m3; rcx = 4;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsq"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpsq (1)", rcx == 0 && rsi == m1 + 32 && rdi == m3 + 32);
+
+	rsi = m1; rdi = m3; rcx = 130;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsb"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpsb (2)",
+	       rcx == 29 && rsi == m1 + 101 && rdi == m3 + 101);
+
+	rsi = m1; rdi = m3; rcx = 65;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsw"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpsw (2)",
+	       rcx == 14 && rsi == m1 + 102 && rdi == m3 + 102);
+
+	rsi = m1; rdi = m3; rcx = 32;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsl"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpll (2)",
+	       rcx == 6 && rsi == m1 + 104 && rdi == m3 + 104);
+
+	rsi = m1; rdi = m3; rcx = 16;
+	asm volatile("xor %[tmp], %[tmp] \n\t"
+		     "repe/cmpsq"
+		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
+		     : : "cc");
+	report("repe/cmpsq (2)",
+	       rcx == 3 && rsi == m1 + 104 && rdi == m3 + 104);
+
+}
+
+void test_cr8(void)
+{
+	unsigned long src, dst;
+
+	dst = 777;
+	src = 3;
+	asm volatile("mov %[src], %%cr8; mov %%cr8, %[dst]"
+		     : [dst]"+r"(dst), [src]"+r"(src));
+	report("mov %cr8", dst == 3 && src == 3);
+}
+
+void test_push(void *mem)
+{
+	unsigned long tmp;
+	unsigned long *stack_top = mem + 4096;
+	unsigned long *new_stack_top;
+	unsigned long memw = 0x123456789abcdeful;
+
+	memset(mem, 0x55, (void *)stack_top - mem);
+
+	asm volatile("mov %%rsp, %[tmp] \n\t"
+		     "mov %[stack_top], %%rsp \n\t"
+		     "pushq $-7 \n\t"
+		     "pushq %[reg] \n\t"
+		     "pushq (%[mem]) \n\t"
+		     "pushq $-7070707 \n\t"
+		     "mov %%rsp, %[new_stack_top] \n\t"
+		     "mov %[tmp], %%rsp"
+		     : [tmp]"=&r"(tmp), [new_stack_top]"=r"(new_stack_top)
+		     : [stack_top]"r"(stack_top),
+		       [reg]"r"(-17l), [mem]"r"(&memw)
+		     : "memory");
+
+	report("push $imm8", stack_top[-1] == -7ul);
+	report("push %reg", stack_top[-2] == -17ul);
+	report("push mem", stack_top[-3] == 0x123456789abcdeful);
+	report("push $imm", stack_top[-4] == -7070707);
+}
+
+void test_pop(void *mem)
+{
+	unsigned long tmp;
+	unsigned long *stack_top = mem + 4096;
+	unsigned long memw = 0x123456789abcdeful;
+	static unsigned long tmp2;
+
+	memset(mem, 0x55, (void *)stack_top - mem);
+
+	asm volatile("pushq %[val] \n\t"
+		     "popq (%[mem])"
+		     : : [val]"m"(memw), [mem]"r"(mem) : "memory");
+	report("pop mem", *(unsigned long *)mem == memw);
+
+	memw = 7 - memw;
+	asm volatile("mov %%rsp, %[tmp] \n\t"
+		     "mov %[stack_top], %%rsp \n\t"
+		     "pushq %[val] \n\t"
+		     "popq %[tmp2] \n\t"
+		     "mov %[tmp], %%rsp"
+		     : [tmp]"=&r"(tmp), [tmp2]"=m"(tmp2)
+		     : [val]"r"(memw), [stack_top]"r"(stack_top)
+		     : "memory");
+	report("pop mem (2)", tmp2 == memw);
+
+	memw = 129443 - memw;
+	asm volatile("mov %%rsp, %[tmp] \n\t"
+		     "mov %[stack_top], %%rsp \n\t"
+		     "pushq %[val] \n\t"
+		     "popq %[tmp2] \n\t"
+		     "mov %[tmp], %%rsp"
+		     : [tmp]"=&r"(tmp), [tmp2]"=r"(tmp2)
+		     : [val]"r"(memw), [stack_top]"r"(stack_top)
+		     : "memory");
+	report("pop reg", tmp2 == memw);
+
+	asm volatile("mov %%rsp, %[tmp] \n\t"
+		     "mov %[stack_top], %%rsp \n\t"
+		     "push $1f \n\t"
+		     "ret \n\t"
+		     "2: jmp 2b \n\t"
+		     "1: mov %[tmp], %%rsp"
+		     : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top)
+		     : "memory");
+	report("ret", 1);
+}
+
+unsigned long read_cr0(void)
+{
+	unsigned long cr0;
+
+	asm volatile ("mov %%cr0, %0" : "=r"(cr0));
+	return cr0;
+}
+
+void test_smsw(void)
+{
+	char mem[16];
+	unsigned short msw, msw_orig, *pmsw;
+	int i, zero;
+
+	msw_orig = read_cr0();
+
+	asm("smsw %0" : "=r"(msw));
+	report("smsw (1)", msw == msw_orig);
+
+	memset(mem, 0, 16);
+	pmsw = (void *)mem;
+	asm("smsw %0" : "=m"(pmsw[4]));
+	zero = 1;
+	for (i = 0; i < 8; ++i)
+		if (i != 4 && pmsw[i])
+			zero = 0;
+	report("smsw (2)", msw == pmsw[4] && zero);
+}
+
+void test_lmsw(void)
+{
+	char mem[16];
+	unsigned short msw, *pmsw;
+	unsigned long cr0;
+
+	cr0 = read_cr0();
+
+	msw = cr0 ^ 8;
+	asm("lmsw %0" : : "r"(msw));
+	printf("before %lx after %lx\n", cr0, read_cr0());
+	report("lmsw (1)", (cr0 ^ read_cr0()) == 8);
+
+	pmsw = (void *)mem;
+	*pmsw = cr0;
+	asm("lmsw %0" : : "m"(*pmsw));
+	printf("before %lx after %lx\n", cr0, read_cr0());
+	report("lmsw (2)", cr0 == read_cr0());
+}
+
+int main()
+{
+	void *mem;
+	unsigned long t1, t2;
+
+	setup_vm();
+	mem = vmap(IORAM_BASE_PHYS, IORAM_LEN);
+
+	// test mov reg, r/m and mov r/m, reg
+	t1 = 0x123456789abcdef;
+	asm volatile("mov %[t1], (%[mem]) \n\t"
+		     "mov (%[mem]), %[t2]"
+		     : [t2]"=r"(t2)
+		     : [t1]"r"(t1), [mem]"r"(mem)
+		     : "memory");
+	report("mov reg, r/m (1)", t2 == 0x123456789abcdef);
+
+	test_cmps(mem);
+
+	test_push(mem);
+	test_pop(mem);
+
+	test_cr8();
+
+	test_smsw();
+	test_lmsw();
+
+	printf("\nSUMMARY: %d tests, %d failures\n", tests, fails);
+	return fails ? 1 : 0;
+}
diff --git a/kvm/user/test/x86/exit.c b/kvm/user/test/x86/exit.c
new file mode 100644
index 0000000..8903621
--- /dev/null
+++ b/kvm/user/test/x86/exit.c
@@ -0,0 +1,7 @@
+#include "runtime.h"
+
+void exit(unsigned code)
+{
+	asm volatile("out %al, %dx" : : "a"(code), "d"(0xf4));
+	asm volatile("cli; hlt");
+}
diff --git a/kvm/user/test/x86/hypercall.c b/kvm/user/test/x86/hypercall.c
new file mode 100644
index 0000000..95120a2
--- /dev/null
+++ b/kvm/user/test/x86/hypercall.c
@@ -0,0 +1,31 @@
+#include "libcflat.h"
+
+#define KVM_HYPERCALL_INTEL ".byte 0x0f,0x01,0xc1"
+#define KVM_HYPERCALL_AMD ".byte 0x0f,0x01,0xd9"
+
+static inline long kvm_hypercall0_intel(unsigned int nr)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL_INTEL
+		     : "=a"(ret)
+		     : "a"(nr));
+	return ret;
+}
+
+static inline long kvm_hypercall0_amd(unsigned int nr)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL_AMD
+		     : "=a"(ret)
+		     : "a"(nr));
+	return ret;
+}
+
+int main(int ac, char **av)
+{
+	kvm_hypercall0_intel(-1u);
+	printf("Hypercall via VMCALL: OK\n");
+	kvm_hypercall0_amd(-1u);
+	printf("Hypercall via VMMCALL: OK\n");
+	return 0;
+}
diff --git a/kvm/user/test/x86/ioram.h b/kvm/user/test/x86/ioram.h
new file mode 100644
index 0000000..2938142
--- /dev/null
+++ b/kvm/user/test/x86/ioram.h
@@ -0,0 +1,7 @@
+#ifndef __IO_RAM_H
+#define __IO_RAM_H
+
+#define IORAM_BASE_PHYS 0xff000000UL
+#define IORAM_LEN       0x10000UL
+
+#endif
diff --git a/kvm/user/test/x86/memtest1.S b/kvm/user/test/x86/memtest1.S
new file mode 100644
index 0000000..3821e86
--- /dev/null
+++ b/kvm/user/test/x86/memtest1.S
@@ -0,0 +1,44 @@
+.text
+	
+start:
+	mov    $0x1000,%r8
+	mov    $0x0a,%ecx
+
+init_page:
+	dec    %ecx
+	jne    no_io
+	mov    $0x0,%al
+	out    %al,$0x80
+	mov    $0x0a,%ecx
+
+no_io:
+	mov    %r8,(%r8)
+	add    $0x1000,%r8
+	cmp    $0x8000000,%r8
+	jne    init_page
+	mov    $0x1000,%r8
+	mov    $0x0a,%ecx
+
+test_loop:
+	dec    %ecx
+	jne    no_io2
+	mov    $0x0,%al
+	out    %al,$0x80
+	mov    $0x0a,%ecx
+
+no_io2:
+	mov    (%r8),%r9
+	cmp    %r8,%r9
+	jne    err
+	add    $0x1000,%r8
+	cmp    $0x8000000,%r8
+	jne    test_loop
+	mov    $0x1000,%r8
+	jmp    test_loop
+
+err:
+	mov    $0xffffffffffffffff,%r12
+	mov    $0xffffffffffffffff,%r13
+	mov    $0x0,%al
+	out    %al,$0x80
+	jmp    err
diff --git a/kvm/user/test/x86/msr.c b/kvm/user/test/x86/msr.c
new file mode 100644
index 0000000..92102fa
--- /dev/null
+++ b/kvm/user/test/x86/msr.c
@@ -0,0 +1,52 @@
+/* msr tests */
+
+#include "libcflat.h"
+
+#define MSR_KERNEL_GS_BASE	0xc0000102 /* SwapGS GS shadow */
+
+int nr_passed, nr_tests;
+
+#ifdef __x86_64__
+static void report(const char *name, int passed)
+{
+	++nr_tests;
+	if (passed)
+		++nr_passed;
+	printf("%s: %s\n", name, passed ? "PASS" : "FAIL");
+}
+
+static void wrmsr(unsigned index, unsigned long long value)
+{
+	asm volatile ("wrmsr" : : "c"(index), "A"(value));
+}
+
+static unsigned long long rdmsr(unsigned index)
+{
+	unsigned long long value;
+
+	asm volatile ("rdmsr" : "=A"(value) : "c"(index));
+
+	return value;
+}
+#endif
+
+static void test_kernel_gs_base(void)
+{
+#ifdef __x86_64__
+	unsigned long long v1 = 0x123456789abcdef, v2;
+
+	wrmsr(MSR_KERNEL_GS_BASE, v1);
+	v2 = rdmsr(MSR_KERNEL_GS_BASE);
+	report("MSR_KERNEL_GS_BASE", v1 == v2);
+#endif
+}
+
+int main(int ac, char **av)
+{
+	test_kernel_gs_base();
+
+	printf("%d tests, %d failures\n", nr_tests, nr_tests - nr_passed);
+
+	return nr_passed == nr_tests ? 0 : 1;
+}
+
diff --git a/kvm/user/test/x86/port80.c b/kvm/user/test/x86/port80.c
new file mode 100644
index 0000000..522c1a4
--- /dev/null
+++ b/kvm/user/test/x86/port80.c
@@ -0,0 +1,12 @@
+#include "libcflat.h"
+
+int main()
+{
+    int i;
+
+    printf("begining port 0x80 write test\n");
+    for (i = 0; i < 10000000; ++i)
+	asm volatile("outb %al, $0x80");
+    printf("done\n");
+    return 0;
+}
diff --git a/kvm/user/test/x86/print.S b/kvm/user/test/x86/print.S
new file mode 100644
index 0000000..c1b1c0d
--- /dev/null
+++ b/kvm/user/test/x86/print.S
@@ -0,0 +1,31 @@
+
+#include "print.h"
+
+#define PSEUDO_SERIAL_PORT 0xf1
+
+	
+.text
+	PRINT "boo"
+	hlt
+1:	jmp 1b
+	
+.globl print
+print:
+	push %rax
+	push %rsi
+	push %rdx
+
+	mov %rdi, %rsi
+	mov $(PSEUDO_SERIAL_PORT), %edx
+
+putchar:
+	cmpb $0, (%rsi)
+	jz done
+	outsb
+	jmp putchar
+done:
+	
+	pop %rdx
+	pop %rsi
+	pop %rax
+	ret
diff --git a/kvm/user/test/x86/print.h b/kvm/user/test/x86/print.h
new file mode 100644
index 0000000..d5bd2f9
--- /dev/null
+++ b/kvm/user/test/x86/print.h
@@ -0,0 +1,19 @@
+#ifndef PRINT_H
+#define PRINT_H
+
+.macro PRINT text
+
+.data
+
+333: .asciz "\text\n"
+
+.previous
+
+	push %rdi
+	lea 333b, %rdi
+	call print
+	pop %rdi
+
+.endm
+
+#endif
diff --git a/kvm/user/test/x86/realmode.c b/kvm/user/test/x86/realmode.c
new file mode 100644
index 0000000..9bf6cb0
--- /dev/null
+++ b/kvm/user/test/x86/realmode.c
@@ -0,0 +1,624 @@
+asm(".code16gcc");
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned u32;
+typedef unsigned long long u64;
+
+void test_function(void);
+
+asm(
+	"test_function: \n\t"
+	"mov $0x1234, %eax \n\t"
+	"ret"
+   );
+
+static int strlen(const char *str)
+{
+	int n;
+
+	for (n = 0; *str; ++str)
+		++n;
+	return n;
+}
+
+static void print_serial(const char *buf)
+{
+	unsigned long len = strlen(buf);
+
+	asm volatile ("cld; addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
+}
+
+static void exit(int code)
+{
+        asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
+}
+
+struct regs {
+	u32 eax, ebx, ecx, edx;
+	u32 esi, edi, esp, ebp;
+	u32 eip, eflags;
+};
+
+static u64 gdt[] = {
+	0,
+	0x00cf9b000000ffffull, // flat 32-bit code segment
+	0x00cf93000000ffffull, // flat 32-bit data segment
+};
+
+static struct {
+	u16 limit;
+	void *base;
+} __attribute__((packed)) gdt_descr = {
+	sizeof(gdt) - 1,
+	gdt,
+};
+
+static void exec_in_big_real_mode(const struct regs *inregs,
+				  struct regs *outregs,
+				  const u8 *insn, int insn_len)
+{
+	unsigned long tmp;
+	static struct regs save;
+	int i;
+	extern u8 test_insn[], test_insn_end[];
+
+	for (i = 0; i < insn_len; ++i)
+		test_insn[i] = insn[i];
+	for (; i < test_insn_end - test_insn; ++i)
+		test_insn[i] = 0x90; // nop
+
+	save = *inregs;
+	asm volatile(
+		"lgdtl %[gdt_descr] \n\t"
+		"mov %%cr0, %[tmp] \n\t"
+		"or $1, %[tmp] \n\t"
+		"mov %[tmp], %%cr0 \n\t"
+		"mov %[bigseg], %%gs \n\t"
+		"and $-2, %[tmp] \n\t"
+		"mov %[tmp], %%cr0 \n\t"
+
+		"xchg %%eax, %[save]+0 \n\t"
+		"xchg %%ebx, %[save]+4 \n\t"
+		"xchg %%ecx, %[save]+8 \n\t"
+		"xchg %%edx, %[save]+12 \n\t"
+		"xchg %%esi, %[save]+16 \n\t"
+		"xchg %%edi, %[save]+20 \n\t"
+		"xchg %%esp, %[save]+24 \n\t"
+		"xchg %%ebp, %[save]+28 \n\t"
+
+		"test_insn: . = . + 16\n\t"
+		"test_insn_end: \n\t"
+
+		"xchg %%eax, %[save]+0 \n\t"
+		"xchg %%ebx, %[save]+4 \n\t"
+		"xchg %%ecx, %[save]+8 \n\t"
+		"xchg %%edx, %[save]+12 \n\t"
+		"xchg %%esi, %[save]+16 \n\t"
+		"xchg %%edi, %[save]+20 \n\t"
+		"xchg %%esp, %[save]+24 \n\t"
+		"xchg %%ebp, %[save]+28 \n\t"
+
+		/* Save EFLAGS in outregs*/
+		"pushfl \n\t"
+		"popl %[save]+36 \n\t"
+
+		"xor %[tmp], %[tmp] \n\t"
+		"mov %[tmp], %%gs \n\t"
+		: [tmp]"=&r"(tmp), [save]"+m"(save)
+		: [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16)
+		: "cc", "memory"
+		);
+	*outregs = save;
+}
+
+#define R_AX 1
+#define R_BX 2
+#define R_CX 4
+#define R_DX 8
+#define R_SI 16
+#define R_DI 32
+#define R_SP 64
+#define R_BP 128
+
+int regs_equal(const struct regs *r1, const struct regs *r2, int ignore)
+{
+	const u32 *p1 = &r1->eax, *p2 = &r2->eax;  // yuck
+	int i;
+
+	for (i = 0; i < 8; ++i)
+		if (!(ignore & (1 << i)) && p1[i] != p2[i])
+			return 0;
+	return 1;
+}
+
+#define MK_INSN(name, str)                         \
+	asm (				           \
+		".pushsection \".text\" \n\t"	   \
+		"insn_" #name ": " str " \n\t"	   \
+		"insn_" #name "_end: \n\t"	   \
+		".popsection \n\t"		   \
+		);				   \
+	extern u8 insn_##name[], insn_##name##_end[]
+
+void test_shld(void)
+{
+	struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs;
+	MK_INSN(shld_test, "shld $8,%edx,%eax\n\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_shld_test,
+			      insn_shld_test_end - insn_shld_test);
+	if (outregs.eax != 0xbeef)
+		print_serial("shld: failure\n");
+	else
+		print_serial("shld: success\n");
+}
+
+void test_mov_imm(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax");
+	MK_INSN(mov_r16_imm_1, "mov $1234, %ax");
+	MK_INSN(mov_r8_imm_1, "mov $0x12, %ah");
+	MK_INSN(mov_r8_imm_2, "mov $0x34, %al");
+	MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_mov_r16_imm_1,
+			      insn_mov_r16_imm_1_end - insn_mov_r16_imm_1);
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234)
+		print_serial("mov test 1: FAIL\n");
+
+	/* test mov $imm, %eax */
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_mov_r32_imm_1,
+			      insn_mov_r32_imm_1_end - insn_mov_r32_imm_1);
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890)
+		print_serial("mov test 2: FAIL\n");
+
+	/* test mov $imm, %al/%ah */
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_mov_r8_imm_1,
+			      insn_mov_r8_imm_1_end - insn_mov_r8_imm_1);
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200)
+		print_serial("mov test 3: FAIL\n");
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_mov_r8_imm_2,
+			      insn_mov_r8_imm_2_end - insn_mov_r8_imm_2);
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34)
+		print_serial("mov test 4: FAIL\n");
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_mov_r8_imm_3,
+			      insn_mov_r8_imm_3_end - insn_mov_r8_imm_3);
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
+		print_serial("mov test 5: FAIL\n");
+}
+
+void test_cmp_imm(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(cmp_test1, "mov $0x34, %al\n\t"
+			   "cmp $0x34, %al\n\t");
+	MK_INSN(cmp_test2, "mov $0x34, %al\n\t"
+			   "cmp $0x39, %al\n\t");
+	MK_INSN(cmp_test3, "mov $0x34, %al\n\t"
+			   "cmp $0x24, %al\n\t");
+
+	/* test cmp imm8 with AL */
+	/* ZF: (bit 6) Zero Flag becomes 1 if an operation results
+	 * in a 0 writeback, or 0 register
+	 */
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_cmp_test1,
+			      insn_cmp_test1_end - insn_cmp_test1);
+	if ((outregs.eflags & (1<<6)) != (1<<6))
+		print_serial("cmp test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_cmp_test2,
+			      insn_cmp_test2_end - insn_cmp_test2);
+	if ((outregs.eflags & (1<<6)) != 0)
+		print_serial("cmp test 2: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_cmp_test3,
+			      insn_cmp_test3_end - insn_cmp_test3);
+	if ((outregs.eflags & (1<<6)) != 0)
+		print_serial("cmp test 3: FAIL\n");
+}
+
+void test_add_imm(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(add_test1, "mov $0x43211234, %eax \n\t"
+			   "add $0x12344321, %eax \n\t");
+	MK_INSN(add_test2, "mov $0x12, %eax \n\t"
+			   "add $0x21, %al\n\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_add_test1,
+			      insn_add_test1_end - insn_add_test1);
+	if (outregs.eax != 0x55555555)
+		print_serial("add test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_add_test2,
+			      insn_add_test2_end - insn_add_test2);
+	if (outregs.eax != 0x33)
+		print_serial("add test 2: FAIL\n");
+}
+
+void test_eflags_insn(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(clc, "clc");
+	MK_INSN(cli, "cli");
+	MK_INSN(sti, "sti");
+	MK_INSN(cld, "cld");
+	MK_INSN(std, "std");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_clc,
+			      insn_clc_end - insn_clc);
+	if (outregs.eflags & 1)
+		print_serial("clc test: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_cli,
+			      insn_cli_end - insn_cli);
+	if (outregs.eflags & (1 << 9))
+		print_serial("cli test: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_sti,
+			      insn_sti_end - insn_sti);
+	if (!(outregs.eflags & (1 << 9)))
+		print_serial("sti test: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_cld,
+			      insn_cld_end - insn_cld);
+	if (outregs.eflags & (1 << 10))
+		print_serial("cld test: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_std,
+			      insn_std_end - insn_std);
+	if (!(outregs.eflags & (1 << 10)))
+		print_serial("std test: FAIL\n");
+}
+
+void test_io(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(io_test1, "mov $0xff, %al \n\t"
+		          "out %al, $0x10 \n\t"
+			  "in $0x10, %al \n\t");
+	MK_INSN(io_test2, "mov $0xffff, %ax \n\t"
+			  "out %ax, $0x10 \n\t"
+			  "in $0x10, %ax \n\t");
+	MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t"
+			  "out %eax, $0x10 \n\t"
+			  "in $0x10, %eax \n\t");
+	MK_INSN(io_test4, "mov $0x10, %dx \n\t"
+			  "mov $0xff, %al \n\t"
+			  "out %al, %dx \n\t"
+			  "in %dx, %al \n\t");
+	MK_INSN(io_test5, "mov $0x10, %dx \n\t"
+			  "mov $0xffff, %ax \n\t"
+			  "out %ax, %dx \n\t"
+			  "in %dx, %ax \n\t");
+	MK_INSN(io_test6, "mov $0x10, %dx \n\t"
+			  "mov $0xffffffff, %eax \n\t"
+			  "out %eax, %dx \n\t"
+			  "in %dx, %eax \n\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_io_test1,
+			      insn_io_test1_end - insn_io_test1);
+
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff)
+		print_serial("I/O test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_io_test2,
+			      insn_io_test2_end - insn_io_test2);
+
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff)
+		print_serial("I/O test 2: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_io_test3,
+			      insn_io_test3_end - insn_io_test3);
+
+	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff)
+		print_serial("I/O test 3: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_io_test4,
+			      insn_io_test4_end - insn_io_test4);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff)
+		print_serial("I/O test 4: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_io_test5,
+			      insn_io_test5_end - insn_io_test5);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff)
+		print_serial("I/O test 5: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_io_test6,
+			      insn_io_test6_end - insn_io_test6);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff)
+		print_serial("I/O test 6: FAIL\n");
+
+}
+
+void test_call(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	u32 esp[16];
+
+	inregs.esp = (u32)esp;
+
+	MK_INSN(call1, "mov $test_function, %eax \n\t"
+		       "call *%eax\n\t");
+	MK_INSN(call_near1, "jmp 2f\n\t"
+			    "1: mov $0x1234, %eax\n\t"
+			    "ret\n\t"
+			    "2: call 1b\t");
+	MK_INSN(call_near2, "call 1f\n\t"
+			    "jmp 2f\n\t"
+			    "1: mov $0x1234, %eax\n\t"
+			    "ret\n\t"
+			    "2:\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_call1,
+			      insn_call1_end - insn_call1);
+	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
+		print_serial("Call Test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_call_near1, insn_call_near1_end - insn_call_near1);
+	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
+		print_serial("Call near Test 1: FAIL\n");
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_call_near2, insn_call_near2_end - insn_call_near2);
+	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
+		print_serial("Call near Test 2: FAIL\n");
+}
+
+void test_jcc_short(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(jnz_short1, "jnz 1f\n\t"
+			    "mov $0x1234, %eax\n\t"
+		            "1:\n\t");
+	MK_INSN(jnz_short2, "1:\n\t"
+			    "cmp $0x1234, %eax\n\t"
+			    "mov $0x1234, %eax\n\t"
+		            "jnz 1b\n\t");
+	MK_INSN(jmp_short1, "jmp 1f\n\t"
+		      "mov $0x1234, %eax\n\t"
+		      "1:\n\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1);
+	if(!regs_equal(&inregs, &outregs, 0))
+		print_serial("JNZ sort Test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2);
+	if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6)))
+		print_serial("JNZ sort Test 2: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1);
+	if(!regs_equal(&inregs, &outregs, 0))
+		print_serial("JMP sort Test 1: FAIL\n");
+}
+
+void test_jcc_near(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	/* encode near jmp manually. gas will not do it if offsets < 127 byte */
+	MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t"
+		           "mov $0x1234, %eax\n\t");
+	MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t"
+			   "mov $0x1234, %eax\n\t"
+		           ".byte 0x0f, 0x85, 0xf0, 0xff\n\t");
+	MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t"
+		           "mov $0x1234, %eax\n\t");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1);
+	if(!regs_equal(&inregs, &outregs, 0))
+		print_serial("JNZ near Test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2);
+	if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6)))
+		print_serial("JNZ near Test 2: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1);
+	if(!regs_equal(&inregs, &outregs, 0))
+		print_serial("JMP near Test 1: FAIL\n");
+}
+
+void test_long_jmp()
+{
+	struct regs inregs = { 0 }, outregs;
+	u32 esp[16];
+
+	inregs.esp = (u32)esp;
+	MK_INSN(long_jmp, "call 1f\n\t"
+			  "jmp 2f\n\t"
+			  "1: jmp $0, $test_function\n\t"
+		          "2:\n\t");
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_long_jmp,
+			      insn_long_jmp_end - insn_long_jmp);
+	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
+		print_serial("Long JMP Test: FAIL\n");
+}
+void test_push_pop()
+{
+	struct regs inregs = { 0 }, outregs;
+	MK_INSN(push32, "mov $0x12345678, %eax\n\t"
+			"push %eax\n\t"
+			"pop %ebx\n\t");
+	MK_INSN(push16, "mov $0x1234, %ax\n\t"
+			"push %ax\n\t"
+			"pop %bx\n\t");
+
+	MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten
+			 "mov $0x123, %ax\n\t"
+			 "mov %ax, %es\n\t"
+			 "push %es\n\t"
+			 "pop %bx \n\t"
+			 );
+	MK_INSN(pop_es, "push %ax\n\t"
+			"pop %es\n\t"
+			"mov %es, %bx\n\t"
+			);
+	MK_INSN(push_pop_ss, "push %ss\n\t"
+			     "pushw %ax\n\t"
+			     "popw %ss\n\t"
+			     "mov %ss, %bx\n\t"
+			     "pop %ss\n\t"
+			);
+	MK_INSN(push_pop_fs, "push %fs\n\t"
+			     "pushl %eax\n\t"
+			     "popl %fs\n\t"
+			     "mov %fs, %ebx\n\t"
+			     "pop %fs\n\t"
+			);
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_push32,
+			      insn_push32_end - insn_push32);
+	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678)
+		print_serial("Push/Pop Test 1: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_push16,
+			      insn_push16_end - insn_push16);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234)
+		print_serial("Push/Pop Test 2: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_push_es,
+			      insn_push_es_end - insn_push_es);
+	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) ||  outregs.ebx != outregs.eax || outregs.eax != 0x123)
+		print_serial("Push/Pop Test 3: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_pop_es,
+			      insn_pop_es_end - insn_pop_es);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax)
+		print_serial("Push/Pop Test 4: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_push_pop_ss,
+			      insn_push_pop_ss_end - insn_push_pop_ss);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax)
+		print_serial("Push/Pop Test 5: FAIL\n");
+
+	exec_in_big_real_mode(&inregs, &outregs,
+			      insn_push_pop_fs,
+			      insn_push_pop_fs_end - insn_push_pop_fs);
+
+	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax)
+		print_serial("Push/Pop Test 6: FAIL\n");
+}
+
+void test_null(void)
+{
+	struct regs inregs = { 0 }, outregs;
+	exec_in_big_real_mode(&inregs, &outregs, 0, 0);
+	if (!regs_equal(&inregs, &outregs, 0))
+		print_serial("null test: FAIL\n");
+}
+
+void realmode_start(void)
+{
+	test_null();
+
+	test_shld();
+	test_push_pop();
+	test_mov_imm();
+	test_cmp_imm();
+	test_add_imm();
+	test_io();
+	test_eflags_insn();
+	test_jcc_short();
+	test_jcc_near();
+	/* test_call() uses short jump so call it after testing jcc */
+	test_call();
+	/* long jmp test uses call near so test it after testing call */
+	test_long_jmp();
+
+	exit(0);
+}
+
+unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff };
+
+struct __attribute__((packed)) {
+	unsigned short limit;
+	void *base;
+} r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt };
+
+asm(
+	".section .init \n\t"
+
+	".code32 \n\t"
+
+	"mb_magic = 0x1BADB002 \n\t"
+	"mb_flags = 0x0 \n\t"
+
+	"# multiboot header \n\t"
+	".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t"
+
+	".globl start \n\t"
+	".data \n\t"
+	". = . + 4096 \n\t"
+	"stacktop: \n\t"
+
+	".text \n\t"
+	"start: \n\t"
+	"lgdt r_gdt_descr \n\t"
+	"ljmp $8, $1f; 1: \n\t"
+	".code16gcc \n\t"
+	"mov $16, %eax \n\t"
+	"mov %ax, %ds \n\t"
+	"mov %ax, %es \n\t"
+	"mov %ax, %fs \n\t"
+	"mov %ax, %gs \n\t"
+	"mov %ax, %ss \n\t"
+	"mov %cr0, %eax \n\t"
+	"btc $0, %eax \n\t"
+	"mov %eax, %cr0 \n\t"
+	"ljmp $0, $realmode_entry \n\t"
+
+	"realmode_entry: \n\t"
+
+	"xor %ax, %ax \n\t"
+	"mov %ax, %ds \n\t"
+	"mov %ax, %es \n\t"
+	"mov %ax, %ss \n\t"
+	"mov %ax, %fs \n\t"
+	"mov %ax, %gs \n\t"
+	"mov $stacktop, %sp\n\t"
+	"ljmp $0, $realmode_start \n\t"
+
+	".code16gcc \n\t"
+	);
diff --git a/kvm/user/test/x86/realmode.lds b/kvm/user/test/x86/realmode.lds
new file mode 100644
index 0000000..c7386b8
--- /dev/null
+++ b/kvm/user/test/x86/realmode.lds
@@ -0,0 +1,12 @@
+SECTIONS
+{
+    . = 16K;
+    stext = .;
+    .text : { *(.init) *(.text) }
+    . = ALIGN(4K);
+    .data : { *(.data) *(.rodata*) }
+    . = ALIGN(16);
+    .bss : { *(.bss) }
+    edata = .;
+}
+
diff --git a/kvm/user/test/x86/runtime.h b/kvm/user/test/x86/runtime.h
new file mode 100644
index 0000000..4b4c302
--- /dev/null
+++ b/kvm/user/test/x86/runtime.h
@@ -0,0 +1,6 @@
+#ifndef H_RUNTIME
+#define H_RUNTIME
+
+void exit(unsigned code) __attribute__((__noreturn__));
+
+#endif
diff --git a/kvm/user/test/x86/sieve.c b/kvm/user/test/x86/sieve.c
new file mode 100644
index 0000000..a707b92
--- /dev/null
+++ b/kvm/user/test/x86/sieve.c
@@ -0,0 +1,89 @@
+#include "vm.h"
+
+void print(const char *text);
+
+void printi(int n)
+{
+    char buf[10], *p = buf;
+    int s = 0, i;
+    
+    if (n < 0) {
+	n = -n;
+	s = 1;
+    }
+
+    while (n) {
+	*p++ = '0' + n % 10;
+	n /= 10;
+    }
+    
+    if (s)
+	*p++ = '-';
+
+    if (p == buf)
+	*p++ = '0';
+    
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print(buf);
+}
+
+int sieve(char* data, int size)
+{
+    int i, j, r = 0;
+
+    for (i = 0; i < size; ++i)
+	data[i] = 1;
+
+    data[0] = data[1] = 0;
+
+    for (i = 2; i < size; ++i)
+	if (data[i]) {
+	    ++r;
+	    for (j = i*2; j < size; j += i)
+		data[j] = 0;
+	}
+    return r;
+}
+
+void test_sieve(const char *msg, char *data, int size)
+{
+    int r;
+
+    print(msg);
+    print(": ");
+    r = sieve(data, size);
+    printi(r);
+    print("\n");
+}
+
+#define STATIC_SIZE 1000000
+#define VSIZE 100000000
+char static_data[STATIC_SIZE];
+
+int main()
+{
+    void *v;
+    int i;
+
+    print("starting sieve\n");
+    test_sieve("static", static_data, STATIC_SIZE);
+    setup_vm();
+    print("mapped: ");
+    test_sieve("mapped", static_data, STATIC_SIZE);
+    for (i = 0; i < 30; ++i) {
+	v = vmalloc(VSIZE);
+	test_sieve("virtual", v, VSIZE);
+	vfree(v);
+    }
+    
+    return 0;
+}
diff --git a/kvm/user/test/x86/simple.S b/kvm/user/test/x86/simple.S
new file mode 100644
index 0000000..f3c844f
--- /dev/null
+++ b/kvm/user/test/x86/simple.S
@@ -0,0 +1,13 @@
+
+	.text
+
+	mov $0, %al
+	mov $10000, %ebx
+1:
+	mov %rbx, %rcx
+2:	
+	loop 2b
+	out %al, $0x80
+	inc %al
+	add $10000, %rbx
+	jmp 1b
diff --git a/kvm/user/test/x86/smptest.c b/kvm/user/test/x86/smptest.c
new file mode 100644
index 0000000..3780599
--- /dev/null
+++ b/kvm/user/test/x86/smptest.c
@@ -0,0 +1,25 @@
+#include "libcflat.h"
+#include "smp.h"
+
+static void ipi_test(void *data)
+{
+    int n = (long)data;
+
+    printf("ipi called, cpu %d\n", n);
+    if (n != smp_id())
+	printf("but wrong cpu %d\n", smp_id());
+}
+
+int main()
+{
+    int ncpus;
+    int i;
+
+    smp_init();
+
+    ncpus = cpu_count();
+    printf("found %d cpus\n", ncpus);
+    for (i = 0; i < ncpus; ++i)
+	on_cpu(i, ipi_test, (void *)(long)i);
+    return 0;
+}
diff --git a/kvm/user/test/x86/stringio.S b/kvm/user/test/x86/stringio.S
new file mode 100644
index 0000000..31ddc47
--- /dev/null
+++ b/kvm/user/test/x86/stringio.S
@@ -0,0 +1,31 @@
+
+.data
+
+.macro str name, value
+
+\name :	.long 1f-2f
+2:	.ascii "\value"
+1:	
+.endm	
+
+	str "forward", "forward"
+	str "backward", "backward"
+		
+.text
+
+
+	cld
+	movl forward, %ecx
+	lea  4+forward, %rsi
+	movw $1, %dx
+	rep outsb
+
+	std
+	movl backward, %ecx
+	lea 4+backward-1(%rcx), %rsi
+	movw $2, %dx
+	rep outsb
+	
+	hlt
+
+
diff --git a/kvm/user/test/x86/test32.S b/kvm/user/test/x86/test32.S
new file mode 100644
index 0000000..a2e0fd7
--- /dev/null
+++ b/kvm/user/test/x86/test32.S
@@ -0,0 +1,8 @@
+.code32
+
+.text
+
+1:
+	mov $0x12, %al
+	out %al, $0x80
+	jmp 1b
diff --git a/kvm/user/test/x86/tsc.c b/kvm/user/test/x86/tsc.c
new file mode 100644
index 0000000..394a9c6
--- /dev/null
+++ b/kvm/user/test/x86/tsc.c
@@ -0,0 +1,38 @@
+#include "libcflat.h"
+
+u64 rdtsc(void)
+{
+	unsigned a, d;
+
+	asm volatile("rdtsc" : "=a"(a), "=d"(d));
+	return a | (u64)d << 32;
+}
+
+void wrtsc(u64 tsc)
+{
+	unsigned a = tsc, d = tsc >> 32;
+
+	asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(0x10));
+}
+
+void test_wrtsc(u64 t1)
+{
+	u64 t2;
+
+	wrtsc(t1);
+	t2 = rdtsc();
+	printf("rdtsc after wrtsc(%lld): %lld\n", t1, t2);
+}
+
+int main()
+{
+	u64 t1, t2;
+
+	t1 = rdtsc();
+	t2 = rdtsc();
+	printf("rdtsc latency %lld\n", (unsigned)(t2 - t1));
+
+	test_wrtsc(0);
+	test_wrtsc(100000000000ull);
+	return 0;
+}
diff --git a/kvm/user/test/x86/vm.c b/kvm/user/test/x86/vm.c
new file mode 100644
index 0000000..ec9c145
--- /dev/null
+++ b/kvm/user/test/x86/vm.c
@@ -0,0 +1,271 @@
+
+#include "vm.h"
+
+void print(const char *s);
+
+#define PAGE_SIZE 4096ul
+#define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
+
+static void *free = 0;
+static void *vfree_top = 0;
+
+static unsigned long virt_to_phys(const void *virt) 
+{ 
+    return (unsigned long)virt;
+}
+
+static void *phys_to_virt(unsigned long phys)
+{
+    return (void *)phys;
+}
+
+void *memset(void *data, int c, unsigned long len)
+{
+    char *s = data;
+
+    while (len--)
+	*s++ = c;
+
+    return data;
+}
+
+static void free_memory(void *mem, unsigned long size)
+{
+    while (size >= PAGE_SIZE) {
+	*(void **)mem = free;
+	free = mem;
+	mem += PAGE_SIZE;
+	size -= PAGE_SIZE;
+    }
+}
+
+void *alloc_page()
+{
+    void *p;
+
+    if (!free)
+	return 0;
+    
+    p = free;
+    free = *(void **)free;
+
+    return p;
+}
+
+void free_page(void *page)
+{
+    *(void **)page = free;
+    free = page;
+}
+
+extern char edata;
+static unsigned long end_of_memory;
+
+#define PTE_PRESENT (1ull << 0)
+#define PTE_PSE     (1ull << 7)
+#define PTE_WRITE   (1ull << 1)
+#define PTE_ADDR    (0xffffffffff000ull)
+
+static void install_pte(unsigned long *cr3, 
+			int pte_level, 
+			void *virt,
+			unsigned long pte)
+{
+    int level;
+    unsigned long *pt = cr3;
+    unsigned offset;
+
+    for (level = 4; level > pte_level; --level) {
+	offset = ((unsigned long)virt >> ((level-1) * 9 + 12)) & 511;
+	if (!(pt[offset] & PTE_PRESENT)) {
+	    unsigned long *new_pt = alloc_page();
+	    memset(new_pt, 0, PAGE_SIZE);
+	    pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE;
+	}
+	pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
+    }
+    offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
+    pt[offset] = pte;
+}
+
+static unsigned long get_pte(unsigned long *cr3, void *virt)
+{
+    int level;
+    unsigned long *pt = cr3, pte;
+    unsigned offset;
+
+    for (level = 4; level > 1; --level) {
+	offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
+	pte = pt[offset];
+	if (!(pte & PTE_PRESENT))
+	    return 0;
+	if (level == 2 && (pte & PTE_PSE))
+	    return pte;
+	pt = phys_to_virt(pte & 0xffffffffff000ull);
+    }
+    offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
+    pte = pt[offset];
+    return pte;
+}
+
+static void install_large_page(unsigned long *cr3, 
+			       unsigned long phys,
+			       void *virt)
+{
+    install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE);
+}
+
+static void install_page(unsigned long *cr3, 
+			 unsigned long phys,
+			 void *virt)
+{
+    install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE);
+}
+
+static inline void load_cr3(unsigned long cr3)
+{
+    asm ( "mov %0, %%cr3" : : "r"(cr3) );
+}
+
+static inline unsigned long read_cr3()
+{
+    unsigned long cr3;
+
+    asm volatile ( "mov %%cr3, %0" : "=r"(cr3) );
+    return cr3;
+}
+
+static inline void load_cr0(unsigned long cr0)
+{
+    asm volatile ( "mov %0, %%cr0" : : "r"(cr0) );
+}
+
+static inline unsigned long read_cr0()
+{
+    unsigned long cr0;
+
+    asm volatile ( "mov %%cr0, %0" : "=r"(cr0) );
+    return cr0;
+}
+
+static inline void load_cr4(unsigned long cr4)
+{
+    asm volatile ( "mov %0, %%cr4" : : "r"(cr4) );
+}
+
+static inline unsigned long read_cr4()
+{
+    unsigned long cr4;
+
+    asm volatile ( "mov %%cr4, %0" : "=r"(cr4) );
+    return cr4;
+}
+
+struct gdt_table_descr
+{
+    unsigned short len;
+    unsigned long *table;
+} __attribute__((packed));
+
+static inline void load_gdt(unsigned long *table, int nent)
+{
+    struct gdt_table_descr descr;
+
+    descr.len = nent * 8 - 1;
+    descr.table = table;
+    asm volatile ( "lgdt %0" : : "m"(descr) );
+}
+
+#define SEG_CS_32 8
+#define SEG_CS_64 16
+
+struct ljmp {
+    void *ofs;
+    unsigned short seg;
+};
+
+static void setup_mmu(unsigned long len)
+{
+    unsigned long *cr3 = alloc_page();
+    unsigned long phys = 0;
+
+    if (len < (1ul << 32))
+        len = 1ul << 32;  /* map mmio 1:1 */
+
+    memset(cr3, 0, PAGE_SIZE);
+    while (phys + LARGE_PAGE_SIZE <= len) {
+	install_large_page(cr3, phys, (void *)phys);
+	phys += LARGE_PAGE_SIZE;
+    }
+    while (phys + PAGE_SIZE <= len) {
+	install_page(cr3, phys, (void *)phys);
+	phys += PAGE_SIZE;
+    }
+    
+    load_cr3(virt_to_phys(cr3));
+    print("paging enabled\n");
+}
+
+static unsigned int inl(unsigned short port)
+{
+    unsigned int val;
+    asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
+    return val;
+}
+
+void setup_vm()
+{
+    end_of_memory = inl(0xd1);
+    free_memory(&edata, end_of_memory - (unsigned long)&edata);
+    setup_mmu(end_of_memory);
+}
+
+void *vmalloc(unsigned long size)
+{
+    void *mem, *p;
+    unsigned pages;
+
+    size += sizeof(unsigned long);
+    
+    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+    vfree_top -= size;
+    mem = p = vfree_top;
+    pages = size / PAGE_SIZE;
+    while (pages--) {
+	install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p);
+	p += PAGE_SIZE;
+    }
+    *(unsigned long *)mem = size;
+    mem += sizeof(unsigned long);
+    return mem;
+}
+
+void vfree(void *mem)
+{
+    unsigned long size = ((unsigned long *)mem)[-1];
+    
+    while (size) {
+	free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
+	mem += PAGE_SIZE;
+	size -= PAGE_SIZE;
+    }
+}
+
+void *vmap(unsigned long long phys, unsigned long size)
+{
+    void *mem, *p;
+    unsigned pages;
+
+    size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+    vfree_top -= size;
+    phys &= ~(unsigned long long)(PAGE_SIZE - 1);
+
+    mem = p = vfree_top;
+    pages = size / PAGE_SIZE;
+    while (pages--) {
+	install_page(phys_to_virt(read_cr3()), phys, p);
+	phys += PAGE_SIZE;
+	p += PAGE_SIZE;
+    }
+    return mem;
+}
diff --git a/kvm/user/test/x86/vm.h b/kvm/user/test/x86/vm.h
new file mode 100644
index 0000000..0a481f1
--- /dev/null
+++ b/kvm/user/test/x86/vm.h
@@ -0,0 +1,10 @@
+#ifndef VM_H
+#define VM_H
+
+void setup_vm();
+
+void *vmalloc(unsigned long size);
+void vfree(void *mem);
+void *vmap(unsigned long long phys, unsigned long size);
+
+#endif
diff --git a/kvm/user/test/x86/vmexit.c b/kvm/user/test/x86/vmexit.c
new file mode 100644
index 0000000..c3a01e0
--- /dev/null
+++ b/kvm/user/test/x86/vmexit.c
@@ -0,0 +1,164 @@
+
+#include "libcflat.h"
+#include "smp.h"
+
+static inline unsigned long long rdtsc()
+{
+	long long r;
+
+#ifdef __x86_64__
+	unsigned a, d;
+
+	asm volatile ("rdtsc" : "=a"(a), "=d"(d));
+	r = a | ((long long)d << 32);
+#else
+	asm volatile ("rdtsc" : "=A"(r));
+#endif
+	return r;
+}
+
+static unsigned int inl(unsigned short port)
+{
+    unsigned int val;
+    asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
+    return val;
+}
+
+#define GOAL (1ull << 30)
+
+#ifdef __x86_64__
+#  define R "r"
+#else
+#  define R "e"
+#endif
+
+static void cpuid(void)
+{
+	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
+		      : : : "eax", "ecx", "edx");
+}
+
+static void vmcall(void)
+{
+	unsigned long a = 0, b, c, d;
+
+	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
+}
+
+static void mov_from_cr8(void)
+{
+	unsigned long cr8;
+
+	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
+}
+
+static void mov_to_cr8(void)
+{
+	unsigned long cr8 = 0;
+
+	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
+}
+
+static int is_smp(void)
+{
+	return cpu_count() > 1;
+}
+
+static void nop(void *junk)
+{
+}
+
+static void ipi(void)
+{
+	on_cpu(1, nop, 0);
+}
+
+static void ipi_halt(void)
+{
+	unsigned long long t;
+
+	on_cpu(1, nop, 0);
+	t = rdtsc() + 2000;
+	while (rdtsc() < t)
+		;
+}
+
+static void inl_pmtimer(void)
+{
+    inl(0xb008);
+}
+
+static struct test {
+	void (*func)(void);
+	const char *name;
+	int (*valid)(void);
+	int parallel;
+} tests[] = {
+	{ cpuid, "cpuid", .parallel = 1,  },
+	{ vmcall, "vmcall", .parallel = 1, },
+	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
+	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
+	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
+	{ ipi, "ipi", is_smp, .parallel = 0, },
+	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
+};
+
+unsigned iterations;
+volatile int nr_cpus_done;
+
+static void run_test(void *_func)
+{
+    int i;
+    void (*func)(void) = _func;
+
+    for (i = 0; i < iterations; ++i)
+        func();
+
+    nr_cpus_done++;
+}
+
+static void do_test(struct test *test)
+{
+	int i;
+	unsigned long long t1, t2;
+        void (*func)(void) = test->func;
+
+        iterations = 32;
+
+        if (test->valid && !test->valid()) {
+		printf("%s (skipped)\n", test->name);
+		return;
+	}
+
+	do {
+		iterations *= 2;
+		t1 = rdtsc();
+
+		if (!test->parallel) {
+			for (i = 0; i < iterations; ++i)
+				func();
+		} else {
+			nr_cpus_done = 0;
+			for (i = cpu_count(); i > 0; i--)
+				on_cpu_async(i-1, run_test, func);
+			while (nr_cpus_done < cpu_count())
+				;
+		}
+		t2 = rdtsc();
+	} while ((t2 - t1) < GOAL);
+	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
+}
+
+#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof((_x)[0]))
+
+int main(void)
+{
+	int i;
+
+	smp_init();
+
+	for (i = 0; i < ARRAY_SIZE(tests); ++i)
+		do_test(&tests[i]);
+
+	return 0;
+}
diff --git a/kvm/vgabios/.cvsignore b/kvm/vgabios/.cvsignore
new file mode 100644
index 0000000..1df04b7
--- /dev/null
+++ b/kvm/vgabios/.cvsignore
@@ -0,0 +1 @@
+vbetables.h
diff --git a/kvm/vgabios/BUGS b/kvm/vgabios/BUGS
new file mode 100644
index 0000000..785f4dc
--- /dev/null
+++ b/kvm/vgabios/BUGS
@@ -0,0 +1,3 @@
+Not all the functions have been implemented yet.
+
+Please report any bugs to <info@vruppert.de>
diff --git a/kvm/vgabios/COPYING b/kvm/vgabios/COPYING
new file mode 100644
index 0000000..223ede7
--- /dev/null
+++ b/kvm/vgabios/COPYING
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/kvm/vgabios/ChangeLog b/kvm/vgabios/ChangeLog
new file mode 100644
index 0000000..75be5bd
--- /dev/null
+++ b/kvm/vgabios/ChangeLog
@@ -0,0 +1,1264 @@
+2008-05-11 08:40  vruppert
+
+	* biossums.c (1.6):
+
+	- fixed a warning
+
+2008-03-02 08:47  vruppert
+
+	* vbe.c (1.60):
+
+	- added debug message for unsupported VBE modes
+
+2008-02-24 09:18  vruppert
+
+	* vbe.c (1.59):
+
+	- in LFB modes the number of banks must be set to 1
+
+2008-01-27 10:44  vruppert
+
+	* Makefile (1.21), biossums.c (1.5), vgabios.c (1.67):
+
+	- added PCI data structure for the Cirrus VGABIOS images
+	- added support for the PCI data structure in biossums
+	- updated year in copyright
+
+2008-01-26 11:46  vruppert
+
+	* BUGS (1.4), Makefile (1.20), README (1.14), TODO (1.13), vbe_display_api.txt (1.14):
+
+	- whitespace cleanup
+
+2006-11-26 10:43  vruppert
+
+	* Makefile (1.19):
+
+	- disable the generation of linemarkers by the preprocessor, since the latest
+	  versions of bcc don't like them
+
+2006-09-02 13:15  vruppert
+
+	* biossums.c (1.4):
+
+	- the biossums utility no longer modifies VGABIOS images with proper checksum
+	  and size
+
+2006-08-19 14:28  vruppert
+
+	* Changelog (1.26), README (1.13), TODO (1.12):
+
+	- updates for 0.6a release
+
+2006-08-19 09:39  vruppert
+
+	* vbe.c (1.58):
+
+	- improved VGA compatible setup for VBE modes (disable CGA and Hercules
+	  compatible memory layout)
+
+2006-08-18 20:39  vruppert
+
+	* vbe.c (1.57):
+
+	- improved VGA compatible setup for >=8bpp VBE modes (CRTC doubleword mode and
+	  GRDC shift register setting added)
+	- now using symbolic name for CRTC address register
+
+2006-08-15 20:42  vruppert
+
+	* vbe.c (1.56), vbetables-gen.c (1.4):
+
+	- init 4bpp VBE modes by a temporary switch to VGA mode 0x6A
+	- all 4bpp VBE modes now enabled
+
+2006-08-14 20:24  vruppert
+
+	* vbe.c (1.55):
+
+	- VGA compatible setup for VBE modes improved (Bochs hack can be removed now)
+
+2006-08-12 07:51  vruppert
+
+	* .cvsignore (1.1):
+
+	- .cvsignore added for auto-generated file
+
+2006-08-12 07:47  vruppert
+
+	* vbe.c (1.54), vbe.h (1.27), vbe_display_api.txt (1.13), vbetables-gen.c (1.3):
+
+	- cleaned up VBE memory size definitions (removed duplicate defines, main
+	  definition now in vbetables-gen.c)
+
+2006-08-09 21:28  vruppert
+
+	* vbetables.h (1.30):
+
+	- removed auto-generated file
+
+2006-08-09 21:26  vruppert
+
+	* vbe.c (1.53), vbe.h (1.26), vbe_display_api.txt (1.12), vbetables-gen.c (1.2),
+	  vbetables.h (1.29):
+
+	- VBE video memory increased to 8 MB
+	- VBE dispi ID changed to B0C4
+	- documentation update
+
+2006-07-11 08:03  vruppert
+
+	* Makefile (1.18), vbetables-gen.c (1.1), vbetables.h (1.28):
+
+	- generate vbetables.h dynamicly
+	  * initial patch from the qemu project by Fabrice Bellard
+	  * only add modes that fit in video memory (still 4 MB)
+	  * several other fixes (e.g. 4 bpp specific stuff, number of pages)
+
+2006-07-10 07:47  vruppert
+
+	* vgabios.c (1.66):
+
+	- biosfn_scroll(): check variable 'i' for underflowing when scrolling downwards
+	  to avoid screen corruption
+
+2006-07-10 07:47  vruppert
+
+	* vbe.c (1.52):
+
+	- VBE set bank functions failure handling added
+	- VBE get/set logical scan line length fixes for the 4bpp mode
+
+2006-07-08 13:27  vruppert
+
+	* vbe.c (1.51), vbetables.h (1.27):
+
+	- added special case for the 4 bpp when setting VBE display start
+	- VBE mode table fixes
+
+2006-07-07 13:30  vruppert
+
+	* clext.c (1.12):
+
+	- bank pointer must be set to 0 after a mode set
+
+2006-06-21 16:58  vruppert
+
+	* vbe.c (1.50), vbetables.h (1.26):
+
+	- improved VBE display capabilities check (X resulution checked now)
+	- removed obsolete defines (LFB always available, always generate dynamic list)
+	- CR/LF to LF fixes
+
+2006-06-18 15:22  vruppert
+
+	* clext.c (1.11), vbe.c (1.49), vbe.h (1.25), vbetables.h (1.25), vgabios.c
+	  (1.65):
+
+	- applied patch from the qemu project (Fabrice Bellard)
+	  * Cirrus SVGA now supports the "no clear" bit when switching to Cirrus or
+	    VESA mode
+	  * Bochs VBE protected mode interface improved
+	  * save/restore video state support for Bochs VBE and standard VGA added
+	  * Bochs VBE prepared for more modi
+
+2006-03-25 10:19  vruppert
+
+	* clext.c (1.10), vgabios.c (1.64), vgatables.h (1.10):
+
+	- applied patch from Fabrice Bellard
+	 * added minimal support for the video parameter table (VPT)
+	 * added Cirrus SVGA mode 0x7b (1600x1200x8)
+
+2005-12-26 19:50  vruppert
+
+	* vbe.c (1.48), vgabios.c (1.63):
+
+	- Bochs VBE protected mode interface added (based on a patch by malc@pulsesoft.com)
+
+2005-12-26 19:50  vruppert
+
+	* biossums.c (1.3):
+
+	- biossums utility now supports VGABIOS sizes up to 64 kBytes
+
+2005-09-21 18:45  vruppert
+
+	* vgatables.h (1.9):
+
+	- mode 0x11: all color planes must be enabled in this 2-color VGA mode
+
+2005-08-30 18:41  vruppert
+
+	* biossums.c (1.2):
+
+	- missing license text added in biossums.c
+
+2005-07-02 18:39  vruppert
+
+	* vgabios.c (1.62):
+
+	- BIOS configuration word usually reports initial mode 80x25 color text
+	- vgabios function 0x0e (write teletype): linefeed (0x0a) only increments the
+	  cursor row value
+
+2005-05-24 16:50  vruppert
+
+	* vbe.c (1.47), vgabios.c (1.61):
+
+	- output to the vgabios info port can be disabled now. It is still enabled by
+	  default and always possible in debug mode. (based on a patch from Alex Beregszaszi)
+
+2005-05-20 16:06  vruppert
+
+	* vbe.c (1.46), vgabios.c (1.60):
+
+	- fixed return value for the default case in the VBE section (non-debug mode)
+	- removed unused macros HALT and PANIC_PORT
+
+2005-03-07 20:39  vruppert
+
+	* README (1.9):
+
+	- updates for 0.5a release
+
+2005-03-06 13:06  vruppert
+
+	* Makefile (1.17):
+
+	- vgabios files with cirrus support added to release target
+
+2005-03-06 12:24  vruppert
+
+	* Makefile (1.16):
+
+	- cross compilation support added (patch from Alex Beregszaszi)
+
+2005-03-05 13:03  vruppert
+
+	* BUGS (1.3), README (1.8), TODO (1.11):
+
+	- documentation updates
+
+2004-12-04 15:26  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.61), VGABIOS-lgpl-latest.cirrus.bin
+	  (1.13), VGABIOS-lgpl-latest.cirrus.debug.bin (1.13),
+	  VGABIOS-lgpl-latest.debug.bin (1.61), clext.c (1.9):
+
+	- Cirrus extension: support for 1280x1024x15 and 1280x1024x16 modes added (patch
+	  from Fabrice Bellard)
+
+2004-08-08 16:53  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.60), VGABIOS-lgpl-latest.cirrus.bin (1.12),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.12),
+	  VGABIOS-lgpl-latest.debug.bin (1.60), clext.c (1.8):
+
+	- use single bank mode for VBE
+	- enable 16k granularity for VBE only
+
+2004-07-30 19:33  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.59), VGABIOS-lgpl-latest.cirrus.bin (1.11),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.11),
+	  VGABIOS-lgpl-latest.debug.bin (1.59), clext.c (1.7):
+
+	- cirrus init: set standard vga mode and reset bitblt
+
+2004-07-22 18:38  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.58), VGABIOS-lgpl-latest.cirrus.bin (1.10),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.10),
+	  VGABIOS-lgpl-latest.debug.bin (1.58), clext.c (1.6), vbe.c (1.45),
+	  vbetables.h (1.24):
+
+	- cirrus extension: tables for mode 1280x1024x8 added
+	- vbe: dispi_set_xres() and dispi_set_virt_width() now modify vga compatible
+	  registers
+	- vbe: mode list entry for mode 800x600x4 fixed
+
+2004-07-18 20:23  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.57), VGABIOS-lgpl-latest.cirrus.bin (1.9),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.9),
+	  VGABIOS-lgpl-latest.debug.bin (1.57), vgabios.c (1.59), vgatables.h (1.8):
+
+	- disable CRTC write protection before setting new values
+	- CRTC line for mode 0x6a fixed
+
+2004-07-07 16:08  vruppert
+
+	* Makefile (1.15), VGABIOS-lgpl-latest.bin (1.56),
+	  VGABIOS-lgpl-latest.cirrus.bin (1.8), VGABIOS-lgpl-latest.cirrus.debug.bin (1.8),
+	  VGABIOS-lgpl-latest.debug.bin (1.56), biossums.c (1.1), clext.c (1.5):
+
+	- biossums utility for the Bochs BIOS adapted for the LGPL'd VGABIOS
+	- VESA3 PMINFO checksum calculated in the source
+	- 24 bpp mode entries fixed (patch from Fabrice Bellard)
+
+2004-06-25 18:28  vruppert
+
+	* VGABIOS-lgpl-latest.cirrus.bin (1.7), VGABIOS-lgpl-latest.cirrus.debug.bin (1.7),
+	  clext.c (1.4):
+
+	- 4MB memory probe added (patch from Fabrice Bellard)
+
+2004-06-25 17:31  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.55), VGABIOS-lgpl-latest.cirrus.bin (1.6),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.6),
+	  VGABIOS-lgpl-latest.debug.bin (1.55), clext.c (1.3):
+
+	- fixed value of sequencer reset register in cirrus mode table
+	- fixed possible overflow error if cirrus start address is >256k
+
+2004-06-23 21:11  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.54), VGABIOS-lgpl-latest.cirrus.bin (1.5),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.5),
+	  VGABIOS-lgpl-latest.debug.bin (1.54), clext.c (1.2):
+
+	- applied new patch for the cirrus extension from suzu
+	  * enable VESA LFB support if a Cirrus PCI adapter is detected
+	  * prepared VBE3 protected mode info block (test case required)
+	- added VBE functions 4F06h and 4F07h
+	- some bugfixes
+
+2004-06-17 18:57  vruppert
+
+	* Makefile (1.14), VGABIOS-lgpl-latest.bin (1.53),
+	  VGABIOS-lgpl-latest.cirrus.bin (1.2), VGABIOS-lgpl-latest.cirrus.debug.bin (1.2),
+	  VGABIOS-lgpl-latest.debug.bin (1.53):
+
+	- fixed makefile targets for the binaries with cirrus extension
+
+2004-06-16 21:11  vruppert
+
+	* Makefile (1.13), VGABIOS-lgpl-latest.bin (1.52),
+	  VGABIOS-lgpl-latest.cirrus.bin (1.1), VGABIOS-lgpl-latest.cirrus.debug.bin (1.1),
+	  VGABIOS-lgpl-latest.debug.bin (1.52), clext.c (1.1), vgabios.c (1.58):
+
+	- applied suzu's cirrus extension patch. Cirrus SVGA detection, most of the
+	  cirrus-specific modes and some basic VBE features are present now.
+
+2004-05-31 21:15  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.51), VGABIOS-lgpl-latest.debug.bin (1.51),
+	  vgabios.c (1.57):
+
+	- write character in planar graphics modes: sequencer map mask must be 0x0f and
+	  bit operation must be 'replace' if bit 7 of attribute is clear
+	- read/write pixel in planar graphics modes: bit mask setup simplified
+
+2004-05-11 18:08  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.50), VGABIOS-lgpl-latest.debug.bin (1.50),
+	  vgabios.c (1.56):
+
+	- biosfn_select_vert_res rewritten in assembler
+	- scroll text in planar graphics modes: attribute for blank line fixed
+	- write character in planar graphics modes: graphics controller values fixed
+
+2004-05-09 20:32  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.49), VGABIOS-lgpl-latest.debug.bin (1.49),
+	  vbe.c (1.44), vbe.h (1.24), vgabios.c (1.55):
+
+	- VBE init code and some dispi ioport functions rewritten in assembler
+	- text scroll functions for CGA graphics modes added
+	- scroll text in graphics modes: attribute for blank line fixed
+
+2004-05-08 16:06  vruppert
+
+	* BUGS (1.2), README (1.7), TODO (1.10), VGABIOS-lgpl-latest.bin (1.48),
+	  VGABIOS-lgpl-latest.debug.bin (1.48), vbe.c (1.43), vbe.h (1.23),
+	  vbe_display_api.txt (1.11), vgabios.c (1.54):
+
+	- VBE internal functions dispi_set_enable and dispi_set_bank now called both from C
+	  and asm code
+	- VBE function 0x03 rewritten in assembler
+	- VBE function 0x08 cleaned up
+	- text output and scroll functions for graphics modes rewritten using case
+	  structures
+	- documentation and comments updated
+
+2004-05-06 21:18  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.47), VGABIOS-lgpl-latest.debug.bin (1.47),
+	  vbe.c (1.42), vbe.h (1.22), vgabios.c (1.53):
+
+	- VBE functions 0x05, 0x06, 0x07 and some dispi ioport functions rewritten in
+	  assembler
+	- VBE functions 0x06 and 0x07: get functions now supported, 15 bpp bug fixed
+
+2004-05-05 19:24  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.46), VGABIOS-lgpl-latest.debug.bin (1.46),
+	  vbe.c (1.41), vbe.h (1.21), vbe_display_api.txt (1.10), vgabios.c (1.52):
+
+	- 8 bit DAC capability flag set
+	- vbe_biosfn_set_get_dac_palette_format implemented
+	- VBE api description updated
+	- C definitions from header files now used assembler code
+
+2004-05-02 17:27  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.45), VGABIOS-lgpl-latest.debug.bin (1.45),
+	  vgabios.c (1.51):
+
+	- text scroll functions for PLANAR1/PLANAR4 graphics modes added
+	- function biosfn_get_ega_info rewritten in assembler
+	- read/write graphics pixel functions rewritten using a case structure
+
+2004-05-01 16:03  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.44), VGABIOS-lgpl-latest.debug.bin (1.44),
+	  vgabios.c (1.50):
+
+	- biosfn_enable_cursor_emulation rewritten in assembler
+	- remap of the cursor shape depends on modeset control bit 0
+	- text output in PLANAR4 modes now supports attribute bit 7 (XOR with background)
+
+2004-04-25 20:13  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.43), VGABIOS-lgpl-latest.debug.bin (1.43),
+	  vgabios.c (1.49), vgatables.h (1.7):
+
+	- table entries for vga mode 0x0f fixed (PLANAR2 exists on EGA only)
+	- function release_font_access now supports the monochrome text mode
+	- PLANAR1 modes now supported in text output functions and read/write pixel
+	- function AH=0x12/BL=0x32 rewritten in assembler
+
+2004-04-25 08:45  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.42), VGABIOS-lgpl-latest.debug.bin (1.42),
+	  vgabios.c (1.48):
+
+	- block address calculation in font functions fixed
+	- functions AX=0x1103, AH=0x12/BL=0x31 and AH=0x12/BL=0x33 rewritten in assembler
+
+2004-04-24 09:59  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.41), VGABIOS-lgpl-latest.debug.bin (1.41),
+	  vgabios.c (1.47):
+
+	- read/write graphics pixel for PLANAR4 modes added
+	- CGA specific functions (group AH = 0x0B) implemented
+
+2004-04-23 14:34  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.40), VGABIOS-lgpl-latest.debug.bin (1.40),
+	  vgabios.c (1.46):
+
+	- remaining palette and dac read/write functions (except gray scale summing)
+	  rewritten in assembler
+
+2004-04-18 13:43  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.39), VGABIOS-lgpl-latest.debug.bin (1.39),
+	  vgabios.c (1.45):
+
+	- some palette and dac read/write functions rewritten in assembler
+	- main int10 debug message now works with assembler functions, too
+
+2004-04-18 09:15  japj
+
+	* vbe.c (1.40):
+
+	updated my email address + put vgabios url in the bios copyright string
+	(instead of my old email address)
+
+2004-04-17 07:18  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.38), VGABIOS-lgpl-latest.debug.bin (1.38),
+	  vgabios.c (1.44):
+
+	- biosfn_set_video_mode: don't load DAC registers if default palette loading is
+	  disabled. Perform gray scale summing if enabled.
+	- biosfn_perform_gray_scale_summing: switch between DAC read and write mode is
+	  required to make this function work. Maximum DAC value always set to 0x3f.
+
+2004-04-08 17:50  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.37), VGABIOS-lgpl-latest.debug.bin (1.37),
+	  vgabios.c (1.43):
+
+	- write character function for the LINEAR8 mode
+	- get_font_access() and release_font_access() rewritten in assembler
+	- fixed wrong variable name in the init code
+
+2004-04-06 19:31  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.36), VGABIOS-lgpl-latest.debug.bin (1.36),
+	  vgabios.c (1.42):
+
+	- init functions rewitten in assembler
+	- function biosfn_set_display_code rewritten in assembler
+
+2004-04-05 19:40  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.35), VGABIOS-lgpl-latest.debug.bin (1.35),
+	  vgabios.c (1.41):
+
+	- functions biosfn_get_video_mode() and biosfn_read_display_code() rewritten
+	  in assembler
+
+2004-04-04 18:20  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.34), VGABIOS-lgpl-latest.debug.bin (1.34),
+	  vgabios.c (1.40):
+
+	- write character function for CGA modes added
+	- read/write graphics pixel for CGA and LINEAR8 modes added
+
+2004-02-23 21:08  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.33), VGABIOS-lgpl-latest.debug.bin (1.33),
+	  vbe.c (1.39):
+
+	- dispi_get_max_bpp(): restore the original value of the vbe enable register
+
+2004-02-22 14:17  vruppert
+
+	* README (1.6), vbe.c (1.38), vbe.h (1.20), vbe_display_api.txt (1.9),
+	  VGABIOS-lgpl-latest.bin (1.32), VGABIOS-lgpl-latest.debug.bin (1.32):
+
+	- new function dispi_get_max_bpp() returns the bpp capabilities of the Bochs gui
+	- create the mode list depending on the supported bpp capability
+	- unused stuff removed
+	- documentation updated
+
+2004-02-21 18:20  vruppert
+
+	* vbe.c (1.37), vbe.h (1.19), vbetables.h (1.23),
+	  VGABIOS-lgpl-latest.bin (1.31), VGABIOS-lgpl-latest.debug.bin (1.31):
+
+	- dynamicly genarated vbe mode_info list works now
+
+2003-11-17 21:04  vruppert
+
+	* vbe.c (1.36), vbetables.h (1.22), vgabios.c (1.39), vgatables.h (1.6),
+	  VGABIOS-lgpl-latest.bin (1.30), VGABIOS-lgpl-latest.debug.bin (1.30):
+
+	- new VBE presence flag stored at unused BDA address 0xB9
+	- VBE init code rewritten
+	- added BIOS TTY flag for VBE mode 0x0102 (TODO: scrolling)
+	- vgabios_init_func: load and activate text font already done by set_video_mode
+	- function biosfn_get_all_palette_reg() fixed
+
+2003-11-06 00:26  cbothamy
+
+	* README (1.5):
+
+	  - add changes for 0.4c release
+
+2003-11-06 00:22  cbothamy
+
+	* VGABIOS-lgpl-latest.bin (1.29), VGABIOS-lgpl-latest.debug.bin
+	  (1.29):
+
+	  - compile vgabios.c rev1.38
+
+2003-11-06 00:21  cbothamy
+
+	* vgabios.c (1.38):
+
+	  - activate char table after loading it when setting a text video
+	  mode
+
+2003-11-06 00:19  cbothamy
+
+	* Makefile (1.12):
+
+	  - when making a release, remove unwanted files first, and exclude
+	  CVS from the tarball
+
+2003-11-04 22:50  cbothamy
+
+	* ChangeLog (1.20, v0_4b):
+
+	  - update ChangeLog for 0.4b release
+
+2003-11-04 22:49  cbothamy
+
+	* README (1.4, v0_4b):
+
+	  - update Changes for 0.4b release
+
+2003-11-04 20:26  vruppert
+
+	* vgabios.c (1.37), VGABIOS-lgpl-latest.bin (1.28),
+	  VGABIOS-lgpl-latest.debug.bin (1.28) (utags: v0_4b):
+
+	  - biosfn_get_font_info(): character height must be returned in CX
+
+2003-11-03 21:57  vruppert
+
+	* vbe.c (1.35, v0_4b), vgabios.c (1.36), VGABIOS-lgpl-latest.bin
+	  (1.27), VGABIOS-lgpl-latest.debug.bin (1.27):
+
+	  - the 'noclearmem' flag is not stored in the 'current video mode'
+	  register (0040h:0049h) - VBE also stores the 'noclear' flag in
+	  the 'video control' register (0040h:0087h)
+
+2003-10-05 10:06  vruppert
+
+	* vbe.h (1.18, v0_4b), vbe_display_api.txt (1.8, v0_4b),
+	  VGABIOS-lgpl-latest.bin (1.26), VGABIOS-lgpl-latest.debug.bin
+	  (1.26):
+
+	  - changed VBE i/o registers to 0x01CE/CF (suggestion from Daniel
+	  Gimpelevich)
+
+2003-08-18 18:38  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.25), VGABIOS-lgpl-latest.debug.bin
+	  (1.25), vgabios.c (1.35):
+
+	  - wrong offsets to the character tables (INT 0x1F/0x43) fixed
+	  (underscore added) - functions accessing the CRT controller
+	  optimized using a local variable 'crtc_addr'
+
+2003-08-17 15:46  cbothamy
+
+	* ChangeLog (1.19, v0_4a):
+
+	  - ChangeLog is now automatically generated by running "cvs2cl -r
+	  -t -P -S" - update ChangeLog for 0.4a release
+
+2003-08-17 15:44  cbothamy
+
+	* README (1.3, v0_4a):
+
+	  - added the old ChangeLog in the HOSTORY section of the README
+	  file - update History for 0.4a release, with a summary of Changes
+
+2003-08-17 15:24  cbothamy
+
+	* Makefile (1.11, v0_4b, v0_4a):
+
+	  - fix Makefile for "release" target
+
+2003-08-16 01:49  cbothamy
+
+	* Makefile (1.10), README (1.2), VGABIOS-lgpl-latest.bin (1.24,
+	  v0_4a), VGABIOS-lgpl-latest.debug.bin (1.24, v0_4a), vgabios.c
+	  (1.34, v0_4a):
+
+	  - update the Makefile for releases - remove references to old
+	  plex86 website - update the Makefile so it build
+	  VGABIOS-lgpl-latest.bin and	VGABIOS-lgpl-latest.debug.bin
+
+2003-08-07 18:17  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.23), VGABIOS-lgpl-latest.debug.bin
+	  (1.23):
+
+	  - current VBE mode now stored in BDA (unused address 0xBA)
+
+2003-08-07 17:54  vruppert
+
+	* vbe.c (1.34), vgatables.h (1.5, v0_4b) (utags: v0_4a):
+
+	  - current VBE mode now stored in BDA (unused address 0xBA)
+
+2003-07-20 18:05  vruppert
+
+	* vgabios.c (1.33), VGABIOS-lgpl-latest.bin (1.22),
+	  VGABIOS-lgpl-latest.debug.bin (1.22):
+
+	  - fixed a few functions accessing the attribute controller
+
+2003-07-19 09:33  vruppert
+
+	* vgabios.c (1.32), VGABIOS-lgpl-latest.bin (1.21),
+	  VGABIOS-lgpl-latest.debug.bin (1.21):
+
+	  - re-enable video after programming the attribute controller -
+	  biosfn_set_all_palette_reg(): number of palette registers fixed
+
+2003-07-16 22:32  vruppert
+
+	* ChangeLog (1.18), vbe.c (1.33), vbe.h (1.17, v0_4a),
+	  vbe_display_api.txt (1.7, v0_4a), vgabios.c (1.31),
+	  VGABIOS-lgpl-latest.bin (1.20), VGABIOS-lgpl-latest.debug.bin
+	  (1.20):
+
+	  - LFB flag now stored in the register VBE_DISPI_INDEX_ENABLE -
+	  release date in Changelog fixed - release date of VBE BIOS 0.6
+	  was the same as VGA BIOS 0.3b - year changed in copyright
+	  messages
+
+2003-07-15 12:40  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.19), VGABIOS-lgpl-latest.debug.bin
+	  (1.19):
+
+	  - new function dispi_get_bpp() - function
+	  vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp -
+	  number of image pages of all VBE modes fixed
+
+2003-07-15 12:35  vruppert
+
+	* vbe.c (1.32), vbetables.h (1.21, v0_4b, v0_4a):
+
+	  - new function dispi_get_bpp() - function
+	  vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp -
+	  number of image pages of all VBE modes fixed
+
+2003-07-14 19:45  vruppert
+
+	* vbe_display_api.txt (1.6):
+
+	  - description of VBE_DISPI_ interface 0xb0c2 added
+
+2003-07-10 19:07  vruppert
+
+	* vbe.c (1.31), vbetables.h (1.20), VGABIOS-lgpl-latest.bin (1.18),
+	  VGABIOS-lgpl-latest.debug.bin (1.18):
+
+	  - 15 bpp VBE modes added - "Bochs own" mode 0x142 (640x480x32bpp)
+	  added
+
+2003-07-01 19:00  vruppert
+
+	* vbe.c (1.30), vbe.h (1.16), vbetables.h (1.19),
+	  VGABIOS-lgpl-latest.bin (1.17), VGABIOS-lgpl-latest.debug.bin
+	  (1.17):
+
+	  - VBE preserve display memory feature implemented - VBE mode
+	  entries 0x117 and 0x118 added
+
+2003-06-30 21:27  vruppert
+
+	* vbe.c (1.29), vbe.h (1.15), vbetables.h (1.18),
+	  VGABIOS-lgpl-latest.bin (1.16), VGABIOS-lgpl-latest.debug.bin
+	  (1.16):
+
+	  - VBE mode info blocks of modes with >8bpp enabled - VBE modes
+	  with 24 bpp: bytes per scanline fixed - vbe_biosfn_set_mode() now
+	  supports >8bpp - VBE will be enabled with new VBE_DISPI_ID2
+	  (0xB0C2)
+
+2003-06-29 12:53  vruppert
+
+	* vbetables.h (1.17), VGABIOS-lgpl-latest.bin (1.15),
+	  VGABIOS-lgpl-latest.debug.bin (1.15):
+
+	  - duplicate lines with VBE_MODE_ATTRIBUTE_GRAPHICS_MODE removed -
+	  VBE mode info items of currently unsupported modes fixed
+
+2003-06-15 21:19  vruppert
+
+	* vgabios.c (1.30), VGABIOS-lgpl-latest.bin (1.14),
+	  VGABIOS-lgpl-latest.debug.bin (1.14):
+
+	  - function write_gfx_char() rewritten
+
+2003-04-26 09:27  vruppert
+
+	* VGABIOS-lgpl-latest.debug.bin (1.13):
+
+	  - added missing VBE function dispi_get_bank() - added missing
+	  return codes for VBE function 4F05h - memory size is always
+	  reported in VBE function 4F00h - fixed scan line length for VBE
+	  mode 0102h - fixed function set_active_page() for graphics modes
+	  - fixed the page sizes of some VGA modes
+
+2003-04-26 09:22  vruppert
+
+	* vbe.c (1.28), vbetables.h (1.16), vgabios.c (1.29), vgatables.h
+	  (1.4), VGABIOS-lgpl-latest.bin (1.13):
+
+	  - added missing VBE function dispi_get_bank() - added missing
+	  return codes for VBE function 4F05h - memory size is always
+	  reported in VBE function 4F00h - fixed scan line length for VBE
+	  mode 0102h - fixed function set_active_page() for graphics modes
+	  - fixed the page sizes of some VGA modes
+
+2003-04-20 09:51  vruppert
+
+	* vgabios.c (1.28), vgatables.h (1.3), VGABIOS-lgpl-latest.bin
+	  (1.12), VGABIOS-lgpl-latest.debug.bin (1.12):
+
+	  - function write_gfx_char() now supports different font sizes -
+	  some entries of the static functionality table fixed
+
+2003-04-18 09:23  vruppert
+
+	* vbe.c (1.27), vbe.h (1.14), vbetables.h (1.15):
+
+	  - applied patch #1331   * new function dispi_set_bank_farcall()
+	  * VBE mode info item WinFuncPtr points to the new function if the
+	  flag	   VBE_WINDOW_ATTRIBUTE_RELOCATABLE is set   * flag
+	  VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE added
+
+2003-02-11 20:17  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.11), VGABIOS-lgpl-latest.debug.bin
+	  (1.11), vbe.c (1.26), vbetables.h (1.14):
+
+	  - VBE mode search rewritten	* improved function
+	  mode_info_find_mode() is now used by the VBE functions     0x4F01
+	  and 0x4F02   * removed all mode list entries with the LFB bit
+	  set. LFB detection is now	present in the function
+	  mode_info_find_mode()
+
+2003-02-09 20:59  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.10), VGABIOS-lgpl-latest.debug.bin
+	  (1.10), vgabios.c (1.27):
+
+	  - function write_gfx_char(): memory address now calculated in
+	  this function;   background color is always black - function
+	  biosfn_write_char_attr(): the count parameter is now used in
+	  graphics   modes too - function biosfn_write_char_only() works
+	  the same way as function   biosfn_write_char_attr() in graphics
+	  mode - copying charmap data optimized using memcpyb()
+
+2003-02-09 11:36  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.9), VGABIOS-lgpl-latest.debug.bin
+	  (1.9):
+
+	  - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA
+	  modes with the LFB flag set removed from the list (Linux doesn't
+	   like mode numbers > 0x07ff)
+
+2003-02-09 11:02  vruppert
+
+	* vbe.c (1.25), vbe.h (1.13), vbetables.h (1.13):
+
+	  - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA
+	  modes with the LFB flag set removed from the list (Linux doesn't
+	   like mode numbers > 0x07ff)
+
+2003-02-08 13:04  vruppert
+
+	* vbe.c (1.24), vgabios.c (1.26):
+
+	  - vbe_biosfn_return_current_mode() now returns the active
+	  standard VGA mode   TODO: return VESA mode if enabled -
+	  biosfn_set_video_mode() now clears the screen in CGA mode
+	  correctly - write character functions are now working in all
+	  PLANAR4 graphics modes - added stubs for unimplemented features
+	  in graphics modes
+
+2003-02-04 22:19  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.8), VGABIOS-lgpl-latest.debug.bin
+	  (1.8):
+
+	  - set video mode: clear vga memory in graphics mode - set video
+	  mode: load default font in text mode - write character
+	  implemented for graphics mode 0x12
+
+2003-02-04 22:06  vruppert
+
+	* vgabios.c (1.25):
+
+	  - set video mode: clear vga memory in graphics mode - set video
+	  mode: load default font in text mode - write character
+	  implemented for graphics mode 0x12
+
+2003-01-21 19:30  vruppert
+
+	* vgabios.c (1.24):
+
+	  - remap the cursor size if the char height is > 8 and the new
+	  values are < 8
+
+2003-01-20 18:24  cbothamy
+
+	* Makefile (1.9):
+
+	  - fix so make -j2 does not overwrite temp files
+
+2003-01-19 12:35  vruppert
+
+	* vgabios.c (1.23):
+
+	  - function set_scan_lines() recalculates the number of rows and
+	  the page size - new values for char height, text rows and page
+	  size are stored in the BIOS	data segment - asm helper function
+	  idiv_u added
+
+2003-01-15 18:49  cbothamy
+
+	* VGABIOS-lgpl-latest.bin (1.7), VGABIOS-lgpl-latest.debug.bin
+	  (1.7):
+
+	  - compile vgabios rev 1.22
+
+2003-01-15 18:49  cbothamy
+
+	* vgabios.c (1.22):
+
+	  - fix bug found by ams : a 8bits index value was compared to
+	  0x100 in some cases	in biosfn_set_all_dac_reg,
+	  biosfn_read_all_dac_reg, biosfn_perform_gray_scale_summing
+
+2003-01-15 17:34  cbothamy
+
+	* Makefile (1.8):
+
+	  - fix symbol table file names, discovered by ams
+
+2003-01-04 21:20  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.6), VGABIOS-lgpl-latest.debug.bin
+	  (1.6), vgabios.c (1.21):
+
+	  - biosfn_set_video_mode(): reset attribute controller flip-flop
+	  before setting   up the controller's registers (bug found with
+	  amidiag)
+
+2003-01-04 09:50  vruppert
+
+	* vbe.c (1.23):
+
+	  - VBE function 0x00 returns VBE 1.x compatible information if no
+	  VBE signature   is present
+
+2003-01-01 12:44  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.5), VGABIOS-lgpl-latest.debug.bin
+	  (1.5):
+
+	  - SVGA mode 0x6A (800x600x4) added to the list of graphics modes
+
+2002-12-31 18:07  vruppert
+
+	* vgatables.h (1.2):
+
+	  - SVGA mode 0x6A (800x600x4) added to the list of graphics modes
+
+2002-11-23 10:38  cbothamy
+
+	* ChangeLog (1.17, v0_3b):
+
+	  - fix changelog for 0.3b release
+
+2002-10-20 17:12  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.4), VGABIOS-lgpl-latest.debug.bin
+	  (1.4), vgabios.c (1.20) (utags: v0_3b):
+
+	  - new function set_scan_lines() for the font size change (patch
+	  from Hartmut Birr) - cursor shape start and end must be updated
+	  in set_scan_lines() - set_scan_lines() is called by the functions
+	  0x1110, 0x1111, 0x1112 and 0x1114   after copying the font data
+
+2002-10-04 08:20  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.3), VGABIOS-lgpl-latest.debug.bin
+	  (1.3), vgabios.c (1.19):
+
+	  - biosfn_set_single_dac_reg(): the red value is stored in DH
+
+2002-09-19 19:05  cbothamy
+
+	* VGABIOS-lgpl-latest.bin (1.2), VGABIOS-lgpl-latest.debug.bin
+	  (1.2):
+
+	  - updated with latest changes
+
+2002-09-19 19:03  cbothamy
+
+	* ChangeLog (1.16), Makefile (1.7, v0_3b), vbe.c (1.22, v0_3b),
+	  vgabios.c (1.18), vgabios.h (1.3, v0_4b, v0_4a, v0_3b):
+
+	  - updated the Makefile - removed display of copyrights.  -
+	  changed the Copyright string to "LGPL VGABios developers"
+
+2002-09-08 21:14  vruppert
+
+	* vgabios.c (1.17):
+
+	  - set the cursor shape depending on the current font height -
+	  clear BL before calling int 0x10 function 0x1103 in
+	  vgabios_init_func
+
+2002-08-23 22:58  cbothamy
+
+	* vbe.c (1.21), vbetables.h (1.12, v0_3b):
+
+	  - added lfb-mode numbers (patch from mathis)
+
+2002-07-21 21:57  japj
+
+	* vbe.c (1.20), vgabios.c (1.16):
+
+	  gcc2/3 preprocessing fix
+
+2002-05-18 16:55  cbothamy
+
+	* vgabios.c (1.15):
+
+	  - include patch from Volker that adds some text font functions
+
+2002-05-01 23:13  japj
+
+	* VGABIOS-lgpl-latest.bin (1.1), VGABIOS-lgpl-latest.debug.bin
+	  (1.1):
+
+	  adding latest bin & debug bin of the vgabios
+
+2002-04-29 14:50  japj
+
+	* ChangeLog (1.15), vbe.c (1.19), vbe.h (1.12, v0_3b), vbetables.h
+	  (1.11), vgabios.c (1.14):
+
+	  - applying hw scrolling/multibuffering patch
+
+2002-04-25 21:59  japj
+
+	* Makefile (1.6), vbe.c (1.18), vgabios.c (1.13):
+
+	  - reverting #asm/##asm & endasm patch (does not work with with
+	  cygwin)
+
+2002-04-19 19:38  japj
+
+	* Makefile (1.5), vbe.c (1.17), vgabios.c (1.12):
+
+	  - fixing preprocessing of vgabios with latest gcc (from Mandrake
+	  8.2)
+
+2002-04-08 23:44  japj
+
+	* ChangeLog (1.14), vbe_display_api.txt (1.5, v0_3b):
+
+	  - preparing docs for new DISPI interface (for hardware scrolling)
+
+2002-04-03 19:06  japj
+
+	* ChangeLog (1.13), TODO (1.9, v0_4b, v0_4a, v0_3b), vbe.c (1.16):
+
+	  - defaulting LFB on + updated changelog & todo
+
+2002-04-03 00:38  cbothamy
+
+	* vbe.c (1.15), vgabios.c (1.11):
+
+	  - changed the logging ports to 0x500 -> 0x502
+
+2002-03-14 17:54  japj
+
+	* vbe.c (1.14):
+
+	  - vbetables.h is dependant upon some defines (VBE_HAVE_LFB), so
+	  put the include *after* the define
+
+2002-03-13 21:47  japj
+
+	* ChangeLog (1.12), TODO (1.8), vbe.c (1.13), vbetables.h (1.10),
+	  vgabios.c (1.10):
+
+	  - made LFB dependant upon define - not implement vbe functions
+	  return failure - updated todo & docs for things after bochs 1.4
+
+2002-03-13 19:46  japj
+
+	* vbe.h (1.11), vbe_display_api.txt (1.4):
+
+	  - added max video memory + documented what is in the 0xb0c0
+	  interface
+
+2002-03-12 02:33  cbothamy
+
+	* ChangeLog (1.11), Makefile (1.4):
+
+	  - updated for 0.3a. Merged vgabios.bin and vbebios.bin
+
+2002-03-10 21:36  japj
+
+	* ChangeLog (1.10), vbetables.h (1.9):
+
+	  - added LFB modes for testing with vbe-lfb patch in Bochs
+
+2002-03-10 17:42  japj
+
+	* vbe.c (1.12, v0_3a):
+
+	  - show people when they do NOT have VBE support available
+
+2002-03-10 17:36  japj
+
+	* TODO (1.7, v0_3a), vbe.c (1.11), vbe.h (1.10, v0_3a), vgabios.c
+	  (1.9, v0_3a):
+
+	  - cleanup of vbe internal functions (set 8bpp mode is now
+	  dependant on ModeInfo content instead of hardcoded functions)
+
+2002-03-10 17:20  cbothamy
+
+	* ChangeLog (1.9, v0_3a), TODO (1.6):
+
+	  - updated for 0.3a
+
+2002-03-10 17:19  cbothamy
+
+	* vbe.c (1.10), vbe.h (1.9):
+
+	  - added vbe_has_vbe_display function that detects an attached vbe
+	  display
+
+2002-03-10 17:12  cbothamy
+
+	* vgabios.c (1.8):
+
+	  - vbe calls are done only if a vbe display is detected
+
+2002-03-10 11:25  japj
+
+	* vbe.h (1.8), vbe_display_api.txt (1.3, v0_3a):
+
+	  - preparing for LFB support
+
+2002-03-09 14:25  japj
+
+	* vgabios.c (1.7):
+
+	  - fixing initial cursor shape to _ instead of -
+
+2002-03-08 23:08  japj
+
+	* ChangeLog (1.8), TODO (1.5), vbe.c (1.9), vbe.h (1.7), vgabios.c
+	  (1.6):
+
+	  - updating vbe code to new API
+
+2002-03-08 21:48  japj
+
+	* vbe.c (1.8), vbe.h (1.6), vbetables.h (1.8, v0_3a):
+
+	  - updating vbe code with #defines from API
+
+2002-03-08 21:31  japj
+
+	* vbe_display_api.txt (1.2):
+
+	  - adding some text about how banks work
+
+2002-03-08 21:09  japj
+
+	* ChangeLog (1.7), vbe_display_api.txt (1.1):
+
+	  - adding vbe_display_api documentation
+
+2002-03-07 21:36  japj
+
+	* ChangeLog (1.6), vbe.c (1.7), vbetables.h (1.7):
+
+	  - added 1024x768xbpp support - some more cleanups/comments
+
+2002-03-06 21:55  japj
+
+	* ChangeLog (1.5), TODO (1.4), vbe.c (1.6), vbetables.h (1.6),
+	  vgabios.c (1.5):
+
+	  - updated changelog with new modi - added 640x480x8 (Mandrake
+	  Installer can use this!) - added pre VBE2 compatible 'detection'
+	  - fixed problem when normal vga set mode wouldn't disable vbe
+	  mode
+
+2002-03-06 20:59  japj
+
+	* TODO (1.3), vbe.c (1.5), vbe.h (1.5), vbetables.h (1.5),
+	  vgabios.c (1.4):
+
+	  - adding 640x400x8 and 800x600x8 vbe support	 (this depends
+	  HEAVILY on my bochs vga code patch - japj)
+
+2002-03-06 18:00  japj
+
+	* vbe.c (1.4), vbe.h (1.4), vbetables.h (1.4):
+
+	  - implemented banked & lfb support for 320x200x8bpp	(some fixes
+	  for vbetest program not displaying anything)
+
+2002-03-05 20:25  japj
+
+	* Makefile (1.3, v0_3a):
+
+	  for vbe debug bios: - print debugging information in assembly
+	  output - print source code in assembly output
+
+2002-03-01 19:39  japj
+
+	* ChangeLog (1.4), TODO (1.2), vbe.c (1.3), vbe.h (1.3),
+	  vbetables.h (1.3):
+
+	  - added vbe support for 320x200x8 using the standard vgamode
+	  (0x13)
+
+2002-02-19 00:29  japj
+
+	* ChangeLog (1.3):
+
+	  - updating ChangeLog with lfbprof
+
+2002-02-18 23:26  japj
+
+	* tests/lfbprof/: lfbprof.c (1.2), lfbprof.h (1.2) (utags: v0_3a,
+	  v0_3b, v0_4a, v0_4b):
+
+	  - fixed unsigned short for mode list (-1 != 0xffff otherwise) -
+	  fixed LfbMapRealPointer macro mask problem (some modes were
+	  skipped) - added some extra 'debugging' printf's
+
+2002-02-18 23:07  japj
+
+	* tests/lfbprof/: Makefile (1.1, v0_4b, v0_4a, v0_3b, v0_3a),
+	  lfbprof.c (1.1), lfbprof.h (1.1):
+
+	  - Adding lfbprof testprogram (for vbe testing purposes)   It
+	  needs to be compiled with the Watcom C Compiler
+
+2002-02-18 18:48  japj
+
+	* vbe.c (1.2), vbe.h (1.2):
+
+	  - cosmetic updates to vbe.c/h + added bunch of FIXMEs for work
+	  that needs to be done
+
+2002-02-18 18:34  japj
+
+	* vbetables.h (1.2):
+
+	  - cosmetic updates in vbetables.h
+
+2002-02-18 18:32  japj
+
+	* ChangeLog (1.2):
+
+	  updated changelog with merge of vbebios 0.2
+
+2002-02-18 18:07  japj
+
+	* vgabios.c (1.3):
+
+	  - small cosmetic cleanup in vgabios vbe code + added FIXMEs
+
+2002-02-18 17:55  japj
+
+	* Makefile (1.2), dataseghack (1.2, v0_4b, v0_4a, v0_3b, v0_3a),
+	  vbe.c (1.1), vbe.h (1.1), vbetables.h (1.1), vgabios.c (1.2),
+	  vgabios.h (1.2, v0_3a):
+
+	  - merging with vbebios 0.2 release
+
+2002-02-18 11:31  cbothamy
+
+	* BUGS (1.1, v0_4b, v0_4a, v0_3b, v0_3a), COPYING (1.1, v0_4b,
+	  v0_4a, v0_3b, v0_3a), ChangeLog (1.1), Makefile (1.1), Notes
+	  (1.1, v0_4b, v0_4a, v0_3b, v0_3a), README (1.1, v0_3b, v0_3a),
+	  TODO (1.1), dataseghack (1.1), vgabios.c (1.1), vgabios.h (1.1),
+	  vgafonts.h (1.1, v0_4b, v0_4a, v0_3b, v0_3a), vgatables.h (1.1,
+	  v0_3b, v0_3a), tests/testbios.c (1.1, v0_4b, v0_4a, v0_3b,
+	  v0_3a):
+
+	  - initial import
+
diff --git a/kvm/vgabios/Makefile b/kvm/vgabios/Makefile
new file mode 100644
index 0000000..00e8c66
--- /dev/null
+++ b/kvm/vgabios/Makefile
@@ -0,0 +1,87 @@
+SHELL = /bin/sh
+
+CC      = gcc
+CFLAGS  = -g -O2 -Wall -Wstrict-prototypes
+LDFLAGS = 
+
+GCC = gcc
+BCC = bcc
+AS86 = as86
+
+RELEASE = `pwd | sed "s-.*/--"`
+RELDATE = `date '+%d %b %Y'`
+RELVERS = `pwd | sed "s-.*/--" | sed "s/vgabios//" | sed "s/-//"`
+
+VGABIOS_DATE = "-DVGABIOS_DATE=\"$(RELDATE)\""
+
+all: bios cirrus-bios
+
+
+bios: biossums vgabios.bin vgabios.debug.bin
+
+cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin
+
+clean:
+	/bin/rm -f  biossums vbetables-gen vbetables.h *.o *.s *.ld86 \
+          temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak
+
+dist-clean: clean
+
+release: 
+	VGABIOS_VERS=\"-DVGABIOS_VERS=\\\"$(RELVERS)\\\"\" make bios cirrus-bios
+	/bin/rm -f  *.o *.s *.ld86 \
+          temp.awk.* vgabios.*.orig _vgabios_.*.c core *.bak .#*
+	cp VGABIOS-lgpl-latest.bin ../$(RELEASE).bin
+	cp VGABIOS-lgpl-latest.debug.bin ../$(RELEASE).debug.bin
+	cp VGABIOS-lgpl-latest.cirrus.bin ../$(RELEASE).cirrus.bin
+	cp VGABIOS-lgpl-latest.cirrus.debug.bin ../$(RELEASE).cirrus.debug.bin
+	tar czvf ../$(RELEASE).tgz --exclude CVS -C .. $(RELEASE)/
+
+vgabios.bin: vgabios.c vgabios.h vgafonts.h vgatables.h vbe.h vbe.c vbetables.h
+	$(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DVBE $(VGABIOS_DATE) > _vgabios_.c
+	$(BCC) -o vgabios.s -C-c -D__i86__ -S -0 _vgabios_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' vgabios.s > _vgabios_.s
+	$(AS86) _vgabios_.s -b vgabios.bin -u -w- -g -0 -j -O -l vgabios.txt
+	rm -f _vgabios_.s _vgabios_.c vgabios.s
+	mv vgabios.bin VGABIOS-lgpl-latest.bin
+	./biossums VGABIOS-lgpl-latest.bin
+	ls -l VGABIOS-lgpl-latest.bin
+
+vgabios.debug.bin: vgabios.c vgabios.h vgafonts.h vgatables.h vbe.h vbe.c vbetables.h
+	$(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DVBE -DDEBUG $(VGABIOS_DATE) > _vgabios-debug_.c
+	$(BCC) -o vgabios-debug.s -C-c -D__i86__ -S -0 _vgabios-debug_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' vgabios-debug.s > _vgabios-debug_.s
+	$(AS86) _vgabios-debug_.s -b vgabios.debug.bin -u -w- -g -0 -j -O -l vgabios.debug.txt
+	rm -f _vgabios-debug_.s _vgabios-debug_.c vgabios-debug.s
+	mv vgabios.debug.bin VGABIOS-lgpl-latest.debug.bin
+	./biossums VGABIOS-lgpl-latest.debug.bin
+	ls -l VGABIOS-lgpl-latest.debug.bin
+
+vgabios-cirrus.bin: vgabios.c vgabios.h vgafonts.h vgatables.h clext.c
+	$(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DCIRRUS -DPCIBIOS $(VGABIOS_DATE) > _vgabios-cirrus_.c
+	$(BCC) -o vgabios-cirrus.s -C-c -D__i86__ -S -0 _vgabios-cirrus_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' vgabios-cirrus.s > _vgabios-cirrus_.s
+	$(AS86) _vgabios-cirrus_.s -b vgabios-cirrus.bin -u -w- -g -0 -j -O -l vgabios.cirrus.txt
+	rm -f _vgabios-cirrus_.s _vgabios-cirrus_.c vgabios-cirrus.s
+	mv vgabios-cirrus.bin VGABIOS-lgpl-latest.cirrus.bin
+	./biossums VGABIOS-lgpl-latest.cirrus.bin
+	ls -l VGABIOS-lgpl-latest.cirrus.bin
+
+vgabios-cirrus.debug.bin: vgabios.c vgabios.h vgafonts.h vgatables.h clext.c
+	$(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DCIRRUS -DCIRRUS_DEBUG -DPCIBIOS $(VGABIOS_DATE) > _vgabios-cirrus-debug_.c
+	$(BCC) -o vgabios-cirrus-debug.s -C-c -D__i86__ -S -0 _vgabios-cirrus-debug_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' vgabios-cirrus-debug.s > _vgabios-cirrus-debug_.s
+	$(AS86) _vgabios-cirrus-debug_.s -b vgabios.cirrus.debug.bin -u -w- -g -0 -j -O -l vgabios.cirrus.debug.txt
+	rm -f _vgabios-cirrus-debug_.s _vgabios-cirrus-debug_.c vgabios-cirrus-debug.s
+	mv vgabios.cirrus.debug.bin VGABIOS-lgpl-latest.cirrus.debug.bin
+	./biossums VGABIOS-lgpl-latest.cirrus.debug.bin
+	ls -l VGABIOS-lgpl-latest.cirrus.debug.bin
+
+biossums: biossums.c
+	$(CC) -o biossums biossums.c
+
+vbetables-gen: vbetables-gen.c
+	$(CC) -o vbetables-gen vbetables-gen.c
+
+vbetables.h: vbetables-gen
+	./vbetables-gen > $@
diff --git a/kvm/vgabios/Notes b/kvm/vgabios/Notes
new file mode 100644
index 0000000..d5b708d
--- /dev/null
+++ b/kvm/vgabios/Notes
@@ -0,0 +1,11 @@
+Development notes
+-----------------
+
+- need to split video init function
+    1. set bios variables
+    2. do the real init with io based on bios variables
+
+- characters format switching will set the bios
+  variables and call function #2 above
+
+- need to rework the tables as explained in Interrupt list
diff --git a/kvm/vgabios/README b/kvm/vgabios/README
new file mode 100644
index 0000000..90141d4
--- /dev/null
+++ b/kvm/vgabios/README
@@ -0,0 +1,219 @@
+Plex86/Bochs VGABios
+--------------------
+
+The goal of this project is to have a LGPL'd Video Bios in plex86,
+Bochs and qemu.
+This VGA Bios is very specific to the emulated VGA card.
+It is NOT meant to drive a physical vga card.
+
+
+Cirrus SVGA extension
+---------------------
+
+The Cirrus SVGA extension is designed for the Cirrus emulation in Bochs and
+qemu. The initial patch for the Cirrus extension has been written by Makoto
+Suzuki (suzu).
+
+
+Install
+-------
+To compile the VGA Bios you will need :
+- gcc
+- bcc
+- as86
+- ld86
+
+Untar the archive, and type make. You should get a "VGABIOS-lgpl-latest.bin"
+file. Alternatively, you can use the binary file "VGABIOS-lgpl-latest.bin",
+i have compiled for you.
+
+Edit your plex86/bochs conf file, and modify the load-rom command in the
+VGA BIOS section, to point to the new vgabios image file.
+
+
+Debugging
+---------
+You can get a very basic debugging system: messages printed by the vgabios.
+You have to register the "unmapped" device driver in plex86 or bochs, and make
+sure it grabs port 0xfff0.
+
+Comment the #undef DEBUG at the beginning of vgabios.c.
+You can then use the "printf" function in the bios.
+
+
+Testing
+-------
+Look at the "testvga.c" file in the archive. This is a minimal Turbo C 2.0
+source file that calls a few int10 functions. Feel free to modify it to suit
+your needs.
+
+
+Copyright and License
+---------------------
+This program has been written by Christophe Bothamy
+It is protected by the GNU Lesser Public License, which you should
+have received a copy of along with this package.
+
+
+Reverse Engineering
+-------------------
+The VGA Bios has been written without reverse-engineering any existing Bios.
+
+
+Acknowledgment
+--------------
+The source code contains code ripped from rombios.c of plex86, written
+by Kevin Lawton <kevin2001@yahoo.com>
+
+The source code contains fonts from fntcol16.zip (c) by Joseph Gil avalable at :
+ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+These fonts are public domain
+
+The source code is based on information taken from :
+- Kevin Lawton's vga card emulation for bochs/plex86
+- Ralf Brown's interrupts list avalaible at
+  http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+- Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+- Michael Abrash's Graphics Programming Black Book
+- Francois Gervais' book "programmation des cartes graphiques cga-ega-vga"
+  edited by sybex
+- DOSEMU 1.0.1 source code for several tables values and formulas
+
+
+Feedback
+--------
+Please report any bugs, comments, patches for this VGA Bios to info@vruppert.de
+You can find the latest release at : http://www.nongnu.org/vgabios/
+For any information on bochs, visit the website http://bochs.sourceforge.net/
+For any information on qemu, visit the website http://fabrice.bellard.free.fr/qemu/
+
+
+History
+-------
+vgabios-0.6b : May 30 2008
+  - Volker
+    . added PCI data structure for the Cirrus VGABIOS images
+    . minor bugfixes in biossums utility, VBE support and makefile
+
+vgabios-0.6a : Aug 19 2006
+  - Volker
+    . added minimal support for the video parameter table (VPT)
+    . Cirrus SVGA now supports the "no clear" bit in Cirrus and VESA mode
+    . Bochs VBE protected mode interface improved
+    . save/restore video state support for Bochs VBE and standard VGA added
+    . generate vbetables.h dynamicly
+    . VBE video memory increased to 8 MB (VBE dispi ID changed to B0C4)
+    . lots of 4bpp VBE fixes (all 4bpp VBE modes now enabled)
+    . VGA compatible setup for VBE modes added
+
+vgabios-0.5d : Dec 29 2005
+  - Volker
+    . Bochs VBE protected mode interface added (based on a patch by malc@pulsesoft.com)
+    . biossums utility now supports VGABIOS sizes up to 64 kBytes
+    . VGA mode 0x11: all color planes must be enabled in this 2-color VGA mode
+
+vgabios-0.5c : Jul 07 2005
+  - Volker
+    . BIOS configuration word usually reports initial mode 80x25 color text
+    . vgabios function 0x0e (write teletype): linefeed (0x0a) only increments the
+      cursor row value
+
+vgabios-0.5b : May 24 2005
+  - Volker
+    . fixed return value for the default case in the VBE section (non-debug mode)
+    . removed unused stuff
+
+vgabios-0.5a : Mar 07 2005
+  - Volker
+    . Cirrus SVGA extension (initial patches from Makoto Suzuki, improvements
+      from Fabrice Bellard)
+    . vgabios image size is now exactly 32k with a checksum
+    . a lot of vgabios and vbe functions rewritten in assembler
+    . dynamicly generated VBE mode info list
+    . write character function for CGA and LINEAR8 modes
+    . read/write graphics pixel for some graphics modes
+    . text scroll feature for some graphics modes
+    . VBE 8-bit DAC support
+
+vgabios-0.4c : Nov 06 2003
+  - Christophe
+    . fix font problem on initial screen of NT4 Loader
+    
+vgabios-0.4b : Nov 04 2003
+  - Volker
+    . fix offset of character tables
+    . optimizations of CRT controller accesses
+    . VBE i/o registers changed to 0x01CE/CF 
+      (suggestion from Daniel Gimpelevich)
+    . "noclear" flag stored in BIOS area
+    . fix character height returned by get_font_info function
+
+vgabios-0.4a : Aug 17 2003
+  - Volker
+    . VBE mode search rewritten (VBE modes with LFB bit removed)
+    . many bugfixes and optimizations
+    . write character function implemented for graphics modes
+    . support for 15bpp, 16bpp, 24bpp and 32bpp VBE modes added
+    . SVGA mode 0x6A added
+    . VBE modes 0x102, 0x117, 0x118 and 0x142 (Bochs specific)
+
+vgabios-0.3b : Nov 23 2002
+  - Christophe
+    . added lfb-mode numbers (patch from mathis)
+    . updated the Makefile
+    . removed display of copyrights.
+    . changed the Copyright string to "LGPL VGABios developers"
+  - Volker
+    . set the cursor shape depending on the current font height
+    . clear BL before calling int 0x10 function 0x1103 in vgabios_init_func
+    . added some text font functions
+  - Jeroen
+    . Forced to new DISPI (0xb0c1) interface (requires latest bochs vbe code)
+    . Added multibuffering support
+    . Added new DISPI interface for: virt width, height, x offset, y offset
+    . Added LFB modes (to be used with the vbe-lfb patch in bochs)
+      see VBE_HAVE_LFB in vbe.c (currently default enabled)
+    . updated TODO & docs for changes after bochs 1.4
+
+vgabios-0.3a : Mar 10 2002
+  - Christophe
+    . Fixed bug in function ah=13
+  - Jeroen
+    . updated vbebios implementation to new api
+    . added vbe_display_api documentation
+    . added 640x400x8, 640x480x8, 800x600x8, 1024x768
+      (>640x480 needs a special bochs patch atm)
+    . added 320x200x8 vbe support (uses the standard 320x200x8 vga mode to
+      display, this allows for testing & having something on screen as well,
+      at least until bochs host side display is up & running)
+    . adding lfbprof (vbe) testprogram (+some small fixes to it)
+    . merging with vbebios 0.2
+
+vgabios-0.2b : Nov 19 2001
+  - Christophe
+    . Fixed bug in function ah=13
+
+vgabios-0.2a : Nov 09 2001
+  - Christophe
+    . Included bugfix from techt@pikeonline.net about grayscale summing
+    . Added the "IBM" string at org 0x1e as Bart Oldeman suggested
+    . Fixed DS and ES that where inverted in the int10 parameters list!
+    . The following have been implemented :
+	- function ax=1a00, ax=1a01, ah=1b
+	- function ax=1130
+    . Added debug messages for unimplemented/unknown functions
+      Must be compiled with DEBUG defined. The output is trapped
+      by the unknown-ioport driver of plex/bochs (port 0xfff0 is used)
+
+vgabios-0.1a : May 8 2001
+  - Christophe
+    . First release. The work has been focused only on text mode.
+    . The following have been implemented :
+	- inits
+	- int 10 handler
+	- functions ah=00, ah=01, ah=02, ah=03, ah=05, ah=06, ah=07, ah=08
+	  ah=09, ah=0a, ah=0e, ah=0f, ax=1000, ax=1001, ax=1002, ax=1003
+	  ax=1007, ax=1008, ax=1009, ax=1010, ax=1012, ax=1013, ax=1015
+	  ax=1017, ax=1018, ax=1019, ax=101a, ax=101b, ah=12 bl=10,
+	  ah=12 bl=30, ah=12 bl=31, ah=12 bl=32, ah=12 bl=33, ah=12 bl=34
+	  ah=13
diff --git a/kvm/vgabios/TODO b/kvm/vgabios/TODO
new file mode 100644
index 0000000..b08ee4b
--- /dev/null
+++ b/kvm/vgabios/TODO
@@ -0,0 +1,26 @@
+Short term :
+------------
+
+General
+  - Fix init mode (ah=00). Should use more BIOS variables
+  - Add new functionalities and modify static functionality table
+  - Performance : 16 bits IO
+
+v0.7
+  - Implement the remaining functions (don't know if all are needed):
+	- chargen ax=1120, ax=1121, ax=1122, ax=1123, ax=1124
+	- display switch interface ah=12 bl=35
+	- video refresh control ah=12 bl=36
+  - Graphic modes
+
+v1.0
+  - Bugfixes
+
+
+=================================================================================================
+VBE:
+----
+Long term:
+- have plex86 host side display interface
+- have text io functions in vbe mode
+
diff --git a/kvm/vgabios/biossums.c b/kvm/vgabios/biossums.c
new file mode 100644
index 0000000..d5816f4
--- /dev/null
+++ b/kvm/vgabios/biossums.c
@@ -0,0 +1,282 @@
+/* biossums.c  --- written by Eike W. for the Bochs BIOS */
+/* adapted for the LGPL'd VGABIOS by vruppert */
+
+/*  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef unsigned char byte;
+
+void check( int value, char* message );
+
+#define MAX_BIOS_DATA 0x10000
+
+long chksum_bios_get_offset( byte* data, long offset );
+byte chksum_bios_calc_value( byte* data, long offset );
+byte chksum_bios_get_value(  byte* data, long offset );
+void chksum_bios_set_value(  byte* data, long offset, byte value );
+
+#define PMID_LEN        20
+#define PMID_CHKSUM     19
+
+long chksum_pmid_get_offset( byte* data, long offset );
+byte chksum_pmid_calc_value( byte* data, long offset );
+byte chksum_pmid_get_value(  byte* data, long offset );
+void chksum_pmid_set_value(  byte* data, long offset, byte value );
+
+#define PCIR_LEN        24
+
+long chksum_pcir_get_offset( byte* data, long offset );
+
+
+byte bios_data[MAX_BIOS_DATA];
+long bios_len;
+
+
+int main(int argc, char* argv[])
+{
+  FILE* stream;
+  long  offset, tmp_offset, pcir_offset;
+  byte  bios_len_byte, cur_val = 0, new_val = 0;
+  int   hits, modified;
+
+  if (argc != 2) {
+    printf( "Error. Need a file-name as an argument.\n" );
+    exit( EXIT_FAILURE );
+  }
+
+  if ((stream = fopen(argv[1], "rb")) == NULL) {
+    printf("Error opening %s for reading.\n", argv[1]);
+    exit(EXIT_FAILURE);
+  }
+  memset(bios_data, 0, MAX_BIOS_DATA);
+  bios_len = fread(bios_data, 1, MAX_BIOS_DATA, stream);
+  if (bios_len > MAX_BIOS_DATA) {
+    printf("Error reading max. 65536 Bytes from %s.\n", argv[1]);
+    fclose(stream);
+    exit(EXIT_FAILURE);
+  }
+  fclose(stream);
+  modified = 0;
+  if (bios_len < 0x8000) {
+    bios_len = 0x8000;
+    modified = 1;
+  } else if ((bios_len & 0x1FF) != 0) {
+    bios_len = (bios_len + 0x200) & ~0x1FF;
+    modified = 1;
+  }
+  bios_len_byte = (byte)(bios_len / 512);
+  if (bios_len_byte != bios_data[2]) {
+    if (modified == 0) {
+      bios_len += 0x200;
+    }
+    bios_data[2] = (byte)(bios_len / 512);
+    modified = 1;
+  }
+
+  hits   = 0;
+  offset = 0L;
+  while( (tmp_offset = chksum_pmid_get_offset( bios_data, offset )) != -1L ) {
+    offset  = tmp_offset;
+    cur_val = chksum_pmid_get_value(  bios_data, offset );
+    new_val = chksum_pmid_calc_value( bios_data, offset );
+    printf( "\nPMID entry at: 0x%4lX\n", offset  );
+    printf( "Current checksum:     0x%02X\n",   cur_val );
+    printf( "Calculated checksum:  0x%02X  ",   new_val );
+    hits++;
+  }
+  if ((hits == 1) && (cur_val != new_val)) {
+    printf("Setting checksum.");
+    chksum_pmid_set_value( bios_data, offset, new_val );
+    if (modified == 0) {
+      bios_len += 0x200;
+      bios_data[2]++;
+    }
+    modified = 1;
+  }
+  if (hits >= 2) {
+    printf( "Multiple PMID entries! No checksum set." );
+  }
+  if (hits) {
+    printf("\n");
+  }
+
+  offset = 0L;
+  pcir_offset = chksum_pcir_get_offset( bios_data, offset );
+  if (pcir_offset != -1L) {
+    if (bios_data[pcir_offset + 16] != bios_data[2]) {
+      bios_data[pcir_offset + 16] = bios_data[2];
+      if (modified == 0) {
+        bios_len += 0x200;
+        bios_data[2]++;
+        bios_data[pcir_offset + 16]++;
+      }
+      modified = 1;
+    }
+  }
+
+  offset  = 0L;
+  do {
+    offset  = chksum_bios_get_offset(bios_data, offset);
+    cur_val = chksum_bios_get_value(bios_data, offset);
+    new_val = chksum_bios_calc_value(bios_data, offset);
+    if ((cur_val != new_val) && (modified == 0)) {
+      bios_len += 0x200;
+      bios_data[2]++;
+      if (pcir_offset != -1L) {
+        bios_data[pcir_offset + 16]++;
+      }
+      modified = 1;
+    } else {
+      printf("\nBios checksum at:   0x%4lX\n", offset);
+      printf("Current checksum:     0x%02X\n", cur_val);
+      printf("Calculated checksum:  0x%02X  ", new_val);
+      if (cur_val != new_val) {
+        printf("Setting checksum.");
+        chksum_bios_set_value(bios_data, offset, new_val);
+        cur_val = new_val;
+        modified = 1;
+      }
+      printf( "\n" );
+    }
+  } while (cur_val != new_val);
+
+  if (modified == 1) {
+    if ((stream = fopen( argv[1], "wb")) == NULL) {
+      printf("Error opening %s for writing.\n", argv[1]);
+      exit(EXIT_FAILURE);
+    }
+    if (fwrite(bios_data, 1, bios_len, stream) < bios_len) {
+      printf("Error writing %d KBytes to %s.\n", bios_len / 1024, argv[1]);
+      fclose(stream);
+      exit(EXIT_FAILURE);
+    }
+    fclose(stream);
+  }
+
+  return (EXIT_SUCCESS);
+}
+
+
+void check( int okay, char* message ) {
+
+  if( !okay ) {
+    printf( "\n\nError. %s.\n", message );
+    exit( EXIT_FAILURE );
+  }
+}
+
+
+long chksum_bios_get_offset( byte* data, long offset ) {
+
+  return (bios_len - 1);
+}
+
+
+byte chksum_bios_calc_value( byte* data, long offset ) {
+
+  int   i;
+  byte  sum;
+
+  sum = 0;
+  for( i = 0; i < offset; i++ ) {
+    sum = sum + *( data + i );
+  }
+  sum = -sum;          /* iso ensures -s + s == 0 on unsigned types */
+  return( sum );
+}
+
+
+byte chksum_bios_get_value( byte* data, long offset ) {
+
+  return( *( data + offset ) );
+}
+
+
+void chksum_bios_set_value( byte* data, long offset, byte value ) {
+
+  *( data + offset ) = value;
+}
+
+
+byte chksum_pmid_calc_value( byte* data, long offset ) {
+
+  int           i;
+  int           len;
+  byte sum;
+
+  len = PMID_LEN;
+  check((offset + len) <= (bios_len - 1), "PMID entry length out of bounds" );
+  sum = 0;
+  for( i = 0; i < len; i++ ) {
+    if( i != PMID_CHKSUM ) {
+      sum = sum + *( data + offset + i );
+    }
+  }
+  sum = -sum;
+  return( sum );
+}
+
+
+long chksum_pmid_get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  while ((offset + PMID_LEN) < (bios_len - 1)) {
+    offset = offset + 1;
+    if( *( data + offset + 0 ) == 'P' && \
+        *( data + offset + 1 ) == 'M' && \
+        *( data + offset + 2 ) == 'I' && \
+        *( data + offset + 3 ) == 'D' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
+
+
+byte chksum_pmid_get_value( byte* data, long offset ) {
+
+  check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" );
+  return(  *( data + offset + PMID_CHKSUM ) );
+}
+
+
+void chksum_pmid_set_value( byte* data, long offset, byte value ) {
+
+  check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" );
+  *( data + offset + PMID_CHKSUM ) = value;
+}
+
+
+long chksum_pcir_get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  while ((offset + PCIR_LEN) < (bios_len - 1)) {
+    offset = offset + 1;
+    if( *( data + offset + 0 ) == 'P' && \
+        *( data + offset + 1 ) == 'C' && \
+        *( data + offset + 2 ) == 'I' && \
+        *( data + offset + 3 ) == 'R' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
diff --git a/kvm/vgabios/clext.c b/kvm/vgabios/clext.c
new file mode 100644
index 0000000..c7a2ad0
--- /dev/null
+++ b/kvm/vgabios/clext.c
@@ -0,0 +1,1688 @@
+//
+//  QEMU Cirrus CLGD 54xx VGABIOS Extension.
+//
+//  Copyright (c) 2004 Makoto Suzuki (suzu)
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library 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
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// 
+
+//#define CIRRUS_VESA3_PMINFO
+#ifdef VBE
+#undef CIRRUS_VESA3_PMINFO
+#endif
+
+#define PM_BIOSMEM_CURRENT_MODE 0x449
+#define PM_BIOSMEM_CRTC_ADDRESS 0x463
+#define PM_BIOSMEM_VBE_MODE 0x4BA
+
+typedef struct
+{
+  /* + 0 */
+  unsigned short mode;
+  unsigned short width;
+  unsigned short height;
+  unsigned short depth;
+  /* + 8 */
+  unsigned short hidden_dac; /* 0x3c6 */
+  unsigned short *seq; /* 0x3c4 */
+  unsigned short *graph; /* 0x3ce */
+  unsigned short *crtc; /* 0x3d4 */
+  /* +16 */
+  unsigned char bitsperpixel;
+  unsigned char vesacolortype;
+  unsigned char vesaredmask;
+  unsigned char vesaredpos;
+  unsigned char vesagreenmask;
+  unsigned char vesagreenpos;
+  unsigned char vesabluemask;
+  unsigned char vesabluepos;
+  /* +24 */
+  unsigned char vesareservedmask;
+  unsigned char vesareservedpos;
+} cirrus_mode_t;
+#define CIRRUS_MODE_SIZE 26
+
+
+/* For VESA BIOS 3.0 */
+#define CIRRUS_PM16INFO_SIZE 20
+
+/* VGA */
+unsigned short cseq_vga[] = {0x0007,0xffff};
+unsigned short cgraph_vga[] = {0x0009,0x000a,0x000b,0xffff};
+unsigned short ccrtc_vga[] = {0x001a,0x001b,0x001d,0xffff};
+
+/* extensions */
+unsigned short cgraph_svgacolor[] = {
+0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08,
+0x0009,0x000a,0x000b,
+0xffff
+};
+/* 640x480x8 */
+unsigned short cseq_640x480x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x580b,0x580c,0x580d,0x580e,
+0x0412,0x0013,0x2017,
+0x331b,0x331c,0x331d,0x331e,
+0xffff
+};
+unsigned short ccrtc_640x480x8[] = {
+0x2c11,
+0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+0x4009,0x000c,0x000d,
+0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 640x480x16 */
+unsigned short cseq_640x480x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x580b,0x580c,0x580d,0x580e,
+0x0412,0x0013,0x2017,
+0x331b,0x331c,0x331d,0x331e,
+0xffff
+};
+unsigned short ccrtc_640x480x16[] = {
+0x2c11,
+0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+0x4009,0x000c,0x000d,
+0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 640x480x24 */
+unsigned short cseq_640x480x24[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+0x580b,0x580c,0x580d,0x580e,
+0x0412,0x0013,0x2017,
+0x331b,0x331c,0x331d,0x331e,
+0xffff
+};
+unsigned short ccrtc_640x480x24[] = {
+0x2c11,
+0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+0x4009,0x000c,0x000d,
+0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 800x600x8 */
+unsigned short cseq_800x600x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x230b,0x230c,0x230d,0x230e,
+0x0412,0x0013,0x2017,
+0x141b,0x141c,0x141d,0x141e,
+0xffff
+};
+unsigned short ccrtc_800x600x8[] = {
+0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+0x6009,0x000c,0x000d,
+0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 800x600x16 */
+unsigned short cseq_800x600x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x230b,0x230c,0x230d,0x230e,
+0x0412,0x0013,0x2017,
+0x141b,0x141c,0x141d,0x141e,
+0xffff
+};
+unsigned short ccrtc_800x600x16[] = {
+0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+0x6009,0x000c,0x000d,
+0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 800x600x24 */
+unsigned short cseq_800x600x24[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+0x230b,0x230c,0x230d,0x230e,
+0x0412,0x0013,0x2017,
+0x141b,0x141c,0x141d,0x141e,
+0xffff
+};
+unsigned short ccrtc_800x600x24[] = {
+0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+0x6009,0x000c,0x000d,
+0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 1024x768x8 */
+unsigned short cseq_1024x768x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1024x768x8[] = {
+0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 1024x768x16 */
+unsigned short cseq_1024x768x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1024x768x16[] = {
+0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 1024x768x24 */
+unsigned short cseq_1024x768x24[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1024x768x24[] = {
+0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 1280x1024x8 */
+unsigned short cseq_1280x1024x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1280x1024x8[] = {
+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 1280x1024x16 */
+unsigned short cseq_1280x1024x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1280x1024x16[] = {
+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+
+/* 1600x1200x8 */
+unsigned short cseq_1600x1200x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1600x1200x8[] = {
+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+
+cirrus_mode_t cirrus_modes[] =
+{
+ {0x5f,640,480,8,0x00,
+   cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x64,640,480,16,0xe1,
+   cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+   6,5,11,6,5,5,0,0,0},
+ {0x66,640,480,15,0xf0,
+   cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+   6,5,10,5,5,5,0,1,15},
+ {0x71,640,480,24,0xe5,
+   cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24,
+   6,8,16,8,8,8,0,0,0},
+
+ {0x5c,800,600,8,0x00,
+   cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x65,800,600,16,0xe1,
+   cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+   6,5,11,6,5,5,0,0,0},
+ {0x67,800,600,15,0xf0,
+   cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+   6,5,10,5,5,5,0,1,15},
+
+ {0x60,1024,768,8,0x00,
+   cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x74,1024,768,16,0xe1,
+   cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+   6,5,11,6,5,5,0,0,0},
+ {0x68,1024,768,15,0xf0,
+   cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+   6,5,10,5,5,5,0,1,15},
+
+ {0x78,800,600,24,0xe5,
+   cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24,
+   6,8,16,8,8,8,0,0,0},
+ {0x79,1024,768,24,0xe5,
+   cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24,
+   6,8,16,8,8,8,0,0,0},
+
+ {0x6d,1280,1024,8,0x00,
+   cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x69,1280,1024,15,0xf0,
+   cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+   6,5,10,5,5,5,0,1,15},
+ {0x75,1280,1024,16,0xe1,
+   cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+   6,5,11,6,5,5,0,0,0},
+
+ {0x7b,1600,1200,8,0x00,
+   cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
+   4,0,0,0,0,0,0,0,0},
+
+ {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
+   0xff,0,0,0,0,0,0,0,0},
+ {0xff,0,0,0,0,0,0,0,0,
+   0xff,0,0,0,0,0,0,0,0},
+};
+
+unsigned char cirrus_id_table[] = {
+  // 5430
+  0xA0, 0x32,
+  // 5446
+  0xB8, 0x39,
+
+  0xff, 0xff
+};
+
+
+unsigned short cirrus_vesa_modelist[] = {
+// 640x480x8
+  0x101, 0x5f,
+// 640x480x15
+  0x110, 0x66,
+// 640x480x16
+  0x111, 0x64,
+// 640x480x24
+  0x112, 0x71,
+// 800x600x8
+  0x103, 0x5c,
+// 800x600x15
+  0x113, 0x67,
+// 800x600x16
+  0x114, 0x65,
+// 800x600x24
+  0x115, 0x78,
+// 1024x768x8
+  0x105, 0x60,
+// 1024x768x15
+  0x116, 0x68,
+// 1024x768x16
+  0x117, 0x74,
+// 1024x768x24
+  0x118, 0x79,
+// 1280x1024x8
+  0x107, 0x6d,
+// 1280x1024x15
+  0x119, 0x69,
+// 1280x1024x16
+  0x11a, 0x75,
+// invalid
+  0xffff,0xffff
+};
+
+
+ASM_START
+
+cirrus_installed:
+.ascii "cirrus-compatible VGA is detected"
+.byte 0x0d,0x0a
+.byte 0x0d,0x0a,0x00
+
+cirrus_not_installed:
+.ascii "cirrus-compatible VGA is not detected"
+.byte 0x0d,0x0a
+.byte 0x0d,0x0a,0x00
+
+cirrus_vesa_vendorname:
+cirrus_vesa_productname:
+cirrus_vesa_oemname:
+.ascii "VGABIOS Cirrus extension"
+.byte 0
+cirrus_vesa_productrevision:
+.ascii "1.0"
+.byte 0
+
+cirrus_init:
+  call cirrus_check
+  jnz no_cirrus
+  SET_INT_VECTOR(0x10, #0xC000, #cirrus_int10_handler)
+  mov al, #0x0f ; memory setup
+  mov dx, #0x3C4
+  out dx, al
+  inc dx
+  in  al, dx
+  and al, #0x18
+  mov ah, al
+  mov al, #0x0a
+  dec dx
+  out dx, ax
+  mov ax, #0x0007 ; set vga mode
+  out dx, ax
+  mov ax, #0x0431 ; reset bitblt
+  mov dx, #0x3CE
+  out dx, ax
+  mov ax, #0x0031
+  out dx, ax
+no_cirrus:
+  ret
+
+cirrus_display_info:
+  push ds
+  push si
+  push cs
+  pop ds
+  call cirrus_check
+  mov si, #cirrus_not_installed
+  jnz cirrus_msgnotinstalled
+  mov si, #cirrus_installed
+
+cirrus_msgnotinstalled:
+  call _display_string
+  pop si
+  pop ds
+  ret
+
+cirrus_check:
+  push ax
+  push dx
+  mov ax, #0x9206
+  mov dx, #0x3C4
+  out dx, ax
+  inc dx
+  in al, dx
+  cmp al, #0x12
+  pop dx
+  pop ax
+  ret
+
+
+cirrus_int10_handler:
+  pushf
+  push bp
+  cmp ah, #0x00  ;; set video mode
+  jz cirrus_set_video_mode
+  cmp ah, #0x12  ;; cirrus extension
+  jz cirrus_extbios
+  cmp ah, #0x4F  ;; VESA extension
+  jz cirrus_vesa
+
+cirrus_unhandled:
+  pop bp
+  popf
+  jmp vgabios_int10_handler
+
+cirrus_return:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  pop bp
+  popf
+  iret
+
+cirrus_set_video_mode:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  push si
+  push ax
+  push bx
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov si, [cirrus_vesa_sel0000_data]
+#else
+  xor si, si
+#endif
+  mov ds, si
+  xor bx, bx
+  mov [PM_BIOSMEM_VBE_MODE], bx
+  pop ds
+  pop bx
+  call cirrus_get_modeentry
+  jnc cirrus_set_video_mode_extended
+  mov al, #0xfe
+  call cirrus_get_modeentry_nomask
+  call cirrus_switch_mode
+  pop ax
+  pop si
+  jmp cirrus_unhandled
+
+cirrus_extbios:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  cmp bl, #0x80
+  jb cirrus_unhandled
+  cmp bl, #0xAF
+  ja cirrus_unhandled
+  push bx
+  and bx, #0x7F
+  shl bx, 1
+ db 0x2e ;; cs:
+  mov bp, cirrus_extbios_handlers[bx]
+  pop bx
+  push #cirrus_return
+  push bp
+  ret
+
+cirrus_vesa:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  cmp al, #0x10
+  ja cirrus_vesa_not_handled
+  push bx
+  xor bx, bx
+  mov bl, al
+  shl bx, 1
+ db 0x2e ;; cs:
+  mov bp, cirrus_vesa_handlers[bx]
+  pop bx
+  push #cirrus_return
+  push bp
+  ret
+
+cirrus_vesa_not_handled:
+  mov ax, #0x014F ;; not implemented
+  jmp cirrus_return
+
+#ifdef CIRRUS_DEBUG
+cirrus_debug_dump:
+  push es
+  push ds
+  pusha
+  push cs
+  pop ds
+  call _cirrus_debugmsg
+  popa
+  pop ds
+  pop es
+  ret
+#endif
+
+cirrus_set_video_mode_extended:
+  call cirrus_switch_mode
+  pop ax ;; mode
+  test al, #0x80
+  jnz cirrus_set_video_mode_extended_1
+  push ax
+  mov ax, #0xffff ; set to 0xff to keep win 2K happy
+  call cirrus_clear_vram
+  pop ax
+cirrus_set_video_mode_extended_1:
+  and al, #0x7f
+
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov si, [cirrus_vesa_sel0000_data]
+#else
+  xor si, si
+#endif
+  mov ds, si
+  mov [PM_BIOSMEM_CURRENT_MODE], al
+  pop ds
+
+  mov al, #0x20
+
+  pop si
+  jmp cirrus_return
+
+cirrus_vesa_pmbios_init:
+  retf
+cirrus_vesa_pmbios_entry:
+  pushf
+  push bp
+  cmp ah, #0x4F
+  jnz cirrus_vesa_pmbios_unimplemented
+  cmp al, #0x0F
+  ja cirrus_vesa_pmbios_unimplemented
+  push bx
+  xor bx, bx
+  mov bl, al
+  shl bx, 1
+ db 0x2e ;; cs:
+  mov bp, cirrus_vesa_handlers[bx]
+  pop bx
+  push #cirrus_vesa_pmbios_return
+  push bp
+  ret
+cirrus_vesa_pmbios_unimplemented:
+  mov ax, #0x014F
+cirrus_vesa_pmbios_return:
+  pop bp
+  popf
+  retf
+
+; in si:mode table
+cirrus_switch_mode:
+  push ds
+  push bx
+  push dx
+  push cs
+  pop ds
+
+  mov bx, [si+10] ;; seq
+  mov dx, #0x3c4
+  mov ax, #0x1206
+  out dx, ax ;; Unlock cirrus special
+  call cirrus_switch_mode_setregs
+
+  mov bx, [si+12] ;; graph
+  mov dx, #0x3ce
+  call cirrus_switch_mode_setregs
+
+  mov bx, [si+14] ;; crtc
+  call cirrus_get_crtc
+  call cirrus_switch_mode_setregs
+
+  mov dx, #0x3c6
+  mov al, #0x00
+  out dx, al
+  in al, dx
+  in al, dx
+  in al, dx
+  in al, dx
+  mov al, [si+8]  ;; hidden dac
+  out dx, al
+  mov al, #0xff
+  out dx, al
+
+  mov al, #0x00
+  mov bl, [si+17]  ;; memory model
+  or  bl, bl
+  jz is_text_mode
+  mov al, #0x01
+  cmp bl, #0x03
+  jnz is_text_mode
+  or al, #0x40
+is_text_mode:
+  mov bl, #0x10
+  call biosfn_get_single_palette_reg
+  and bh, #0xfe
+  or bh, al
+  call biosfn_set_single_palette_reg
+
+  pop dx
+  pop bx
+  pop ds
+  ret
+
+cirrus_enable_16k_granularity:
+  push ax
+  push dx
+  mov dx, #0x3ce
+  mov al, #0x0b
+  out dx, al
+  inc dx
+  in al, dx
+  or al, #0x20 ;; enable 16k
+  out dx, al
+  pop dx
+  pop ax
+  ret
+
+cirrus_switch_mode_setregs:
+csms_1:
+  mov ax, [bx]
+  cmp ax, #0xffff
+  jz csms_2
+  out dx, ax
+  add bx, #0x2
+  jmp csms_1
+csms_2:
+  ret
+
+cirrus_extbios_80h:
+  push dx
+  call cirrus_get_crtc
+  mov al, #0x27
+  out dx, al
+  inc dx
+  in al, dx
+  mov bx, #_cirrus_id_table
+c80h_1:
+ db 0x2e ;; cs:
+  mov ah, [bx]
+  cmp ah, al
+  jz c80h_2
+  cmp ah, #0xff
+  jz c80h_2
+  inc bx
+  inc bx
+  jmp c80h_1
+c80h_2:
+ db 0x2e ;; cs:
+  mov al, 0x1[bx]
+  pop dx
+  mov ah, #0x00
+  xor bx, bx
+  ret
+
+cirrus_extbios_81h:
+  mov ax, #0x100 ;; XXX
+  ret
+cirrus_extbios_82h:
+  push dx
+  call cirrus_get_crtc
+  xor ax, ax
+  mov al, #0x27
+  out dx, al
+  inc dx
+  in al, dx
+  and al, #0x03
+  mov ah, #0xAF
+  pop dx
+  ret
+
+cirrus_extbios_85h:
+  push cx
+  push dx
+  mov dx, #0x3C4
+  mov al, #0x0f ;; get DRAM band width
+  out dx, al
+  inc dx
+  in al, dx
+  ;; al = 4 << bandwidth
+  mov cl, al
+  shr cl, #0x03
+  and cl, #0x03
+  cmp cl, #0x03
+  je c85h2
+  mov al, #0x04
+  shl al, cl
+  jmp c85h3
+c85h2:
+;; 4MB or 2MB
+  and al, #0x80
+  mov al, #0x20 ;; 2 MB
+  je c85h3
+  mov al, #0x40 ;; 4 MB
+c85h3:
+  pop dx
+  pop cx
+  ret
+
+cirrus_extbios_9Ah:
+  mov ax, #0x4060
+  mov cx, #0x1132
+  ret
+
+cirrus_extbios_A0h:
+  call cirrus_get_modeentry
+  mov ah, #0x01
+  sbb ah, #0x00
+  mov bx, cirrus_extbios_A0h_callback
+  mov si, #0xffff
+  mov di, bx
+  mov ds, bx
+  mov es, bx
+  ret
+
+cirrus_extbios_A0h_callback:
+  ;; fatal: not implemented yet
+  cli
+  hlt
+  retf
+
+cirrus_extbios_A1h:
+  mov bx, #0x0E00 ;; IBM 8512/8513, color
+  ret
+
+cirrus_extbios_A2h:
+  mov al, #0x07   ;; HSync 31.5 - 64.0 kHz
+  ret
+
+cirrus_extbios_AEh:
+  mov al, #0x01   ;; High Refresh 75Hz
+  ret
+
+cirrus_extbios_unimplemented:
+  ret
+
+cirrus_vesa_00h:
+  push ds
+  push si
+  mov bp, di
+  push es
+  pop ds
+  cld
+  mov ax, [di]
+  cmp ax, #0x4256 ;; VB
+  jnz cv00_1
+  mov ax, [di+2]
+  cmp ax, #0x3245 ;; E2
+  jnz cv00_1
+  ;; VBE2
+  lea di, 0x14[bp]
+  mov ax, #0x0100 ;; soft ver.
+  stosw
+  mov ax, # cirrus_vesa_vendorname
+  stosw
+  mov ax, cs
+  stosw
+  mov ax, # cirrus_vesa_productname
+  stosw
+  mov ax, cs
+  stosw
+  mov ax, # cirrus_vesa_productrevision
+  stosw
+  mov ax, cs
+  stosw
+cv00_1:
+  mov di, bp
+  mov ax, #0x4556 ;; VE
+  stosw
+  mov ax, #0x4153 ;; SA
+  stosw
+  mov ax, #0x0200 ;; v2.00
+  stosw
+  mov ax, # cirrus_vesa_oemname
+  stosw
+  mov ax, cs
+  stosw
+  xor ax, ax ;; caps
+  stosw
+  stosw
+  lea ax, 0x40[bp]
+  stosw
+  mov ax, es
+  stosw
+  call cirrus_extbios_85h ;; vram in 64k
+  mov ah, #0x00
+  stosw
+
+  push cs
+  pop ds
+  lea di, 0x40[bp]
+  mov si, #_cirrus_vesa_modelist
+cv00_2:
+  lodsw
+  stosw
+  add si, #2
+  cmp ax, #0xffff
+  jnz cv00_2
+
+  mov ax, #0x004F
+  mov di, bp
+  pop si
+  pop ds
+  ret
+
+cirrus_vesa_01h:
+  mov ax, cx
+  and ax, #0x3fff
+  call cirrus_vesamode_to_mode
+  cmp ax, #0xffff
+  jnz cirrus_vesa_01h_1
+  jmp cirrus_vesa_unimplemented
+cirrus_vesa_01h_1:
+  push ds
+  push si
+  push cx
+  push dx
+  push bx
+  mov bp, di
+  cld
+  push cs
+  pop ds
+  call cirrus_get_modeentry_nomask
+
+  push di
+  xor ax, ax
+  mov cx, #0x80
+  rep
+    stosw ;; clear buffer
+  pop di
+
+  mov ax, #0x003b ;; mode
+  stosw
+  mov ax, #0x0007 ;; attr
+  stosw
+  mov ax, #0x0010 ;; granularity =16K
+  stosw
+  mov ax, #0x0040 ;; size =64K
+  stosw
+  mov ax, #0xA000 ;; segment A
+  stosw
+  xor ax, ax ;; no segment B
+  stosw
+  mov ax, #cirrus_vesa_05h_farentry
+  stosw
+  mov ax, cs
+  stosw
+  call cirrus_get_line_offset_entry
+  stosw ;; bytes per scan line
+  mov ax, [si+2] ;; width
+  stosw
+  mov ax, [si+4] ;; height
+  stosw
+  mov ax, #0x08
+  stosb
+  mov ax, #0x10
+  stosb
+  mov al, #1 ;; count of planes
+  stosb
+  mov al, [si+6] ;; bpp
+  stosb
+  mov al, #0x1 ;; XXX number of banks
+  stosb
+  mov al, [si+17]
+  stosb ;; memory model
+  mov al, #0x0   ;; XXX size of bank in K
+  stosb
+  call cirrus_get_line_offset_entry
+  mov bx, [si+4]
+  mul bx ;; dx:ax=vramdisp
+  or ax, ax
+  jz cirrus_vesa_01h_3
+  inc dx
+cirrus_vesa_01h_3:
+  call cirrus_extbios_85h ;; al=vram in 64k
+  mov ah, #0x00
+  mov cx, dx
+  xor dx, dx
+  div cx
+  dec ax
+  stosb  ;; number of image pages = vramtotal/vramdisp-1
+  mov al, #0x00
+  stosb
+
+  ;; v1.2+ stuffs
+  push si
+  add si, #18
+  movsw
+  movsw
+  movsw
+  movsw
+  pop si
+
+  mov ah, [si+16]
+  mov al, #0x0
+  sub ah, #9
+  rcl al, #1 ; bit 0=palette flag
+  stosb ;; direct screen mode info
+
+  ;; v2.0+ stuffs
+  ;; 32-bit LFB address
+  xor ax, ax
+  stosw
+  call cirrus_get_lfb_addr
+  stosw
+  or ax, ax
+  jz cirrus_vesa_01h_4
+  push di
+  mov di, bp
+ db 0x26 ;; es:
+  mov ax, [di]
+  or ax, #0x0080 ;; mode bit 7:LFB
+  stosw
+  pop di
+cirrus_vesa_01h_4:
+
+  xor ax, ax
+  stosw ; reserved
+  stosw ; reserved
+  stosw ; reserved
+
+  mov ax, #0x004F
+  mov di, bp
+  pop bx
+  pop dx
+  pop cx
+  pop si
+  pop ds
+
+  test cx, #0x4000 ;; LFB flag
+  jz cirrus_vesa_01h_5
+  push cx
+ db 0x26 ;; es:
+  mov cx, [di]
+  cmp cx, #0x0080 ;; is LFB supported?
+  jnz cirrus_vesa_01h_6
+  mov ax, #0x014F ;; error - no LFB
+cirrus_vesa_01h_6:
+  pop cx
+cirrus_vesa_01h_5:
+  ret
+
+cirrus_vesa_02h:
+  ;; XXX support CRTC registers
+  test bx, #0x3e00
+  jnz cirrus_vesa_02h_2 ;; unknown flags
+  mov ax, bx
+  and ax, #0x1ff ;; bit 8-0 mode
+  cmp ax, #0x100 ;; legacy VGA mode
+  jb cirrus_vesa_02h_legacy
+  call cirrus_vesamode_to_mode
+  cmp ax, #0xffff
+  jnz cirrus_vesa_02h_1
+cirrus_vesa_02h_2:
+  jmp cirrus_vesa_unimplemented
+cirrus_vesa_02h_legacy:
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  cmp byte ptr [cirrus_vesa_is_protected_mode], #0
+  jnz cirrus_vesa_02h_2
+#endif // CIRRUS_VESA3_PMINFO
+  int #0x10
+  mov ax, #0x004F
+  ret
+cirrus_vesa_02h_1:
+  push si
+  push ax
+  call cirrus_get_modeentry_nomask
+  call cirrus_switch_mode
+  test bx, #0x4000 ;; LFB
+  jnz cirrus_vesa_02h_3
+  call cirrus_enable_16k_granularity
+cirrus_vesa_02h_3:
+  test bx, #0x8000 ;; no clear
+  jnz cirrus_vesa_02h_4
+  push ax
+  xor ax,ax
+  call cirrus_clear_vram
+  pop ax
+cirrus_vesa_02h_4:
+  pop ax
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov si, [cirrus_vesa_sel0000_data]
+#else
+  xor si, si
+#endif
+  mov ds, si
+  mov [PM_BIOSMEM_CURRENT_MODE], al
+  mov [PM_BIOSMEM_VBE_MODE], bx
+  pop ds
+  pop si
+  mov ax, #0x004F
+  ret
+
+cirrus_vesa_03h:
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov ax, [cirrus_vesa_sel0000_data]
+#else
+  xor ax, ax
+#endif
+  mov  ds, ax
+  mov  bx, # PM_BIOSMEM_VBE_MODE
+  mov  ax, [bx]
+  mov  bx, ax
+  test bx, bx
+  jnz   cirrus_vesa_03h_1
+  mov  bx, # PM_BIOSMEM_CURRENT_MODE
+  mov  al, [bx]
+  mov  bl, al
+  xor  bh, bh
+cirrus_vesa_03h_1:
+  mov  ax, #0x004f
+  pop  ds
+  ret
+
+cirrus_vesa_05h_farentry:
+  call cirrus_vesa_05h
+  retf
+
+cirrus_vesa_05h:
+  cmp bl, #0x01
+  ja cirrus_vesa_05h_1
+  cmp bh, #0x00
+  jz cirrus_vesa_05h_setmempage
+  cmp bh, #0x01
+  jz cirrus_vesa_05h_getmempage
+cirrus_vesa_05h_1:
+  jmp cirrus_vesa_unimplemented
+cirrus_vesa_05h_setmempage:
+  or dh, dh ; address must be < 0x100
+  jnz cirrus_vesa_05h_1
+  push dx
+  mov al, bl ;; bl=bank number
+  add al, #0x09
+  mov ah, dl ;; dx=window address in granularity
+  mov dx, #0x3ce
+  out dx, ax
+  pop dx
+  mov ax, #0x004F
+  ret
+cirrus_vesa_05h_getmempage:
+  mov al, bl ;; bl=bank number
+  add al, #0x09
+  mov dx, #0x3ce
+  out dx, al
+  inc dx
+  in al, dx
+  xor dx, dx
+  mov dl, al ;; dx=window address in granularity
+  mov ax, #0x004F
+  ret
+
+cirrus_vesa_06h:
+  mov  ax, cx
+  cmp  bl, #0x01
+  je   cirrus_vesa_06h_3
+  cmp  bl, #0x02
+  je   cirrus_vesa_06h_2
+  jb   cirrus_vesa_06h_1
+  mov  ax, #0x0100
+  ret
+cirrus_vesa_06h_1:
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  mov  ax, cx
+  mul  bx
+cirrus_vesa_06h_2:
+  call cirrus_set_line_offset
+cirrus_vesa_06h_3:
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  xor  dx, dx
+  call cirrus_get_line_offset
+  push ax
+  div  bx
+  mov  cx, ax
+  pop  bx
+  call cirrus_extbios_85h ;; al=vram in 64k
+  xor  dx, dx
+  mov  dl, al
+  xor  ax, ax
+  div  bx
+  mov  dx, ax
+  mov  ax, #0x004f
+  ret
+
+cirrus_vesa_07h:
+  cmp  bl, #0x80
+  je   cirrus_vesa_07h_1
+  cmp  bl, #0x01
+  je   cirrus_vesa_07h_2
+  jb   cirrus_vesa_07h_1
+  mov  ax, #0x0100
+  ret
+cirrus_vesa_07h_1:
+  push dx
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  mov  ax, cx
+  mul  bx
+  pop  bx
+  push ax
+  call cirrus_get_line_offset
+  mul  bx
+  pop  bx
+  add  ax, bx
+  jnc  cirrus_vesa_07h_3
+  inc  dx
+cirrus_vesa_07h_3:
+  push dx
+  and  dx, #0x0003
+  mov  bx, #0x04
+  div  bx
+  pop  dx
+  shr  dx, #2
+  call cirrus_set_start_addr
+  mov  ax, #0x004f
+  ret
+cirrus_vesa_07h_2:
+  call cirrus_get_start_addr
+  shl  dx, #2
+  push dx
+  mov  bx, #0x04
+  mul  bx
+  pop  bx
+  or   dx, bx
+  push ax
+  call cirrus_get_line_offset
+  mov  bx, ax
+  pop  ax
+  div  bx
+  push ax
+  push dx
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  pop  ax
+  xor  dx, dx
+  div  bx
+  mov  cx, ax
+  pop  dx
+  mov  ax, #0x004f
+  ret
+
+cirrus_vesa_10h:
+  cmp bl, #0x00
+  jne cirrus_vesa_10h_01
+  mov bx, #0x0f30
+  mov ax, #0x004f
+  ret
+cirrus_vesa_10h_01:
+  cmp bl, #0x01
+  jne cirrus_vesa_10h_02
+  push dx
+  push ds
+  mov dx, #0x40
+  mov ds, dx
+  mov [0xb9], bh
+  pop ds
+  pop dx
+  mov ax, #0x004f
+  ret
+cirrus_vesa_10h_02:
+  cmp bl, #0x02
+  jne cirrus_vesa_unimplemented
+  push dx
+  push ds
+  mov dx, #0x40
+  mov ds, dx
+  mov bh, [0xb9]
+  pop ds
+  pop dx
+  mov ax, #0x004f
+  ret
+
+cirrus_vesa_unimplemented:
+  mov ax, #0x014F ;; not implemented
+  ret
+
+
+;; in ax:vesamode, out ax:cirrusmode
+cirrus_vesamode_to_mode:
+  push ds
+  push cx
+  push si
+  push cs
+  pop ds
+  mov cx, #0xffff
+  mov si, #_cirrus_vesa_modelist
+cvtm_1:
+  cmp [si],ax
+  jz cvtm_2
+  cmp [si],cx
+  jz cvtm_2
+  add si, #4
+  jmp cvtm_1
+cvtm_2:
+  mov ax,[si+2]
+  pop si
+  pop cx
+  pop ds
+  ret
+
+  ; cirrus_get_crtc
+  ;; NOTE - may be called in protected mode
+cirrus_get_crtc:
+  push ds
+  push ax
+  mov  dx, #0x3cc
+  in   al, dx
+  and  al, #0x01
+  shl  al, #5
+  mov  dx, #0x3b4
+  add  dl, al
+  pop  ax
+  pop  ds
+  ret
+
+;; in - al:mode, out - cflag:result, si:table, ax:destroyed
+cirrus_get_modeentry:
+  and al, #0x7f
+cirrus_get_modeentry_nomask:
+  mov si, #_cirrus_modes
+cgm_1:
+ db 0x2e ;; cs:
+  mov ah, [si]
+  cmp al, ah
+  jz cgm_2
+  cmp ah, #0xff
+  jz cgm_4
+  add si, # CIRRUS_MODE_SIZE
+  jmp cgm_1
+cgm_4:
+  xor si, si
+  stc ;; video mode is not supported
+  jmp cgm_3
+cgm_2:
+  clc ;; video mode is supported
+cgm_3:
+  ret
+
+  ; get LFB address
+  ; out - ax:LFB address (high 16 bit)
+  ;; NOTE - may be called in protected mode
+cirrus_get_lfb_addr:
+  push cx
+  push dx
+  push eax
+    xor cx, cx
+    mov dl, #0x00
+    call cirrus_pci_read
+    cmp ax, #0xffff
+    jz cirrus_get_lfb_addr_5
+ cirrus_get_lfb_addr_3:
+    mov dl, #0x00
+    call cirrus_pci_read
+    cmp ax, #0x1013 ;; cirrus
+    jz cirrus_get_lfb_addr_4
+    add cx, #0x8
+    cmp cx, #0x200 ;; search bus #0 and #1
+    jb cirrus_get_lfb_addr_3
+ cirrus_get_lfb_addr_5:
+    xor dx, dx ;; no LFB
+    jmp cirrus_get_lfb_addr_6
+ cirrus_get_lfb_addr_4:
+    mov dl, #0x10 ;; I/O space #0
+    call cirrus_pci_read
+    test ax, #0xfff1
+    jnz cirrus_get_lfb_addr_5
+    shr eax, #16
+    mov dx, ax ;; LFB address
+ cirrus_get_lfb_addr_6:
+  pop eax
+  mov ax, dx
+  pop dx
+  pop cx
+  ret
+
+cirrus_pci_read:
+  mov eax, #0x00800000
+  mov ax, cx
+  shl eax, #8
+  mov al, dl
+  mov dx, #0xcf8
+  out dx, eax
+  add dl, #4
+  in  eax, dx
+  ret
+
+;; out - al:bytes per pixel
+cirrus_get_bpp_bytes:
+  push dx
+  mov  dx, #0x03c4
+  mov  al, #0x07
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0x0e
+  cmp  al, #0x06
+  jne  cirrus_get_bpp_bytes_1
+  and  al, #0x02
+cirrus_get_bpp_bytes_1:
+  shr  al, #1
+  cmp  al, #0x04
+  je  cirrus_get_bpp_bytes_2
+  inc  al
+cirrus_get_bpp_bytes_2:
+  pop  dx
+  ret
+
+;; in - ax: new line offset
+cirrus_set_line_offset:
+  shr  ax, #3
+  push ax
+  call cirrus_get_crtc
+  mov  al, #0x13
+  out  dx, al
+  inc  dx
+  pop  ax
+  out  dx, al
+  dec  dx
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  shl  ah, #4
+  in   al, dx
+  and  al, #ef
+  or   al, ah
+  out  dx, al
+  ret
+
+;; out - ax: active line offset
+cirrus_get_line_offset:
+  push dx
+  push bx
+  call cirrus_get_crtc
+  mov  al, #0x13
+  out  dx, al
+  inc  dx
+  in   al, dx
+  mov  bl, al
+  dec  dx
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  in   al, dx
+  mov  ah, al
+  shr  ah, #4
+  and  ah, #0x01
+  mov  al, bl
+  shl  ax, #3
+  pop  bx
+  pop  dx
+  ret
+
+;; in - si: table
+;; out - ax: line offset for mode
+cirrus_get_line_offset_entry:
+  push bx
+  mov  bx, [si+14] ;; crtc table
+  push bx
+offset_loop1:
+  mov  ax, [bx]
+  cmp  al, #0x13
+  je   offset_found1
+  inc  bx
+  inc  bx
+  jnz  offset_loop1
+offset_found1:
+  xor  al, al
+  shr  ax, #5
+  pop  bx
+  push ax
+offset_loop2:
+  mov  ax, [bx]
+  cmp  al, #0x1b
+  je offset_found2
+  inc  bx
+  inc  bx
+  jnz offset_loop2
+offset_found2:
+  pop  bx
+  and  ax, #0x1000
+  shr  ax, #1
+  or   ax, bx
+  pop  bx
+  ret
+
+;; in - new address in DX:AX
+cirrus_set_start_addr:
+  push bx
+  push dx
+  push ax
+  call cirrus_get_crtc
+  mov  al, #0x0d
+  out  dx, al
+  inc  dx
+  pop  ax
+  out  dx, al
+  dec  dx
+  mov  al, #0x0c
+  out  dx, al
+  inc  dx
+  mov  al, ah
+  out  dx, al
+  dec  dx
+  mov  al, #0x1d
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0x7f
+  pop  bx
+  mov  ah, bl
+  shl  bl, #4
+  and  bl, #0x80
+  or   al, bl
+  out  dx, al
+  dec  dx
+  mov  bl, ah
+  and  ah, #0x01
+  shl  bl, #1
+  and  bl, #0x0c
+  or   ah, bl
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0xf2
+  or   al, ah
+  out  dx, al
+  pop  bx
+  ret
+
+;; out - current address in DX:AX
+cirrus_get_start_addr:
+  push bx
+  call cirrus_get_crtc
+  mov  al, #0x0c
+  out  dx, al
+  inc  dx
+  in   al, dx
+  mov  ah, al
+  dec  dx
+  mov  al, #0x0d
+  out  dx, al
+  inc  dx
+  in   al, dx
+  push ax
+  dec  dx
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  in   al, dx
+  dec  dx
+  mov  bl, al
+  and  al, #0x01
+  and  bl, #0x0c
+  shr  bl, #1
+  or   bl, al
+  mov  al, #0x1d
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0x80
+  shr  al, #4
+  or   bl, al
+  mov  dl, bl
+  xor  dh, dh
+  pop  ax
+  pop  bx
+  ret
+
+cirrus_clear_vram:
+  pusha
+  push es
+  mov si, ax
+
+  call cirrus_enable_16k_granularity
+  call cirrus_extbios_85h
+  shl al, #2
+  mov bl, al
+  xor ah,ah
+cirrus_clear_vram_1:
+  mov al, #0x09
+  mov dx, #0x3ce
+  out dx, ax
+  push ax
+  mov cx, #0xa000
+  mov es, cx
+  xor di, di
+  mov ax, si
+  mov cx, #8192
+  cld
+  rep 
+      stosw
+  pop ax
+  inc ah
+  cmp ah, bl
+  jne cirrus_clear_vram_1
+
+  xor ah,ah
+  mov dx, #0x3ce
+  out dx, ax
+
+  pop es
+  popa
+  ret
+
+cirrus_extbios_handlers:
+  ;; 80h
+  dw cirrus_extbios_80h
+  dw cirrus_extbios_81h
+  dw cirrus_extbios_82h
+  dw cirrus_extbios_unimplemented
+  ;; 84h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_85h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 88h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 8Ch
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 90h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 94h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 98h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_9Ah
+  dw cirrus_extbios_unimplemented
+  ;; 9Ch
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; A0h
+  dw cirrus_extbios_A0h
+  dw cirrus_extbios_A1h
+  dw cirrus_extbios_A2h
+  dw cirrus_extbios_unimplemented
+  ;; A4h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; A8h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; ACh
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_AEh
+  dw cirrus_extbios_unimplemented
+
+cirrus_vesa_handlers:
+  ;; 00h
+  dw cirrus_vesa_00h
+  dw cirrus_vesa_01h
+  dw cirrus_vesa_02h
+  dw cirrus_vesa_03h
+  ;; 04h
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_05h
+  dw cirrus_vesa_06h
+  dw cirrus_vesa_07h
+  ;; 08h
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  ;; 0Ch
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  ;; 10h
+  dw cirrus_vesa_10h
+
+
+ASM_END
+
+#ifdef CIRRUS_VESA3_PMINFO
+ASM_START
+cirrus_vesa_pminfo:
+  /* + 0 */
+  .byte 0x50,0x4d,0x49,0x44 ;; signature[4]
+  /* + 4 */
+  dw cirrus_vesa_pmbios_entry ;; entry_bios
+  dw cirrus_vesa_pmbios_init  ;; entry_init
+  /* + 8 */
+cirrus_vesa_sel0000_data:
+  dw 0x0000 ;; sel_00000
+cirrus_vesa_selA000_data:
+  dw 0xA000 ;; sel_A0000
+  /* +12 */
+cirrus_vesa_selB000_data:
+  dw 0xB000 ;; sel_B0000
+cirrus_vesa_selB800_data:
+  dw 0xB800 ;; sel_B8000
+  /* +16 */
+cirrus_vesa_selC000_data:
+  dw 0xC000 ;; sel_C0000
+cirrus_vesa_is_protected_mode:
+  ;; protected mode flag and checksum
+  dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \
+     + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01
+ASM_END
+#endif // CIRRUS_VESA3_PMINFO
+
+
+#ifdef CIRRUS_DEBUG
+static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05))
+  printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
diff --git a/kvm/vgabios/dataseghack b/kvm/vgabios/dataseghack
new file mode 100755
index 0000000..02a2d4c
--- /dev/null
+++ b/kvm/vgabios/dataseghack
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+awk \
+  'BEGIN { }\
+  /^\.text/,/DATA_SEG_DEFS_HERE/ { print }\
+  END { }'\
+  $1 > temp.awk.1
+
+awk \
+  'BEGIN { i = 0; last = "hello" }\
+  /BLOCK_STRINGS_BEGIN/,/^\.bss/ { if ( i > 1 ) { print last } last = $0; i = i + 1 }\
+  END { }'\
+  $1 > temp.awk.2
+
+awk \
+  'BEGIN { }\
+  /DATA_SEG_DEFS_HERE/,/BLOCK_STRINGS_BEGIN/ { print }\
+  END { }'\
+  $1 > temp.awk.3
+
+cp $1 $1.orig
+cat temp.awk.1 temp.awk.2 temp.awk.3 | sed -e 's/^\.data//' -e 's/^\.bss//' -e 's/^\.text//' > $1
+/bin/rm -f temp.awk.1 temp.awk.2 temp.awk.3 $1.orig
diff --git a/kvm/vgabios/tests/lfbprof/Makefile b/kvm/vgabios/tests/lfbprof/Makefile
new file mode 100644
index 0000000..7c42e38
--- /dev/null
+++ b/kvm/vgabios/tests/lfbprof/Makefile
@@ -0,0 +1,5 @@
+# Very simple makefile for LFBPROF.C using Watcom C++ 10.0a with DOS4GW
+
+lfbprof.exe: lfbprof.c lfbprof.h
+    wcl386 -zq -s -d2 lfbprof.c
+
diff --git a/kvm/vgabios/tests/lfbprof/lfbprof.c b/kvm/vgabios/tests/lfbprof/lfbprof.c
new file mode 100644
index 0000000..df37452
--- /dev/null
+++ b/kvm/vgabios/tests/lfbprof/lfbprof.c
@@ -0,0 +1,594 @@
+/****************************************************************************
+*
+*                   VBE 2.0 Linear Framebuffer Profiler
+*                    By Kendall Bennett and Brian Hook
+*
+* Filename:     LFBPROF.C
+* Language:     ANSI C
+* Environment:  Watcom C/C++ 10.0a with DOS4GW
+*
+* Description:  Simple program to profile the speed of screen clearing
+*               and full screen BitBlt operations using a VESA VBE 2.0
+*               linear framebuffer from 32 bit protected mode.
+*
+*               For simplicity, this program only supports 256 color
+*               SuperVGA video modes that support a linear framebuffer.
+*
+*
+* 2002/02/18: Jeroen Janssen <japj at xs4all dot nl>
+*               - fixed unsigned short for mode list (-1 != 0xffff otherwise)
+*               - fixed LfbMapRealPointer macro mask problem (some modes were skipped)
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <dos.h>
+#include "lfbprof.h"
+
+/*---------------------------- Global Variables ---------------------------*/
+
+int     VESABuf_len = 1024;         /* Length of VESABuf                */
+int     VESABuf_sel = 0;            /* Selector for VESABuf             */
+int     VESABuf_rseg;               /* Real mode segment of VESABuf     */
+unsigned short   modeList[50];      /* List of available VBE modes      */
+float   clearsPerSec;               /* Number of clears per second      */
+float   clearsMbPerSec;             /* Memory transfer for clears       */
+float   bitBltsPerSec;              /* Number of BitBlt's per second    */
+float   bitBltsMbPerSec;            /* Memory transfer for bitblt's     */
+int     xres,yres;                  /* Video mode resolution            */
+int     bytesperline;               /* Bytes per scanline for mode      */
+long    imageSize;                  /* Length of the video image        */
+char    *LFBPtr;                	/* Pointer to linear framebuffer    */
+
+/*------------------------- DPMI interface routines -----------------------*/
+
+void DPMI_allocRealSeg(int size,int *sel,int *r_seg)
+/****************************************************************************
+*
+* Function:     DPMI_allocRealSeg
+* Parameters:   size    - Size of memory block to allocate
+*               sel     - Place to return protected mode selector
+*               r_seg   - Place to return real mode segment
+*
+* Description:  Allocates a block of real mode memory using DPMI services.
+*               This routine returns both a protected mode selector and
+*               real mode segment for accessing the memory block.
+*
+****************************************************************************/
+{
+    union REGS      r;
+
+    r.w.ax = 0x100;                 /* DPMI allocate DOS memory         */
+    r.w.bx = (size + 0xF) >> 4;     /* number of paragraphs             */
+    int386(0x31, &r, &r);
+    if (r.w.cflag)
+        FatalError("DPMI_allocRealSeg failed!");
+    *sel = r.w.dx;                  /* Protected mode selector          */
+    *r_seg = r.w.ax;                /* Real mode segment                */
+}
+
+void DPMI_freeRealSeg(unsigned sel)
+/****************************************************************************
+*
+* Function:     DPMI_allocRealSeg
+* Parameters:   sel - Protected mode selector of block to free
+*
+* Description:  Frees a block of real mode memory.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 0x101;                 /* DPMI free DOS memory             */
+    r.w.dx = sel;                   /* DX := selector from 0x100        */
+    int386(0x31, &r, &r);
+}
+
+typedef struct {
+    long    edi;
+    long    esi;
+    long    ebp;
+    long    reserved;
+    long    ebx;
+    long    edx;
+    long    ecx;
+    long    eax;
+    short   flags;
+    short   es,ds,fs,gs,ip,cs,sp,ss;
+    } _RMREGS;
+
+#define IN(reg)     rmregs.e##reg = in->x.reg
+#define OUT(reg)    out->x.reg = rmregs.e##reg
+
+int DPMI_int86(int intno, RMREGS *in, RMREGS *out)
+/****************************************************************************
+*
+* Function:     DPMI_int86
+* Parameters:   intno   - Interrupt number to issue
+*               in      - Pointer to structure for input registers
+*               out     - Pointer to structure for output registers
+* Returns:      Value returned by interrupt in AX
+*
+* Description:  Issues a real mode interrupt using DPMI services.
+*
+****************************************************************************/
+{
+    _RMREGS         rmregs;
+    union REGS      r;
+    struct SREGS    sr;
+
+    memset(&rmregs, 0, sizeof(rmregs));
+    IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di);
+
+    segread(&sr);
+    r.w.ax = 0x300;                 /* DPMI issue real interrupt        */
+    r.h.bl = intno;
+    r.h.bh = 0;
+    r.w.cx = 0;
+    sr.es = sr.ds;
+    r.x.edi = (unsigned)&rmregs;
+    int386x(0x31, &r, &r, &sr);     /* Issue the interrupt              */
+
+    OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di);
+    out->x.cflag = rmregs.flags & 0x1;
+    return out->x.ax;
+}
+
+int DPMI_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs)
+/****************************************************************************
+*
+* Function:     DPMI_int86
+* Parameters:   intno   - Interrupt number to issue
+*               in      - Pointer to structure for input registers
+*               out     - Pointer to structure for output registers
+*               sregs   - Values to load into segment registers
+* Returns:      Value returned by interrupt in AX
+*
+* Description:  Issues a real mode interrupt using DPMI services.
+*
+****************************************************************************/
+{
+    _RMREGS         rmregs;
+    union REGS      r;
+    struct SREGS    sr;
+
+    memset(&rmregs, 0, sizeof(rmregs));
+    IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di);
+    rmregs.es = sregs->es;
+    rmregs.ds = sregs->ds;
+
+    segread(&sr);
+    r.w.ax = 0x300;                 /* DPMI issue real interrupt        */
+    r.h.bl = intno;
+    r.h.bh = 0;
+    r.w.cx = 0;
+    sr.es = sr.ds;
+    r.x.edi = (unsigned)&rmregs;
+    int386x(0x31, &r, &r, &sr);     /* Issue the interrupt */
+
+    OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di);
+    sregs->es = rmregs.es;
+    sregs->cs = rmregs.cs;
+    sregs->ss = rmregs.ss;
+    sregs->ds = rmregs.ds;
+    out->x.cflag = rmregs.flags & 0x1;
+    return out->x.ax;
+}
+
+int DPMI_allocSelector(void)
+/****************************************************************************
+*
+* Function:     DPMI_allocSelector
+* Returns:      Newly allocated protected mode selector
+*
+* Description:  Allocates a new protected mode selector using DPMI
+*               services. This selector has a base address and limit of 0.
+*
+****************************************************************************/
+{
+    int         sel;
+    union REGS  r;
+
+    r.w.ax = 0;                     /* DPMI allocate selector           */
+    r.w.cx = 1;                     /* Allocate a single selector       */
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_allocSelector() failed!");
+    sel = r.w.ax;
+
+    r.w.ax = 9;                     /* DPMI set access rights           */
+    r.w.bx = sel;
+    r.w.cx = 0x8092;                /* 32 bit page granular             */
+    int386(0x31, &r, &r);
+    return sel;
+}
+
+long DPMI_mapPhysicalToLinear(long physAddr,long limit)
+/****************************************************************************
+*
+* Function:     DPMI_mapPhysicalToLinear
+* Parameters:   physAddr    - Physical memory address to map
+*               limit       - Length-1 of physical memory region to map
+* Returns:      Starting linear address for mapped memory
+*
+* Description:  Maps a section of physical memory into the linear address
+*               space of a process using DPMI calls. Note that this linear
+*               address cannot be used directly, but must be used as the
+*               base address for a selector.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 0x800;                 /* DPMI map physical to linear      */
+    r.w.bx = physAddr >> 16;
+    r.w.cx = physAddr & 0xFFFF;
+    r.w.si = limit >> 16;
+    r.w.di = limit & 0xFFFF;
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_mapPhysicalToLinear() failed!");
+    return ((long)r.w.bx << 16) + r.w.cx;
+}
+
+void DPMI_setSelectorBase(int sel,long linAddr)
+/****************************************************************************
+*
+* Function:     DPMI_setSelectorBase
+* Parameters:   sel     - Selector to change base address for
+*               linAddr - Linear address used for new base address
+*
+* Description:  Sets the base address for the specified selector.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 7;                     /* DPMI set selector base address   */
+    r.w.bx = sel;
+    r.w.cx = linAddr >> 16;
+    r.w.dx = linAddr & 0xFFFF;
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_setSelectorBase() failed!");
+}
+
+void DPMI_setSelectorLimit(int sel,long limit)
+/****************************************************************************
+*
+* Function:     DPMI_setSelectorLimit
+* Parameters:   sel     - Selector to change limit for
+*               limit   - Limit-1 for the selector
+*
+* Description:  Sets the memory limit for the specified selector.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 8;                     /* DPMI set selector limit          */
+    r.w.bx = sel;
+    r.w.cx = limit >> 16;
+    r.w.dx = limit & 0xFFFF;
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_setSelectorLimit() failed!");
+}
+
+/*-------------------------- VBE Interface routines -----------------------*/
+
+void FatalError(char *msg)
+{
+    fprintf(stderr,"%s\n", msg);
+    exit(1);
+}
+
+static void ExitVBEBuf(void)
+{
+    DPMI_freeRealSeg(VESABuf_sel);
+}
+
+void VBE_initRMBuf(void)
+/****************************************************************************
+*
+* Function:     VBE_initRMBuf
+* Description:  Initialises the VBE transfer buffer in real mode memory.
+*               This routine is called by the VESAVBE module every time
+*               it needs to use the transfer buffer, so we simply allocate
+*               it once and then return.
+*
+****************************************************************************/
+{
+    if (!VESABuf_sel) {
+        DPMI_allocRealSeg(VESABuf_len, &VESABuf_sel, &VESABuf_rseg);
+        atexit(ExitVBEBuf);
+        }
+}
+
+void VBE_callESDI(RMREGS *regs, void *buffer, int size)
+/****************************************************************************
+*
+* Function:     VBE_callESDI
+* Parameters:   regs    - Registers to load when calling VBE
+*               buffer  - Buffer to copy VBE info block to
+*               size    - Size of buffer to fill
+*
+* Description:  Calls the VESA VBE and passes in a buffer for the VBE to
+*               store information in, which is then copied into the users
+*               buffer space. This works in protected mode as the buffer
+*               passed to the VESA VBE is allocated in conventional
+*               memory, and is then copied into the users memory block.
+*
+****************************************************************************/
+{
+    RMSREGS sregs;
+
+    VBE_initRMBuf();
+    sregs.es = VESABuf_rseg;
+    regs->x.di = 0;
+    _fmemcpy(MK_FP(VESABuf_sel,0),buffer,size);
+    DPMI_int86x(0x10, regs, regs, &sregs);
+    _fmemcpy(buffer,MK_FP(VESABuf_sel,0),size);
+}
+
+int VBE_detect(void)
+/****************************************************************************
+*
+* Function:     VBE_detect
+* Parameters:   vgaInfo - Place to store the VGA information block
+* Returns:      VBE version number, or 0 if not detected.
+*
+* Description:  Detects if a VESA VBE is out there and functioning
+*               correctly. If we detect a VBE interface we return the
+*               VGAInfoBlock returned by the VBE and the VBE version number.
+*
+****************************************************************************/
+{
+    RMREGS      regs;
+    unsigned    short    *p1,*p2;
+    VBE_vgaInfo vgaInfo;
+
+    /* Put 'VBE2' into the signature area so that the VBE 2.0 BIOS knows
+     * that we have passed a 512 byte extended block to it, and wish
+     * the extended information to be filled in.
+     */
+    strncpy(vgaInfo.VESASignature,"VBE2",4);
+
+    /* Get the SuperVGA Information block */
+    regs.x.ax = 0x4F00;
+    VBE_callESDI(&regs, &vgaInfo, sizeof(VBE_vgaInfo));
+    if (regs.x.ax != 0x004F)
+        return 0;
+    if (strncmp(vgaInfo.VESASignature,"VESA",4) != 0)
+        return 0;
+
+    /* Now that we have detected a VBE interface, copy the list of available
+     * video modes into our local buffer. We *must* copy this mode list,
+     * since the VBE will build the mode list in the VBE_vgaInfo buffer
+     * that we have passed, so the next call to the VBE will trash the
+     * list of modes.
+     */
+    printf("videomodeptr %x\n",vgaInfo.VideoModePtr);
+    p1 = LfbMapRealPointer(vgaInfo.VideoModePtr);
+    p2 = modeList;
+    while (*p1 != -1)
+    {
+        printf("found mode %x\n",*p1);
+        *p2++ = *p1++;
+    }
+    *p2 = -1;
+    return vgaInfo.VESAVersion;
+}
+
+int VBE_getModeInfo(int mode,VBE_modeInfo *modeInfo)
+/****************************************************************************
+*
+* Function:     VBE_getModeInfo
+* Parameters:   mode        - VBE mode to get information for
+*               modeInfo    - Place to store VBE mode information
+* Returns:      1 on success, 0 if function failed.
+*
+* Description:  Obtains information about a specific video mode from the
+*               VBE. You should use this function to find the video mode
+*               you wish to set, as the new VBE 2.0 mode numbers may be
+*               completely arbitrary.
+*
+****************************************************************************/
+{
+    RMREGS  regs;
+
+    regs.x.ax = 0x4F01;             /* Get mode information         */
+    regs.x.cx = mode;
+    VBE_callESDI(&regs, modeInfo, sizeof(VBE_modeInfo));
+    if (regs.x.ax != 0x004F)
+        return 0;
+    if ((modeInfo->ModeAttributes & vbeMdAvailable) == 0)
+        return 0;
+    return 1;
+}
+
+void VBE_setVideoMode(int mode)
+/****************************************************************************
+*
+* Function:     VBE_setVideoMode
+* Parameters:   mode    - VBE mode number to initialise
+*
+****************************************************************************/
+{
+    RMREGS  regs;
+    regs.x.ax = 0x4F02;
+    regs.x.bx = mode;
+    DPMI_int86(0x10,&regs,&regs);
+}
+
+/*-------------------- Application specific routines ----------------------*/
+
+void *GetPtrToLFB(long physAddr)
+/****************************************************************************
+*
+* Function:     GetPtrToLFB
+* Parameters:   physAddr    - Physical memory address of linear framebuffer
+* Returns:      Far pointer to the linear framebuffer memory
+*
+****************************************************************************/
+{
+    int     sel;
+    long    linAddr,limit = (4096 * 1024) - 1;
+
+//	sel = DPMI_allocSelector();
+	linAddr = DPMI_mapPhysicalToLinear(physAddr,limit);
+//	DPMI_setSelectorBase(sel,linAddr);
+//	DPMI_setSelectorLimit(sel,limit);
+//	return MK_FP(sel,0);
+	return (void*)linAddr;
+}
+
+void AvailableModes(void)
+/****************************************************************************
+*
+* Function:     AvailableModes
+*
+* Description:  Display a list of available LFB mode resolutions.
+*
+****************************************************************************/
+{
+    unsigned short           *p;
+    VBE_modeInfo    modeInfo;
+
+    printf("Usage: LFBPROF <xres> <yres>\n\n");
+    printf("Available 256 color video modes:\n");
+    for (p = modeList; *p != -1; p++) {
+        if (VBE_getModeInfo(*p, &modeInfo)) {
+            /* Filter out only 8 bit linear framebuffer modes */
+            if ((modeInfo.ModeAttributes & vbeMdLinear) == 0)
+                continue;
+            if (modeInfo.MemoryModel != vbeMemPK
+                || modeInfo.BitsPerPixel != 8
+                || modeInfo.NumberOfPlanes != 1)
+                continue;
+            printf("    %4d x %4d %d bits per pixel\n",
+                modeInfo.XResolution, modeInfo.YResolution,
+                modeInfo.BitsPerPixel);
+            }
+        }
+    exit(1);
+}
+
+void InitGraphics(int x,int y)
+/****************************************************************************
+*
+* Function:     InitGraphics
+* Parameters:   x,y - Requested video mode resolution
+*
+* Description:  Initialise the specified video mode. We search through
+*               the list of available video modes for one that matches
+*               the resolution and color depth are are looking for.
+*
+****************************************************************************/
+{
+    unsigned short           *p;
+    VBE_modeInfo    modeInfo;
+    printf("InitGraphics\n");
+
+    for (p = modeList; *p != -1; p++) {
+        if (VBE_getModeInfo(*p, &modeInfo)) {
+            /* Filter out only 8 bit linear framebuffer modes */
+            if ((modeInfo.ModeAttributes & vbeMdLinear) == 0)
+                continue;
+            if (modeInfo.MemoryModel != vbeMemPK
+                || modeInfo.BitsPerPixel != 8
+                || modeInfo.NumberOfPlanes != 1)
+                continue;
+            if (modeInfo.XResolution != x || modeInfo.YResolution != y)
+                continue;
+            xres = x;
+            yres = y;
+            bytesperline = modeInfo.BytesPerScanLine;
+            imageSize = bytesperline * yres;
+            VBE_setVideoMode(*p | vbeUseLFB);
+            LFBPtr = GetPtrToLFB(modeInfo.PhysBasePtr);
+            return;
+            }
+        }
+    printf("Valid video mode not found\n");
+    exit(1);
+}
+
+void EndGraphics(void)
+/****************************************************************************
+*
+* Function:     EndGraphics
+*
+* Description:  Restores text mode.
+*
+****************************************************************************/
+{
+    RMREGS  regs;
+    printf("EndGraphics\n");
+    regs.x.ax = 0x3;
+    DPMI_int86(0x10, &regs, &regs);
+}
+
+void ProfileMode(void)
+/****************************************************************************
+*
+* Function:     ProfileMode
+*
+* Description:  Profiles framebuffer performance for simple screen clearing
+*               and for copying from system memory to video memory (BitBlt).
+*               This routine thrashes the CPU cache by cycling through
+*               enough system memory buffers to invalidate the entire
+*               CPU external cache before re-using the first memory buffer
+*               again.
+*
+****************************************************************************/
+{
+    int     i,numClears,numBlts,maxImages;
+    long    startTicks,endTicks;
+    void    *image[10],*dst;
+    printf("ProfileMode\n");
+
+    /* Profile screen clearing operation */
+    startTicks = LfbGetTicks();
+    numClears = 0;
+    while ((LfbGetTicks() - startTicks) < 182)
+		LfbMemset(LFBPtr,numClears++,imageSize);
+	endTicks = LfbGetTicks();
+	clearsPerSec = numClears / ((endTicks - startTicks) * 0.054925);
+	clearsMbPerSec = (clearsPerSec * imageSize) / 1048576.0;
+
+	/* Profile system memory to video memory copies */
+	maxImages = ((512 * 1024U) / imageSize) + 2;
+	for (i = 0; i < maxImages; i++) {
+		image[i] = malloc(imageSize);
+		if (image[i] == NULL)
+			FatalError("Not enough memory to profile BitBlt!");
+		memset(image[i],i+1,imageSize);
+		}
+	startTicks = LfbGetTicks();
+	numBlts = 0;
+	while ((LfbGetTicks() - startTicks) < 182)
+		LfbMemcpy(LFBPtr,image[numBlts++ % maxImages],imageSize);
+    endTicks = LfbGetTicks();
+    bitBltsPerSec = numBlts / ((endTicks - startTicks) * 0.054925);
+    bitBltsMbPerSec = (bitBltsPerSec * imageSize) / 1048576.0;
+}
+
+void main(int argc, char *argv[])
+{
+    if (VBE_detect() < 0x200)
+        FatalError("This program requires VBE 2.0; Please install UniVBE 5.1.");
+    if (argc != 3)
+        AvailableModes();       /* Display available modes              */
+
+    InitGraphics(atoi(argv[1]),atoi(argv[2]));  /* Start graphics       */
+    ProfileMode();              /* Profile the video mode               */
+    EndGraphics();              /* Restore text mode                    */
+
+    printf("Profiling results for %dx%d 8 bits per pixel.\n",xres,yres);
+    printf("%3.2f clears/s, %2.2f Mb/s\n", clearsPerSec, clearsMbPerSec);
+    printf("%3.2f bitBlt/s, %2.2f Mb/s\n", bitBltsPerSec, bitBltsMbPerSec);
+}
diff --git a/kvm/vgabios/tests/lfbprof/lfbprof.h b/kvm/vgabios/tests/lfbprof/lfbprof.h
new file mode 100644
index 0000000..bae0e09
--- /dev/null
+++ b/kvm/vgabios/tests/lfbprof/lfbprof.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+*
+*                   VBE 2.0 Linear Framebuffer Profiler
+*                    By Kendall Bennett and Brian Hook
+*
+* Filename:     LFBPROF.H
+* Language:     ANSI C
+* Environment:  Watcom C/C++ 10.0a with DOS4GW
+*
+* Description:  Header file for the LFBPROF.C progam.
+*
+****************************************************************************/
+
+#ifndef __LFBPROF_H
+#define __LFBPROF_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+/* SuperVGA information block */
+
+typedef struct {
+    char    VESASignature[4];       /* 'VESA' 4 byte signature          */
+    short   VESAVersion;            /* VBE version number               */
+    long    OemStringPtr;           /* Pointer to OEM string            */
+    long    Capabilities;           /* Capabilities of video card       */
+    long    VideoModePtr;           /* Pointer to supported modes       */
+    short   TotalMemory;            /* Number of 64kb memory blocks     */
+
+    /* VBE 2.0 extensions */
+
+    short   OemSoftwareRev;         /* OEM Software revision number     */
+    long    OemVendorNamePtr;       /* Pointer to Vendor Name string    */
+    long    OemProductNamePtr;      /* Pointer to Product Name string   */
+    long    OemProductRevPtr;       /* Pointer to Product Revision str  */
+    char    reserved[222];          /* Pad to 256 byte block size       */
+    char    OemDATA[256];           /* Scratch pad for OEM data         */
+    } VBE_vgaInfo;
+
+/* SuperVGA mode information block */
+
+typedef struct {
+    short   ModeAttributes;         /* Mode attributes                  */
+    char    WinAAttributes;         /* Window A attributes              */
+    char    WinBAttributes;         /* Window B attributes              */
+    short   WinGranularity;         /* Window granularity in k          */
+    short   WinSize;                /* Window size in k                 */
+    short   WinASegment;            /* Window A segment                 */
+    short   WinBSegment;            /* Window B segment                 */
+    long    WinFuncPtr;             /* Pointer to window function       */
+    short   BytesPerScanLine;       /* Bytes per scanline               */
+    short   XResolution;            /* Horizontal resolution            */
+    short   YResolution;            /* Vertical resolution              */
+    char    XCharSize;              /* Character cell width             */
+    char    YCharSize;              /* Character cell height            */
+    char    NumberOfPlanes;         /* Number of memory planes          */
+    char    BitsPerPixel;           /* Bits per pixel                   */
+    char    NumberOfBanks;          /* Number of CGA style banks        */
+    char    MemoryModel;            /* Memory model type                */
+    char    BankSize;               /* Size of CGA style banks          */
+    char    NumberOfImagePages;     /* Number of images pages           */
+    char    res1;                   /* Reserved                         */
+    char    RedMaskSize;            /* Size of direct color red mask    */
+    char    RedFieldPosition;       /* Bit posn of lsb of red mask      */
+    char    GreenMaskSize;          /* Size of direct color green mask  */
+    char    GreenFieldPosition;     /* Bit posn of lsb of green mask    */
+    char    BlueMaskSize;           /* Size of direct color blue mask   */
+    char    BlueFieldPosition;      /* Bit posn of lsb of blue mask     */
+    char    RsvdMaskSize;           /* Size of direct color res mask    */
+    char    RsvdFieldPosition;      /* Bit posn of lsb of res mask      */
+    char    DirectColorModeInfo;    /* Direct color mode attributes     */
+
+    /* VBE 2.0 extensions */
+
+    long    PhysBasePtr;            /* Physical address for linear buf  */
+    long    OffScreenMemOffset;     /* Pointer to start of offscreen mem*/
+    short   OffScreenMemSize;       /* Amount of offscreen mem in 1K's  */
+    char    res2[206];              /* Pad to 256 byte block size       */
+    } VBE_modeInfo;
+
+#define vbeMemPK        4           /* Packed Pixel memory model        */
+#define vbeUseLFB       0x4000      /* Enable linear framebuffer mode   */
+
+/* Flags for the mode attributes returned by VBE_getModeInfo. If
+ * vbeMdNonBanked is set to 1 and vbeMdLinear is also set to 1, then only
+ * the linear framebuffer mode is available.
+ */
+
+#define vbeMdAvailable  0x0001      /* Video mode is available          */
+#define vbeMdColorMode  0x0008      /* Mode is a color video mode       */
+#define vbeMdGraphMode  0x0010      /* Mode is a graphics mode          */
+#define vbeMdNonBanked  0x0040      /* Banked mode is not supported     */
+#define vbeMdLinear     0x0080      /* Linear mode supported            */
+
+/* Structures for issuing real mode interrupts with DPMI */
+
+struct _RMWORDREGS {
+    unsigned short ax, bx, cx, dx, si, di, cflag;
+    };
+
+struct _RMBYTEREGS {
+    unsigned char   al, ah, bl, bh, cl, ch, dl, dh;
+    };
+
+typedef union {
+    struct  _RMWORDREGS x;
+    struct  _RMBYTEREGS h;
+    } RMREGS;
+
+typedef struct {
+    unsigned short  es;
+    unsigned short  cs;
+    unsigned short  ss;
+    unsigned short  ds;
+    } RMSREGS;
+
+/* Inline assembler block fill/move routines */
+
+void LfbMemset(void *p,int c,int n);
+#pragma aux LfbMemset =             \
+	"shr    ecx,2"                  \
+	"xor    eax,eax"                \
+	"mov    al,bl"                  \
+	"shl    ebx,8"                  \
+	"or     ax,bx"                  \
+	"mov    ebx,eax"                \
+	"shl    ebx,16"                 \
+	"or     eax,ebx"                \
+	"rep    stosd"                  \
+	parm [edi] [ebx] [ecx];
+
+void LfbMemcpy(void *dst,void *src,int n);
+#pragma aux LfbMemcpy =             \
+	"shr    ecx,2"                  \
+	"rep    movsd"                  \
+	parm [edi] [esi] [ecx];
+
+/* Map a real mode pointer into address space */
+
+#define LfbMapRealPointer(p)    (void*)(((unsigned)((p)  & 0xFFFF0000) >> 12) + ((p) & 0xFFFF))
+
+/* Get the current timer tick count */
+
+#define LfbGetTicks()       *((long*)0x46C)
+
+#pragma pack()
+
+#endif  /* __LFBPROF_H */
diff --git a/kvm/vgabios/tests/testbios.c b/kvm/vgabios/tests/testbios.c
new file mode 100644
index 0000000..99da5a6
--- /dev/null
+++ b/kvm/vgabios/tests/testbios.c
@@ -0,0 +1,353 @@
+/* 

+   This is a little turbo C program that executes

+   several int10, and let you inspect the content

+   of the vgabios area

+

+   It is used to test the behavior of the vgabios

+*/

+

+#include <stdio.h>

+#include <dos.h>

+#include <conio.h>

+

+

+typedef unsigned char  Bit8u;

+typedef unsigned short Bit16u;

+

+typedef struct

+{Bit8u initial;

+ Bit8u current;

+ Bit16u nbcols;

+ Bit16u regen;

+ Bit16u start;

+ Bit16u curpos[8];

+ Bit8u curtyp;

+ Bit8u curpage;

+ Bit16u crtc;

+ Bit16u msr;

+ Bit16u cgapal;

+ Bit8u nbrows;

+ Bit16u cheight;

+ Bit8u ctl;

+ Bit8u switches;

+ Bit8u modeset;

+ Bit8u dcc;

+ Bit16u vsseg;

+ Bit16u vsoffset;

+} BIOSAREA;

+

+void int10ax0003(struct REGPACK *regs)

+{

+ regs->r_ax=0x0003;

+ intr(0x10,regs);

+}

+

+void int10ax02(struct REGPACK *regs)

+{

+ regs->r_ax=0x0200;

+ regs->r_bx=0x0000;

+ regs->r_dx=0x1710;

+ intr(0x10,regs);

+ printf("We are now at 24/17");

+}

+

+void int10ax03(struct REGPACK *regs)

+{

+ regs->r_ax=0x0300;

+ regs->r_bx=0x0000;

+ intr(0x10,regs);

+ printf("\nCursor is ax%04x cx%04x dx%04x\n",regs->r_ax,regs->r_cx,regs->r_dx);

+}

+

+void int10ax0501(struct REGPACK *regs)

+{

+ regs->r_ax=0x0501;

+ intr(0x10,regs);

+ regs->r_ax=0x0e61;

+ regs->r_bx=0x0000;

+ intr(0x10,regs);

+ printf("We are now on page 2");

+}

+

+void int10ax0602(struct REGPACK *regs)

+{

+ regs->r_ax=0x0602;

+ regs->r_bx=0x0700;

+ regs->r_cx=0x0101;

+ regs->r_dx=0x0a0a;

+ intr(0x10,regs);

+ printf("Scrolled 2 up");

+}

+

+void int10ax0702(struct REGPACK *regs)

+{

+ regs->r_ax=0x0702;

+ regs->r_bx=0x0700;

+ regs->r_cx=0x0101;

+ regs->r_dx=0x0a0a;

+ intr(0x10,regs);

+ printf("Scrolled 2 down");

+}

+

+void int10ax08(struct REGPACK *regs)

+{

+ regs->r_ax=0x0800;

+ regs->r_bx=0x0000;

+ intr(0x10,regs);

+}

+

+void int10ax09(struct REGPACK *regs)

+{

+ char attr;

+ regs->r_ax=0x0501;

+ intr(0x10,regs);

+ for(attr=0;attr<16;attr++)

+  {printf("%02x ",attr);

+   regs->r_ax=0x0961+attr;

+   regs->r_bx=0x0100+attr;

+   regs->r_cx=0x0016;

+   intr(0x10,regs);

+   printf("\n");

+  }

+}

+

+void int10ax0a(struct REGPACK *regs)

+{

+ regs->r_ax=0x0501;

+ intr(0x10,regs);

+ regs->r_ax=0x0a62;

+ regs->r_bx=0x0101;

+ regs->r_cx=0x0016;

+ intr(0x10,regs);

+}

+

+void int10ax0f(struct REGPACK *regs)

+{

+ regs->r_ax=0x0501;

+ intr(0x10,regs);

+ regs->r_ax=0x0f00;

+ intr(0x10,regs);

+}

+

+void int10ax1b(struct REGPACK *regs)

+{unsigned char table[64];

+ unsigned char far *ptable;

+ int  i;

+

+ regs->r_ax=0x0501;

+ intr(0x10,regs);

+ regs->r_ax=0x1b00;

+ regs->r_bx=0x0000;

+ ptable=&table;

+ regs->r_es=FP_SEG(ptable);

+ regs->r_di=FP_OFF(ptable);

+ printf("Read state info in %04x:%04x\n",regs->r_es,regs->r_di);

+ intr(0x10,regs);

+

+ for(i=0;i<64;i++)

+  {if(i%16==0)printf("\n%02x ",i);

+   printf("%02x ",table[i]);

+  }

+ printf("\n");

+}

+

+static unsigned char var[64];

+

+void int10ax13(struct REGPACK *regs)

+{unsigned char far *pvar;

+

+ pvar=&var;

+

+ regs->r_ax=0x1300;

+ regs->r_bx=0x000b;

+ regs->r_dx=0x1010;

+ regs->r_cx=0x0002;

+ regs->r_es=FP_SEG(pvar);

+ regs->r_bp=FP_OFF(pvar);

+ pokeb(regs->r_es,regs->r_bp,'t');

+ pokeb(regs->r_es,regs->r_bp+1,'b');

+ printf("Writing from %04x:%04x\n",regs->r_es,regs->r_bp);

+ intr(0x10,regs);

+ 

+}

+

+void switch_50(struct REGPACK *regs)

+{

+ regs->r_ax=0x1202;

+ regs->r_bx=0x3000;

+ intr(0x10,regs);

+ regs->r_ax=0x0003;

+ intr(0x10,regs);

+ regs->r_ax=0x1112;

+ regs->r_bx=0x0000;

+ intr(0x10,regs);

+}

+

+char exec_function(struct REGPACK *regs)

+{char c;

+

+ printf("--- Functions --------------------\n");

+ printf("a. int10 ax0003\t");

+ printf("b. int10 ax02\t");

+ printf("c. int10 ax03\t");

+ printf("d. int10 ax0501\n");

+ printf("e. int10 ax0602\t");

+ printf("f. int10 ax0702\t");

+ printf("g. int10 ax08\t");

+ printf("h. int10 ax09\t");

+ printf("i. int10 ax0a\n");

+ printf("j. int10 ax0f\t");

+ printf("k. int10 ax1b\t");

+ printf("l. int10 ax13\n");

+ printf("q. Quit\t");

+ printf("r. switch to 50 lines\n");

+ c=getche();

+ 

+ switch(c)

+  {case 'a':

+    int10ax0003(regs);

+    break;

+   case 'b':

+    int10ax02(regs);

+    break;

+   case 'c':

+    int10ax03(regs);

+    break;

+   case 'd':

+    int10ax0501(regs);

+    break;

+   case 'e':

+    int10ax0602(regs);

+    break;

+   case 'f':

+    int10ax0702(regs);

+    break;

+   case 'g':

+    int10ax08(regs);

+    break;

+   case 'h':

+    int10ax09(regs);

+    break;

+   case 'i':

+    int10ax0a(regs);

+    break;

+   case 'j':

+    int10ax0f(regs);

+    break;

+   case 'k':

+    int10ax1b(regs);

+    break;

+   case 'l':

+    int10ax13(regs);

+    break;

+   case 'q':

+    break;

+   case 'r':

+    switch_50(regs);

+    break;

+   default:

+    printf("No such function!\n");

+  }

+

+ if(c=='q')return 1;

+ while(kbhit()==0);

+ c=getch();

+ 

+ return 0;

+}

+

+void read_bios_area(BIOSAREA *biosarea)

+{

+ biosarea->initial=peekb(0x40,0x10);

+ biosarea->current=peekb(0x40,0x49);

+ biosarea->nbcols=peek(0x40,0x4a);

+ biosarea->regen=peek(0x40,0x4c);

+ biosarea->start=peek(0x40,0x4e);

+ biosarea->curpos[0]=peek(0x40,0x50);

+ biosarea->curpos[1]=peek(0x40,0x52);

+ biosarea->curpos[2]=peek(0x40,0x54);

+ biosarea->curpos[3]=peek(0x40,0x56);

+ biosarea->curpos[4]=peek(0x40,0x58);

+ biosarea->curpos[5]=peek(0x40,0x5a);

+ biosarea->curpos[6]=peek(0x40,0x5c);

+ biosarea->curpos[7]=peek(0x40,0x5e);

+ biosarea->curtyp=peek(0x40,0x60);

+ biosarea->curpage=peekb(0x40,0x62);

+ biosarea->crtc=peek(0x40,0x63);

+ biosarea->msr=peekb(0x40,0x65);

+ biosarea->cgapal=peekb(0x40,0x66);

+ biosarea->nbrows=peekb(0x40,0x84);

+ biosarea->cheight=peek(0x40,0x85);

+ biosarea->ctl=peekb(0x40,0x87);

+ biosarea->switches=peekb(0x40,0x88);

+ biosarea->modeset=peekb(0x40,0x89);

+ biosarea->dcc=peekb(0x40,0x8a);

+ biosarea->vsseg=peek(0x40,0xa8);

+ biosarea->vsoffset=peek(0x40,0xaa);

+}

+

+void show_bios_area(BIOSAREA *biosarea)

+{

+ printf("--- BIOS area --------------------\n");

+ printf("initial : %02x\t",biosarea->initial);

+ printf("current : %02x\t",biosarea->current);

+ printf("nbcols  : %04x\t",biosarea->nbcols);

+ printf("regen   : %04x\t",biosarea->regen);

+ printf("start   : %04x\n",biosarea->start);

+ printf("curpos  : %04x %04x %04x %04x %04x %04x %04x %04x\n",

+   biosarea->curpos[0], biosarea->curpos[1], biosarea->curpos[2], biosarea->curpos[3],

+   biosarea->curpos[4], biosarea->curpos[5], biosarea->curpos[6], biosarea->curpos[7]);

+ printf("curtyp  : %04x\t",biosarea->curtyp);

+ printf("curpage : %02x\t",biosarea->curpage);

+ printf("crtc    : %04x\t",biosarea->crtc);

+ printf("msr     : %04x\n",biosarea->msr);

+ printf("cgapal  : %04x\t",biosarea->cgapal);

+ printf("nbrows-1: %02x\t",biosarea->nbrows);

+ printf("cheight : %04x\t",biosarea->cheight);

+ printf("ctl     : %02x\n",biosarea->ctl);

+ printf("switches: %02x\t",biosarea->switches);

+ printf("modeset : %02x\t",biosarea->modeset);

+ printf("dcc     : %02x\t",biosarea->dcc);

+ printf("vs      : %04x:%04x\n",biosarea->vsseg,biosarea->vsoffset);

+}

+

+void show_regs(struct REGPACK *regs)

+{

+ printf("--- Registers --------------------\n");

+ printf("ax %04x\t",regs->r_ax);

+ printf("bx %04x\t",regs->r_bx);

+ printf("cx %04x\t",regs->r_cx);

+ printf("dx %04x\t",regs->r_dx);

+ printf("ds %04x\t",regs->r_ds);

+ printf("si %04x\t",regs->r_si);

+ printf("es %04x\t",regs->r_es);

+ printf("di %04x\n",regs->r_di);

+}

+

+void reset_videomode()

+{

+ struct REGPACK regs;

+

+ regs.r_ax=0x0003;

+ intr(0x10,&regs);

+}

+

+void main()

+{

+

+ BIOSAREA biosarea;

+ struct REGPACK regs;

+

+ directvideo=0;

+ 

+ while(1)

+  {

+   read_bios_area(&biosarea);

+

+   reset_videomode();

+   show_bios_area(&biosarea);

+   show_regs(&regs);

+

+   if(exec_function(&regs)!=0)break;

+  }

+}

diff --git a/kvm/vgabios/vbe.c b/kvm/vgabios/vbe.c
new file mode 100644
index 0000000..6173ca0
--- /dev/null
+++ b/kvm/vgabios/vbe.c
@@ -0,0 +1,1432 @@
+// ============================================================================================
+//  
+//  Copyright (C) 2002 Jeroen Janssen
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library 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
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// 
+// ============================================================================================
+//  
+//  This VBE is part of the VGA Bios specific to the plex86/bochs Emulated VGA card. 
+//  You can NOT drive any physical vga card with it. 
+//
+// ============================================================================================
+//  
+//  This VBE Bios is based on information taken from :
+//   - VESA BIOS EXTENSION (VBE) Core Functions Standard Version 3.0 located at www.vesa.org
+//
+// ============================================================================================
+
+
+// defines available
+
+// disable VESA/VBE2 check in vbe info
+//#define VBE2_NO_VESA_CHECK
+
+
+#include "vbe.h"
+#include "vbetables.h"
+
+#define VBE_TOTAL_VIDEO_MEMORY_DIV_64K (VBE_DISPI_TOTAL_VIDEO_MEMORY_MB*1024/64)
+
+// The current OEM Software Revision of this VBE Bios
+#define VBE_OEM_SOFTWARE_REV 0x0002;
+
+extern char vbebios_copyright;
+extern char vbebios_vendor_name;
+extern char vbebios_product_name;
+extern char vbebios_product_revision;
+
+ASM_START
+// FIXME: 'merge' these (c) etc strings with the vgabios.c strings?
+_vbebios_copyright:
+.ascii       "Bochs/Plex86 VBE(C) 2003 http://savannah.nongnu.org/projects/vgabios/"
+.byte        0x00
+
+_vbebios_vendor_name:
+.ascii       "Bochs/Plex86 Developers"
+.byte        0x00
+
+_vbebios_product_name:
+.ascii       "Bochs/Plex86 VBE Adapter"
+.byte        0x00
+
+_vbebios_product_revision:
+.ascii       "$Id$"
+.byte        0x00
+
+_vbebios_info_string:
+.ascii      "Bochs VBE Display Adapter enabled"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte	0x00
+
+_no_vbebios_info_string:
+.ascii      "NO Bochs VBE Support available!"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte 0x00
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+msg_vbe_init:
+.ascii      "VBE Bios $Id$"
+.byte	0x0a,0x0d, 0x00
+#endif
+
+  .align 2
+vesa_pm_start:
+  dw vesa_pm_set_window - vesa_pm_start
+  dw vesa_pm_set_display_start - vesa_pm_start
+  dw vesa_pm_unimplemented - vesa_pm_start
+  dw vesa_pm_io_ports_table - vesa_pm_start
+vesa_pm_io_ports_table:
+  dw VBE_DISPI_IOPORT_INDEX
+  dw VBE_DISPI_IOPORT_INDEX + 1
+  dw VBE_DISPI_IOPORT_DATA
+  dw VBE_DISPI_IOPORT_DATA + 1
+  dw 0xffff
+  dw 0xffff
+
+  USE32
+vesa_pm_set_window:
+  cmp  bx, #0x00
+  je  vesa_pm_set_display_window1
+  mov  ax, #0x0100
+  ret
+vesa_pm_set_display_window1:
+  mov  ax, dx
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BANK
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  in   ax, dx
+  pop  dx
+  cmp  dx, ax
+  jne  illegal_window
+  mov  ax, #0x004f
+  ret
+illegal_window:
+  mov  ax, #0x014f
+  ret
+
+vesa_pm_set_display_start:
+  cmp  bl, #0x80
+  je   vesa_pm_set_display_start1
+  cmp  bl, #0x00
+  je   vesa_pm_set_display_start1
+  mov  ax, #0x0100
+  ret
+vesa_pm_set_display_start1:
+; convert offset to (X, Y) coordinate 
+; (would be simpler to change Bochs VBE API...)
+  push eax
+  push ecx
+  push edx
+  push esi
+  push edi
+  shl edx, #16
+  and ecx, #0xffff
+  or ecx, edx
+  shl ecx, #2
+  mov eax, ecx
+
+  push eax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  movzx ecx, ax
+
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  movzx esi, ax
+  pop  eax
+
+  cmp esi, #4
+  jz bpp4_mode
+  add esi, #7
+  shr esi, #3
+  imul ecx, esi
+  xor edx, edx
+  div ecx
+  mov edi, eax
+  mov eax, edx
+  xor edx, edx
+  div esi
+  jmp set_xy_regs
+
+bpp4_mode:
+  shr ecx, #1
+  xor edx, edx
+  div ecx
+  mov edi, eax
+  mov eax, edx
+  shl eax, #1
+
+set_xy_regs:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_X_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+
+  mov  ax, di
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+
+  pop edi
+  pop esi
+  pop edx
+  pop ecx
+  pop eax
+  mov  ax, #0x004f
+  ret
+
+vesa_pm_unimplemented:
+  mov ax, #0x014f
+  ret
+  USE16
+vesa_pm_end:
+
+; DISPI ioport functions
+
+dispi_get_id:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ID
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+dispi_set_id:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ID
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+ASM_END
+
+static void dispi_set_xres(xres)
+  Bit16u xres;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+  push ax
+  push dx
+
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_XRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  mov  ax, 4[bp] ; xres
+  out  dx, ax
+
+  pop  dx
+  pop  ax
+  pop  bp
+ASM_END
+}
+
+static void dispi_set_yres(yres)
+  Bit16u yres;
+{
+  outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_YRES);
+  outw(VBE_DISPI_IOPORT_DATA,yres);
+}
+
+static void dispi_set_bpp(bpp)
+  Bit16u bpp;
+{
+  outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_BPP);
+  outw(VBE_DISPI_IOPORT_DATA,bpp);
+}
+
+ASM_START
+; AL = bits per pixel / AH = bytes per pixel
+dispi_get_bpp:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  mov  ah, al
+  shr  ah, 3
+  test al, #0x07
+  jz   get_bpp_noinc
+  inc  ah
+get_bpp_noinc:
+  pop  dx
+  ret
+
+; get display capabilities
+
+_dispi_get_max_xres:
+  push dx
+  push bx
+  call dispi_get_enable
+  mov  bx, ax
+  or   ax, # VBE_DISPI_GETCAPS
+  call _dispi_set_enable
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_XRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  push ax
+  mov  ax, bx
+  call _dispi_set_enable
+  pop  ax
+  pop  bx
+  pop  dx
+  ret
+
+_dispi_get_max_bpp:
+  push dx
+  push bx
+  call dispi_get_enable
+  mov  bx, ax
+  or   ax, # VBE_DISPI_GETCAPS
+  call _dispi_set_enable
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  push ax
+  mov  ax, bx
+  call _dispi_set_enable
+  pop  ax
+  pop  bx
+  pop  dx
+  ret
+
+_dispi_set_enable:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ENABLE
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_enable:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ENABLE
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+_dispi_set_bank:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BANK
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_bank:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BANK
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+ASM_END
+
+static void dispi_set_bank_farcall()
+{
+ASM_START
+  cmp bx,#0x0100
+  je dispi_set_bank_farcall_get
+  or bx,bx
+  jnz dispi_set_bank_farcall_error
+  mov ax,dx
+  push dx
+  push ax
+  mov ax,# VBE_DISPI_INDEX_BANK
+  mov dx,# VBE_DISPI_IOPORT_INDEX
+  out dx,ax
+  pop ax
+  mov dx,# VBE_DISPI_IOPORT_DATA
+  out dx,ax
+  in  ax,dx
+  pop dx
+  cmp dx,ax
+  jne dispi_set_bank_farcall_error
+  mov ax, #0x004f
+  retf
+dispi_set_bank_farcall_get:
+  mov ax,# VBE_DISPI_INDEX_BANK
+  mov dx,# VBE_DISPI_IOPORT_INDEX
+  out dx,ax
+  mov dx,# VBE_DISPI_IOPORT_DATA
+  in ax,dx
+  mov dx,ax
+  retf
+dispi_set_bank_farcall_error:
+  mov ax,#0x014F
+  retf
+ASM_END
+}
+
+ASM_START
+dispi_set_x_offset:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_X_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_x_offset:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_X_OFFSET
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+dispi_set_y_offset:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_y_offset:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+vga_set_virt_width:
+  push ax
+  push bx
+  push dx
+  mov  bx, ax
+  call dispi_get_bpp
+  cmp  al, #0x04
+  ja   set_width_svga
+  shr  bx, #1
+set_width_svga:
+  shr  bx, #3
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ah, bl
+  mov  al, #0x13
+  out  dx, ax
+  pop  dx
+  pop  bx
+  pop  ax
+  ret
+
+dispi_set_virt_width:
+  call vga_set_virt_width
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_virt_width:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+dispi_get_virt_height:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_HEIGHT
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+_vga_compat_setup:
+  push ax
+  push dx
+
+  ; set CRT X resolution
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_XRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  push ax
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ax, #0x0011
+  out  dx, ax
+  pop  ax
+  push ax
+  shr  ax, #3
+  dec  ax
+  mov  ah, al
+  mov  al, #0x01
+  out  dx, ax
+  pop  ax
+  call vga_set_virt_width
+
+  ; set CRT Y resolution
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_YRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  dec  ax
+  push ax
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ah, al
+  mov  al, #0x12
+  out  dx, ax
+  pop  ax
+  mov  al, #0x07
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0xbd
+  test ah, #0x01
+  jz   bit8_clear
+  or   al, #0x02
+bit8_clear:
+  test ah, #0x02
+  jz   bit9_clear
+  or   al, #0x40
+bit9_clear:
+  out  dx, al
+
+  ; other settings
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ax, #0x0009
+  out  dx, ax
+  mov  al, #0x17
+  out  dx, al
+  mov  dx, # VGAREG_VGA_CRTC_DATA
+  in   al, dx
+  or   al, #0x03
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_RESET
+  in   al, dx
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  mov  al, #0x10
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_READ_DATA
+  in   al, dx
+  or   al, #0x01
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  out  dx, al
+  mov  al, #0x20
+  out  dx, al
+  mov  dx, # VGAREG_GRDC_ADDRESS
+  mov  ax, #0x0506
+  out  dx, ax
+  mov  dx, # VGAREG_SEQU_ADDRESS
+  mov  ax, #0x0f02
+  out  dx, ax
+
+  ; settings for >= 8bpp
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  cmp  al, #0x08
+  jb   vga_compat_end
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  al, #0x14
+  out  dx, al
+  mov  dx, # VGAREG_VGA_CRTC_DATA
+  in   al, dx
+  or   al, #0x40
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_RESET
+  in   al, dx
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  mov  al, #0x10
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_READ_DATA
+  in   al, dx
+  or   al, #0x40
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  out  dx, al
+  mov  al, #0x20
+  out  dx, al
+  mov  dx, # VGAREG_SEQU_ADDRESS
+  mov  al, #0x04
+  out  dx, al
+  mov  dx, # VGAREG_SEQU_DATA
+  in   al, dx
+  or   al, #0x08
+  out  dx, al
+  mov  dx, # VGAREG_GRDC_ADDRESS
+  mov  al, #0x05
+  out  dx, al
+  mov  dx, # VGAREG_GRDC_DATA
+  in   al, dx
+  and  al, #0x9f
+  or   al, #0x40
+  out  dx, al
+
+vga_compat_end:
+  pop  dx
+  pop  ax
+ASM_END
+
+
+// ModeInfo helper function
+static ModeInfoListItem* mode_info_find_mode(mode, using_lfb)
+  Bit16u mode; Boolean using_lfb;
+{
+  ModeInfoListItem  *cur_info=&mode_info_list;
+
+  while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST)
+  {
+    if (cur_info->mode == mode)
+    {
+      if (!using_lfb)
+      {
+        return cur_info;
+      }
+      else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
+      {
+        return cur_info;
+      }
+      else
+      {
+        cur_info++;
+      }
+    }
+    else
+    {
+      cur_info++;
+    }
+  }
+
+  return 0;
+}
+
+ASM_START
+
+; Has VBE display - Returns true if VBE display detected
+
+_vbe_has_vbe_display:
+  push ds
+  push bx
+  mov  ax, # BIOSMEM_SEG
+  mov  ds, ax
+  mov  bx, # BIOSMEM_VBE_FLAG
+  mov  al, [bx]
+  and  al, #0x01
+  xor  ah, ah
+  pop  bx
+  pop  ds
+  ret
+
+; VBE Init - Initialise the Vesa Bios Extension Code
+; This function does a sanity check on the host side display code interface.
+
+vbe_init:
+  mov  ax, # VBE_DISPI_ID0
+  call dispi_set_id
+  call dispi_get_id
+  cmp  ax, # VBE_DISPI_ID0
+  jne  no_vbe_interface
+  push ds
+  push bx
+  mov  ax, # BIOSMEM_SEG
+  mov  ds, ax
+  mov  bx, # BIOSMEM_VBE_FLAG
+  mov  al, #0x01
+  mov  [bx], al
+  pop  bx
+  pop  ds
+  mov  ax, # VBE_DISPI_ID4
+  call dispi_set_id
+no_vbe_interface:
+#if defined(USE_BX_INFO) || defined(DEBUG)
+  mov  bx, #msg_vbe_init
+  push bx
+  call _printf
+  inc  sp
+  inc  sp
+#endif
+  ret
+
+; VBE Display Info - Display information on screen about the VBE
+
+vbe_display_info:
+  call _vbe_has_vbe_display
+  test ax, ax
+  jz   no_vbe_flag
+  mov  ax, #0xc000
+  mov  ds, ax
+  mov  si, #_vbebios_info_string
+  jmp  _display_string
+no_vbe_flag:
+  mov  ax, #0xc000
+  mov  ds, ax
+  mov  si, #_no_vbebios_info_string
+  jmp  _display_string
+ASM_END  
+
+/** Function 00h - Return VBE Controller Information
+ * 
+ * Input:
+ *              AX      = 4F00h
+ *              ES:DI   = Pointer to buffer in which to place VbeInfoBlock structure
+ *                        (VbeSignature should be VBE2 when VBE 2.0 information is desired and
+ *                        the info block is 512 bytes in size)
+ * Output:
+ *              AX      = VBE Return Status
+ * 
+ */
+void vbe_biosfn_return_controller_information(AX, ES, DI)
+Bit16u *AX;Bit16u ES;Bit16u DI;
+{
+        Bit16u            ss=get_SS();
+        VbeInfoBlock      vbe_info_block;
+        Bit16u            status;
+        Bit16u            result;
+        Bit16u            vbe2_info;
+        Bit16u            cur_mode=0;
+        Bit16u            cur_ptr=34;
+        ModeInfoListItem  *cur_info=&mode_info_list;
+        
+        status = read_word(ss, AX);
+        
+#ifdef DEBUG
+        printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status);
+#endif
+
+        vbe2_info = 0;
+#ifdef VBE2_NO_VESA_CHECK
+#else
+        // get vbe_info_block into local variable
+        memcpyb(ss, &vbe_info_block, ES, DI, sizeof(vbe_info_block));
+
+        // check for VBE2 signature
+        if (((vbe_info_block.VbeSignature[0] == 'V') &&
+             (vbe_info_block.VbeSignature[1] == 'B') &&
+             (vbe_info_block.VbeSignature[2] == 'E') &&
+             (vbe_info_block.VbeSignature[3] == '2')) ||
+             
+            ((vbe_info_block.VbeSignature[0] == 'V') &&
+             (vbe_info_block.VbeSignature[1] == 'E') &&
+             (vbe_info_block.VbeSignature[2] == 'S') &&
+             (vbe_info_block.VbeSignature[3] == 'A')) )
+        {
+                vbe2_info = 1;
+#ifdef DEBUG
+                printf("VBE correct VESA/VBE2 signature found\n");
+#endif
+        }
+#endif
+                
+        // VBE Signature
+        vbe_info_block.VbeSignature[0] = 'V';
+        vbe_info_block.VbeSignature[1] = 'E';
+        vbe_info_block.VbeSignature[2] = 'S';
+        vbe_info_block.VbeSignature[3] = 'A';
+        
+        // VBE Version supported
+        vbe_info_block.VbeVersion = 0x0200;
+        
+        // OEM String
+        vbe_info_block.OemStringPtr_Seg = 0xc000;
+        vbe_info_block.OemStringPtr_Off = &vbebios_copyright;
+        
+        // Capabilities
+        vbe_info_block.Capabilities[0] = VBE_CAPABILITY_8BIT_DAC;
+        vbe_info_block.Capabilities[1] = 0;
+        vbe_info_block.Capabilities[2] = 0;
+        vbe_info_block.Capabilities[3] = 0;
+
+        // VBE Video Mode Pointer (dynamicly generated from the mode_info_list)
+        vbe_info_block.VideoModePtr_Seg= ES ;
+        vbe_info_block.VideoModePtr_Off= DI + 34;
+
+        // VBE Total Memory (in 64b blocks)
+        vbe_info_block.TotalMemory = VBE_TOTAL_VIDEO_MEMORY_DIV_64K;
+
+        if (vbe2_info)
+	{
+                // OEM Stuff
+                vbe_info_block.OemSoftwareRev = VBE_OEM_SOFTWARE_REV;
+                vbe_info_block.OemVendorNamePtr_Seg = 0xc000;
+                vbe_info_block.OemVendorNamePtr_Off = &vbebios_vendor_name;
+                vbe_info_block.OemProductNamePtr_Seg = 0xc000;
+                vbe_info_block.OemProductNamePtr_Off = &vbebios_product_name;
+                vbe_info_block.OemProductRevPtr_Seg = 0xc000;
+                vbe_info_block.OemProductRevPtr_Off = &vbebios_product_revision;
+
+                // copy updates in vbe_info_block back
+                memcpyb(ES, DI, ss, &vbe_info_block, sizeof(vbe_info_block));
+        }
+	else
+	{
+                // copy updates in vbe_info_block back (VBE 1.x compatibility)
+                memcpyb(ES, DI, ss, &vbe_info_block, 256);
+	}
+                
+        do
+        {
+                if ((cur_info->info.XResolution <= dispi_get_max_xres()) &&
+                    (cur_info->info.BitsPerPixel <= dispi_get_max_bpp())) {
+#ifdef DEBUG
+                  printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode);
+#endif
+                  write_word(ES, DI + cur_ptr, cur_info->mode);
+                  cur_mode++;
+                  cur_ptr+=2;
+                } else {
+#ifdef DEBUG
+                  printf("VBE mode %x (xres=%x / bpp=%02x) not supported by display\n", cur_info->mode,cur_info->info.XResolution,cur_info->info.BitsPerPixel);
+#endif
+                }
+                cur_info++;
+        } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST);
+        
+        // Add vesa mode list terminator
+        write_word(ES, DI + cur_ptr, cur_info->mode);
+
+        result = 0x4f;
+
+        write_word(ss, AX, result);
+}
+
+
+/** Function 01h - Return VBE Mode Information
+ * 
+ * Input:
+ *              AX      = 4F01h
+ *              CX      = Mode Number
+ *              ES:DI   = Pointer to buffer in which to place ModeInfoBlock structure
+ * Output:
+ *              AX      = VBE Return Status
+ * 
+ */
+void vbe_biosfn_return_mode_information(AX, CX, ES, DI)
+Bit16u *AX;Bit16u CX; Bit16u ES;Bit16u DI;
+{
+        Bit16u            result=0x0100;
+        Bit16u            ss=get_SS();
+        ModeInfoBlock     info;
+        ModeInfoListItem  *cur_info;
+        Boolean           using_lfb;
+
+#ifdef DEBUG
+        printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX);
+#endif
+
+        using_lfb=((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
+        
+        CX = (CX & 0x1ff);
+        
+        cur_info = mode_info_find_mode(CX, using_lfb, &cur_info);
+
+        if (cur_info != 0)
+        {
+#ifdef DEBUG
+                printf("VBE found mode %x\n",CX);
+#endif        
+                memsetb(ss, &info, 0, sizeof(ModeInfoBlock));
+                memcpyb(ss, &info, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact));
+                if (using_lfb) {
+                  info.NumberOfBanks = 1;
+                }
+                if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
+                  info.WinFuncPtr = 0xC0000000UL;
+                  *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall);
+                }
+                
+                result = 0x4f;
+        }
+        else
+        {
+#ifdef DEBUG
+                printf("VBE *NOT* found mode %x\n",CX);
+#endif
+                result = 0x100;
+        }
+        
+        if (result == 0x4f)
+        {
+                // copy updates in mode_info_block back
+                memcpyb(ES, DI, ss, &info, sizeof(info));
+        }
+
+        write_word(ss, AX, result);
+}
+
+/** Function 02h - Set VBE Mode
+ * 
+ * Input:
+ *              AX      = 4F02h
+ *              BX      = Desired Mode to set
+ *              ES:DI   = Pointer to CRTCInfoBlock structure
+ * Output:
+ *              AX      = VBE Return Status
+ * 
+ */
+void vbe_biosfn_set_mode(AX, BX, ES, DI)
+Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI;
+{
+        Bit16u            ss = get_SS();
+        Bit16u            result;
+        ModeInfoListItem  *cur_info;
+        Boolean           using_lfb;
+        Bit8u             no_clear;
+        Bit8u             lfb_flag;
+
+        using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
+        lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0;
+        no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0;
+
+        BX = (BX & 0x1ff);
+
+        //result=read_word(ss,AX);
+        
+        // check for non vesa mode
+        if (BX<VBE_MODE_VESA_DEFINED)
+        {
+                Bit8u   mode;
+                
+                dispi_set_enable(VBE_DISPI_DISABLED);
+                // call the vgabios in order to set the video mode
+                // this allows for going back to textmode with a VBE call (some applications expect that to work)
+                
+                mode=(BX & 0xff);
+                biosfn_set_video_mode(mode);
+                result = 0x4f;
+        }
+        
+        cur_info = mode_info_find_mode(BX, using_lfb, &cur_info);
+
+        if (cur_info != 0)
+        {
+#ifdef DEBUG
+                printf("VBE found mode %x, setting:\n", BX);
+                printf("\txres%x yres%x bpp%x\n",
+                        cur_info->info.XResolution,
+                        cur_info->info.YResolution,
+                        cur_info->info.BitsPerPixel);
+#endif
+                
+                // first disable current mode (when switching between vesa modi)
+                dispi_set_enable(VBE_DISPI_DISABLED);
+
+                if (cur_info->info.BitsPerPixel == 4)
+                {
+                  biosfn_set_video_mode(0x6a);
+                }
+
+                dispi_set_bpp(cur_info->info.BitsPerPixel);
+                dispi_set_xres(cur_info->info.XResolution);
+                dispi_set_yres(cur_info->info.YResolution);
+                dispi_set_bank(0);
+                dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
+                vga_compat_setup();
+
+                write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
+                write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
+
+                result = 0x4f;                  
+        }
+        else
+        {
+#ifdef DEBUG
+                printf("VBE *NOT* found mode %x\n" , BX);
+#endif        
+                result = 0x100;
+                
+                // FIXME: redirect non VBE modi to normal VGA bios operation
+                //        (switch back to VGA mode
+                if (BX == 3)
+                        result = 0x4f;
+        }
+
+        write_word(ss, AX, result);
+}
+
+/** Function 03h - Return Current VBE Mode
+ * 
+ * Input:
+ *              AX      = 4F03h
+ * Output:
+ *              AX      = VBE Return Status
+ *              BX      = Current VBE Mode
+ * 
+ */
+ASM_START
+vbe_biosfn_return_current_mode:
+  push ds
+  mov  ax, # BIOSMEM_SEG
+  mov  ds, ax
+  call dispi_get_enable
+  and  ax, # VBE_DISPI_ENABLED
+  jz   no_vbe_mode
+  mov  bx, # BIOSMEM_VBE_MODE
+  mov  ax, [bx]
+  mov  bx, ax
+  jnz  vbe_03_ok
+no_vbe_mode:
+  mov  bx, # BIOSMEM_CURRENT_MODE
+  mov  al, [bx]
+  mov  bl, al
+  xor  bh, bh
+vbe_03_ok:
+  mov  ax, #0x004f
+  pop  ds
+  ret
+ASM_END
+
+
+Bit16u vbe_biosfn_read_video_state_size()
+{
+    return 9 * 2;
+}
+
+void vbe_biosfn_save_video_state(ES, BX)
+     Bit16u ES; Bit16u BX;
+{
+    Bit16u enable, i;
+
+    outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
+    enable = inw(VBE_DISPI_IOPORT_DATA);
+    write_word(ES, BX, enable);
+    BX += 2;
+    if (!(enable & VBE_DISPI_ENABLED)) 
+        return;
+    for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
+        if (i != VBE_DISPI_INDEX_ENABLE) {
+            outw(VBE_DISPI_IOPORT_INDEX, i);
+            write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
+            BX += 2;
+        }
+    }
+}
+
+
+void vbe_biosfn_restore_video_state(ES, BX)
+     Bit16u ES; Bit16u BX;
+{
+    Bit16u enable, i;
+
+    enable = read_word(ES, BX);
+    BX += 2;
+    
+    if (!(enable & VBE_DISPI_ENABLED)) {
+        outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
+        outw(VBE_DISPI_IOPORT_DATA, enable);
+    } else {
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
+        outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+        BX += 2;
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
+        outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+        BX += 2;
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
+        outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+        BX += 2;
+        outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
+        outw(VBE_DISPI_IOPORT_DATA, enable);
+
+        for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
+            outw(VBE_DISPI_IOPORT_INDEX, i);
+            outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+            BX += 2;
+        }
+    }
+}
+
+/** Function 04h - Save/Restore State
+ * 
+ * Input:
+ *              AX      = 4F04h
+ *              DL      = 00h Return Save/Restore State buffer size
+ *                        01h Save State
+ *                        02h Restore State
+ *              CX      = Requested states
+ *              ES:BX   = Pointer to buffer (if DL <> 00h)
+ * Output:
+ *              AX      = VBE Return Status
+ *              BX      = Number of 64-byte blocks to hold the state buffer (if DL=00h)
+ * 
+ */
+void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX)
+Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX;
+{
+    Bit16u ss=get_SS();
+    Bit16u result, val;
+
+    result = 0x4f;
+    switch(GET_DL()) {
+    case 0x00:
+        val = biosfn_read_video_state_size2(CX);
+#ifdef DEBUG
+        printf("VGA state size=%x\n", val);
+#endif
+        if (CX & 8)
+            val += vbe_biosfn_read_video_state_size();
+        write_word(ss, BX, val);
+        break;
+    case 0x01:
+        val = read_word(ss, BX);
+        val = biosfn_save_video_state(CX, ES, val);
+#ifdef DEBUG
+        printf("VGA save_state offset=%x\n", val);
+#endif
+        if (CX & 8)
+            vbe_biosfn_save_video_state(ES, val);
+        break;
+    case 0x02:
+        val = read_word(ss, BX);
+        val = biosfn_restore_video_state(CX, ES, val);
+#ifdef DEBUG
+        printf("VGA restore_state offset=%x\n", val);
+#endif
+        if (CX & 8)
+            vbe_biosfn_restore_video_state(ES, val);
+        break;
+    default:
+        // function failed
+        result = 0x100;
+        break;
+    }
+    write_word(ss, AX, result);
+}
+
+/** Function 05h - Display Window Control
+ * 
+ * Input:
+ *              AX      = 4F05h
+ *     (16-bit) BH      = 00h Set memory window
+ *                      = 01h Get memory window
+ *              BL      = Window number
+ *                      = 00h Window A
+ *                      = 01h Window B
+ *              DX      = Window number in video memory in window
+ *                        granularity units (Set Memory Window only)
+ * Note:
+ *              If this function is called while in a linear frame buffer mode,
+ *              this function must fail with completion code AH=03h
+ * 
+ * Output:
+ *              AX      = VBE Return Status
+ *              DX      = Window number in window granularity units
+ *                        (Get Memory Window only)
+ */
+ASM_START
+vbe_biosfn_display_window_control:
+  cmp  bl, #0x00
+  jne  vbe_05_failed
+  cmp  bh, #0x01
+  je   get_display_window
+  jb   set_display_window
+  mov  ax, #0x0100
+  ret
+set_display_window:
+  mov  ax, dx
+  call _dispi_set_bank
+  call dispi_get_bank
+  cmp  ax, dx
+  jne  vbe_05_failed
+  mov  ax, #0x004f
+  ret
+get_display_window:
+  call dispi_get_bank
+  mov  dx, ax
+  mov  ax, #0x004f
+  ret
+vbe_05_failed:
+  mov  ax, #0x014f
+  ret
+ASM_END
+
+
+/** Function 06h - Set/Get Logical Scan Line Length
+ *
+ * Input:
+ *              AX      = 4F06h
+ *              BL      = 00h Set Scan Line Length in Pixels
+ *                      = 01h Get Scan Line Length
+ *                      = 02h Set Scan Line Length in Bytes
+ *                      = 03h Get Maximum Scan Line Length
+ *              CX      = If BL=00h Desired Width in Pixels
+ *                        If BL=02h Desired Width in Bytes
+ *                        (Ignored for Get Functions)
+ * 
+ * Output: 
+ *              AX      = VBE Return Status
+ *              BX      = Bytes Per Scan Line
+ *              CX      = Actual Pixels Per Scan Line
+ *                        (truncated to nearest complete pixel)
+ *              DX      = Maximum Number of Scan Lines 
+ */
+ASM_START
+vbe_biosfn_set_get_logical_scan_line_length:
+  mov  ax, cx
+  cmp  bl, #0x01
+  je   get_logical_scan_line_length
+  cmp  bl, #0x02
+  je   set_logical_scan_line_bytes
+  jb   set_logical_scan_line_pixels
+  mov  ax, #0x0100
+  ret
+set_logical_scan_line_bytes:
+  push ax
+  call dispi_get_bpp
+  xor  bh, bh
+  mov  bl, ah
+  or   bl, bl
+  jnz  no_4bpp_1
+  shl  ax, #3
+  mov  bl, #1
+no_4bpp_1:
+  xor  dx, dx
+  pop  ax
+  div  bx
+set_logical_scan_line_pixels:
+  call dispi_set_virt_width
+get_logical_scan_line_length:
+  call dispi_get_bpp
+  xor  bh, bh
+  mov  bl, ah
+  call dispi_get_virt_width
+  mov  cx, ax
+  or   bl, bl
+  jnz  no_4bpp_2
+  shr  ax, #3
+  mov  bl, #1
+no_4bpp_2:
+  mul  bx
+  mov  bx, ax
+  call dispi_get_virt_height
+  mov  dx, ax
+  mov  ax, #0x004f
+  ret
+ASM_END
+
+
+/** Function 07h - Set/Get Display Start
+ * 
+ * Input(16-bit):
+ *              AX      = 4F07h
+ *              BH      = 00h Reserved and must be 00h
+ *              BL      = 00h Set Display Start
+ *                      = 01h Get Display Start
+ *                      = 02h Schedule Display Start (Alternate)
+ *                      = 03h Schedule Stereoscopic Display Start
+ *                      = 04h Get Scheduled Display Start Status
+ *                      = 05h Enable Stereoscopic Mode
+ *                      = 06h Disable Stereoscopic Mode
+ *                      = 80h Set Display Start during Vertical Retrace
+ *                      = 82h Set Display Start during Vertical Retrace (Alternate)
+ *                      = 83h Set Stereoscopic Display Start during Vertical Retrace
+ *              ECX     = If BL=02h/82h Display Start Address in bytes
+ *                        If BL=03h/83h Left Image Start Address in bytes
+ *              EDX     = If BL=03h/83h Right Image Start Address in bytes
+ *              CX      = If BL=00h/80h First Displayed Pixel In Scan Line
+ *              DX      = If BL=00h/80h First Displayed Scan Line
+ *
+ * Output:
+ *              AX      = VBE Return Status
+ *              BH      = If BL=01h Reserved and will be 0
+ *              CX      = If BL=01h First Displayed Pixel In Scan Line
+ *                        If BL=04h 0 if flip has not occurred, not 0 if it has
+ *              DX      = If BL=01h First Displayed Scan Line
+ *
+ * Input(32-bit): 
+ *              BH      = 00h Reserved and must be 00h
+ *              BL      = 00h Set Display Start
+ *                      = 80h Set Display Start during Vertical Retrace
+ *              CX      = Bits 0-15 of display start address
+ *              DX      = Bits 16-31 of display start address
+ *              ES      = Selector for memory mapped registers 
+ */
+ASM_START
+vbe_biosfn_set_get_display_start:
+  cmp  bl, #0x80
+  je   set_display_start
+  cmp  bl, #0x01
+  je   get_display_start
+  jb   set_display_start
+  mov  ax, #0x0100
+  ret
+set_display_start:
+  mov  ax, cx
+  call dispi_set_x_offset
+  mov  ax, dx
+  call dispi_set_y_offset
+  mov  ax, #0x004f
+  ret
+get_display_start:
+  call dispi_get_x_offset
+  mov  cx, ax
+  call dispi_get_y_offset
+  mov  dx, ax
+  xor  bh, bh
+  mov  ax, #0x004f
+  ret
+ASM_END
+  
+
+/** Function 08h - Set/Get Dac Palette Format
+ * 
+ * Input:
+ *              AX      = 4F08h
+ *              BL      = 00h set DAC palette width
+ *                      = 01h get DAC palette width
+ *              BH      = If BL=00h: desired number of bits per primary color
+ * Output:
+ *              AX      = VBE Return Status
+ *              BH      = current number of bits per primary color (06h = standard VGA)
+ */
+ASM_START
+vbe_biosfn_set_get_dac_palette_format:
+  cmp  bl, #0x01
+  je   get_dac_palette_format
+  jb   set_dac_palette_format
+  mov  ax, #0x0100
+  ret
+set_dac_palette_format:
+  call dispi_get_enable
+  cmp  bh, #0x06
+  je   set_normal_dac
+  cmp  bh, #0x08
+  jne  vbe_08_unsupported
+  or   ax, # VBE_DISPI_8BIT_DAC
+  jnz  set_dac_mode
+set_normal_dac:
+  and  ax, #~ VBE_DISPI_8BIT_DAC
+set_dac_mode:
+  call _dispi_set_enable
+get_dac_palette_format:
+  mov  bh, #0x06
+  call dispi_get_enable
+  and  ax, # VBE_DISPI_8BIT_DAC
+  jz   vbe_08_ok
+  mov  bh, #0x08
+vbe_08_ok:
+  mov  ax, #0x004f
+  ret
+vbe_08_unsupported:
+  mov  ax, #0x014f
+  ret
+ASM_END
+
+
+/** Function 09h - Set/Get Palette Data
+ * 
+ * Input:
+ *              AX      = 4F09h
+ * Output:
+ *              AX      = VBE Return Status
+ *
+ * FIXME: incomplete API description, Input & Output
+ */
+void vbe_biosfn_set_get_palette_data(AX)
+{
+}
+
+/** Function 0Ah - Return VBE Protected Mode Interface
+ * Input:    AX   = 4F0Ah   VBE 2.0 Protected Mode Interface
+ *           BL   = 00h          Return protected mode table
+ *
+ *
+ * Output:   AX   =         Status
+ *           ES   =         Real Mode Segment of Table
+ *           DI   =         Offset of Table
+ *           CX   =         Length of Table including protected mode code
+ *                          (for copying purposes)
+ */
+ASM_START
+vbe_biosfn_return_protected_mode_interface:
+  test bl, bl
+  jnz _fail
+  mov di, #0xc000
+  mov es, di
+  mov di, # vesa_pm_start
+  mov cx, # vesa_pm_end
+  sub cx, di
+  mov ax, #0x004f
+  ret
+_fail:
+  mov ax, #0x014f
+  ret
+ASM_END
diff --git a/kvm/vgabios/vbe.h b/kvm/vgabios/vbe.h
new file mode 100644
index 0000000..60434ac
--- /dev/null
+++ b/kvm/vgabios/vbe.h
@@ -0,0 +1,313 @@
+#ifndef vbe_h_included
+#define vbe_h_included
+
+#include "vgabios.h"
+
+// DISPI helper function
+void dispi_set_enable(enable);
+
+/** VBE int10 API
+ *
+ *  See the function descriptions in vbe.c for more information
+ */
+Boolean vbe_has_vbe_display();
+void vbe_biosfn_return_controller_information(AX, ES, DI);
+void vbe_biosfn_return_mode_information(AX, CX, ES, DI);
+void vbe_biosfn_set_mode(AX, BX, ES, DI);
+void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX);
+void vbe_biosfn_set_get_palette_data(AX);
+void vbe_biosfn_return_protected_mode_interface(AX);
+
+// The official VBE Information Block
+typedef struct VbeInfoBlock
+{ 
+   Bit8u  VbeSignature[4];
+   Bit16u VbeVersion;
+   Bit16u OemStringPtr_Off;
+   Bit16u OemStringPtr_Seg;
+   Bit8u  Capabilities[4];
+   Bit16u VideoModePtr_Off;
+   Bit16u VideoModePtr_Seg;
+   Bit16u TotalMemory;
+   Bit16u OemSoftwareRev;
+   Bit16u OemVendorNamePtr_Off;
+   Bit16u OemVendorNamePtr_Seg;
+   Bit16u OemProductNamePtr_Off;
+   Bit16u OemProductNamePtr_Seg;
+   Bit16u OemProductRevPtr_Off;
+   Bit16u OemProductRevPtr_Seg;
+   Bit16u  Reserved[111]; // used for dynamicly generated mode list
+   Bit8u  OemData[256];
+} VbeInfoBlock;
+
+
+// This one is for compactly storing a static list of mode info blocks
+// this saves us 189 bytes per block
+typedef struct ModeInfoBlockCompact
+{
+// Mandatory information for all VBE revisions
+   Bit16u ModeAttributes;
+   Bit8u  WinAAttributes;
+   Bit8u  WinBAttributes;
+   Bit16u WinGranularity;
+   Bit16u WinSize;
+   Bit16u WinASegment;
+   Bit16u WinBSegment;
+   Bit32u WinFuncPtr;
+   Bit16u BytesPerScanLine;
+// Mandatory information for VBE 1.2 and above
+   Bit16u XResolution;
+   Bit16u YResolution;
+   Bit8u  XCharSize;
+   Bit8u  YCharSize;
+   Bit8u  NumberOfPlanes;
+   Bit8u  BitsPerPixel;
+   Bit8u  NumberOfBanks;
+   Bit8u  MemoryModel;
+   Bit8u  BankSize;
+   Bit8u  NumberOfImagePages;
+   Bit8u  Reserved_page;
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+   Bit8u  RedMaskSize;
+   Bit8u  RedFieldPosition;
+   Bit8u  GreenMaskSize;
+   Bit8u  GreenFieldPosition;
+   Bit8u  BlueMaskSize;
+   Bit8u  BlueFieldPosition;
+   Bit8u  RsvdMaskSize;
+   Bit8u  RsvdFieldPosition;
+   Bit8u  DirectColorModeInfo;
+// Mandatory information for VBE 2.0 and above
+   Bit32u PhysBasePtr;
+   Bit32u OffScreenMemOffset;
+   Bit16u OffScreenMemSize;
+// Mandatory information for VBE 3.0 and above
+   Bit16u LinBytesPerScanLine;
+   Bit8u  BnkNumberOfPages;
+   Bit8u  LinNumberOfPages;
+   Bit8u  LinRedMaskSize;
+   Bit8u  LinRedFieldPosition;
+   Bit8u  LinGreenMaskSize;
+   Bit8u  LinGreenFieldPosition;
+   Bit8u  LinBlueMaskSize;
+   Bit8u  LinBlueFieldPosition;
+   Bit8u  LinRsvdMaskSize;
+   Bit8u  LinRsvdFieldPosition;
+   Bit32u MaxPixelClock;
+//   Bit8u  Reserved[189]; // DO NOT PUT THIS IN HERE because of Compact Mode Info storage in bios 
+} ModeInfoBlockCompact;
+
+typedef struct ModeInfoBlock
+{
+// Mandatory information for all VBE revisions
+   Bit16u ModeAttributes;
+   Bit8u  WinAAttributes;
+   Bit8u  WinBAttributes;
+   Bit16u WinGranularity;
+   Bit16u WinSize;
+   Bit16u WinASegment;
+   Bit16u WinBSegment;
+   Bit32u WinFuncPtr;
+   Bit16u BytesPerScanLine;
+// Mandatory information for VBE 1.2 and above
+   Bit16u XResolution;
+   Bit16u YResolution;
+   Bit8u  XCharSize;
+   Bit8u  YCharSize;
+   Bit8u  NumberOfPlanes;
+   Bit8u  BitsPerPixel;
+   Bit8u  NumberOfBanks;
+   Bit8u  MemoryModel;
+   Bit8u  BankSize;
+   Bit8u  NumberOfImagePages;
+   Bit8u  Reserved_page;
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+   Bit8u  RedMaskSize;
+   Bit8u  RedFieldPosition;
+   Bit8u  GreenMaskSize;
+   Bit8u  GreenFieldPosition;
+   Bit8u  BlueMaskSize;
+   Bit8u  BlueFieldPosition;
+   Bit8u  RsvdMaskSize;
+   Bit8u  RsvdFieldPosition;
+   Bit8u  DirectColorModeInfo;
+// Mandatory information for VBE 2.0 and above
+   Bit32u PhysBasePtr;
+   Bit32u OffScreenMemOffset;
+   Bit16u OffScreenMemSize;
+// Mandatory information for VBE 3.0 and above
+   Bit16u LinBytesPerScanLine;
+   Bit8u  BnkNumberOfPages;
+   Bit8u  LinNumberOfPages;
+   Bit8u  LinRedMaskSize;
+   Bit8u  LinRedFieldPosition;
+   Bit8u  LinGreenMaskSize;
+   Bit8u  LinGreenFieldPosition;
+   Bit8u  LinBlueMaskSize;
+   Bit8u  LinBlueFieldPosition;
+   Bit8u  LinRsvdMaskSize;
+   Bit8u  LinRsvdFieldPosition;
+   Bit32u MaxPixelClock;
+   Bit8u  Reserved[189];
+} ModeInfoBlock;
+
+typedef struct ModeInfoListItem
+{
+  Bit16u                mode;
+  ModeInfoBlockCompact  info;
+} ModeInfoListItem;
+
+// VBE Return Status Info
+// AL
+#define VBE_RETURN_STATUS_SUPPORTED                      0x4F
+#define VBE_RETURN_STATUS_UNSUPPORTED                    0x00
+// AH
+#define VBE_RETURN_STATUS_SUCCESSFULL                    0x00
+#define VBE_RETURN_STATUS_FAILED                         0x01
+#define VBE_RETURN_STATUS_NOT_SUPPORTED                  0x02
+#define VBE_RETURN_STATUS_INVALID                        0x03
+
+// VBE Mode Numbers
+
+#define VBE_MODE_VESA_DEFINED                            0x0100
+#define VBE_MODE_REFRESH_RATE_USE_CRTC                   0x0800
+#define VBE_MODE_LINEAR_FRAME_BUFFER                     0x4000
+#define VBE_MODE_PRESERVE_DISPLAY_MEMORY                 0x8000
+
+// VBE GFX Mode Number
+
+#define VBE_VESA_MODE_640X400X8                          0x100
+#define VBE_VESA_MODE_640X480X8                          0x101
+#define VBE_VESA_MODE_800X600X4                          0x102
+#define VBE_VESA_MODE_800X600X8                          0x103
+#define VBE_VESA_MODE_1024X768X4                         0x104
+#define VBE_VESA_MODE_1024X768X8                         0x105
+#define VBE_VESA_MODE_1280X1024X4                        0x106
+#define VBE_VESA_MODE_1280X1024X8                        0x107
+#define VBE_VESA_MODE_320X200X1555                       0x10D
+#define VBE_VESA_MODE_320X200X565                        0x10E
+#define VBE_VESA_MODE_320X200X888                        0x10F
+#define VBE_VESA_MODE_640X480X1555                       0x110
+#define VBE_VESA_MODE_640X480X565                        0x111
+#define VBE_VESA_MODE_640X480X888                        0x112
+#define VBE_VESA_MODE_800X600X1555                       0x113
+#define VBE_VESA_MODE_800X600X565                        0x114
+#define VBE_VESA_MODE_800X600X888                        0x115
+#define VBE_VESA_MODE_1024X768X1555                      0x116
+#define VBE_VESA_MODE_1024X768X565                       0x117
+#define VBE_VESA_MODE_1024X768X888                       0x118
+#define VBE_VESA_MODE_1280X1024X1555                     0x119
+#define VBE_VESA_MODE_1280X1024X565                      0x11A
+#define VBE_VESA_MODE_1280X1024X888                      0x11B
+#define VBE_VESA_MODE_1600X1200X8                        0x11C
+#define VBE_VESA_MODE_1600X1200X1555                     0x11D
+#define VBE_VESA_MODE_1600X1200X565                      0x11E
+#define VBE_VESA_MODE_1600X1200X888                      0x11F
+
+// BOCHS/PLEX86 'own' mode numbers
+#define VBE_OWN_MODE_320X200X8888                        0x140
+#define VBE_OWN_MODE_640X400X8888                        0x141
+#define VBE_OWN_MODE_640X480X8888                        0x142
+#define VBE_OWN_MODE_800X600X8888                        0x143
+#define VBE_OWN_MODE_1024X768X8888                       0x144
+#define VBE_OWN_MODE_1280X1024X8888                      0x145
+#define VBE_OWN_MODE_320X200X8                           0x146
+#define VBE_OWN_MODE_1600X1200X8888                      0x147
+#define VBE_OWN_MODE_1152X864X8                          0x148
+#define VBE_OWN_MODE_1152X864X1555                       0x149
+#define VBE_OWN_MODE_1152X864X565                        0x14a
+#define VBE_OWN_MODE_1152X864X888                        0x14b
+#define VBE_OWN_MODE_1152X864X8888                       0x14c
+
+#define VBE_VESA_MODE_END_OF_LIST                        0xFFFF
+
+// Capabilities
+
+#define VBE_CAPABILITY_8BIT_DAC                          0x0001
+#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE                0x0002
+#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT              0x0004
+#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT              0x0008
+#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC               0x0010
+
+// Mode Attributes
+
+#define VBE_MODE_ATTRIBUTE_SUPPORTED                     0x0001
+#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE  0x0002
+#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT              0x0004
+#define VBE_MODE_ATTRIBUTE_COLOR_MODE                    0x0008
+#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE                 0x0010
+#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE            0x0020
+#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW      0x0040
+#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE      0x0080
+#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE              0x0100
+#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE                0x0200
+#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER        0x0400
+#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800
+#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS    0x1000
+
+#define VBE_MODE_ATTTRIBUTE_LFB_ONLY                     ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE )
+
+// Window attributes
+
+#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE                 0x01
+#define VBE_WINDOW_ATTRIBUTE_READABLE                    0x02
+#define VBE_WINDOW_ATTRIBUTE_WRITEABLE                   0x04
+
+// Memory model
+
+#define VBE_MEMORYMODEL_TEXT_MODE                        0x00
+#define VBE_MEMORYMODEL_CGA_GRAPHICS                     0x01
+#define VBE_MEMORYMODEL_HERCULES_GRAPHICS                0x02
+#define VBE_MEMORYMODEL_PLANAR                           0x03
+#define VBE_MEMORYMODEL_PACKED_PIXEL                     0x04
+#define VBE_MEMORYMODEL_NON_CHAIN_4_256                  0x05
+#define VBE_MEMORYMODEL_DIRECT_COLOR                     0x06
+#define VBE_MEMORYMODEL_YUV                              0x07
+
+// DirectColorModeInfo
+
+#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE          0x01
+#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE          0x02
+
+// GUEST <-> HOST Communication API
+
+// FIXME: either dynamicly ask host for this or put somewhere high in physical memory
+//        like 0xE0000000
+
+
+  #define VBE_DISPI_BANK_ADDRESS          0xA0000
+  #define VBE_DISPI_BANK_SIZE_KB          64
+  
+  #define VBE_DISPI_MAX_XRES              1024
+  #define VBE_DISPI_MAX_YRES              768
+  
+  #define VBE_DISPI_IOPORT_INDEX          0x01CE
+  #define VBE_DISPI_IOPORT_DATA           0x01CF
+  
+  #define VBE_DISPI_INDEX_ID              0x0
+  #define VBE_DISPI_INDEX_XRES            0x1
+  #define VBE_DISPI_INDEX_YRES            0x2
+  #define VBE_DISPI_INDEX_BPP             0x3
+  #define VBE_DISPI_INDEX_ENABLE          0x4
+  #define VBE_DISPI_INDEX_BANK            0x5
+  #define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+  #define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+  #define VBE_DISPI_INDEX_X_OFFSET        0x8
+  #define VBE_DISPI_INDEX_Y_OFFSET        0x9
+      
+  #define VBE_DISPI_ID0                   0xB0C0
+  #define VBE_DISPI_ID1                   0xB0C1
+  #define VBE_DISPI_ID2                   0xB0C2
+  #define VBE_DISPI_ID3                   0xB0C3
+  #define VBE_DISPI_ID4                   0xB0C4
+  
+  #define VBE_DISPI_DISABLED              0x00
+  #define VBE_DISPI_ENABLED               0x01
+  #define VBE_DISPI_GETCAPS               0x02
+  #define VBE_DISPI_8BIT_DAC              0x20
+  #define VBE_DISPI_LFB_ENABLED           0x40
+  #define VBE_DISPI_NOCLEARMEM            0x80
+  
+  #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+#endif
diff --git a/kvm/vgabios/vbe_display_api.txt b/kvm/vgabios/vbe_display_api.txt
new file mode 100644
index 0000000..fddb78b
--- /dev/null
+++ b/kvm/vgabios/vbe_display_api.txt
@@ -0,0 +1,237 @@
+VBE Display API
+-------------------------------------------------------------------------------------------------------------
+  This document is part of the Bochs/VBEBios documentation,
+  it specifies the bochs host <-> vbebios client communication.
+  
+  That means, the display code implementation and the vbebios code depend
+  very heavily on each other. As such, this documents needs be synchronised
+  between bochs CVS and the vgabios CVS.
+  
+  This document does not describe how the VBEBios implements the VBE2/3 spec.
+  This document does not describe how the Bochs display code will display gfx based upon this spec.
+
+
+API History
+-----------
+0xb0c0            supports the following VBE_DISPI_ interfaces (present in Bochs 1.4):
+                  VBE_DISPI_INDEX_ID
+                  VBE_DISPI_INDEX_XRES
+                  VBE_DISPI_INDEX_YRES
+                  VBE_DISPI_INDEX_BPP
+                  VBE_DISPI_INDEX_ENABLE
+                  VBE_DISPI_INDEX_BANK
+
+                  Bpp format supported is:
+                  VBE_DISPI_BPP_8
+
+0xb0c1            supports 0xb0c0 VBE_DISPI_ interfaces, additional interfaces (present in Bochs 2.0):
+                  VBE_DISPI_INDEX_VIRT_WIDTH
+                  VBE_DISPI_INDEX_VIRT_HEIGHT
+                  VBE_DISPI_INDEX_X_OFFSET
+                  VBE_DISPI_INDEX_Y_OFFSET
+
+0xb0c2            supports 0xb0c1 VBE_DISPI_ interfaces, interfaces updated for
+                  additional features (present in Bochs 2.1):
+                  VBE_DISPI_INDEX_BPP supports >8bpp color depth (value = bits)
+                  VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_NOCLEARMEM and VBE_DISPI_LFB_ENABLED
+                  VBE i/o registers changed from 0xFF80/81 to 0x01CE/CF
+
+0xb0c3            supports 0xb0c2 VBE_DISPI_ interfaces, interfaces updated for
+                  additional features:
+                  VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_GETCAPS and VBE_DISPI_8BIT_DAC
+
+0xb0c4            VBE video memory increased to 8 MB
+
+
+History
+-------
+  Version 0.6     2002 Nov 23  Jeroen Janssen
+                  - Added LFB support
+                  - Added Virt width, height and x,y offset
+
+  Version 0.5     2002 March 08   Jeroen Janssen
+                  - Added documentation about panic behaviour / current limits of the data values.
+                  - Changed BPP API (in order to include future (A)RGB formats)
+                  - Initial version (based upon extended display text of the vbe bochs display patch)
+
+
+Todo
+----
+  Version 0.6+    [random order]
+                  - Add lots of different (A)RGB formats
+  
+References
+----------
+  [VBE3]          VBE 3 Specification at
+                  http://www.vesa.org/vbe3.pdf
+
+  [BOCHS]         Bochs Open Source IA-32 Emulator at
+                  http://bochs.sourceforge.net
+
+  [VBEBIOS]       VBE Bios for Bochs at
+                  http://savannah.gnu.org/projects/vgabios/
+
+  [Screenshots]   Screenshots of programs using the VBE Bios at
+                  http://japj.org/projects/bochs_plex86/screenshots.html
+
+Abbreviations
+-------------
+  VBE             Vesa Bios Extension
+  DISPI           (Bochs) Display Interface
+  BPP             Bits Per Pixel
+  LFB             Linear Frame Buffer
+
+
+#defines
+--------
+vbetables-gen.c
+  #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8
+
+vbe.h
+  #define VBE_DISPI_BANK_ADDRESS          0xA0000
+  #define VBE_DISPI_BANK_SIZE_KB          64
+
+  #define VBE_DISPI_MAX_XRES              1024
+  #define VBE_DISPI_MAX_YRES              768
+
+  #define VBE_DISPI_IOPORT_INDEX          0x01CE
+  #define VBE_DISPI_IOPORT_DATA           0x01CF
+
+  #define VBE_DISPI_INDEX_ID              0x0
+  #define VBE_DISPI_INDEX_XRES            0x1
+  #define VBE_DISPI_INDEX_YRES            0x2
+  #define VBE_DISPI_INDEX_BPP             0x3
+  #define VBE_DISPI_INDEX_ENABLE          0x4
+  #define VBE_DISPI_INDEX_BANK            0x5
+  #define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+  #define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+  #define VBE_DISPI_INDEX_X_OFFSET        0x8
+  #define VBE_DISPI_INDEX_Y_OFFSET        0x9
+
+  #define VBE_DISPI_ID0                   0xB0C0
+  #define VBE_DISPI_ID1                   0xB0C1
+  #define VBE_DISPI_ID2                   0xB0C2
+  #define VBE_DISPI_ID3                   0xB0C3
+  #define VBE_DISPI_ID4                   0xB0C4
+
+  #define VBE_DISPI_DISABLED              0x00
+  #define VBE_DISPI_ENABLED               0x01
+  #define VBE_DISPI_VBE_ENABLED           0x40
+  #define VBE_DISPI_NOCLEARMEM            0x80
+
+  #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+API
+---
+  The display api works by using a index (VBE_DISPI_IOPORT_INDEX) and
+  data (VBE_DISPI_IOPORT_DATA) ioport. One writes the index of the parameter to the index port.
+  Next, the parameter value can be read or written.
+
+[0xb0c0]
+  * VBE_DISPI_INDEX_ID  : WORD {R,W}
+    This parameter can be used to detect the current display API (both bochs & vbebios).
+    The bios writes VBE_DISPI_ID0 to the dataport and reads it back again.
+    This way, the display code knows the vbebios 'ID' and the vbebios can check if the correct
+    display code is present.
+    As a result, a PANIC can be generated if an incompatible vbebios/display code combination is detected.
+    This panic can be generated from the bochs display code (NOT the bios, see Notes).
+
+    Example values: VBE_DISPI_ID0
+
+  * VBE_DISPI_INDEX_XRES : WORD {R,W}
+    This parameter can be used to read/write the vbe display X resolution (in pixels).
+    It's illegal to set the XRES when the VBE is enabled (display code should generate PANIC).
+
+    If the value written exceeds VBE_DISPI_MAX_XRES, the display code needs to generate a PANIC.
+
+    Example values:   320,640,800,1024
+
+  * VBE_DISPI_INDEX_YRES : WORD {R,W}
+    This parameter can be used to read/write the vbe display Y resolution (in pixels).
+    It's illegal to set the YRES when the VBE is enabled (display code should generate PANIC).
+
+    If the value written exceeds VBE_DISPI_MAX_YRES, the display code needs to generate a PANIC.
+
+    Example values:   200,400,480,600,768
+
+  * VBE_DISPI_INDEX_BPP : WORD {R,W}
+    This parameter can be used to read/write the vbe display BPP.
+    It's illegal to set the BPP when the VBE is enabled (display code should generate PANIC).
+
+    If the value written is an incompatible BPP, the display code needs to generate a PANIC.
+
+    Example values:   VBE_DISPI_BPP_8
+
+  * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+    This parameter can be used to read/write the vbe ENABLED state.
+    If the bios writes VBE_DISPI_ENABLED then the display code will setup a hostside display mode
+    with the current XRES, YRES and BPP settings.
+    If the bios write VBE_DISPI_DISABLED then the display code will switch back to normal vga mode behaviour.
+
+    Example values: VBE_DISPI_ENABLED, VBE_DISPI_DISABLED
+
+  * VBE_DISPI_INDEX_BANK : WORD {R,W}
+    This parameter can be used to read/write the current selected BANK (at 0xA0000).
+    This can be used for switching banks in banked mode.
+
+[0xb0c1]
+  * VBE_DISPI_INDEX_VIRT_WIDTH : WORD {R,W}
+    This parameter can be used to read/write the current virtual width.
+    Upon enabling a mode, this will be set to the current xres
+    Setting this field during enabled mode will result in the virtual width to be changed.
+    Value will be adjusted if current setting is not possible.
+
+  * VBE_DISPI_INDEX_VIRT_HEIGHT : WORD {R}
+    This parameter can be read in order to obtain the current virtual height.
+    This setting will be adjusted after setting a virtual width in order to stay within limit of video memory.
+
+  * VBE_DISPI_INDEX_X_OFFSET : WORD {R,W}
+    The current X offset (in pixels!) of the visible screen part.
+    Writing a new offset will also result in a complete screen refresh.
+
+  * VBE_DISPI_INDEX_Y_OFFSET : WORD {R,W}
+    The current Y offset (in pixels!) of the visible screen part.
+    Writing a new offset will also result in a complete screen refresh.
+
+
+[0xb0c2]
+  * VBE_DISPI_INDEX_BPP : WORD {R,W}
+    The value written is now the number of bits per pixel. A value of 0 is treated
+    the same as 8 for backward compatibilty. These values are supported: 8, 15,
+    16, 24 and 32. The value of 4 is not yet handled in the VBE code.
+  * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+    The new flag VBE_DISPI_NOCLEARMEM allows to preserve the VBE video memory.
+    The new flag VBE_DISPI_LFB_ENABLED indicates the usage of the LFB.
+
+[0xb0c3]
+  * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+    If the new flag VBE_DISPI_GETCAPS is enabled, the xres, yres and bpp registers
+    return the gui capabilities.
+    The new flag VBE_DISPI_8BIT_DAC switches the DAC to 8 bit mode.
+
+[0xb0c4]
+  * VBE_DISPI_TOTAL_VIDEO_MEMORY_MB set to 8 (moved to auto-generated vbetables.h)
+
+Displaying GFX (banked mode)
+--------------
+  What happens is that the total screen is devided in banks of 'VBE_DISPI_BANK_SIZE_KB' KiloByte in size.
+  If you want to set a pixel you can calculate its bank by doing:
+
+    offset = pixel_x + pixel_y * resolution_x;
+    bank = offset / 64 Kb (rounded 1.9999 -> 1)
+
+    bank_pixel_pos = offset - bank * 64Kb
+
+  Now you can set the current bank and put the pixel at VBE_DISPI_BANK_ADDRESS + bank_pixel_pos
+
+Displaying GFX (linear frame buffer mode)
+--------------
+  NOT WRITTEN YET
+
+Notes
+-----
+  * Since the XRES/YRES/BPP may not be written when VBE is enabled, if you want to switch from one VBE mode
+    to another, you will need to disable VBE first.
+
+  * Note when the bios doesn't find a valid DISPI_ID, it can disable the VBE functions. This allows people to
+    use the same bios for both vbe enabled and disabled bochs executables.
diff --git a/kvm/vgabios/vbetables-gen.c b/kvm/vgabios/vbetables-gen.c
new file mode 100644
index 0000000..3bf979d
--- /dev/null
+++ b/kvm/vgabios/vbetables-gen.c
@@ -0,0 +1,264 @@
+/* Generate the VGABIOS VBE Tables */
+#include <stdlib.h>
+#include <stdio.h>
+
+#define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 16
+
+typedef struct {
+    int width;
+    int height;
+    int depth;
+    int mode;
+} ModeInfo;
+
+ModeInfo modes[] = {
+    /* standard VESA modes */
+{ 640, 400, 8                          , 0x100},
+{ 640, 480, 8                          , 0x101},
+{ 800, 600, 4                          , 0x102},
+{ 800, 600, 8                          , 0x103},
+{ 1024, 768, 4                         , 0x104},
+{ 1024, 768, 8                         , 0x105},
+{ 1280, 1024, 4                        , 0x106},
+{ 1280, 1024, 8                        , 0x107},
+{ 320, 200, 15                       , 0x10D},
+{ 320, 200, 16                        , 0x10E},
+{ 320, 200, 24                        , 0x10F},
+{ 640, 480, 15                       , 0x110},
+{ 640, 480, 16                        , 0x111},
+{ 640, 480, 24                        , 0x112},
+{ 800, 600, 15                       , 0x113},
+{ 800, 600, 16                        , 0x114},
+{ 800, 600, 24                        , 0x115},
+{ 1024, 768, 15                      , 0x116},
+{ 1024, 768, 16                       , 0x117},
+{ 1024, 768, 24                       , 0x118},
+{ 1280, 1024, 15                     , 0x119},
+{ 1280, 1024, 16                      , 0x11A},
+{ 1280, 1024, 24                      , 0x11B},
+{ 1600, 1200, 8                        , 0x11C},
+{ 1600, 1200, 15                     , 0x11D},
+{ 1600, 1200, 16                      , 0x11E},
+{ 1600, 1200, 24                      , 0x11F},
+
+      /* BOCHS/PLE, 86 'own' mode numbers */
+{ 320, 200, 32                        , 0x140},
+{ 640, 400, 32                        , 0x141},
+{ 640, 480, 32                        , 0x142},
+{ 800, 600, 32                        , 0x143},
+{ 1024, 768, 32                       , 0x144},
+{ 1280, 1024, 32                      , 0x145},
+{ 320, 200, 8                           , 0x146},
+{ 1600, 1200, 32                      , 0x147},
+{ 1152, 864, 8                      , 0x148},
+{ 1152, 864, 15                      , 0x149},
+{ 1152, 864, 16                      , 0x14a},
+{ 1152, 864, 24                      , 0x14b},
+{ 1152, 864, 32                      , 0x14c},
+{ 1280, 768, 16                      , 0x175},
+{ 1280, 768, 24                      , 0x176},
+{ 1280, 768, 32                      , 0x177},
+{ 1280, 800, 16                      , 0x178},
+{ 1280, 800, 24                      , 0x179},
+{ 1280, 800, 32                      , 0x17a},
+{ 1280, 960, 16                      , 0x17b},
+{ 1280, 960, 24                      , 0x17c},
+{ 1280, 960, 32                      , 0x17d},
+{ 1440, 900, 16                      , 0x17e},
+{ 1440, 900, 24                      , 0x17f},
+{ 1440, 900, 32                      , 0x180},
+{ 1400, 1050, 16                     , 0x181},
+{ 1400, 1050, 24                     , 0x182},
+{ 1400, 1050, 32                     , 0x183},
+{ 1680, 1050, 16                     , 0x184},
+{ 1680, 1050, 24                     , 0x185},
+{ 1680, 1050, 32                     , 0x186},
+{ 1920, 1200, 16                     , 0x187},
+{ 1920, 1200, 24                     , 0x188},
+{ 1920, 1200, 32                     , 0x189},
+{ 2560, 1600, 16                     , 0x18a},
+{ 2560, 1600, 24                     , 0x18b},
+{ 2560, 1600, 32                     , 0x18c},
+{ 0, },
+};
+
+int main(int argc, char **argv)
+{
+  const ModeInfo *pm;
+  int pages, pitch;
+  int r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos;
+  const char *str;
+  long vram_size = VBE_DISPI_TOTAL_VIDEO_MEMORY_MB * 1024 * 1024;
+
+  printf("/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n");
+  printf("#define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB %d\n\n", VBE_DISPI_TOTAL_VIDEO_MEMORY_MB);
+  printf("static ModeInfoListItem mode_info_list[]=\n");
+  printf("{\n");
+  for (pm = modes; pm->mode != 0; pm++) {
+    if (pm->depth == 4)
+      pitch = (pm->width + 7) / 8;
+    else
+      pitch = pm->width * ((pm->depth + 7) / 8);
+    pages = vram_size / (pm->height * pitch);
+    if (pages > 0) {
+      printf("{ 0x%04x, /* %dx%dx%d */\n", 
+             pm->mode, pm->width, pm->height, pm->depth);
+      if (pm->depth == 4)
+        printf("{ /*Bit16u ModeAttributes*/ %s,\n", 
+               "VBE_MODE_ATTRIBUTE_SUPPORTED | "
+               "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | "
+               "VBE_MODE_ATTRIBUTE_COLOR_MODE | "
+               "VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT | "
+               "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE");
+      else
+        printf("{ /*Bit16u ModeAttributes*/ %s,\n", 
+               "VBE_MODE_ATTRIBUTE_SUPPORTED | "
+               "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | "
+               "VBE_MODE_ATTRIBUTE_COLOR_MODE | "
+               "VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | "
+               "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE");
+      printf("/*Bit8u  WinAAttributes*/ %s,\n",
+             "VBE_WINDOW_ATTRIBUTE_RELOCATABLE | "
+             "VBE_WINDOW_ATTRIBUTE_READABLE | "
+             "VBE_WINDOW_ATTRIBUTE_WRITEABLE");
+
+      printf("/*Bit8u  WinBAttributes*/ %d,\n", 0);
+
+      printf("/*Bit16u WinGranularity*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
+
+      printf("/*Bit16u WinSize*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
+
+      printf("/*Bit16u WinASegment*/ %s,\n", "VGAMEM_GRAPH");
+
+      printf("/*Bit16u WinBSegment*/ 0x%04x,\n", 0);
+
+      printf("/*Bit32u WinFuncPtr*/ %d,\n", 0);
+
+      printf("/*Bit16u BytesPerScanLine*/ %d,\n", pitch);
+
+      // Mandatory information for VBE 1.2 and above
+      printf("/*Bit16u XResolution*/ %d,\n", pm->width);
+      printf("/*Bit16u YResolution*/ %d,\n", pm->height);
+      printf("/*Bit8u  XCharSize*/ %d,\n", 8);
+      printf("/*Bit8u  YCharSize*/ %d,\n", 16);
+      if (pm->depth == 4) {
+        printf("/*Bit8u  NumberOfPlanes*/ %d,\n", 4);
+      } else {
+        printf("/*Bit8u  NumberOfPlanes*/ %d,\n", 1);
+      }
+      printf("/*Bit8u  BitsPerPixel*/ %d,\n", pm->depth);
+      printf("/*Bit8u  NumberOfBanks*/ %d,\n", 
+             (pm->height * pitch + 65535) / 65536);
+
+      if (pm->depth == 4)
+        str = "VBE_MEMORYMODEL_PLANAR";
+      else if (pm->depth == 8)
+        str = "VBE_MEMORYMODEL_PACKED_PIXEL";
+      else
+        str = "VBE_MEMORYMODEL_DIRECT_COLOR";
+      printf("/*Bit8u  MemoryModel*/ %s,\n", str);
+      printf("/*Bit8u  BankSize*/ %d,\n", 0);
+      if (pm->depth == 4)
+        printf("/*Bit8u  NumberOfImagePages*/ %d,\n", (pages / 4) - 1);
+      else
+        printf("/*Bit8u  NumberOfImagePages*/ %d,\n", pages - 1);
+      printf("/*Bit8u  Reserved_page*/ %d,\n", 0);
+
+      // Direct Color fields (required for direct/6 and YUV/7 memory models)
+      switch(pm->depth) {
+        case 15:
+          r_size = 5;
+          r_pos = 10;
+          g_size = 5;
+          g_pos = 5;
+          b_size = 5;
+          b_pos = 0;
+          a_size = 1;
+          a_pos = 15;
+          break;
+        case 16:
+          r_size = 5;
+          r_pos = 11;
+          g_size = 6;
+          g_pos = 5;
+          b_size = 5;
+          b_pos = 0;
+          a_size = 0;
+          a_pos = 0;
+          break;
+        case 24:
+          r_size = 8;
+          r_pos = 16;
+          g_size = 8;
+          g_pos = 8;
+          b_size = 8;
+          b_pos = 0;
+          a_size = 0;
+          a_pos = 0;
+          break;
+        case 32:
+          r_size = 8;
+          r_pos = 16;
+          g_size = 8;
+          g_pos = 8;
+          b_size = 8;
+          b_pos = 0;
+          a_size = 8;
+          a_pos = 24;
+          break;
+        default:
+          r_size = 0;
+          r_pos = 0;
+          g_size = 0;
+          g_pos = 0;
+          b_size = 0;
+          b_pos = 0;
+          a_size = 0;
+          a_pos = 0;
+          break;
+      }
+
+      printf("/*Bit8u  RedMaskSize*/ %d,\n", r_size);               
+      printf("/*Bit8u  RedFieldPosition*/ %d,\n", r_pos);          
+      printf("/*Bit8u  GreenMaskSize*/ %d,\n", g_size);             
+      printf("/*Bit8u  GreenFieldPosition*/ %d,\n", g_pos);        
+      printf("/*Bit8u  BlueMaskSize*/ %d,\n", b_size);              
+      printf("/*Bit8u  BlueFieldPosition*/ %d,\n", b_pos);         
+      printf("/*Bit8u  RsvdMaskSize*/ %d,\n", a_size);              
+      printf("/*Bit8u  RsvdFieldPosition*/ %d,\n", a_pos);         
+      if (pm->depth == 32)
+        printf("/*Bit8u  DirectColorModeInfo*/ %s,\n",
+               "VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE");
+      else
+        printf("/*Bit8u  DirectColorModeInfo*/ %s,\n", "0");
+
+// Mandatory information for VBE 2.0 and above
+      if (pm->depth > 4)
+        printf("/*Bit32u PhysBasePtr*/ %s,\n",
+               "VBE_DISPI_LFB_PHYSICAL_ADDRESS");
+      else
+        printf("/*Bit32u PhysBasePtr*/ %s,\n", "0");
+      printf("/*Bit32u OffScreenMemOffset*/ %d,\n", 0);
+      printf("/*Bit16u OffScreenMemSize*/ %d,\n", 0);
+      // Mandatory information for VBE 3.0 and above
+      printf("/*Bit16u LinBytesPerScanLine*/ %d,\n", pitch);
+      printf("/*Bit8u  BnkNumberOfPages*/ %d,\n", 0);
+      printf("/*Bit8u  LinNumberOfPages*/ %d,\n", 0);
+      printf("/*Bit8u  LinRedMaskSize*/ %d,\n", r_size);
+      printf("/*Bit8u  LinRedFieldPosition*/ %d,\n", r_pos);
+      printf("/*Bit8u  LinGreenMaskSize*/ %d,\n", g_size);
+      printf("/*Bit8u  LinGreenFieldPosition*/ %d,\n", g_pos);
+      printf("/*Bit8u  LinBlueMaskSize*/ %d,\n", b_size);
+      printf("/*Bit8u  LinBlueFieldPosition*/ %d,\n", b_pos);
+      printf("/*Bit8u  LinRsvdMaskSize*/ %d,\n", a_size);
+      printf("/*Bit8u  LinRsvdFieldPosition*/ %d,\n", a_pos);
+      printf("/*Bit32u MaxPixelClock*/ %d,\n", 0);
+      printf("} },\n");
+    }
+  }
+  printf("{ VBE_VESA_MODE_END_OF_LIST,\n");
+  printf("{ 0,\n");
+  printf("} },\n");
+  printf("};\n");
+  return 0;
+}
diff --git a/kvm/vgabios/vgabios.c b/kvm/vgabios/vgabios.c
new file mode 100644
index 0000000..e6fe2a0
--- /dev/null
+++ b/kvm/vgabios/vgabios.c
@@ -0,0 +1,3853 @@
+// ============================================================================================
+/*
+ * vgabios.c
+ */
+// ============================================================================================
+//  
+//  Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library 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
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// 
+// ============================================================================================
+//  
+//  This VGA Bios is specific to the plex86/bochs Emulated VGA card. 
+//  You can NOT drive any physical vga card with it. 
+//     
+// ============================================================================================
+//  
+//  This file contains code ripped from :
+//   - rombios.c of plex86 
+//
+//  This VGA Bios contains fonts from :
+//   - fntcol16.zip (c) by Joseph Gil avalable at :
+//      ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+//     These fonts are public domain 
+//
+//  This VGA Bios is based on information taken from :
+//   - Kevin Lawton's vga card emulation for bochs/plex86
+//   - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+//   - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+//   - Michael Abrash's Graphics Programming Black Book
+//   - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
+//   - DOSEMU 1.0.1 source code for several tables values and formulas
+//
+// Thanks for patches, comments and ideas to :
+//   - techt@pikeonline.net
+//
+// ============================================================================================
+
+#include "vgabios.h"
+
+#ifdef VBE
+#include "vbe.h"
+#endif
+
+#define USE_BX_INFO
+
+/* Declares */
+static Bit8u          read_byte();
+static Bit16u         read_word();
+static void           write_byte();
+static void           write_word();
+static Bit8u          inb();
+static Bit16u         inw();
+static void           outb();
+static void           outw();
+
+static Bit16u         get_SS();
+
+// Output
+static void           printf();
+static void           unimplemented();
+static void           unknown();
+
+static Bit8u find_vga_entry();
+
+static void memsetb();
+static void memsetw();
+static void memcpyb();
+static void memcpyw();
+
+static void biosfn_set_video_mode();
+static void biosfn_set_cursor_shape();
+static void biosfn_set_cursor_pos();
+static void biosfn_get_cursor_pos();
+static void biosfn_set_active_page();
+static void biosfn_scroll();
+static void biosfn_read_char_attr();
+static void biosfn_write_char_attr();
+static void biosfn_write_char_only();
+static void biosfn_write_pixel();
+static void biosfn_read_pixel();
+static void biosfn_write_teletype();
+static void biosfn_perform_gray_scale_summing();
+static void biosfn_load_text_user_pat();
+static void biosfn_load_text_8_14_pat();
+static void biosfn_load_text_8_8_pat();
+static void biosfn_load_text_8_16_pat();
+static void biosfn_load_gfx_8_8_chars();
+static void biosfn_load_gfx_user_chars();
+static void biosfn_load_gfx_8_14_chars();
+static void biosfn_load_gfx_8_8_dd_chars();
+static void biosfn_load_gfx_8_16_chars();
+static void biosfn_get_font_info();
+static void biosfn_alternate_prtsc();
+static void biosfn_switch_video_interface();
+static void biosfn_enable_video_refresh_control();
+static void biosfn_write_string();
+static void biosfn_read_state_info();
+static void biosfn_read_video_state_size();
+static Bit16u biosfn_save_video_state();
+static Bit16u biosfn_restore_video_state();
+extern Bit8u video_save_pointer_table[];
+
+// This is for compiling with gcc2 and gcc3
+#define ASM_START #asm
+#define ASM_END   #endasm
+
+ASM_START
+
+MACRO SET_INT_VECTOR
+  push ds
+  xor ax, ax
+  mov ds, ax
+  mov ax, ?3
+  mov ?1*4, ax
+  mov ax, ?2
+  mov ?1*4+2, ax
+  pop ds
+MEND
+
+ASM_END
+
+ASM_START
+.text
+.rom
+.org 0
+
+use16 386
+
+vgabios_start:
+.byte	0x55, 0xaa	/* BIOS signature, required for BIOS extensions */
+
+.byte	0x40		/* BIOS extension length in units of 512 bytes */
+
+
+vgabios_entry_point:
+           
+  jmp vgabios_init_func
+
+#ifdef PCIBIOS
+.org 0x18
+.word vgabios_pci_data
+#endif
+
+// Info from Bart Oldeman
+.org 0x1e
+.ascii  "IBM"
+.byte   0x00
+
+vgabios_name:
+.ascii	"Plex86/Bochs VGABios"
+#ifdef PCIBIOS
+.ascii	" (PCI)"
+#endif
+.ascii	" "
+.byte	0x00
+
+vgabios_version:
+#ifndef VGABIOS_VERS
+.ascii	"current-cvs"
+#else
+.ascii VGABIOS_VERS
+#endif
+.ascii	" "
+
+vgabios_date:
+.ascii  VGABIOS_DATE
+.byte   0x0a,0x0d
+.byte	0x00
+
+vgabios_copyright:
+.ascii	"(C) 2008 the LGPL VGABios developers Team"
+.byte	0x0a,0x0d
+.byte	0x00
+
+vgabios_license:
+.ascii	"This VGA/VBE Bios is released under the GNU LGPL"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte	0x00
+
+vgabios_website:
+.ascii	"Please visit :"
+.byte	0x0a,0x0d
+;;.ascii  " . http://www.plex86.org"
+;;.byte	0x0a,0x0d
+.ascii	" . http://bochs.sourceforge.net"
+.byte	0x0a,0x0d
+.ascii	" . http://www.nongnu.org/vgabios"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte	0x00
+
+#ifdef PCIBIOS
+vgabios_pci_data:
+.ascii "PCIR"
+#ifdef CIRRUS
+.word 0x1013
+.word 0x00b8 // CLGD5446
+#else
+#error "Unknown PCI vendor and device id"
+#endif
+.word 0 // reserved
+.word 0x18 // dlen
+.byte 0 // revision
+.byte 0x0 // class,hi: vga display
+.word 0x300 // class,lo: vga display
+.word 0x40 // bios size
+.word 1 // revision
+.byte 0 // intel x86 data
+.byte 0x80 // last image
+.word 0 // reserved
+#endif
+
+
+;; ============================================================================================
+;;
+;; Init Entry point
+;;
+;; ============================================================================================
+vgabios_init_func:
+
+;; init vga card
+  call init_vga_card
+
+;; init basic bios vars
+  call init_bios_area
+
+#ifdef VBE  
+;; init vbe functions
+  call vbe_init  
+#endif
+
+;; set int10 vect
+  SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler)
+
+#ifdef CIRRUS
+  call cirrus_init
+#endif
+
+;; display splash screen
+  call _display_splash_screen
+
+;; init video mode and clear the screen
+  mov ax,#0x0003
+  int #0x10
+
+;; show info
+  call _display_info
+
+#ifdef VBE  
+;; show vbe info
+  call vbe_display_info  
+#endif
+
+#ifdef CIRRUS
+;; show cirrus info
+  call cirrus_display_info
+#endif
+
+  retf
+ASM_END
+
+/*
+ *  int10 handled here
+ */
+ASM_START
+vgabios_int10_handler:
+  pushf
+#ifdef DEBUG
+  push es
+  push ds
+  pusha
+  mov   bx, #0xc000
+  mov   ds, bx
+  call _int10_debugmsg
+  popa
+  pop ds
+  pop es
+#endif
+  cmp   ah, #0x0f
+  jne   int10_test_1A
+  call  biosfn_get_video_mode
+  jmp   int10_end
+int10_test_1A:
+  cmp   ah, #0x1a
+  jne   int10_test_0B
+  call  biosfn_group_1A
+  jmp   int10_end
+int10_test_0B:
+  cmp   ah, #0x0b
+  jne   int10_test_1103
+  call  biosfn_group_0B
+  jmp   int10_end
+int10_test_1103:
+  cmp   ax, #0x1103
+  jne   int10_test_12
+  call  biosfn_set_text_block_specifier
+  jmp   int10_end
+int10_test_12:
+  cmp   ah, #0x12
+  jne   int10_test_101B
+  cmp   bl, #0x10
+  jne   int10_test_BL30
+  call  biosfn_get_ega_info
+  jmp   int10_end
+int10_test_BL30:
+  cmp   bl, #0x30
+  jne   int10_test_BL31
+  call  biosfn_select_vert_res
+  jmp   int10_end
+int10_test_BL31:
+  cmp   bl, #0x31
+  jne   int10_test_BL32
+  call  biosfn_enable_default_palette_loading
+  jmp   int10_end
+int10_test_BL32:
+  cmp   bl, #0x32
+  jne   int10_test_BL33
+  call  biosfn_enable_video_addressing
+  jmp   int10_end
+int10_test_BL33:
+  cmp   bl, #0x33
+  jne   int10_test_BL34
+  call  biosfn_enable_grayscale_summing
+  jmp   int10_end
+int10_test_BL34:
+  cmp   bl, #0x34
+  jne   int10_normal
+  call  biosfn_enable_cursor_emulation
+  jmp   int10_end
+int10_test_101B:
+  cmp   ax, #0x101b
+  je    int10_normal
+  cmp   ah, #0x10
+#ifndef VBE
+  jne   int10_normal
+#else
+  jne   int10_test_4F
+#endif
+  call  biosfn_group_10
+  jmp   int10_end
+#ifdef VBE
+int10_test_4F:
+  cmp   ah, #0x4f
+  jne   int10_normal
+  cmp   al, #0x03
+  jne   int10_test_vbe_05
+  call  vbe_biosfn_return_current_mode
+  jmp   int10_end
+int10_test_vbe_05:
+  cmp   al, #0x05
+  jne   int10_test_vbe_06
+  call  vbe_biosfn_display_window_control
+  jmp   int10_end
+int10_test_vbe_06:
+  cmp   al, #0x06
+  jne   int10_test_vbe_07
+  call  vbe_biosfn_set_get_logical_scan_line_length
+  jmp   int10_end
+int10_test_vbe_07:
+  cmp   al, #0x07
+  jne   int10_test_vbe_08
+  call  vbe_biosfn_set_get_display_start
+  jmp   int10_end
+int10_test_vbe_08:
+  cmp   al, #0x08
+  jne   int10_test_vbe_0A
+  call  vbe_biosfn_set_get_dac_palette_format
+  jmp   int10_end
+int10_test_vbe_0A:
+  cmp   al, #0x0A
+  jne   int10_normal
+  call  vbe_biosfn_return_protected_mode_interface
+  jmp   int10_end
+#endif
+
+int10_normal:
+  push es
+  push ds
+  pusha
+
+;; We have to set ds to access the right data segment
+  mov   bx, #0xc000
+  mov   ds, bx
+  call _int10_func
+
+  popa
+  pop ds
+  pop es
+int10_end:
+  popf
+  iret
+ASM_END
+
+#include "vgatables.h"
+#include "vgafonts.h"
+
+/*
+ * Boot time harware inits 
+ */
+ASM_START
+init_vga_card:
+;; switch to color mode and enable CPU access 480 lines
+  mov dx, #0x3C2
+  mov al, #0xC3
+  outb dx,al
+
+;; more than 64k 3C4/04
+  mov dx, #0x3C4
+  mov al, #0x04
+  outb dx,al
+  mov dx, #0x3C5
+  mov al, #0x02
+  outb dx,al
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+  mov  bx, #msg_vga_init
+  push bx
+  call _printf
+#endif
+  inc  sp
+  inc  sp
+  ret
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+msg_vga_init:
+.ascii "VGABios $Id$"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ *  Boot time bios area inits 
+ */
+ASM_START
+init_bios_area:
+  push  ds
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+
+;; init detected hardware BIOS Area
+  mov   bx, # BIOSMEM_INITIAL_MODE
+  mov   ax, [bx]
+  and   ax, #0xffcf
+;; set 80x25 color (not clear from RBIL but usual)
+  or    ax, #0x0020
+  mov   [bx], ax
+
+;; Just for the first int10 find its children
+
+;; the default char height
+  mov   bx, # BIOSMEM_CHAR_HEIGHT
+  mov   al, #0x10
+  mov   [bx], al
+
+;; Clear the screen 
+  mov   bx, # BIOSMEM_VIDEO_CTL
+  mov   al, #0x60
+  mov   [bx], al
+
+;; Set the basic screen we have
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   al, #0xf9
+  mov   [bx], al
+
+;; Set the basic modeset options
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, #0x51
+  mov   [bx], al
+
+;; Set the  default MSR
+  mov   bx, # BIOSMEM_CURRENT_MSR
+  mov   al, #0x09
+  mov   [bx], al
+
+  pop ds
+  ret
+
+_video_save_pointer_table:
+  .word _video_param_table
+  .word 0xc000
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ *  Boot time Splash screen
+ */
+static void display_splash_screen()
+{
+}
+
+// --------------------------------------------------------------------------------------------
+/*
+ *  Tell who we are
+ */
+
+static void display_info()
+{
+ASM_START
+ mov ax,#0xc000
+ mov ds,ax
+ mov si,#vgabios_name
+ call _display_string
+ mov si,#vgabios_version
+ call _display_string
+ 
+ ;;mov si,#vgabios_copyright
+ ;;call _display_string
+ ;;mov si,#crlf
+ ;;call _display_string
+
+ mov si,#vgabios_license
+ call _display_string
+ mov si,#vgabios_website
+ call _display_string
+ASM_END
+}
+
+static void display_string()
+{
+ // Get length of string
+ASM_START
+ mov ax,ds
+ mov es,ax
+ mov di,si
+ xor cx,cx
+ not cx
+ xor al,al
+ cld
+ repne 
+  scasb
+ not cx
+ dec cx
+ push cx
+
+ mov ax,#0x0300
+ mov bx,#0x0000
+ int #0x10
+ 
+ pop cx
+ mov ax,#0x1301
+ mov bx,#0x000b
+ mov bp,si
+ int #0x10
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+#ifdef DEBUG
+static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ // 0E is write char...
+ if(GET_AH()!=0x0E)
+  printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+/*
+ * int10 main dispatcher
+ */
+static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+
+ // BIOS functions
+ switch(GET_AH())
+  {
+   case 0x00:
+     biosfn_set_video_mode(GET_AL());
+     switch(GET_AL()&0x7F)
+      {case 6: 
+        SET_AL(0x3F);
+        break;
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+       case 7:
+        SET_AL(0x30);
+        break;
+      default:
+        SET_AL(0x20);
+      }
+     break;
+   case 0x01:
+     biosfn_set_cursor_shape(GET_CH(),GET_CL());
+     break;
+   case 0x02:
+     biosfn_set_cursor_pos(GET_BH(),DX);
+     break;
+   case 0x03:
+     biosfn_get_cursor_pos(GET_BH(),&CX,&DX);
+     break;
+   case 0x04:
+     // Read light pen pos (unimplemented)
+#ifdef DEBUG
+     unimplemented();
+#endif
+     AX=0x00;
+     BX=0x00;
+     CX=0x00;
+     DX=0x00;
+     break;
+   case 0x05:
+     biosfn_set_active_page(GET_AL());
+     break;
+   case 0x06:
+     biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
+     break;
+   case 0x07:
+     biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
+     break;
+   case 0x08:
+     biosfn_read_char_attr(GET_BH(),&AX);
+     break;
+   case 0x09:
+     biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
+     break;
+   case 0x0A:
+     biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
+     break;
+   case 0x0C:
+     biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
+     break;
+   case 0x0D:
+     biosfn_read_pixel(GET_BH(),CX,DX,&AX);
+     break;
+   case 0x0E:
+     // Ralf Brown Interrupt list is WRONG on bh(page)
+     // We do output only on the current page !
+     biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
+     break;
+   case 0x10:
+     // All other functions of group AH=0x10 rewritten in assembler
+     biosfn_perform_gray_scale_summing(BX,CX);
+     break;
+   case 0x11:
+     switch(GET_AL())
+      {
+       case 0x00:
+       case 0x10:
+        biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
+        break;
+       case 0x01:
+       case 0x11:
+        biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
+        break;
+       case 0x02:
+       case 0x12:
+        biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
+        break;
+       case 0x04:
+       case 0x14:
+        biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
+        break;
+       case 0x20:
+        biosfn_load_gfx_8_8_chars(ES,BP);
+        break;
+       case 0x21:
+        biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
+        break;
+       case 0x22:
+        biosfn_load_gfx_8_14_chars(GET_BL());
+        break;
+       case 0x23:
+        biosfn_load_gfx_8_8_dd_chars(GET_BL());
+        break;
+       case 0x24:
+        biosfn_load_gfx_8_16_chars(GET_BL());
+        break;
+       case 0x30:
+        biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX);
+        break;
+#ifdef DEBUG
+       default:
+        unknown();
+#endif
+      }
+     
+     break;
+   case 0x12:
+     switch(GET_BL())
+      {
+       case 0x20:
+        biosfn_alternate_prtsc();
+        break;
+       case 0x35:
+        biosfn_switch_video_interface(GET_AL(),ES,DX);
+        SET_AL(0x12);
+        break;
+       case 0x36:
+        biosfn_enable_video_refresh_control(GET_AL());
+        SET_AL(0x12);
+        break;
+#ifdef DEBUG
+       default:
+        unknown();
+#endif
+      }
+     break;
+   case 0x13:
+     biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
+     break;
+   case 0x1B:
+     biosfn_read_state_info(BX,ES,DI);
+     SET_AL(0x1B);
+     break;
+   case 0x1C:
+     switch(GET_AL())
+      {
+       case 0x00:
+        biosfn_read_video_state_size(CX,&BX);
+        break;
+       case 0x01:
+        biosfn_save_video_state(CX,ES,BX);
+        break;
+       case 0x02:
+        biosfn_restore_video_state(CX,ES,BX);
+        break;
+#ifdef DEBUG
+       default:
+        unknown();
+#endif
+      }
+     SET_AL(0x1C);
+     break;
+
+#ifdef VBE 
+   case 0x4f:
+     if (vbe_has_vbe_display()) {
+       switch(GET_AL())
+       {
+         case 0x00:
+          vbe_biosfn_return_controller_information(&AX,ES,DI);
+          break;
+         case 0x01:
+          vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+          break;
+         case 0x02:
+          vbe_biosfn_set_mode(&AX,BX,ES,DI);
+          break;
+         case 0x04:
+          vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+          break;
+         case 0x09:
+          //FIXME
+#ifdef DEBUG
+          unimplemented();
+#endif
+          // function failed
+          AX=0x100;
+          break;
+         case 0x0A:
+          //FIXME
+#ifdef DEBUG
+          unimplemented();
+#endif
+          // function failed
+          AX=0x100;
+          break;
+         default:
+#ifdef DEBUG
+          unknown();
+#endif   		 
+          // function failed
+          AX=0x100;
+          }
+        }
+        else {
+          // No VBE display
+          AX=0x0100;
+          }
+        break;
+#endif
+
+#ifdef DEBUG
+   default:
+     unknown();
+#endif
+  }
+}
+
+// ============================================================================================
+// 
+// BIOS functions
+// 
+// ============================================================================================
+
+static void biosfn_set_video_mode(mode) Bit8u mode; 
+{// mode: Bit 7 is 1 if no clear screen
+
+ // Should we clear the screen ?
+ Bit8u noclearmem=mode&0x80;
+ Bit8u line,mmask,*palette,vpti;
+ Bit16u i,twidth,theightm1,cheight;
+ Bit8u modeset_ctl,video_ctl,vga_switches;
+ Bit16u crtc_addr;
+ 
+#ifdef VBE
+ if (vbe_has_vbe_display()) { 
+   dispi_set_enable(VBE_DISPI_DISABLED);
+  }
+#endif // def VBE
+ 
+ // The real mode
+ mode=mode&0x7f;
+
+ // find the entry in the video modes
+ line=find_vga_entry(mode);
+
+#ifdef DEBUG
+ printf("mode search %02x found line %02x\n",mode,line);
+#endif
+
+ if(line==0xFF)
+  return;
+
+ vpti=line_to_vpti[line];
+ twidth=video_param_table[vpti].twidth;
+ theightm1=video_param_table[vpti].theightm1;
+ cheight=video_param_table[vpti].cheight;
+ 
+ // Read the bios vga control
+ video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
+
+ // Read the bios vga switches
+ vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
+
+ // Read the bios mode set control
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+
+ // Then we know the number of lines
+// FIXME
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if((modeset_ctl&0x08)==0)
+  {// Set the PEL mask
+   outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
+
+   // Set the whole dac always, from 0
+   outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+
+   // From which palette
+   switch(vga_modes[line].dacmodel)
+    {case 0:
+      palette=&palette0;
+      break;
+     case 1:
+      palette=&palette1;
+      break;
+     case 2:
+      palette=&palette2;
+      break;
+     case 3:
+      palette=&palette3;
+      break;
+    }
+   // Always 256*3 values
+   for(i=0;i<0x0100;i++)
+    {if(i<=dac_regs[vga_modes[line].dacmodel])
+      {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
+       outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
+       outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
+      }
+     else
+      {outb(VGAREG_DAC_DATA,0);
+       outb(VGAREG_DAC_DATA,0);
+       outb(VGAREG_DAC_DATA,0);
+      }
+    }
+   if((modeset_ctl&0x02)==0x02)
+    {
+     biosfn_perform_gray_scale_summing(0x00, 0x100);
+    }
+  }
+
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ // Set Attribute Ctl
+ for(i=0;i<=0x13;i++)
+  {outb(VGAREG_ACTL_ADDRESS,i);
+   outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
+  }
+ outb(VGAREG_ACTL_ADDRESS,0x14);
+ outb(VGAREG_ACTL_WRITE_DATA,0x00);
+
+ // Set Sequencer Ctl
+ outb(VGAREG_SEQU_ADDRESS,0);
+ outb(VGAREG_SEQU_DATA,0x03);
+ for(i=1;i<=4;i++)
+  {outb(VGAREG_SEQU_ADDRESS,i);
+   outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
+  }
+
+ // Set Grafx Ctl
+ for(i=0;i<=8;i++)
+  {outb(VGAREG_GRDC_ADDRESS,i);
+   outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
+  }
+
+ // Set CRTC address VGA or MDA 
+ crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
+
+ // Disable CRTC write protection
+ outw(crtc_addr,0x0011);
+ // Set CRTC regs
+ for(i=0;i<=0x18;i++)
+  {outb(crtc_addr,i);
+   outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
+  }
+
+ // Set the misc register
+ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
+
+ // Enable video
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+ inb(VGAREG_ACTL_RESET);
+
+ if(noclearmem==0x00)
+  {
+   if(vga_modes[line].class==TEXT)
+    {
+     memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
+    }
+   else
+    {
+     if(mode<0x0d)
+      {
+       memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
+      }
+     else
+      {
+       outb( VGAREG_SEQU_ADDRESS, 0x02 );
+       mmask = inb( VGAREG_SEQU_DATA );
+       outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
+       memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
+       outb( VGAREG_SEQU_DATA, mmask );
+      }
+    }
+  }
+
+ // Set the BIOS mem
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
+ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l);
+ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
+ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
+ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
+
+ // FIXME We nearly have the good tables. to be reworked
+ write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08);    // 8 is VGA should be ok for now
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table);
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000);
+
+ // FIXME
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
+ 
+ // Set cursor shape
+ if(vga_modes[line].class==TEXT)
+  {
+   biosfn_set_cursor_shape(0x06,0x07);
+  }
+
+ // Set cursor pos for page 0..7
+ for(i=0;i<8;i++)
+  biosfn_set_cursor_pos(i,0x0000);
+
+ // Set active page 0
+ biosfn_set_active_page(0x00);
+
+ // Write the fonts in memory
+ if(vga_modes[line].class==TEXT)
+  { 
+ASM_START
+  ;; copy and activate 8x16 font
+  mov ax, #0x1104
+  mov bl, #0x00
+  int #0x10
+  mov ax, #0x1103
+  mov bl, #0x00
+  int #0x10
+ASM_END
+  }
+
+ // Set the ints 0x1F and 0x43
+ASM_START
+ SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
+ASM_END
+
+  switch(cheight)
+   {case 8:
+ASM_START
+     SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
+ASM_END
+     break;
+    case 14:
+ASM_START
+     SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
+ASM_END
+     break;
+    case 16:
+ASM_START
+     SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
+ASM_END
+     break;
+   }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_shape (CH,CL) 
+Bit8u CH;Bit8u CL; 
+{Bit16u cheight,curs,crtc_addr;
+ Bit8u modeset_ctl;
+
+ CH&=0x3f;
+ CL&=0x1f;
+
+ curs=(CH<<8)+CL;
+ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs);
+
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+ cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
+ if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20))
+  {
+   if(CL!=(CH+1))
+    {
+     CH = ((CH+1) * cheight / 8) -1;
+    }
+   else
+    {
+     CH = ((CL+1) * cheight / 8) - 2;
+    }
+   CL = ((CL+1) * cheight / 8) - 1;
+  }
+
+ // CTRC regs 0x0a and 0x0b
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0a);
+ outb(crtc_addr+1,CH);
+ outb(crtc_addr,0x0b);
+ outb(crtc_addr+1,CL);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_pos (page, cursor) 
+Bit8u page;Bit16u cursor;
+{
+ Bit8u xcurs,ycurs,current;
+ Bit16u nbcols,nbrows,address,crtc_addr;
+
+ // Should not happen...
+ if(page>7)return;
+
+ // Bios cursor pos
+ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
+
+ // Set the hardware cursor
+ current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+ if(page==current)
+  {
+   // Get the dimensions
+   nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+   nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+
+   xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+ 
+   // Calculate the address knowing nbcols nbrows and page num
+   address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
+   
+   // CRTC regs 0x0e and 0x0f
+   crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+   outb(crtc_addr,0x0e);
+   outb(crtc_addr+1,(address&0xff00)>>8);
+   outb(crtc_addr,0x0f);
+   outb(crtc_addr+1,address&0x00ff);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_cursor_pos (page,shape, pos) 
+Bit8u page;Bit16u *shape;Bit16u *pos;
+{
+ Bit16u ss=get_SS();
+
+ // Default
+ write_word(ss, shape, 0);
+ write_word(ss, pos, 0);
+
+ if(page>7)return;
+ // FIXME should handle VGA 14/16 lines
+ write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE));
+ write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2));
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_active_page (page) 
+Bit8u page;
+{
+ Bit16u cursor,dummy,crtc_addr;
+ Bit16u nbcols,nbrows,address;
+ Bit8u mode,line;
+
+ if(page>7)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get pos curs pos for the right page 
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Get the dimensions
+   nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+   nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ 
+   // Calculate the address knowing nbcols nbrows and page num
+   address=SCREEN_MEM_START(nbcols,nbrows,page);
+   write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
+
+   // Start address
+   address=SCREEN_IO_START(nbcols,nbrows,page);
+  }
+ else
+  {
+   address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l);
+  }
+
+ // CRTC regs 0x0c and 0x0d
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0c);
+ outb(crtc_addr+1,(address&0xff00)>>8);
+ outb(crtc_addr,0x0d);
+ outb(crtc_addr+1,address&0x00ff);
+
+ // And change the BIOS page
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
+
+#ifdef DEBUG
+ printf("Set active page %02x address %04x\n",page,address);
+#endif
+
+ // Display the cursor, now the page is active
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=ysrc*cheight*nbcols+xstart;
+ dest=ydest*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0105);
+ for(i=0;i<cheight;i++)
+  {
+   memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
+  }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=ystart*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ for(i=0;i<cheight;i++)
+  {
+   memsetb(0xa000,dest+i*nbcols,attr,cols);
+  }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=((ysrc*cheight*nbcols)>>1)+xstart;
+ dest=((ydest*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+  {
+   if (i & 1)
+     memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
+   else
+     memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=((ystart*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+  {
+   if (i & 1)
+     memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
+   else
+     memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
+Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir;
+{
+ // page == 0xFF if current
+
+ Bit8u mode,line,cheight,bpp,cols;
+ Bit16u nbcols,nbrows,i;
+ Bit16u address;
+
+ if(rul>rlr)return;
+ if(cul>clr)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ // Get the current page
+ if(page==0xFF)
+  page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ if(rlr>=nbrows)rlr=nbrows-1;
+ if(clr>=nbcols)clr=nbcols-1;
+ if(nblines>nbrows)nblines=0;
+ cols=clr-cul+1;
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page);
+#ifdef DEBUG
+   printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
+#endif
+
+   if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+    {
+     memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols);
+    }
+   else
+    {// if Scroll up
+     if(dir==SCROLL_UP)
+      {for(i=rul;i<=rlr;i++)
+        {
+         if((i+nblines>rlr)||(nblines==0))
+          memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+         else
+          memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
+        }
+      }
+     else
+      {for(i=rlr;i>=rul;i--)
+        {
+         if((i<rul+nblines)||(nblines==0))
+          memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+         else
+          memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
+         if (i>rlr) break;
+        }
+      }
+    }
+  }
+ else
+  {
+   // FIXME gfx mode not complete
+   cheight=video_param_table[line_to_vpti[line]].cheight;
+   switch(vga_modes[line].memmodel)
+    {
+     case PLANAR4:
+     case PLANAR1:
+       if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+        {
+         outw(VGAREG_GRDC_ADDRESS, 0x0205);
+         memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
+         outw(VGAREG_GRDC_ADDRESS, 0x0005);
+        }
+       else
+        {// if Scroll up
+         if(dir==SCROLL_UP)
+          {for(i=rul;i<=rlr;i++)
+            {
+             if((i+nblines>rlr)||(nblines==0))
+              vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
+            }
+          }
+         else
+          {for(i=rlr;i>=rul;i--)
+            {
+             if((i<rul+nblines)||(nblines==0))
+              vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
+             if (i>rlr) break;
+            }
+          }
+        }
+       break;
+     case CGA:
+       bpp=vga_modes[line].pixbits;
+       if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+        {
+         memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
+        }
+       else
+        {
+         if(bpp==2)
+          {
+           cul<<=1;
+           cols<<=1;
+           nbcols<<=1;
+          }
+         // if Scroll up
+         if(dir==SCROLL_UP)
+          {for(i=rul;i<=rlr;i++)
+            {
+             if((i+nblines>rlr)||(nblines==0))
+              vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
+            }
+          }
+         else
+          {for(i=rlr;i>=rul;i--)
+            {
+             if((i<rul+nblines)||(nblines==0))
+              vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
+             if (i>rlr) break;
+            }
+          }
+        }
+       break;
+#ifdef DEBUG
+     default:
+       printf("Scroll in graphics mode ");
+       unimplemented();
+#endif
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_char_attr (page,car) 
+Bit8u page;Bit16u *car;
+{Bit16u ss=get_SS();
+ Bit8u xcurs,ycurs,mode,line;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+   write_word(ss,car,read_word(vga_modes[line].sstart,address));
+  }
+ else
+  {
+   // FIXME gfx mode
+#ifdef DEBUG
+   unimplemented();
+#endif
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight;
+{
+ Bit8u i,j,mask;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ switch(cheight)
+  {case 14:
+    fdata = &vgafont14;
+    break;
+   case 16:
+    fdata = &vgafont16;
+    break;
+   default:
+    fdata = &vgafont8;
+  }
+ addr=xcurs+ycurs*cheight*nbcols;
+ src = car * cheight;
+ outw(VGAREG_SEQU_ADDRESS, 0x0f02);
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ if(attr&0x80)
+  {
+   outw(VGAREG_GRDC_ADDRESS, 0x1803);
+  }
+ else
+  {
+   outw(VGAREG_GRDC_ADDRESS, 0x0003);
+  }
+ for(i=0;i<cheight;i++)
+  {
+   dest=addr+i*nbcols;
+   for(j=0;j<8;j++)
+    {
+     mask=0x80>>j;
+     outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+     read_byte(0xa000,dest);
+     if(fdata[src+i]&mask)
+      {
+       write_byte(0xa000,dest,attr&0x0f);
+      }
+     else
+      {
+       write_byte(0xa000,dest,0x00);
+      }
+    }
+  }
+ASM_START
+  mov dx, # VGAREG_GRDC_ADDRESS
+  mov ax, #0xff08
+  out dx, ax
+  mov ax, #0x0005
+  out dx, ax
+  mov ax, #0x0003
+  out dx, ax
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=(xcurs*bpp)+ycurs*320;
+ src = car * 8;
+ for(i=0;i<8;i++)
+  {
+   dest=addr+(i>>1)*80;
+   if (i & 1) dest += 0x2000;
+   mask = 0x80;
+   if (bpp == 1)
+    {
+     if (attr & 0x80)
+      {
+       data = read_byte(0xb800,dest);
+      }
+     else
+      {
+       data = 0x00;
+      }
+     for(j=0;j<8;j++)
+      {
+       if (fdata[src+i] & mask)
+        {
+         if (attr & 0x80)
+          {
+           data ^= (attr & 0x01) << (7-j);
+          }
+         else
+          {
+           data |= (attr & 0x01) << (7-j);
+          }
+        }
+       mask >>= 1;
+      }
+     write_byte(0xb800,dest,data);
+    }
+   else
+    {
+     while (mask > 0)
+      {
+       if (attr & 0x80)
+        {
+         data = read_byte(0xb800,dest);
+        }
+       else
+        {
+         data = 0x00;
+        }
+       for(j=0;j<4;j++)
+        {
+         if (fdata[src+i] & mask)
+          {
+           if (attr & 0x80)
+            {
+             data ^= (attr & 0x03) << ((3-j)*2);
+            }
+           else
+            {
+             data |= (attr & 0x03) << ((3-j)*2);
+            }
+          }
+         mask >>= 1;
+        }
+       write_byte(0xb800,dest,data);
+       dest += 1;
+      }
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=xcurs*8+ycurs*nbcols*64;
+ src = car * 8;
+ for(i=0;i<8;i++)
+  {
+   dest=addr+i*nbcols*8;
+   mask = 0x80;
+   for(j=0;j<8;j++)
+    {
+     data = 0x00;
+     if (fdata[src+i] & mask)
+      {
+       data = attr;
+      }
+     write_byte(0xa000,dest+j,data);
+     mask >>= 1;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_attr (car,page,attr,count) 
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+   dummy=((Bit16u)attr<<8)+car;
+   memsetw(vga_modes[line].sstart,address,dummy,count);
+  }
+ else
+  {
+   // FIXME gfx mode not complete
+   cheight=video_param_table[line_to_vpti[line]].cheight;
+   bpp=vga_modes[line].pixbits;
+   while((count-->0) && (xcurs<nbcols))
+    {
+     switch(vga_modes[line].memmodel)
+      {
+       case PLANAR4:
+       case PLANAR1:
+         write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+         break;
+       case CGA:
+         write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+         break;
+       case LINEAR8:
+         write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+         break;
+#ifdef DEBUG
+       default:
+         unimplemented();
+#endif
+      }
+     xcurs++;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_only (car,page,attr,count)
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+   while(count-->0)
+    {write_byte(vga_modes[line].sstart,address,car);
+     address+=2;
+    }
+  }
+ else
+  {
+   // FIXME gfx mode not complete
+   cheight=video_param_table[line_to_vpti[line]].cheight;
+   bpp=vga_modes[line].pixbits;
+   while((count-->0) && (xcurs<nbcols))
+    {
+     switch(vga_modes[line].memmodel)
+      {
+       case PLANAR4:
+       case PLANAR1:
+         write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+         break;
+       case CGA:
+         write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+         break;
+       case LINEAR8:
+         write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+         break;
+#ifdef DEBUG
+       default:
+         unimplemented();
+#endif
+      }
+     xcurs++;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_0B:
+  cmp   bh, #0x00
+  je    biosfn_set_border_color
+  cmp   bh, #0x01
+  je    biosfn_set_palette
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+biosfn_set_border_color:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x00
+  out   dx, al
+  mov   al, bl
+  and   al, #0x0f
+  test  al, #0x08
+  jz    set_low_border
+  add   al, #0x08
+set_low_border:
+  out   dx, al
+  mov   cl, #0x01
+  and   bl, #0x10
+set_intensity_loop:
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xef
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  inc   cl
+  cmp   cl, #0x04
+  jne   set_intensity_loop
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+biosfn_set_palette:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   cl, #0x01
+  and   bl, #0x01
+set_cga_palette_loop:
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xfe
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  inc   cl
+  cmp   cl, #0x04
+  jne   set_cga_palette_loop
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
+{
+ Bit8u mode,line,mask,attr,data;
+ Bit16u addr;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+  {
+   case PLANAR4:
+   case PLANAR1:
+     addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+     mask = 0x80 >> (CX & 0x07);
+     outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+     outw(VGAREG_GRDC_ADDRESS, 0x0205);
+     data = read_byte(0xa000,addr);
+     if (AL & 0x80)
+      {
+       outw(VGAREG_GRDC_ADDRESS, 0x1803);
+      }
+     write_byte(0xa000,addr,AL);
+ASM_START
+     mov dx, # VGAREG_GRDC_ADDRESS
+     mov ax, #0xff08
+     out dx, ax
+     mov ax, #0x0005
+     out dx, ax
+     mov ax, #0x0003
+     out dx, ax
+ASM_END
+     break;
+   case CGA:
+     if(vga_modes[line].pixbits==2)
+      {
+       addr=(CX>>2)+(DX>>1)*80;
+      }
+     else
+      {
+       addr=(CX>>3)+(DX>>1)*80;
+      }
+     if (DX & 1) addr += 0x2000;
+     data = read_byte(0xb800,addr);
+     if(vga_modes[line].pixbits==2)
+      {
+       attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
+       mask = 0x03 << ((3 - (CX & 0x03)) * 2);
+      }
+     else
+      {
+       attr = (AL & 0x01) << (7 - (CX & 0x07));
+       mask = 0x01 << (7 - (CX & 0x07));
+      }
+     if (AL & 0x80)
+      {
+       data ^= attr;
+      }
+     else
+      {
+       data &= ~mask;
+       data |= attr;
+      }
+     write_byte(0xb800,addr,data);
+     break;
+   case LINEAR8:
+     addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+     write_byte(0xa000,addr,AL);
+     break;
+#ifdef DEBUG
+   default:
+     unimplemented();
+#endif
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX;
+{
+ Bit8u mode,line,mask,attr,data,i;
+ Bit16u addr;
+ Bit16u ss=get_SS();
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+  {
+   case PLANAR4:
+   case PLANAR1:
+     addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+     mask = 0x80 >> (CX & 0x07);
+     attr = 0x00;
+     for(i=0;i<4;i++)
+      {
+       outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
+       data = read_byte(0xa000,addr) & mask;
+       if (data > 0) attr |= (0x01 << i);
+      }
+     break;
+   case CGA:
+     addr=(CX>>2)+(DX>>1)*80;
+     if (DX & 1) addr += 0x2000;
+     data = read_byte(0xb800,addr);
+     if(vga_modes[line].pixbits==2)
+      {
+       attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
+      }
+     else
+      {
+       attr = (data >> (7 - (CX & 0x07))) & 0x01;
+      }
+     break;
+   case LINEAR8:
+     addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+     attr=read_byte(0xa000,addr);
+     break;
+   default:
+#ifdef DEBUG
+     unimplemented();
+#endif
+     attr = 0;
+  }
+ write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_teletype (car, page, attr, flag) 
+Bit8u car;Bit8u page;Bit8u attr;Bit8u flag;
+{// flag = WITH_ATTR / NO_ATTR
+
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // special case if page is 0xff, use current page
+ if(page==0xff)
+  page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ switch(car)
+  {
+   case 7:
+    //FIXME should beep
+    break;
+
+   case 8:
+    if(xcurs>0)xcurs--;
+    break;
+
+   case '\r':
+    xcurs=0;
+    break;
+
+   case '\n':
+    ycurs++;
+    break;
+
+   case '\t':
+    do
+     {
+      biosfn_write_teletype(' ',page,attr,flag);
+      biosfn_get_cursor_pos(page,&dummy,&cursor);
+      xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+     }while(xcurs%8==0);
+    break;
+
+   default:
+
+    if(vga_modes[line].class==TEXT)
+     {
+      // Compute the address  
+      address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+      // Write the char 
+      write_byte(vga_modes[line].sstart,address,car);
+
+      if(flag==WITH_ATTR)
+       write_byte(vga_modes[line].sstart,address+1,attr);
+     }
+    else
+     {
+      // FIXME gfx mode not complete
+      cheight=video_param_table[line_to_vpti[line]].cheight;
+      bpp=vga_modes[line].pixbits;
+      switch(vga_modes[line].memmodel)
+       {
+        case PLANAR4:
+        case PLANAR1:
+          write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+          break;
+        case CGA:
+          write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+          break;
+        case LINEAR8:
+          write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+          break;
+#ifdef DEBUG
+        default:
+          unimplemented();
+#endif
+       }
+     }
+    xcurs++;
+  }
+
+ // Do we need to wrap ?
+ if(xcurs==nbcols)
+  {xcurs=0;
+   ycurs++;
+  }
+
+ // Do we need to scroll ?
+ if(ycurs==nbrows)
+  {
+   if(vga_modes[line].class==TEXT)
+    {
+     biosfn_scroll(0x01,0x07,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+    }
+   else
+    {
+     biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+    }
+   ycurs-=1;
+  }
+ 
+ // Set the cursor for the page
+ cursor=ycurs; cursor<<=8; cursor+=xcurs;
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_video_mode:
+  push  ds
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  push  bx
+  mov   bx, # BIOSMEM_CURRENT_PAGE
+  mov   al, [bx]
+  pop   bx
+  mov   bh, al
+  push  bx
+  mov   bx, # BIOSMEM_VIDEO_CTL
+  mov   ah, [bx]
+  and   ah, #0x80
+  mov   bx, # BIOSMEM_CURRENT_MODE
+  mov   al, [bx]
+  or    al, ah
+  mov   bx, # BIOSMEM_NB_COLS
+  mov   ah, [bx]
+  pop   bx
+  pop   ds
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_10:
+  cmp   al, #0x00
+  jne   int10_test_1001
+  jmp   biosfn_set_single_palette_reg
+int10_test_1001:
+  cmp   al, #0x01
+  jne   int10_test_1002
+  jmp   biosfn_set_overscan_border_color
+int10_test_1002:
+  cmp   al, #0x02
+  jne   int10_test_1003
+  jmp   biosfn_set_all_palette_reg
+int10_test_1003:
+  cmp   al, #0x03
+  jne   int10_test_1007
+  jmp   biosfn_toggle_intensity
+int10_test_1007:
+  cmp   al, #0x07
+  jne   int10_test_1008
+  jmp   biosfn_get_single_palette_reg
+int10_test_1008:
+  cmp   al, #0x08
+  jne   int10_test_1009
+  jmp   biosfn_read_overscan_border_color
+int10_test_1009:
+  cmp   al, #0x09
+  jne   int10_test_1010
+  jmp   biosfn_get_all_palette_reg
+int10_test_1010:
+  cmp   al, #0x10
+  jne   int10_test_1012
+  jmp  biosfn_set_single_dac_reg
+int10_test_1012:
+  cmp   al, #0x12
+  jne   int10_test_1013
+  jmp   biosfn_set_all_dac_reg
+int10_test_1013:
+  cmp   al, #0x13
+  jne   int10_test_1015
+  jmp   biosfn_select_video_dac_color_page
+int10_test_1015:
+  cmp   al, #0x15
+  jne   int10_test_1017
+  jmp   biosfn_read_single_dac_reg
+int10_test_1017:
+  cmp   al, #0x17
+  jne   int10_test_1018
+  jmp   biosfn_read_all_dac_reg
+int10_test_1018:
+  cmp   al, #0x18
+  jne   int10_test_1019
+  jmp   biosfn_set_pel_mask
+int10_test_1019:
+  cmp   al, #0x19
+  jne   int10_test_101A
+  jmp   biosfn_read_pel_mask
+int10_test_101A:
+  cmp   al, #0x1a
+  jne   int10_group_10_unknown
+  jmp   biosfn_read_video_dac_state
+int10_group_10_unknown:
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+
+biosfn_set_single_palette_reg:
+  cmp   bl, #0x14
+  ja    no_actl_reg1
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, bl
+  out   dx, al
+  mov   al, bh
+  out   dx, al
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   ax
+no_actl_reg1:
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_overscan_border_color:
+  push  bx
+  mov   bl, #0x11
+  call  biosfn_set_single_palette_reg
+  pop   bx
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_palette_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   bx, dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   cl, #0x00
+  mov   dx, # VGAREG_ACTL_ADDRESS
+set_palette_loop:
+  mov   al, cl
+  out   dx, al
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  inc   cl
+  cmp   cl, #0x10
+  jne   set_palette_loop
+  mov   al, #0x11
+  out   dx, al
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_toggle_intensity:
+  push  ax
+  push  bx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x10
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xf7
+  and   bl, #0x01
+  shl   bl, 3
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_single_palette_reg:
+  cmp   bl, #0x14
+  ja    no_actl_reg2
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, bl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  mov   bh, al
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   ax
+no_actl_reg2:
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_overscan_border_color:
+  push  ax
+  push  bx
+  mov   bl, #0x11
+  call  biosfn_get_single_palette_reg
+  mov   al, bh
+  pop   bx
+  mov   bh, al
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_all_palette_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   bx, dx
+  mov   cl, #0x00
+get_palette_loop:
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  inc   cl
+  cmp   cl, #0x10
+  jne   get_palette_loop
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x11
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_single_dac_reg:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_DAC_WRITE_ADDRESS
+  mov   al, bl
+  out   dx, al
+  mov   dx, # VGAREG_DAC_DATA
+  pop   ax
+  push  ax
+  mov   al, ah
+  out   dx, al
+  mov   al, ch
+  out   dx, al
+  mov   al, cl
+  out   dx, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_dac_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_DAC_WRITE_ADDRESS
+  mov   al, bl
+  out   dx, al
+  pop   dx
+  push  dx
+  mov   bx, dx
+  mov   dx, # VGAREG_DAC_DATA
+set_dac_loop:
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  dec   cx
+  jnz   set_dac_loop
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_video_dac_color_page:
+  push  ax
+  push  bx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x10
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   bl, #0x01
+  jnz   set_dac_page
+  and   al, #0x7f
+  shl   bh, 7
+  or    al, bh
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  jmp   set_actl_normal
+set_dac_page:
+  push  ax
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x14
+  out   dx, al
+  pop   ax
+  and   al, #0x80
+  jnz   set_dac_16_page
+  shl   bh, 2
+set_dac_16_page:
+  and   bh, #0x0f
+  mov   al, bh
+  out   dx, al
+set_actl_normal:
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_single_dac_reg:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_DAC_READ_ADDRESS
+  mov   al, bl
+  out   dx, al
+  pop   ax
+  mov   ah, al
+  mov   dx, # VGAREG_DAC_DATA
+  in    al, dx
+  xchg  al, ah
+  push  ax
+  in    al, dx
+  mov   ch, al
+  in    al, dx
+  mov   cl, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_all_dac_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_DAC_READ_ADDRESS
+  mov   al, bl
+  out   dx, al
+  pop   dx
+  push  dx
+  mov   bx, dx
+  mov   dx, # VGAREG_DAC_DATA
+read_dac_loop:
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  dec   cx
+  jnz   read_dac_loop
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_pel_mask:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_PEL_MASK
+  mov   al, bl
+  out   dx, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_pel_mask:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_PEL_MASK
+  in    al, dx
+  mov   bl, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_video_dac_state:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x10
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  mov   bl, al
+  shr   bl, 7
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x14
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  mov   bh, al
+  and   bh, #0x0f
+  test  bl, #0x01
+  jnz   get_dac_16_page
+  shr   bh, 2
+get_dac_16_page:
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_perform_gray_scale_summing (start,count) 
+Bit16u start;Bit16u count;
+{Bit8u r,g,b;
+ Bit16u i;
+ Bit16u index;
+
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x00);
+
+ for( index = 0; index < count; index++ ) 
+  {
+   // set read address and switch to read mode
+   outb(VGAREG_DAC_READ_ADDRESS,start);
+   // get 6-bit wide RGB data values
+   r=inb( VGAREG_DAC_DATA );
+   g=inb( VGAREG_DAC_DATA );
+   b=inb( VGAREG_DAC_DATA );
+
+   // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+   i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
+
+   if(i>0x3f)i=0x3f;
+ 
+   // set write address and switch to write mode
+   outb(VGAREG_DAC_WRITE_ADDRESS,start);
+   // write new intensity value
+   outb( VGAREG_DAC_DATA, i&0xff );
+   outb( VGAREG_DAC_DATA, i&0xff );
+   outb( VGAREG_DAC_DATA, i&0xff );
+   start++;
+  }  
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+}
+
+// --------------------------------------------------------------------------------------------
+static void get_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0402
+ out dx, ax
+ mov ax, #0x0704
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0x0204
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0406
+ out dx, ax
+ASM_END
+}
+
+static void release_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0302
+ out dx, ax
+ mov ax, #0x0304
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_READ_MISC_OUTPUT
+ in  al, dx
+ and al, #0x01
+ shl al, 2
+ or  al, #0x0a
+ mov ah, al
+ mov al, #0x06
+ mov dx, # VGAREG_GRDC_ADDRESS
+ out dx, ax
+ mov ax, #0x0004
+ out dx, ax
+ mov ax, #0x1005
+ out dx, ax
+ASM_END
+}
+
+ASM_START
+idiv_u:
+  xor dx,dx
+  div bx
+  ret
+ASM_END
+
+static void set_scan_lines(lines) Bit8u lines;
+{
+ Bit16u crtc_addr,cols,page,vde;
+ Bit8u crtc_r9,ovl,rows;
+
+ crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr, 0x09);
+ crtc_r9 = inb(crtc_addr+1);
+ crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+ outb(crtc_addr+1, crtc_r9);
+ if(lines==8)
+  {
+   biosfn_set_cursor_shape(0x06,0x07);
+  }
+ else
+  {
+   biosfn_set_cursor_shape(lines-4,lines-3);
+  }
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
+ outb(crtc_addr, 0x12);
+ vde = inb(crtc_addr+1);
+ outb(crtc_addr, 0x07);
+ ovl = inb(crtc_addr+1);
+ vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+ rows = vde / lines;
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
+ cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
+}
+
+static void biosfn_load_text_user_pat (AL,ES,BP,CX,DX,BL,BH) Bit8u AL;Bit16u ES;Bit16u BP;Bit16u CX;Bit16u DX;Bit8u BL;Bit8u BH;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<CX;i++)
+  {
+   src = BP + i * BH;
+   dest = blockaddr + (DX + i) * 32;
+   memcpyb(0xA000, dest, ES, src, BH);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(BH);
+  }
+}
+
+static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+  {
+   src = i * 14;
+   dest = blockaddr + i * 32;
+   memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(14);
+  }
+}
+
+static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+  {
+   src = i * 8;
+   dest = blockaddr + i * 32;
+   memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(8);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_text_block_specifier:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_SEQU_ADDRESS
+  mov   ah, bl
+  mov   al, #0x03
+  out   dx, ax
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+  {
+   src = i * 16;
+   dest = blockaddr + i * 32;
+   memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(16);
+  }
+}
+
+static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_font_info (BH,ES,BP,CX,DX) 
+Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX;
+{Bit16u ss=get_SS();
+ 
+ switch(BH)
+  {case 0x00:
+    write_word(ss,ES,read_word(0x00,0x1f*4));
+    write_word(ss,BP,read_word(0x00,(0x1f*4)+2));
+    break;
+   case 0x01:
+    write_word(ss,ES,read_word(0x00,0x43*4));
+    write_word(ss,BP,read_word(0x00,(0x43*4)+2));
+    break;
+   case 0x02:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont14);
+    break;
+   case 0x03:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont8);
+    break;
+   case 0x04:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont8+128*8);
+    break;
+   case 0x05:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont14alt);
+    break;
+   case 0x06:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont16);
+    break;
+   case 0x07:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont16alt);
+    break;
+   default:
+    #ifdef DEBUG
+     printf("Get font info BH(%02x) was discarded\n",BH);
+    #endif
+    return;
+  }
+ // Set byte/char of on screen font
+ write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT));
+
+ // Set Highest char row
+ write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS));
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_ega_info:
+  push  ds
+  push  ax
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  xor   ch, ch
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   cl, [bx]
+  and   cl, #0x0f
+  mov   bx, # BIOSMEM_CRTC_ADDRESS
+  mov   ax, [bx]
+  mov   bx, #0x0003
+  cmp   ax, # VGAREG_MDA_CRTC_ADDRESS
+  jne   mode_ega_color
+  mov   bh, #0x01
+mode_ega_color:
+  pop   ax
+  pop   ds
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_alternate_prtsc()
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_vert_res:
+
+; res : 00 200 lines, 01 350 lines, 02 400 lines
+
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   ah, [bx]
+  cmp   dl, #0x01
+  je    vert_res_350
+  jb    vert_res_200
+  cmp   dl, #0x02
+  je    vert_res_400
+#ifdef DEBUG
+  mov   al, dl
+  xor   ah, ah
+  push  ax
+  mov   bx, #msg_vert_res
+  push  bx
+  call  _printf
+  add   sp, #4
+#endif
+  jmp   set_retcode
+vert_res_400:
+
+  ; reset modeset ctl bit 7 and set bit 4
+  ; set switches bit 3-0 to 0x09
+
+  and   al, #0x7f
+  or    al, #0x10
+  and   ah, #0xf0
+  or    ah, #0x09
+  jnz   set_vert_res
+vert_res_350:
+
+  ; reset modeset ctl bit 7 and bit 4
+  ; set switches bit 3-0 to 0x09
+
+  and   al, #0x6f
+  and   ah, #0xf0
+  or    ah, #0x09
+  jnz   set_vert_res
+vert_res_200:
+
+  ; set modeset ctl bit 7 and reset bit 4
+  ; set switches bit 3-0 to 0x08
+
+  and   al, #0xef
+  or    al, #0x80
+  and   ah, #0xf0
+  or    ah, #0x08
+set_vert_res:
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   [bx], al
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   [bx], ah
+set_retcode:
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+
+#ifdef DEBUG
+msg_vert_res:
+.ascii "Select vert res (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+
+
+biosfn_enable_default_palette_loading:
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  and   dl, #0x01
+  shl   dl, 3
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  and   al, #0xf7
+  or    al, dl
+  mov   [bx], al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+
+
+biosfn_enable_video_addressing:
+  push  bx
+  push  dx
+  mov   bl, al
+  and   bl, #0x01
+  xor   bl, #0x01
+  shl   bl, 1
+  mov   dx, # VGAREG_READ_MISC_OUTPUT
+  in    al, dx
+  and   al, #0xfd
+  or    al, bl
+  mov   dx, # VGAREG_WRITE_MISC_OUTPUT
+  out   dx, al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  ret
+
+
+biosfn_enable_grayscale_summing:
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  and   dl, #0x01
+  xor   dl, #0x01
+  shl   dl, 1
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  and   al, #0xfd
+  or    al, dl
+  mov   [bx], al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+
+
+biosfn_enable_cursor_emulation:
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  and   dl, #0x01
+  xor   dl, #0x01
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  and   al, #0xfe
+  or    al, dl
+  mov   [bx], al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset) 
+Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset;
+{
+ Bit16u newcurs,oldcurs,dummy;
+ Bit8u car,carattr;
+
+ // Read curs info for the page
+ biosfn_get_cursor_pos(page,&dummy,&oldcurs);
+
+ // if row=0xff special case : use current cursor position
+ if(row==0xff)
+  {col=oldcurs&0x00ff;
+   row=(oldcurs&0xff00)>>8;
+  }
+
+ newcurs=row; newcurs<<=8; newcurs+=col;
+ biosfn_set_cursor_pos(page,newcurs);
+ 
+ while(count--!=0)
+  {
+   car=read_byte(seg,offset++);
+   if((flag&0x02)!=0)
+    attr=read_byte(seg,offset++);
+
+   biosfn_write_teletype(car,page,attr,WITH_ATTR);
+  }
+ 
+ // Set back curs pos 
+ if((flag&0x01)==0)
+  biosfn_set_cursor_pos(page,oldcurs);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_1A:
+  cmp   al, #0x00
+  je    biosfn_read_display_code
+  cmp   al, #0x01
+  je    biosfn_set_display_code
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+biosfn_read_display_code:
+  push  ds
+  push  ax
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_DCC_INDEX
+  mov   al, [bx]
+  mov   bl, al
+  xor   bh, bh
+  pop   ax
+  mov   al, ah
+  pop   ds
+  ret
+biosfn_set_display_code:
+  push  ds
+  push  ax
+  push  bx
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   ax, bx
+  mov   bx, # BIOSMEM_DCC_INDEX
+  mov   [bx], al
+#ifdef DEBUG
+  mov   al, ah
+  xor   ah, ah
+  push  ax
+  mov   bx, #msg_alt_dcc
+  push  bx
+  call  _printf
+  add   sp, #4
+#endif
+  pop   bx
+  pop   ax
+  mov   al, ah
+  pop   ds
+  ret
+
+#ifdef DEBUG
+msg_alt_dcc:
+.ascii "Alternate Display code (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_state_info (BX,ES,DI) 
+Bit16u BX;Bit16u ES;Bit16u DI;
+{
+ // Address of static functionality table
+ write_word(ES,DI+0x00,&static_functionality);
+ write_word(ES,DI+0x02,0xC000);
+
+ // Hard coded copy from BIOS area. Should it be cleaner ?
+ memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
+ memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
+ 
+ write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
+ write_byte(ES,DI+0x26,0);
+ write_byte(ES,DI+0x27,16);
+ write_byte(ES,DI+0x28,0);
+ write_byte(ES,DI+0x29,8);
+ write_byte(ES,DI+0x2a,2);
+ write_byte(ES,DI+0x2b,0);
+ write_byte(ES,DI+0x2c,0);
+ write_byte(ES,DI+0x31,3);
+ write_byte(ES,DI+0x32,0);
+ 
+ memsetb(ES,DI+0x33,0,13);
+}
+
+// --------------------------------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------
+static Bit16u biosfn_read_video_state_size2 (CX) 
+     Bit16u CX;
+{
+    Bit16u size;
+    size = 0;
+    if (CX & 1) {
+        size += 0x46;
+    }
+    if (CX & 2) {
+        size += (5 + 8 + 5) * 2 + 6;
+    }
+    if (CX & 4) {
+        size += 3 + 256 * 3 + 1;
+}
+    return size;
+}
+
+static void biosfn_read_video_state_size (CX, BX) 
+     Bit16u CX; Bit16u *BX;
+{
+    Bit16u ss=get_SS();
+    write_word(ss, BX, biosfn_read_video_state_size2(CX));
+}
+
+static Bit16u biosfn_save_video_state (CX,ES,BX) 
+     Bit16u CX;Bit16u ES;Bit16u BX;
+{
+    Bit16u i, v, crtc_addr, ar_index;
+
+    crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
+    if (CX & 1) {
+        write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
+        write_byte(ES, BX, inb(crtc_addr)); BX++;
+        write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
+        inb(VGAREG_ACTL_RESET);
+        ar_index = inb(VGAREG_ACTL_ADDRESS);
+        write_byte(ES, BX, ar_index); BX++;
+        write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
+
+        for(i=1;i<=4;i++){
+            outb(VGAREG_SEQU_ADDRESS, i);
+            write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
+        }
+        outb(VGAREG_SEQU_ADDRESS, 0);
+        write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
+
+        for(i=0;i<=0x18;i++) {
+            outb(crtc_addr,i);
+            write_byte(ES, BX, inb(crtc_addr+1)); BX++;
+        }
+
+        for(i=0;i<=0x13;i++) {
+            inb(VGAREG_ACTL_RESET);
+            outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
+            write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
+        }
+        inb(VGAREG_ACTL_RESET);
+
+        for(i=0;i<=8;i++) {
+            outb(VGAREG_GRDC_ADDRESS,i);
+            write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
+        }
+
+        write_word(ES, BX, crtc_addr); BX+= 2;
+
+        /* XXX: read plane latches */
+        write_byte(ES, BX, 0); BX++;
+        write_byte(ES, BX, 0); BX++;
+        write_byte(ES, BX, 0); BX++;
+        write_byte(ES, BX, 0); BX++;
+    }
+    if (CX & 2) {
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
+        for(i=0;i<8;i++) {
+            write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
+            BX += 2;
+        }
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
+        /* current font */
+        write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
+        write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
+        write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
+        write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
+    }
+    if (CX & 4) {
+        /* XXX: check this */
+        write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
+        write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
+        write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
+        // Set the whole dac always, from 0
+        outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+        for(i=0;i<256*3;i++) {
+            write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
+        }
+        write_byte(ES, BX, 0); BX++; /* color select register */
+    }
+    return BX;
+}
+
+static Bit16u biosfn_restore_video_state (CX,ES,BX) 
+     Bit16u CX;Bit16u ES;Bit16u BX;
+{
+    Bit16u i, crtc_addr, v, addr1, ar_index;
+
+    if (CX & 1) {
+        // Reset Attribute Ctl flip-flop
+        inb(VGAREG_ACTL_RESET);
+
+        crtc_addr = read_word(ES, BX + 0x40);
+        addr1 = BX;
+        BX += 5;
+        
+        for(i=1;i<=4;i++){
+            outb(VGAREG_SEQU_ADDRESS, i);
+            outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
+        }
+        outb(VGAREG_SEQU_ADDRESS, 0);
+        outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
+
+        // Disable CRTC write protection
+        outw(crtc_addr,0x0011);
+        // Set CRTC regs
+        for(i=0;i<=0x18;i++) {
+            if (i != 0x11) {
+                outb(crtc_addr,i);
+                outb(crtc_addr+1, read_byte(ES, BX));
+            }
+            BX++;
+        }
+        // select crtc base address
+        v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
+        if (crtc_addr = 0x3d4)
+            v |= 0x01;
+        outb(VGAREG_WRITE_MISC_OUTPUT, v);
+
+        // enable write protection if needed
+        outb(crtc_addr, 0x11);
+        outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
+        
+        // Set Attribute Ctl
+        ar_index = read_byte(ES, addr1 + 0x03);
+        inb(VGAREG_ACTL_RESET);
+        for(i=0;i<=0x13;i++) {
+            outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
+            outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
+        }
+        outb(VGAREG_ACTL_ADDRESS, ar_index);
+        inb(VGAREG_ACTL_RESET);
+        
+        for(i=0;i<=8;i++) {
+            outb(VGAREG_GRDC_ADDRESS,i);
+            outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
+        }
+        BX += 2; /* crtc_addr */
+        BX += 4; /* plane latches */
+        
+        outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
+        outb(crtc_addr, read_byte(ES, addr1)); addr1++;
+        outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
+        addr1++;
+        outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
+    }
+    if (CX & 2) {
+        write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
+        write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
+        write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
+        write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
+        write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
+        write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
+        write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
+        write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
+        write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
+        write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
+        for(i=0;i<8;i++) {
+            write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
+            BX += 2;
+        }
+        write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
+        write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
+        /* current font */
+        write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
+        write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
+        write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
+        write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
+    }
+    if (CX & 4) {
+        BX++;
+        v = read_byte(ES, BX); BX++;
+        outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
+        // Set the whole dac always, from 0
+        outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+        for(i=0;i<256*3;i++) {
+            outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
+        }
+        BX++;
+        outb(VGAREG_DAC_WRITE_ADDRESS, v);
+    }
+    return BX;
+}
+
+// ============================================================================================
+//
+// Video Utils
+//
+// ============================================================================================
+ 
+// --------------------------------------------------------------------------------------------
+static Bit8u find_vga_entry(mode) 
+Bit8u mode;
+{
+ Bit8u i,line=0xFF;
+ for(i=0;i<=MODE_MAX;i++)
+  if(vga_modes[i].svgamode==mode)
+   {line=i;
+    break;
+   }
+ return line;
+}
+
+/* =========================================================== */
+/*
+ * Misc Utils
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static void memsetb(seg,offset,value,count)
+  Bit16u seg;
+  Bit16u offset;
+  Bit16u value;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+
+    mov  cx, 10[bp] ; count
+    cmp  cx, #0x00
+    je   memsetb_end
+    mov  ax, 4[bp] ; segment
+    mov  es, ax
+    mov  ax, 6[bp] ; offset
+    mov  di, ax
+    mov  al, 8[bp] ; value
+    cld
+    rep
+     stosb
+
+memsetb_end:
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memsetw(seg,offset,value,count)
+  Bit16u seg;
+  Bit16u offset;
+  Bit16u value;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+
+    mov  cx, 10[bp] ; count
+    cmp  cx, #0x00
+    je   memsetw_end
+    mov  ax, 4[bp] ; segment
+    mov  es, ax
+    mov  ax, 6[bp] ; offset
+    mov  di, ax
+    mov  ax, 8[bp] ; value
+    cld
+    rep
+     stosw
+
+memsetw_end:
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyb(dseg,doffset,sseg,soffset,count)
+  Bit16u dseg;
+  Bit16u doffset;
+  Bit16u sseg;
+  Bit16u soffset;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+    push ds
+    push si
+
+    mov  cx, 12[bp] ; count
+    cmp  cx, #0x0000
+    je   memcpyb_end
+    mov  ax, 4[bp] ; dsegment
+    mov  es, ax
+    mov  ax, 6[bp] ; doffset
+    mov  di, ax
+    mov  ax, 8[bp] ; ssegment
+    mov  ds, ax
+    mov  ax, 10[bp] ; soffset
+    mov  si, ax
+    cld
+    rep
+     movsb
+
+memcpyb_end:
+    pop si
+    pop ds
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyw(dseg,doffset,sseg,soffset,count)
+  Bit16u dseg;
+  Bit16u doffset;
+  Bit16u sseg;
+  Bit16u soffset;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+    push ds
+    push si
+
+    mov  cx, 12[bp] ; count
+    cmp  cx, #0x0000
+    je   memcpyw_end
+    mov  ax, 4[bp] ; dsegment
+    mov  es, ax
+    mov  ax, 6[bp] ; doffset
+    mov  di, ax
+    mov  ax, 8[bp] ; ssegment
+    mov  ds, ax
+    mov  ax, 10[bp] ; soffset
+    mov  si, ax
+    cld
+    rep
+     movsw
+
+memcpyw_end:
+    pop si
+    pop ds
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+/* =========================================================== */
+/*
+ * These functions where ripped from Kevin's rombios.c
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static Bit8u
+read_byte(seg, offset)
+  Bit16u seg;
+  Bit16u offset;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  al, [bx]
+    ;; al = return value (byte)
+    pop  ds
+    pop  bx
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static Bit16u
+read_word(seg, offset)
+  Bit16u seg;
+  Bit16u offset;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  ax, [bx]
+    ;; ax = return value (word)
+    pop  ds
+    pop  bx
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_byte(seg, offset, data)
+  Bit16u seg;
+  Bit16u offset;
+  Bit8u  data;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  al, 8[bp] ; data byte
+    mov  [bx], al  ; write data byte
+    pop  ds
+    pop  bx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_word(seg, offset, data)
+  Bit16u seg;
+  Bit16u offset;
+  Bit16u data;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  ax, 8[bp] ; data word
+    mov  [bx], ax  ; write data word
+    pop  ds
+    pop  bx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ Bit8u
+inb(port)
+  Bit16u port;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push dx
+    mov  dx, 4[bp]
+    in   al, dx
+    pop  dx
+
+  pop  bp
+ASM_END
+}
+
+  Bit16u
+inw(port)
+  Bit16u port;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push dx
+    mov  dx, 4[bp]
+    in   ax, dx
+    pop  dx
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+  void
+outb(port, val)
+  Bit16u port;
+  Bit8u  val;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push dx
+    mov  dx, 4[bp]
+    mov  al, 6[bp]
+    out  dx, al
+    pop  dx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+  void
+outw(port, val)
+  Bit16u port;
+  Bit16u  val;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push dx
+    mov  dx, 4[bp]
+    mov  ax, 6[bp]
+    out  dx, ax
+    pop  dx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+Bit16u get_SS()
+{
+ASM_START
+  mov  ax, ss
+ASM_END
+}
+
+#ifdef DEBUG
+void unimplemented()
+{
+ printf("--> Unimplemented\n");
+}
+
+void unknown()
+{
+ printf("--> Unknown int10\n");
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
+void printf(s)
+  Bit8u *s;
+{
+  Bit8u c, format_char;
+  Boolean  in_format;
+  unsigned format_width, i;
+  Bit16u  *arg_ptr;
+  Bit16u   arg_seg, arg, digit, nibble, shift_count;
+
+  arg_ptr = &s;
+  arg_seg = get_SS();
+
+  in_format = 0;
+  format_width = 0;
+
+  while (c = read_byte(0xc000, s)) {
+    if ( c == '%' ) {
+      in_format = 1;
+      format_width = 0;
+      }
+    else if (in_format) {
+      if ( (c>='0') && (c<='9') ) {
+        format_width = (format_width * 10) + (c - '0');
+        }
+      else if (c == 'x') {
+        arg_ptr++; // increment to next arg
+        arg = read_word(arg_seg, arg_ptr);
+        if (format_width == 0)
+          format_width = 4;
+        i = 0;
+        digit = format_width - 1;
+        for (i=0; i<format_width; i++) {
+          nibble = (arg >> (4 * digit)) & 0x000f;
+          if (nibble <= 9)
+            outb(0x0500, nibble + '0');
+          else
+            outb(0x0500, (nibble - 10) + 'A');
+          digit--;
+          }
+        in_format = 0;
+        }
+      //else if (c == 'd') {
+      //  in_format = 0;
+      //  }
+      }
+    else {
+      outb(0x0500, c);
+      }
+    s ++;
+    }
+}
+#endif
+
+#ifdef VBE
+#include "vbe.c"
+#endif
+
+#ifdef CIRRUS
+#include "clext.c"
+#endif
+
+// --------------------------------------------------------------------------------------------
+
+ASM_START 
+;; DATA_SEG_DEFS_HERE
+ASM_END
+
+ASM_START
+.ascii "vgabios ends here"
+.byte  0x00
+vgabios_end:
+.byte 0xCB
+;; BLOCK_STRINGS_BEGIN
+ASM_END
diff --git a/kvm/vgabios/vgabios.h b/kvm/vgabios/vgabios.h
new file mode 100644
index 0000000..3ad4bae
--- /dev/null
+++ b/kvm/vgabios/vgabios.h
@@ -0,0 +1,47 @@
+#ifndef vgabios_h_included
+#define vgabios_h_included
+
+/* Types */
+typedef unsigned char  Bit8u;
+typedef unsigned short Bit16u;
+typedef unsigned long  Bit32u;
+typedef unsigned short Boolean;
+
+/* Defines */
+
+#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
+#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
+#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
+#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
+#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
+#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
+#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
+#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
+
+#define GET_AL() ( AX & 0x00ff )
+#define GET_BL() ( BX & 0x00ff )
+#define GET_CL() ( CX & 0x00ff )
+#define GET_DL() ( DX & 0x00ff )
+#define GET_AH() ( AX >> 8 )
+#define GET_BH() ( BX >> 8 )
+#define GET_CH() ( CX >> 8 )
+#define GET_DH() ( DX >> 8 )
+
+#define SET_CF()     FLAGS |= 0x0001
+#define CLEAR_CF()   FLAGS &= 0xfffe
+#define GET_CF()     (FLAGS & 0x0001)
+
+#define SET_ZF()     FLAGS |= 0x0040
+#define CLEAR_ZF()   FLAGS &= 0xffbf
+#define GET_ZF()     (FLAGS & 0x0040)
+
+#define SCROLL_DOWN 0
+#define SCROLL_UP   1
+#define NO_ATTR     2
+#define WITH_ATTR   3
+
+#define SCREEN_SIZE(x,y) (((x*y*2)|0x00ff)+1)
+#define SCREEN_MEM_START(x,y,p) ((((x*y*2)|0x00ff)+1)*p)
+#define SCREEN_IO_START(x,y,p) ((((x*y)|0x00ff)+1)*p)
+
+#endif
diff --git a/kvm/vgabios/vgafonts.h b/kvm/vgabios/vgafonts.h
new file mode 100644
index 0000000..0c213e6
--- /dev/null
+++ b/kvm/vgabios/vgafonts.h
@@ -0,0 +1,784 @@
+/*
+ * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * The package is (c) by Joseph Gil
+ * The individual fonts are public domain
+ */ 
+static Bit8u vgafont8[256*8]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont14[256*14]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont16[256*16]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont14alt[1]={0x00};
+static Bit8u vgafont16alt[1]={0x00};
diff --git a/kvm/vgabios/vgatables.h b/kvm/vgabios/vgatables.h
new file mode 100644
index 0000000..3ac96bb
--- /dev/null
+++ b/kvm/vgabios/vgatables.h
@@ -0,0 +1,622 @@
+/*
+ *
+ * BIOS Memory 
+ *
+ */
+#define BIOSMEM_SEG 0x40
+
+#define BIOSMEM_INITIAL_MODE  0x10
+#define BIOSMEM_CURRENT_MODE  0x49
+#define BIOSMEM_NB_COLS       0x4A
+#define BIOSMEM_PAGE_SIZE     0x4C
+#define BIOSMEM_CURRENT_START 0x4E
+#define BIOSMEM_CURSOR_POS    0x50
+#define BIOSMEM_CURSOR_TYPE   0x60
+#define BIOSMEM_CURRENT_PAGE  0x62
+#define BIOSMEM_CRTC_ADDRESS  0x63
+#define BIOSMEM_CURRENT_MSR   0x65
+#define BIOSMEM_CURRENT_PAL   0x66
+#define BIOSMEM_NB_ROWS       0x84
+#define BIOSMEM_CHAR_HEIGHT   0x85
+#define BIOSMEM_VIDEO_CTL     0x87
+#define BIOSMEM_SWITCHES      0x88
+#define BIOSMEM_MODESET_CTL   0x89
+#define BIOSMEM_DCC_INDEX     0x8A
+#define BIOSMEM_VS_POINTER    0xA8
+#define BIOSMEM_VBE_FLAG      0xB9
+#define BIOSMEM_VBE_MODE      0xBA
+
+
+/*
+ *
+ * VGA registers
+ *
+ */
+#define VGAREG_ACTL_ADDRESS            0x3c0
+#define VGAREG_ACTL_WRITE_DATA         0x3c0
+#define VGAREG_ACTL_READ_DATA          0x3c1
+
+#define VGAREG_INPUT_STATUS            0x3c2
+#define VGAREG_WRITE_MISC_OUTPUT       0x3c2
+#define VGAREG_VIDEO_ENABLE            0x3c3
+#define VGAREG_SEQU_ADDRESS            0x3c4
+#define VGAREG_SEQU_DATA               0x3c5
+
+#define VGAREG_PEL_MASK                0x3c6
+#define VGAREG_DAC_STATE               0x3c7
+#define VGAREG_DAC_READ_ADDRESS        0x3c7
+#define VGAREG_DAC_WRITE_ADDRESS       0x3c8
+#define VGAREG_DAC_DATA                0x3c9
+
+#define VGAREG_READ_FEATURE_CTL        0x3ca
+#define VGAREG_READ_MISC_OUTPUT        0x3cc
+
+#define VGAREG_GRDC_ADDRESS            0x3ce
+#define VGAREG_GRDC_DATA               0x3cf
+
+#define VGAREG_MDA_CRTC_ADDRESS        0x3b4
+#define VGAREG_MDA_CRTC_DATA           0x3b5
+#define VGAREG_VGA_CRTC_ADDRESS        0x3d4
+#define VGAREG_VGA_CRTC_DATA           0x3d5
+
+#define VGAREG_MDA_WRITE_FEATURE_CTL   0x3ba
+#define VGAREG_VGA_WRITE_FEATURE_CTL   0x3da
+#define VGAREG_ACTL_RESET              0x3da
+
+#define VGAREG_MDA_MODECTL             0x3b8
+#define VGAREG_CGA_MODECTL             0x3d8
+#define VGAREG_CGA_PALETTE             0x3d9
+
+/* Video memory */
+#define VGAMEM_GRAPH 0xA000
+#define VGAMEM_CTEXT 0xB800
+#define VGAMEM_MTEXT 0xB000
+
+/*
+ *
+ * Tables of default values for each mode
+ *
+ */
+#define MODE_MAX   15
+#define TEXT       0x00
+#define GRAPH      0x01
+
+#define CTEXT      0x00
+#define MTEXT      0x01
+#define CGA        0x02
+#define PLANAR1    0x03
+#define PLANAR4    0x04
+#define LINEAR8    0x05
+
+// for SVGA
+#define LINEAR15   0x10
+#define LINEAR16   0x11
+#define LINEAR24   0x12
+#define LINEAR32   0x13
+
+typedef struct
+{Bit8u  svgamode;
+ Bit8u  class;    /* TEXT, GRAPH */
+ Bit8u  memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
+ Bit8u  pixbits;
+ Bit16u sstart;
+ Bit8u  pelmask;
+ Bit8u  dacmodel; /* 0 1 2 3 */
+} VGAMODES;
+
+static VGAMODES vga_modes[MODE_MAX+1]=
+{//mode  class  model bits sstart  pelm  dac
+ {0x00, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x01, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x02, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x03, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x04, GRAPH, CGA,     2, 0xB800, 0xFF, 0x01},
+ {0x05, GRAPH, CGA,     2, 0xB800, 0xFF, 0x01},
+ {0x06, GRAPH, CGA,     1, 0xB800, 0xFF, 0x01},
+ {0x07, TEXT,  MTEXT,   4, 0xB000, 0xFF, 0x00},
+ {0x0D, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x01},
+ {0x0E, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x01},
+ {0x0F, GRAPH, PLANAR1, 1, 0xA000, 0xFF, 0x00},
+ {0x10, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02},
+ {0x11, GRAPH, PLANAR1, 1, 0xA000, 0xFF, 0x02},
+ {0x12, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02},
+ {0x13, GRAPH, LINEAR8, 8, 0xA000, 0xFF, 0x03},
+ {0x6A, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02}
+};
+
+/* convert index in vga_modes[] to index in video_param_table[] */
+static Bit8u line_to_vpti[MODE_MAX+1]={
+    0x17, 0x17, 0x18, 0x18, 0x04, 0x05, 0x06, 0x07, 
+    0x0d, 0x0e, 0x11, 0x12, 0x1a, 0x1b, 0x1c, 0x1d,
+};
+
+/* Default Palette */
+#define DAC_MAX_MODEL 3
+
+static Bit8u dac_regs[DAC_MAX_MODEL+1]=
+{0x3f,0x3f,0x3f,0xff};
+
+/* standard BIOS Video Parameter Table */
+typedef struct {
+    Bit8u  twidth;
+    Bit8u  theightm1;
+    Bit8u  cheight;
+    Bit8u  slength_l;
+    Bit8u  slength_h;
+    Bit8u  sequ_regs[4];
+    Bit8u  miscreg;
+    Bit8u  crtc_regs[25];
+    Bit8u  actl_regs[20];
+    Bit8u  grdc_regs[9];
+} VideoParamTableEntry;
+
+static VideoParamTableEntry video_param_table[30] = {
+{
+ /* index=0x00 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x01 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x02 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x03 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x04 vga mode 0x04 */
+ 40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
+ 0x09, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff, /* crtc_regs */
+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x05 vga mode 0x05 */
+ 40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
+ 0x09, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff, /* crtc_regs */
+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x06 vga mode 0x06 */
+ 80, 24, 8, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x01, 0x01, 0x00, 0x06, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
+ 0xff, /* crtc_regs */
+ 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x01, 0x00, 0x01, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x07 vga mode 0x07 */
+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x66, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x08 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x09 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0a no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0b no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0c no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0d vga mode 0x0d */
+ 40, 24, 8, 0x00, 0x20, /* tw, th-1, ch, slength */
+ 0x09, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x0e vga mode 0x0e */
+ 80, 24, 8, 0x00, 0x40, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x0f no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x10 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x11 vga mode 0x0f */
+ 80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xa3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x12 vga mode 0x10 */
+ 80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xa3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x13 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x14 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x15 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x16 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x17 vga mode 0x01 */
+ 40, 24, 16, 0x00, 0x08, /* tw, th-1, ch, slength */
+ 0x08, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x67, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x18 vga mode 0x03 */
+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x67, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x19 vga mode 0x07 */
+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x66, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1a vga mode 0x11 */
+ 80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xe3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1b vga mode 0x12 */
+ 80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xe3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1c vga mode 0x13 */
+ 40, 24, 8, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x0e, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x41, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1d vga mode 0x6a */
+ 100, 36, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xe3, /* miscreg */
+ 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+};
+
+/* Mono */
+static Bit8u palette0[63+1][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f 
+};
+
+static Bit8u palette1[63+1][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f 
+};
+
+static Bit8u palette2[63+1][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
+  0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a, 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
+  0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f, 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
+  0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a, 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
+  0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f, 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
+  0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a, 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f 
+};
+
+static Bit8u palette3[256][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b, 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
+  0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28, 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f, 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
+  0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00, 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
+  0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f, 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
+  0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f, 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
+
+  0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f, 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
+  0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37, 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
+  0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f, 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
+  0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d, 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
+  0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a, 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
+  0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c, 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
+  0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00, 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
+  0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15, 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
+
+  0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c, 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
+  0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e, 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
+  0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18, 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
+  0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c, 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
+  0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14, 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
+  0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a, 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
+  0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10, 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
+  0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00, 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
+
+  0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c, 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
+  0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10, 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
+  0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08, 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
+  0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e, 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
+  0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10, 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
+  0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b, 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
+  0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f, 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
+};
+
+static Bit8u static_functionality[0x10]=
+{
+ /* 0 */ 0xff,  // All modes supported #1
+ /* 1 */ 0xe0,  // All modes supported #2
+ /* 2 */ 0x0f,  // All modes supported #3
+ /* 3 */ 0x00, 0x00, 0x00, 0x00,  // reserved
+ /* 7 */ 0x07,  // 200, 350, 400 scan lines
+ /* 8 */ 0x02,  // mamimum number of visible charsets in text mode
+ /* 9 */ 0x08,  // total number of charset blocks in text mode
+ /* a */ 0xe7,  // Change to add new functions
+ /* b */ 0x0c,  // Change to add new functions
+ /* c */ 0x00,  // reserved
+ /* d */ 0x00,  // reserved
+ /* e */ 0x00,  // Change to add new functions
+ /* f */ 0x00   // reserved
+};
diff --git a/monitor.c b/monitor.c
index c0dc48e..6ff6e1f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -56,6 +56,9 @@
 #include "json-streamer.h"
 #include "json-parser.h"
 #include "osdep.h"
+#include "exec-all.h"
+
+#include "qemu-kvm.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -727,6 +730,9 @@
         monitor_printf(mon, " (halted)");
     }
 
+    monitor_printf(mon, " thread_id=%" PRId64 " ",
+					qdict_get_int(cpu, "thread_id"));
+
     monitor_printf(mon, "\n");
 }
 
@@ -791,6 +797,7 @@
 #elif defined(TARGET_MIPS)
         qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
 #endif
+        qdict_put(cpu, "thread_id", qint_from_int(env->thread_id));
 
         qlist_append(cpu_list, cpu);
     }
@@ -805,6 +812,27 @@
         monitor_printf(mon, "Invalid CPU index\n");
 }
 
+static void do_cpu_set_nr(Monitor *mon, const QDict *qdict)
+{
+    int state, value;
+    const char *status;
+
+    status = qdict_get_str(qdict, "state");
+    value = qdict_get_int(qdict, "cpu");
+
+    if (!strcmp(status, "online"))
+       state = 1;
+    else if (!strcmp(status, "offline"))
+       state = 0;
+    else {
+        monitor_printf(mon, "invalid status: %s\n", status);
+        return;
+    }
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+    qemu_system_cpu_hot_add(value, state);
+#endif
+}
+
 static void do_info_jit(Monitor *mon)
 {
     dump_exec_info((FILE *)mon, monitor_fprintf);
@@ -2015,7 +2043,10 @@
 
     for (env = first_cpu; env != NULL; env = env->next_cpu)
         if (env->cpu_index == cpu_index) {
-            cpu_interrupt(env, CPU_INTERRUPT_NMI);
+            if (kvm_enabled())
+                kvm_inject_interrupt(env, CPU_INTERRUPT_NMI);
+            else
+                cpu_interrupt(env, CPU_INTERRUPT_NMI);
             break;
         }
 }
diff --git a/osdep.c b/osdep.c
index 9949606..b7b4411 100644
--- a/osdep.c
+++ b/osdep.c
@@ -104,7 +104,11 @@
 /* alloc shared memory pages */
 void *qemu_vmalloc(size_t size)
 {
+#ifndef __ia64__
     return qemu_memalign(getpagesize(), size);
+#else
+    return qemu_memalign(65536, size);
+#endif
 }
 
 void qemu_vfree(void *ptr)
diff --git a/pc-bios/bios-vista.diff b/pc-bios/bios-vista.diff
new file mode 100644
index 0000000..684a310
--- /dev/null
+++ b/pc-bios/bios-vista.diff
@@ -0,0 +1,17 @@
+Index: rombios32.c
+===================================================================
+RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v
+retrieving revision 1.9
+diff -u -w -r1.9 rombios32.c
+--- rombios32.c 20 Feb 2007 09:36:55 -0000      1.9
++++ rombios32.c 2 May 2007 06:07:31 -0000
+@@ -1191,7 +1191,7 @@
+ {
+     memcpy(h->signature, sig, 4);
+     h->length = cpu_to_le32(len);
+-    h->revision = 0;
++    h->revision = 1;
+ #ifdef BX_QEMU
+     memcpy(h->oem_id, "QEMU  ", 6);
+     memcpy(h->oem_table_id, "QEMU", 4);
+
diff --git a/pc-bios/bochs-manifest b/pc-bios/bochs-manifest
new file mode 100644
index 0000000..1b25aa4
--- /dev/null
+++ b/pc-bios/bochs-manifest
@@ -0,0 +1,24 @@
+.cvsignore                               1.2
+BIOS-bochs-latest                        1.145
+BIOS-bochs-legacy                        1.9
+Makefile.in                              1.26
+VGABIOS-elpin-2.40                       1.4
+VGABIOS-elpin-LICENSE                    1.3
+VGABIOS-lgpl-README                      1.9
+VGABIOS-lgpl-latest                      1.13
+VGABIOS-lgpl-latest-cirrus               1.5
+VGABIOS-lgpl-latest-cirrus-debug         1.5
+VGABIOS-lgpl-latest-debug                1.9
+acpi-dsdt.dsl                            1.1
+acpi-dsdt.hex                            1.1
+apmbios.S                                1.5
+bios_usage                               1.1
+biossums.c                               1.3
+makesym.perl                             1.1
+notes                                    1.1
+rombios.c                                1.178
+rombios.h                                1.4
+rombios32.c                              1.9
+rombios32.ld                             1.1
+rombios32start.S                         1.3
+usage.cc                                 1.4
diff --git a/pc-bios/openbios-sparc b/pc-bios/openbios-sparc
new file mode 100644
index 0000000..7a729aa
--- /dev/null
+++ b/pc-bios/openbios-sparc
Binary files differ
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index 54db882..84c7701 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -15,6 +15,8 @@
 
 build-all: multiboot.bin linuxboot.bin
 
+build-all: extboot.bin vapic.bin
+
 %.img: %.o
 	$(call quiet-command,$(LD) -Ttext 0 -e _start -s -o $@ $<,"  Building $(TARGET_DIR)$@")
 
diff --git a/pc-bios/optionrom/extboot.S b/pc-bios/optionrom/extboot.S
new file mode 100644
index 0000000..1e60f68
--- /dev/null
+++ b/pc-bios/optionrom/extboot.S
@@ -0,0 +1,695 @@
+/*
+ * Extended Boot Option ROM
+ *
+ * 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 Corporation, 2007
+ *   Authors: Anthony Liguori <aliguori@us.ibm.com>
+ */
+
+.code16
+.text
+	.global _start
+_start:
+	.short 0xaa55
+	.byte (_end - _start) / 512
+	push %eax
+	push %ds
+
+	/* setup ds so we can access the IVT */
+	xor %ax, %ax
+	mov %ax, %ds
+
+	/* there is one more bootable HD */
+	incb 0x0475
+
+	/* save old int 19 */
+	mov (0x19*4), %eax
+	mov %eax, %cs:old_int19
+
+	/* install out int 19 handler */
+	movw $int19_handler, (0x19*4)
+	mov %cs, (0x19*4+2)
+
+	pop %ds
+	pop %eax
+	lret
+
+int19_handler:
+	push %eax
+	push %bx
+	push %cx
+	push %dx
+	push %ds
+
+	/* setup ds to access IVT */
+	xor %ax, %ax
+	mov %ax, %ds
+
+	movw $0x404, %dx
+	inb %dx, %al
+	cmp $1, %al
+	je 1f
+	cmp $2, %al
+	je 2f
+	jmp 3f
+
+1: /* hook int13: intb(0x404) == 1 */
+	/* save old int 13 to int 2c */
+	mov (0x13*4), %eax
+	mov %eax, %cs:old_int13
+
+	/* install our int 13 handler */
+	movw $int13_handler, (0x13*4)
+	mov %cs, (0x13*4+2)
+	jmp 3f
+
+2: /* linux boot: intb(0x404) == 2 */
+	cli
+	cld
+	mov $0x9000, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+	mov $0x8ffe, %sp
+	ljmp $0x9000 + 0x20, $0
+
+3: /* fall through: inb(0x404) == 0 */
+	/* restore previous int $0x19 handler */
+	mov %cs:old_int19,%eax
+	mov %eax,(0x19*4)
+	
+	pop %ds
+	pop %dx
+	pop %cx
+	pop %bx
+	pop %eax
+	ljmpw *%cs:old_int19
+
+#define FLAGS_CF	0x01
+
+/* The two macro below clear/set the carry flag to indicate the status
+ * of the interrupt execution. It is not enough to issue a clc/stc instruction,
+ * since the value of the flags register will be overwritten by whatever is
+ * in the stack frame
+ */
+.macro clc_stack
+	push %bp
+	mov %sp, %bp
+	/* 8 = 2 (bp, just pushed) + 2 (ip) + 3 (real mode interrupt frame) */
+	and $(~FLAGS_CF), 8(%bp)
+	pop %bp
+.endm
+
+.macro stc_stack
+	push %bp
+	/* 8 = 2 (bp, just pushed) + 2 (ip) + 3 (real mode interrupt frame) */
+	or $(FLAGS_CF), 8(%bp)
+	pop %bp
+.endm
+
+/* we clobber %bx */
+.macro alloca size
+	push %ds
+	push %bp
+	mov %sp, %bp  /* remember the current stack position */
+
+	mov %ss, %bx
+	mov %bx, %ds
+
+	sub \size, %sp
+	and $(~0x0F), %sp
+	mov %sp, %bx
+
+	push %bp
+	mov 0(%bp), %bp
+.endm
+
+/* we clobber %bp */
+.macro allocbpa size
+	mov %sp, %bp  /* remember the current stack position */
+	sub \size, %sp
+	and $(~0x0F), %sp
+	push %bp
+	mov %sp, %bp
+	add $2, %bp
+.endm
+
+.macro freea
+	pop %sp
+	add $2, %sp
+	pop %ds
+.endm
+
+.macro freebpa
+	pop %sp
+.endm
+
+.macro dump reg
+	push %ax
+	push %dx
+
+	mov \reg, %ax
+	mov $0x406, %dx
+	outw %ax, %dx
+
+	pop %dx
+	pop %ax
+.endm
+
+.macro callout value
+	push %bp
+	push %bx
+	mov %sp, %bp
+	alloca $16
+	push %ax
+	push %dx
+
+	mov %ax, 0(%bx)     /* ax */
+	mov 0(%bp), %ax     /* bx */
+	mov %ax, 2(%bx)
+	mov %cx, 4(%bx)     /* cx */
+	mov %dx, 6(%bx)     /* dx */
+	mov %si, 8(%bx)     /* si */
+	mov %ds, 10(%bx)    /* ds */
+	mov %es, 12(%bx)    /* ds */
+	movw \value, 14(%bx) /* value */
+
+	mov %bx, %ax
+	shr $4, %ax
+	mov %ds, %dx
+	add %dx, %ax
+
+	mov $0x407, %dx
+	outw %ax, %dx
+
+	pop %dx
+	pop %ax
+	freea
+	pop %bx
+	pop %bp
+.endm
+
+send_command:
+	push %bp
+	mov %sp, %bp
+	push %ax
+	push %bx
+	push %dx
+
+	mov 4(%bp), %ax
+	shr $4, %ax
+	and $0x0FFF, %ax
+	mov %ss, %bx
+	add %bx, %ax
+
+	mov $0x405, %dx
+	outw %ax, %dx
+
+	pop %dx
+	pop %bx
+	pop %ax
+	pop %bp
+
+	push %ax
+	mov 2(%bx), %ax
+	pop %ax
+
+	ret
+
+add32:  /* lo, hi, lo, hi */
+	push %bp
+	mov %sp, %bp
+
+	movw 4(%bp), %cx  /* hi */
+	movw 6(%bp), %dx  /* lo */
+
+	add  10(%bp), %dx
+	jnc 1f
+	add $1, %cx
+1:	add 8(%bp), %cx
+
+	pop %bp
+	ret
+
+mul32:  /* lo,      hi,     lo,     hi */
+	/* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
+	push %bp
+	mov %sp, %bp
+	push %ax
+	push %bx
+
+	xor %cx, %cx
+	xor %dx, %dx
+
+	/* for (i = 0; i < 16;) */
+	xor %bx, %bx
+0:
+	cmp $16, %bx
+	jge 2f
+
+	mov 6(%bp), %ax
+	and $1, %ax
+	cmp $1, %ax
+	jne 1f
+	push 10(%bp)
+	push 8(%bp)
+	push %dx
+	push %cx
+	call add32
+	add $8, %sp
+1:
+	shlw $1, 8(%bp)
+	movw 10(%bp), %ax
+	and $0x8000, %ax
+	cmp $0x8000, %ax
+	jne 1f
+	orw $1, 8(%bp)
+1:
+	shlw $1, 10(%bp)
+	shrw $1, 6(%bp)
+
+	/* i++) { */
+	add $1, %bx
+	jmp 0b
+
+2:
+	pop %bx
+	pop %ax
+	pop %bp
+	ret
+
+disk_reset:
+	movb $0, %ah
+	clc_stack
+	ret
+
+/* this really should be a function, not a macro but i'm lazy */
+.macro read_write_disk_sectors cmd
+	push %ax
+	push %bx
+	push %cx
+	push %dx
+	push %si
+
+	push %bp
+	sub $10, %sp
+	mov %sp, %bp
+
+	/* save nb_sectors */
+	mov %al, 6(%bp)
+	movb $0, 7(%bp)
+
+	/* save buffer */
+	mov %bx, 8(%bp)
+
+	/* cylinders */
+	xor %ax, %ax
+	mov %cl, %al
+	shl $2, %ax
+	and $0x300, %ax
+	mov %ch, %al
+	mov %ax, 0(%bp)
+
+	/* heads */
+	xor %ax, %ax
+	mov %dh, %al
+	mov %ax, 2(%bp)
+
+	/* sectors - 1 */
+	xor %ax, %ax
+	mov %cl, %al
+	and $0x3F, %al
+	sub $1, %ax
+	mov %ax, 4(%bp)
+
+	alloca $16
+
+	movw $0, 0(%bx) /* read c,h,s */
+	push %bx
+	call send_command
+	add $2, %sp
+
+	mov 6(%bx), %ax /* total_sectors */
+	mov 2(%bp), %si /* *= heads */
+	mul %si
+	add 4(%bp), %ax /* += sectors - 1 */
+
+	push 4(%bx) /* total_heads */
+	push $0
+	push 6(%bx) /* total_sectors */
+	push $0
+	call mul32
+	add $8, %sp
+
+	push 0(%bp) /* cylinders */
+	push $0
+	push %dx
+	push %cx
+	call mul32
+	add $8, %sp
+
+	add %ax, %dx
+	jnc 1f
+	add $1, %cx
+1:
+	freea
+
+	alloca $16
+
+	movw \cmd, 0(%bx) /* read */
+	movw 6(%bp), %ax /* nb_sectors */
+	movw %ax, 2(%bx)
+	movw %es, 4(%bx) /* segment */
+	movw 8(%bp), %ax /* offset */
+	mov %ax, 6(%bx)
+	movw %dx, 8(%bx) /* sector */
+	movw %cx, 10(%bx)
+	movw $0, 12(%bx)
+	movw $0, 14(%bx)
+
+	push %bx
+	call send_command
+	add $2, %sp
+
+	freea
+
+	add $10, %sp
+	pop %bp
+
+	pop %si
+	pop %dx
+	pop %cx
+	pop %bx
+	pop %ax
+
+	mov $0, %ah
+	clc_stack
+	ret
+.endm
+
+read_disk_sectors:
+	read_write_disk_sectors $0x01
+
+write_disk_sectors:
+	read_write_disk_sectors $0x02
+
+read_disk_drive_parameters:
+	push %bx
+
+	/* allocate memory for packet, pointer gets returned in bx */
+	alloca $16
+
+	/* issue command */
+	movw $0, 0(%bx) /* cmd = 0, read c,h,s */
+	push %bx
+	call send_command
+	add $2, %sp
+
+	/* normalize sector value */
+	movb 6(%bx), %cl
+	andb $0x3F, %cl
+	movb %cl, 6(%bx)
+
+	/* normalize cylinders */
+	subw $2, 2(%bx)
+
+	/* normalize heads */
+	subw $1, 4(%bx)
+
+	/* return code */
+	mov $0, %ah
+
+	/* cylinders */
+	movb 2(%bx), %ch
+	movb 3(%bx), %cl
+	shlb $6, %cl
+	andb $0xC0, %cl
+
+	/* sectors */
+	orb 6(%bx), %cl
+
+	/* heads */
+	movb 4(%bx), %dh
+
+	/* drives */
+	movb $1, %dl
+
+	/* status */
+	mov $0, %ah
+
+	freea
+
+	pop %bx
+
+	/* do this last since it's the most sensitive */
+	clc_stack
+	ret
+
+alternate_disk_reset:
+	movb $0, %ah
+	clc_stack
+	ret
+
+read_disk_drive_size:
+	push %bx
+	alloca $16
+
+	movw $0, 0(%bx) /* cmd = 0, read c,h,s */
+	push %bx
+	call send_command
+	add $2, %sp
+
+	/* cylinders - 1 to cx:dx */
+	mov 2(%bx), %dx
+	xor %cx, %cx
+	sub $1, %dx
+
+	/* heads */
+	push 4(%bx)
+	push $0
+	push %dx
+	push %cx
+	call mul32
+	add $8, %sp
+
+	/* sectors */
+	push 6(%bx)
+	push $0
+	push %dx
+	push %cx
+	call mul32
+	add $8, %sp
+
+	/* status */
+	mov $3, %ah
+
+	freea
+	pop %bx
+
+	clc_stack
+	ret
+
+check_if_extensions_present:
+	mov $0x30, %ah
+	mov $0xAA55, %bx
+	mov $0x07, %cx
+	clc_stack
+	ret
+
+.macro extended_read_write_sectors cmd
+	cmpb $10, 0(%si)
+	jg 1f
+	mov $1, %ah
+	stc_stack
+	ret
+1:
+	push %ax
+	push %bp
+	allocbpa $16
+
+	movw \cmd, 0(%bp) /* read */
+	movw 2(%si), %ax   /* nb_sectors */
+	movw %ax, 2(%bp)
+	movw 4(%si), %ax   /* offset */
+	movw %ax, 6(%bp)
+	movw 6(%si), %ax   /* segment */
+	movw %ax, 4(%bp)
+	movw 8(%si), %ax   /* block */
+	movw %ax, 8(%bp)
+	movw 10(%si), %ax
+	movw %ax, 10(%bp)
+	movw 12(%si), %ax
+	movw %ax, 12(%bp)
+	movw 14(%si), %ax
+	movw %ax, 14(%bp)
+
+	push %bp
+	call send_command
+	add $2, %sp
+
+	freebpa
+	pop %bp
+	pop %ax
+
+	mov $0, %ah
+	clc_stack
+	ret
+.endm
+
+extended_read_sectors:
+	extended_read_write_sectors $0x01
+
+extended_write_sectors:
+	extended_read_write_sectors $0x02
+
+get_extended_drive_parameters:
+	push %ax
+	push %bp
+	push %cx
+	push %dx
+
+	allocbpa $16
+
+	movw $0, 0(%bp) /* read c,h,s */
+	push %bp
+	call send_command
+	add $2, %sp
+
+	/* write size */
+	movw $26, 0(%si)
+
+	/* set flags to 2 */
+	movw $2, 2(%si)
+
+	/* cylinders */
+	mov 2(%bp), %ax
+	mov %ax, 4(%si)
+	xor %ax, %ax
+	mov %ax, 6(%si)
+
+	/* heads */
+	mov 4(%bp), %ax
+	mov %ax, 8(%si)
+	xor %ax, %ax
+	mov %ax, 10(%si)
+
+	/* sectors */
+	mov 6(%bp), %ax
+	mov %ax, 12(%si)
+	xor %ax, %ax
+	mov %ax, 14(%si)
+
+	/* set total number of sectors */
+	mov 8(%bp), %ax
+	mov %ax, 16(%si)
+	mov 10(%bp), %ax
+	mov %ax, 18(%si)
+	mov 12(%bp), %ax
+	mov %ax, 20(%si)
+	mov 14(%bp), %ax
+	mov %ax, 22(%si)
+
+	/* number of bytes per sector */
+	movw $512, 24(%si)
+
+	freebpa
+
+	pop %dx
+	pop %cx
+	pop %bp
+	pop %ax
+
+	mov $0, %ah
+	clc_stack
+	ret
+
+terminate_disk_emulation:
+	mov $1, %ah
+	stc_stack
+	ret
+
+int13_handler:
+	cmp $0x80, %dl
+	je 1f
+	ljmpw *%cs:old_int13
+1:
+	cmp $0x0, %ah
+	jne 1f
+	call disk_reset
+	iret
+1:
+	cmp $0x2, %ah
+	jne 1f
+	call read_disk_sectors
+	iret
+1:
+	cmp $0x8, %ah
+	jne 1f
+	call read_disk_drive_parameters
+	iret
+1:
+	cmp $0x15, %ah
+	jne 1f
+	call read_disk_drive_size
+	iret
+1:
+	cmp $0x41, %ah
+	jne 1f
+	call check_if_extensions_present
+	iret
+1:
+	cmp $0x42, %ah
+	jne 1f
+	call extended_read_sectors
+	iret
+1:
+	cmp $0x48, %ah
+	jne 1f
+	call get_extended_drive_parameters
+	iret
+1:
+	cmp $0x4b, %ah
+	jne 1f
+	call terminate_disk_emulation
+	iret
+1:
+	cmp $0x0d, %ah
+	jne 1f
+	call alternate_disk_reset
+	iret
+1:
+	cmp $0x03, %ah
+	jne 1f
+	call write_disk_sectors
+	iret
+1:
+	cmp $0x43, %ah
+	jne 1f
+	call extended_write_sectors
+	iret
+1:
+	int $0x18  /* boot failed */
+	iret
+
+/* Variables */
+.align 4, 0
+old_int13:	.long 0
+old_int19:	.long 0
+	
+.align 512, 0
+_end:
diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S
index c4c9109..8aebe51 100644
--- a/pc-bios/optionrom/linuxboot.S
+++ b/pc-bios/optionrom/linuxboot.S
@@ -86,9 +86,10 @@
 	/* Now create the GDT descriptor */
 	movw		$((3 * 8) - 1), -16(%bp)
 	mov		%cs, %eax
+	movzwl		%ax, %eax
 	shl		$4, %eax
-	addl		$gdt, %ebx
-	movl		%ebx, -14(%bp)
+	addl		$gdt, %eax
+	movl		%eax, -14(%bp)
 
 	/* And load the GDT */
 	data32 lgdt	-16(%bp)
diff --git a/pc-bios/optionrom/vapic.S b/pc-bios/optionrom/vapic.S
new file mode 100644
index 0000000..afe98a9
--- /dev/null
+++ b/pc-bios/optionrom/vapic.S
@@ -0,0 +1,315 @@
+	.text 0
+	.code16
+.global _start
+_start:
+	.short 0xaa55
+	.byte (_end - _start) / 512
+	mov $vapic_base, %ax
+	out %ax, $0x7e
+	lret
+
+	.code32
+vapic_size = 2*4096
+
+.macro fixup delta=-4
+777:
+	.text 1
+	.long 777b + \delta  - vapic_base
+	.text 0
+.endm
+
+.macro reenable_vtpr
+	out %al, $0x7e
+.endm
+
+.text 1
+	fixup_start = .
+.text 0
+
+.align 16
+
+vapic_base:
+	.ascii "kvm aPiC"
+
+	/* relocation data */
+	.long vapic_base	; fixup
+	.long fixup_start	; fixup
+	.long fixup_end		; fixup
+
+	.long vapic		; fixup
+	.long vapic_size
+vcpu_shift:
+	.long 0
+real_tpr:
+	.long 0
+	.long up_set_tpr	; fixup
+	.long up_set_tpr_eax	; fixup
+	.long up_get_tpr_eax	; fixup
+	.long up_get_tpr_ecx	; fixup
+	.long up_get_tpr_edx	; fixup
+	.long up_get_tpr_ebx	; fixup
+	.long 0 /* esp. won't work. */
+	.long up_get_tpr_ebp	; fixup
+	.long up_get_tpr_esi	; fixup
+	.long up_get_tpr_edi	; fixup
+	.long up_get_tpr_stack  ; fixup
+	.long mp_set_tpr	; fixup
+	.long mp_set_tpr_eax	; fixup
+	.long mp_get_tpr_eax	; fixup
+	.long mp_get_tpr_ecx	; fixup
+	.long mp_get_tpr_edx	; fixup
+	.long mp_get_tpr_ebx	; fixup
+	.long 0 /* esp. won't work. */
+	.long mp_get_tpr_ebp	; fixup
+	.long mp_get_tpr_esi	; fixup
+	.long mp_get_tpr_edi	; fixup
+	.long mp_get_tpr_stack  ; fixup
+
+.macro kvm_hypercall
+	.byte 0x0f, 0x01, 0xc1
+.endm
+
+kvm_hypercall_vapic_poll_irq = 1
+
+pcr_cpu = 0x51
+
+.align 64
+
+mp_get_tpr_eax:
+	pushf
+	cli
+	reenable_vtpr
+	push %ecx
+
+	fs/movzbl pcr_cpu, %eax
+
+	mov vcpu_shift, %ecx	; fixup
+	shl %cl, %eax
+	testb $1, vapic+4(%eax)	; fixup delta=-5
+	jz mp_get_tpr_bad
+	movzbl vapic(%eax), %eax ; fixup
+
+mp_get_tpr_out:
+	pop %ecx
+	popf
+	ret
+
+mp_get_tpr_bad:
+	mov real_tpr, %eax	; fixup
+	mov (%eax), %eax
+	jmp mp_get_tpr_out
+
+mp_get_tpr_ebx:
+	mov %eax, %ebx
+	call mp_get_tpr_eax
+	xchg %eax, %ebx
+	ret
+
+mp_get_tpr_ecx:
+	mov %eax, %ecx
+	call mp_get_tpr_eax
+	xchg %eax, %ecx
+	ret
+
+mp_get_tpr_edx:
+	mov %eax, %edx
+	call mp_get_tpr_eax
+	xchg %eax, %edx
+	ret
+
+mp_get_tpr_esi:
+	mov %eax, %esi
+	call mp_get_tpr_eax
+	xchg %eax, %esi
+	ret
+
+mp_get_tpr_edi:
+	mov %eax, %edi
+	call mp_get_tpr_edi
+	xchg %eax, %edi
+	ret
+
+mp_get_tpr_ebp:
+	mov %eax, %ebp
+	call mp_get_tpr_eax
+	xchg %eax, %ebp
+	ret
+
+mp_get_tpr_stack:
+	call mp_get_tpr_eax
+	xchg %eax, 4(%esp)
+	ret
+
+mp_set_tpr_eax:
+	push %eax
+	call mp_set_tpr
+	ret
+
+mp_set_tpr:
+	pushf
+	push %eax
+	push %ecx
+	push %edx
+	push %ebx
+	cli
+	reenable_vtpr
+
+mp_set_tpr_failed:
+	fs/movzbl pcr_cpu, %edx
+
+	mov vcpu_shift, %ecx	; fixup
+	shl %cl, %edx
+
+	testb $1, vapic+4(%edx)	; fixup delta=-5
+	jz mp_set_tpr_bad
+
+	mov vapic(%edx), %eax	; fixup
+
+	mov %eax, %ebx
+	mov 24(%esp), %bl
+
+	/* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
+
+	lock cmpxchg %ebx, vapic(%edx) ; fixup
+	jnz mp_set_tpr_failed
+
+	/* compute ppr */
+	cmp %bh, %bl
+	jae mp_tpr_is_bigger
+mp_isr_is_bigger:
+	mov %bh, %bl
+mp_tpr_is_bigger:
+	/* %bl = ppr */
+	mov %bl, %ch   /* ch = ppr */
+	rol $8, %ebx
+	/* now: %bl = irr, %bh = ppr */
+	cmp %bh, %bl
+	ja mp_set_tpr_poll_irq
+
+mp_set_tpr_out:
+	pop %ebx
+	pop %edx
+	pop %ecx
+	pop %eax
+	popf
+	ret $4
+
+mp_set_tpr_poll_irq:
+	mov $kvm_hypercall_vapic_poll_irq, %eax
+	kvm_hypercall
+	jmp mp_set_tpr_out
+
+mp_set_tpr_bad:
+	mov 24(%esp), %ecx
+	mov real_tpr, %eax	; fixup
+	mov %ecx, (%eax)
+	jmp mp_set_tpr_out
+
+up_get_tpr_eax:
+	reenable_vtpr
+	movzbl vapic, %eax ; fixup
+	ret
+
+up_get_tpr_ebx:
+	reenable_vtpr
+	movzbl vapic, %ebx ; fixup
+	ret
+
+up_get_tpr_ecx:
+	reenable_vtpr
+	movzbl vapic, %ecx ; fixup
+	ret
+
+up_get_tpr_edx:
+	reenable_vtpr
+	movzbl vapic, %edx ; fixup
+	ret
+
+up_get_tpr_esi:
+	reenable_vtpr
+	movzbl vapic, %esi ; fixup
+	ret
+
+up_get_tpr_edi:
+	reenable_vtpr
+	movzbl vapic, %edi ; fixup
+	ret
+
+up_get_tpr_ebp:
+	reenable_vtpr
+	movzbl vapic, %ebp ; fixup
+	ret
+
+up_get_tpr_stack:
+	reenable_vtpr
+	movzbl vapic, %eax ; fixup
+	xchg %eax, 4(%esp)
+	ret
+
+up_set_tpr_eax:
+	push %eax
+	call up_set_tpr
+	ret
+
+up_set_tpr:
+	pushf
+	push %eax
+	push %ecx
+	push %ebx
+	reenable_vtpr
+
+up_set_tpr_failed:
+	mov vapic, %eax	; fixup
+
+	mov %eax, %ebx
+	mov 20(%esp), %bl
+
+	/* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
+
+	lock cmpxchg %ebx, vapic ; fixup
+	jnz up_set_tpr_failed
+
+	/* compute ppr */
+	cmp %bh, %bl
+	jae up_tpr_is_bigger
+up_isr_is_bigger:
+	mov %bh, %bl
+up_tpr_is_bigger:
+	/* %bl = ppr */
+	mov %bl, %ch   /* ch = ppr */
+	rol $8, %ebx
+	/* now: %bl = irr, %bh = ppr */
+	cmp %bh, %bl
+	ja up_set_tpr_poll_irq
+
+up_set_tpr_out:
+	pop %ebx
+	pop %ecx
+	pop %eax
+	popf
+	ret $4
+
+up_set_tpr_poll_irq:
+	mov $kvm_hypercall_vapic_poll_irq, %eax
+	kvm_hypercall
+	jmp up_set_tpr_out
+
+.text 1
+	fixup_end = .
+.text 0
+
+/*
+ * vapic format:
+ *  per-vcpu records of size 2^vcpu shift.
+ *     byte 0: tpr (r/w)
+ *     byte 1: highest in-service interrupt (isr) (r/o); bits 3:0 are zero
+ *     byte 2: zero (r/o)
+ *     byte 3: highest pending interrupt (irr) (r/o)
+ */
+.text 2
+
+.align 128
+
+vapic:
+. = . + vapic_size
+_end:
diff --git a/pc-bios/vapic.bin b/pc-bios/vapic.bin
new file mode 100755
index 0000000..35f0cf2
--- /dev/null
+++ b/pc-bios/vapic.bin
Binary files differ
diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin
index 4fa8f99..7007bf0 100644
--- a/pc-bios/vgabios-cirrus.bin
+++ b/pc-bios/vgabios-cirrus.bin
Binary files differ
diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin
index fa6f815..c38c62a 100644
--- a/pc-bios/vgabios.bin
+++ b/pc-bios/vgabios.bin
Binary files differ
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index dc14f53..272e998 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -26,6 +26,7 @@
 #include "osdep.h"
 #include "qemu-common.h"
 #include "block_int.h"
+#include "compatfd.h"
 
 #include "block/raw-posix-aio.h"
 
@@ -53,7 +54,7 @@
 };
 
 typedef struct PosixAioState {
-    int rfd, wfd;
+    int fd;
     struct qemu_paiocb *first_aio;
 } PosixAioState;
 
@@ -472,18 +473,29 @@
 static void posix_aio_read(void *opaque)
 {
     PosixAioState *s = opaque;
-    ssize_t len;
+    union {
+        struct qemu_signalfd_siginfo siginfo;
+        char buf[128];
+    } sig;
+    size_t offset;
 
-    /* read all bytes from signal pipe */
-    for (;;) {
-        char bytes[16];
+    /* try to read from signalfd, don't freak out if we can't read anything */
+    offset = 0;
+    while (offset < 128) {
+        ssize_t len;
 
-        len = read(s->rfd, bytes, sizeof(bytes));
+        len = read(s->fd, sig.buf + offset, 128 - offset);
         if (len == -1 && errno == EINTR)
-            continue; /* try again */
-        if (len == sizeof(bytes))
-            continue; /* more to read */
-        break;
+            continue;
+        if (len == -1 && errno == EAGAIN) {
+            /* there is no natural reason for this to happen,
+             * so we'll spin hard until we get everything just
+             * to be on the safe side. */
+            if (offset > 0)
+                continue;
+        }
+
+        offset += len;
     }
 
     posix_aio_process_queue(s);
@@ -497,17 +509,6 @@
 
 static PosixAioState *posix_aio_state;
 
-static void aio_signal_handler(int signum)
-{
-    if (posix_aio_state) {
-        char byte = 0;
-
-        write(posix_aio_state->wfd, &byte, sizeof(byte));
-    }
-
-    qemu_service_io();
-}
-
 static void paio_remove(struct qemu_paiocb *acb)
 {
     struct qemu_paiocb **pacb;
@@ -609,9 +610,8 @@
 
 int paio_init(void)
 {
-    struct sigaction act;
+    sigset_t mask;
     PosixAioState *s;
-    int fds[2];
     int ret;
 
     if (posix_aio_state)
@@ -619,24 +619,21 @@
 
     s = qemu_malloc(sizeof(PosixAioState));
 
-    sigfillset(&act.sa_mask);
-    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
-    act.sa_handler = aio_signal_handler;
-    sigaction(SIGUSR2, &act, NULL);
+    /* Make sure to block AIO signal */
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &mask, NULL);
 
     s->first_aio = NULL;
-    if (qemu_pipe(fds) == -1) {
-        fprintf(stderr, "failed to create pipe\n");
+    s->fd = qemu_signalfd(&mask);
+    if (s->fd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
         return -1;
     }
 
-    s->rfd = fds[0];
-    s->wfd = fds[1];
+    fcntl(s->fd, F_SETFL, O_NONBLOCK);
 
-    fcntl(s->rfd, F_SETFL, O_NONBLOCK);
-    fcntl(s->wfd, F_SETFL, O_NONBLOCK);
-
-    qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
+    qemu_aio_set_fd_handler(s->fd, posix_aio_read, NULL, posix_aio_flush,
         posix_aio_process_queue, s);
 
     ret = pthread_attr_init(&attr);
diff --git a/qemu-common.h b/qemu-common.h
index 8630f8c..5fbe0f9 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -225,6 +225,14 @@
 /* Force QEMU to stop what it's doing and service IO */
 void qemu_service_io(void);
 
+/* work queue */
+struct qemu_work_item {
+    struct qemu_work_item *next;
+    void (*func)(void *data);
+    void *data;
+    int done;
+};
+
 /* Force QEMU to process pending events */
 void qemu_notify_event(void);
 
diff --git a/qemu-config.c b/qemu-config.c
index c3203c8..2caf76c 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -78,6 +78,10 @@
         },{
             .name = "readonly",
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "boot",
+            .type = QEMU_OPT_BOOL,
+            .help = "make this a boot drive",
         },
         { /* end if list */ }
     },
diff --git a/qemu-kvm-helper.c b/qemu-kvm-helper.c
new file mode 100644
index 0000000..9420eb1
--- /dev/null
+++ b/qemu-kvm-helper.c
@@ -0,0 +1,40 @@
+
+#include "config.h"
+#include "config-host.h"
+
+#include "exec.h"
+
+#include "qemu-kvm.h"
+
+void qemu_kvm_call_with_env(void (*func)(void *), void *data, CPUState *newenv)
+{
+    CPUState *oldenv;
+#define DECLARE_HOST_REGS
+#include "hostregs_helper.h"
+
+    oldenv = newenv;
+
+#define SAVE_HOST_REGS
+#include "hostregs_helper.h"
+
+    env = newenv;
+
+    env_to_regs();
+    func(data);
+    regs_to_env();
+
+    env = oldenv;
+
+#include "hostregs_helper.h"
+}
+
+static void call_helper_cpuid(void *junk)
+{
+    helper_cpuid();
+}
+
+void qemu_kvm_cpuid_on_env(CPUState *env)
+{
+    qemu_kvm_call_with_env(call_helper_cpuid, NULL, env);
+}
+
diff --git a/qemu-kvm-ia64.c b/qemu-kvm-ia64.c
new file mode 100644
index 0000000..a11fde8
--- /dev/null
+++ b/qemu-kvm-ia64.c
@@ -0,0 +1,143 @@
+#include "config.h"
+#include "config-host.h"
+
+#include <string.h>
+
+#include "hw/hw.h"
+#include "qemu-kvm.h"
+#include <pthread.h>
+#include <sys/utsname.h>
+#include <sys/io.h>
+
+
+
+int kvm_arch_qemu_create_context(void)
+{
+    return 0;
+}
+
+void kvm_arch_load_regs(CPUState *env)
+{
+}
+
+
+void kvm_arch_save_regs(CPUState *env)
+{
+}
+
+int kvm_arch_init_vcpu(CPUState *cenv)
+{
+    return 0;
+}
+
+int kvm_arch_halt(kvm_vcpu_context_t vcpu)
+{
+    CPUState *env = cpu_single_env;
+    env->hflags |= HF_HALTED_MASK;
+    return 1;
+}
+
+void kvm_arch_pre_kvm_run(void *opaque, CPUState *env)
+{
+}
+
+void kvm_arch_post_kvm_run(void *opaque, CPUState *env)
+{
+}
+
+int kvm_arch_has_work(CPUState *env)
+{
+    return 1;
+}
+
+int kvm_arch_try_push_interrupts(void *opaque)
+{
+    return 1;
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *current_env,
+                                  struct kvm_sw_breakpoint *bp)
+{
+    return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *current_env,
+                                  struct kvm_sw_breakpoint *bp)
+{
+    return -EINVAL;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+				  target_ulong len, int type)
+{
+    return -ENOSYS;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+				  target_ulong len, int type)
+{
+    return -ENOSYS;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+}
+
+int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
+{
+    return 0;
+}
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
+{
+}
+
+void kvm_arch_save_mpstate(CPUState *env)
+{
+#ifdef KVM_CAP_MP_STATE
+    int r;
+    struct kvm_mp_state mp_state;
+
+    r = kvm_get_mpstate(env->kvm_cpu_state.vcpu_ctx, &mp_state);
+    if (r < 0)
+        env->mp_state = -1;
+    else
+        env->mp_state = mp_state.mp_state;
+#endif
+}
+
+void kvm_arch_load_mpstate(CPUState *env)
+{
+#ifdef KVM_CAP_MP_STATE
+    struct kvm_mp_state mp_state = { .mp_state = env->mp_state };
+
+    /*
+     * -1 indicates that the host did not support GET_MP_STATE ioctl,
+     *  so don't touch it.
+     */
+    if (env->mp_state != -1)
+        kvm_set_mpstate(env->kvm_cpu_state.vcpu_ctx, &mp_state);
+#endif
+}
+
+void kvm_arch_cpu_reset(CPUState *env)
+{
+    if (kvm_irqchip_in_kernel(kvm_context)) {
+#ifdef KVM_CAP_MP_STATE
+	kvm_reset_mpstate(env->kvm_cpu_state.vcpu_ctx);
+#endif
+    } else {
+	env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+	env->halted = 1;
+    }
+}
+
+void kvm_arch_do_ioperm(void *_data)
+{
+    struct ioperm_data *data = _data;
+    ioperm(data->start_port, data->num, data->turn_on);
+}
+
+void kvm_arch_process_irqchip_events(CPUState *env)
+{
+}
diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c
new file mode 100644
index 0000000..82e362c
--- /dev/null
+++ b/qemu-kvm-x86.c
@@ -0,0 +1,1704 @@
+/*
+ * qemu/kvm integration, x86 specific code
+ *
+ * Copyright (C) 2006-2008 Qumranet Technologies
+ *
+ * Licensed under the terms of the GNU GPL version 2 or higher.
+ */
+
+#include "config.h"
+#include "config-host.h"
+
+#include <string.h>
+#include "hw/hw.h"
+#include "gdbstub.h"
+#include <sys/io.h>
+
+#include "qemu-kvm.h"
+#include "libkvm.h"
+#include <pthread.h>
+#include <sys/utsname.h>
+#include <linux/kvm_para.h>
+#include <sys/ioctl.h>
+
+#include "kvm.h"
+#include "hw/pc.h"
+
+#define MSR_IA32_TSC		0x10
+
+static struct kvm_msr_list *kvm_msr_list;
+extern unsigned int kvm_shadow_memory;
+static int kvm_has_msr_star;
+static int kvm_has_vm_hsave_pa;
+
+static int lm_capable_kernel;
+
+int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr)
+{
+#ifdef KVM_CAP_SET_TSS_ADDR
+	int r;
+
+	r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
+	if (r > 0) {
+		r = kvm_vm_ioctl(kvm_state, KVM_SET_TSS_ADDR, addr);
+		if (r < 0) {
+			fprintf(stderr, "kvm_set_tss_addr: %m\n");
+			return r;
+		}
+		return 0;
+	}
+#endif
+	return -ENOSYS;
+}
+
+static int kvm_init_tss(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_SET_TSS_ADDR
+	int r;
+
+	r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
+	if (r > 0) {
+		/*
+		 * this address is 3 pages before the bios, and the bios should present
+		 * as unavaible memory
+		 */
+		r = kvm_set_tss_addr(kvm, 0xfeffd000);
+		if (r < 0) {
+			fprintf(stderr, "kvm_init_tss: unable to set tss addr\n");
+			return r;
+		}
+
+	}
+#endif
+	return 0;
+}
+
+static int kvm_set_identity_map_addr(kvm_context_t kvm, uint64_t addr)
+{
+#ifdef KVM_CAP_SET_IDENTITY_MAP_ADDR
+	int r;
+
+	r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SET_IDENTITY_MAP_ADDR);
+	if (r > 0) {
+		r = kvm_vm_ioctl(kvm_state, KVM_SET_IDENTITY_MAP_ADDR, &addr);
+		if (r == -1) {
+			fprintf(stderr, "kvm_set_identity_map_addr: %m\n");
+			return -errno;
+		}
+		return 0;
+	}
+#endif
+	return -ENOSYS;
+}
+
+static int kvm_init_identity_map_page(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_SET_IDENTITY_MAP_ADDR
+	int r;
+
+	r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SET_IDENTITY_MAP_ADDR);
+	if (r > 0) {
+		/*
+		 * this address is 4 pages before the bios, and the bios should present
+		 * as unavaible memory
+		 */
+		r = kvm_set_identity_map_addr(kvm, 0xfeffc000);
+		if (r < 0) {
+			fprintf(stderr, "kvm_init_identity_map_page: "
+				"unable to set identity mapping addr\n");
+			return r;
+		}
+
+	}
+#endif
+	return 0;
+}
+
+static int kvm_create_pit(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_PIT
+	int r;
+
+	kvm->pit_in_kernel = 0;
+	if (!kvm->no_pit_creation) {
+		r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_PIT);
+		if (r > 0) {
+			r = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
+			if (r >= 0)
+				kvm->pit_in_kernel = 1;
+			else {
+				fprintf(stderr, "Create kernel PIC irqchip failed\n");
+				return r;
+			}
+		}
+	}
+#endif
+	return 0;
+}
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+			void **vm_mem)
+{
+	int r = 0;
+
+	r = kvm_init_tss(kvm);
+	if (r < 0)
+		return r;
+
+	r = kvm_init_identity_map_page(kvm);
+	if (r < 0)
+		return r;
+
+	r = kvm_create_pit(kvm);
+	if (r < 0)
+		return r;
+
+	r = kvm_init_coalesced_mmio(kvm);
+	if (r < 0)
+		return r;
+
+#ifdef KVM_EXIT_TPR_ACCESS
+    kvm_tpr_opt_setup();
+#endif
+
+	return 0;
+}
+
+#ifdef KVM_EXIT_TPR_ACCESS
+
+static int kvm_handle_tpr_access(CPUState *env)
+{
+	struct kvm_run *run = env->kvm_run;
+	kvm_tpr_access_report(env,
+                         run->tpr_access.rip,
+                         run->tpr_access.is_write);
+    return 0;
+}
+
+
+int kvm_enable_vapic(CPUState *env, uint64_t vapic)
+{
+	struct kvm_vapic_addr va = {
+		.vapic_addr = vapic,
+	};
+
+	return kvm_vcpu_ioctl(env, KVM_SET_VAPIC_ADDR, &va);
+}
+
+#endif
+
+int kvm_arch_run(CPUState *env)
+{
+	int r = 0;
+	struct kvm_run *run = env->kvm_run;
+
+
+	switch (run->exit_reason) {
+#ifdef KVM_EXIT_SET_TPR
+		case KVM_EXIT_SET_TPR:
+			break;
+#endif
+#ifdef KVM_EXIT_TPR_ACCESS
+		case KVM_EXIT_TPR_ACCESS:
+			r = kvm_handle_tpr_access(env);
+			break;
+#endif
+		default:
+			r = 1;
+			break;
+	}
+
+	return r;
+}
+
+#define MAX_ALIAS_SLOTS 4
+static struct {
+	uint64_t start;
+	uint64_t len;
+} kvm_aliases[MAX_ALIAS_SLOTS];
+
+static int get_alias_slot(uint64_t start)
+{
+	int i;
+
+	for (i=0; i<MAX_ALIAS_SLOTS; i++)
+		if (kvm_aliases[i].start == start)
+			return i;
+	return -1;
+}
+static int get_free_alias_slot(void)
+{
+        int i;
+
+        for (i=0; i<MAX_ALIAS_SLOTS; i++)
+                if (kvm_aliases[i].len == 0)
+                        return i;
+        return -1;
+}
+
+static void register_alias(int slot, uint64_t start, uint64_t len)
+{
+	kvm_aliases[slot].start = start;
+	kvm_aliases[slot].len   = len;
+}
+
+int kvm_create_memory_alias(kvm_context_t kvm,
+			    uint64_t phys_start,
+			    uint64_t len,
+			    uint64_t target_phys)
+{
+	struct kvm_memory_alias alias = {
+		.flags = 0,
+		.guest_phys_addr = phys_start,
+		.memory_size = len,
+		.target_phys_addr = target_phys,
+	};
+	int r;
+	int slot;
+
+	slot = get_alias_slot(phys_start);
+	if (slot < 0)
+		slot = get_free_alias_slot();
+	if (slot < 0)
+		return -EBUSY;
+	alias.slot = slot;
+
+	r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ALIAS, &alias);
+	if (r == -1)
+	    return -errno;
+
+	register_alias(slot, phys_start, len);
+	return 0;
+}
+
+int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start)
+{
+	return kvm_create_memory_alias(kvm, phys_start, 0, 0);
+}
+
+#ifdef KVM_CAP_IRQCHIP
+
+int kvm_get_lapic(CPUState *env, struct kvm_lapic_state *s)
+{
+	int r = 0;
+
+	if (!kvm_irqchip_in_kernel())
+		return r;
+
+	r = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, s);
+	if (r < 0)
+		fprintf(stderr, "KVM_GET_LAPIC failed\n");
+	return r;
+}
+
+int kvm_set_lapic(CPUState *env, struct kvm_lapic_state *s)
+{
+	int r = 0;
+
+	if (!kvm_irqchip_in_kernel())
+		return 0;
+
+	r = kvm_vcpu_ioctl(env, KVM_SET_LAPIC, s);
+
+	if (r < 0)
+		fprintf(stderr, "KVM_SET_LAPIC failed\n");
+	return r;
+}
+
+#endif
+
+#ifdef KVM_CAP_PIT
+
+int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s)
+{
+	if (!kvm->pit_in_kernel)
+		return 0;
+	return kvm_vm_ioctl(kvm_state, KVM_GET_PIT, s);
+}
+
+int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s)
+{
+	if (!kvm->pit_in_kernel)
+		return 0;
+	return kvm_vm_ioctl(kvm_state, KVM_SET_PIT, s);
+}
+
+#ifdef KVM_CAP_PIT_STATE2
+int kvm_get_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2)
+{
+	if (!kvm->pit_in_kernel)
+		return 0;
+	return kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, ps2);
+}
+
+int kvm_set_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2)
+{
+	if (!kvm->pit_in_kernel)
+		return 0;
+	return kvm_vm_ioctl(kvm_state, KVM_SET_PIT2, ps2);
+}
+
+#endif
+#endif
+
+int kvm_has_pit_state2(kvm_context_t kvm)
+{
+	int r = 0;
+
+#ifdef KVM_CAP_PIT_STATE2
+	r = kvm_check_extension(kvm_state, KVM_CAP_PIT_STATE2);
+#endif
+	return r;
+}
+
+void kvm_show_code(CPUState *env)
+{
+#define SHOW_CODE_LEN 50
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int r, n;
+	int back_offset;
+	unsigned char code;
+	char code_str[SHOW_CODE_LEN * 3 + 1];
+	unsigned long rip;
+
+	r = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+	if (r < 0 ) {
+		perror("KVM_GET_SREGS");
+		return;
+	}
+	r = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+	if (r < 0) {
+		perror("KVM_GET_REGS");
+		return;
+	}
+	rip = sregs.cs.base + regs.rip;
+	back_offset = regs.rip;
+	if (back_offset > 20)
+	    back_offset = 20;
+	*code_str = 0;
+	for (n = -back_offset; n < SHOW_CODE_LEN-back_offset; ++n) {
+		if (n == 0)
+			strcat(code_str, " -->");
+		cpu_physical_memory_rw(rip + n, &code, 1, 1);
+		sprintf(code_str + strlen(code_str), " %02x", code);
+	}
+	fprintf(stderr, "code:%s\n", code_str);
+}
+
+
+/*
+ * 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;
+
+	sizer.nmsrs = 0;
+	r = kvm_ioctl(kvm_state, KVM_GET_MSR_INDEX_LIST, &sizer);
+	if (r < 0 && r != -E2BIG)
+		return NULL;
+	/* Old kernel modules had a bug and could write beyond the provided
+	   memory. Allocate at least a safe amount of 1K. */
+	msrs = qemu_malloc(MAX(1024, sizeof(*msrs) +
+				       sizer.nmsrs * sizeof(*msrs->indices)));
+
+	msrs->nmsrs = sizer.nmsrs;
+	r = kvm_ioctl(kvm_state, KVM_GET_MSR_INDEX_LIST, msrs);
+	if (r < 0) {
+		free(msrs);
+		errno = r;
+		return NULL;
+	}
+	return msrs;
+}
+
+int kvm_get_msrs(CPUState *env, struct kvm_msr_entry *msrs, int n)
+{
+    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r;
+
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = kvm_vcpu_ioctl(env, KVM_GET_MSRS, kmsrs);
+    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
+    free(kmsrs);
+    return r;
+}
+
+int kvm_set_msrs(CPUState *env, struct kvm_msr_entry *msrs, int n)
+{
+    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r;
+
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = kvm_vcpu_ioctl(env, KVM_SET_MSRS, kmsrs);
+    free(kmsrs);
+    return r;
+}
+
+int kvm_get_mce_cap_supported(kvm_context_t kvm, uint64_t *mce_cap,
+                              int *max_banks)
+{
+#ifdef KVM_CAP_MCE
+    int r;
+
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+    if (r > 0) {
+        *max_banks = r;
+        return kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap);
+    }
+#endif
+    return -ENOSYS;
+}
+
+int kvm_setup_mce(CPUState *env, uint64_t *mcg_cap)
+{
+#ifdef KVM_CAP_MCE
+    return kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, mcg_cap);
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_set_mce(CPUState *env, struct kvm_x86_mce *m)
+{
+#ifdef KVM_CAP_MCE
+    return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, m);
+#else
+    return -ENOSYS;
+#endif
+}
+
+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(CPUState *env)
+{
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	int r;
+
+	r = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+	if (r < 0) {
+		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 = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+	if (r < 0) {
+		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_set_cr8(CPUState *env, uint64_t cr8)
+{
+	env->kvm_run->cr8 = cr8;
+}
+
+int kvm_setup_cpuid(CPUState *env, int nent,
+		    struct kvm_cpuid_entry *entries)
+{
+	struct kvm_cpuid *cpuid;
+	int r;
+
+	cpuid = qemu_malloc(sizeof(*cpuid) + nent * sizeof(*entries));
+
+	cpuid->nent = nent;
+	memcpy(cpuid->entries, entries, nent * sizeof(*entries));
+	r = kvm_vcpu_ioctl(env, KVM_SET_CPUID, cpuid);
+
+	free(cpuid);
+	return r;
+}
+
+int kvm_setup_cpuid2(CPUState *env, int nent,
+		     struct kvm_cpuid_entry2 *entries)
+{
+	struct kvm_cpuid2 *cpuid;
+	int r;
+
+	cpuid = qemu_malloc(sizeof(*cpuid) + nent * sizeof(*entries));
+
+	cpuid->nent = nent;
+	memcpy(cpuid->entries, entries, nent * sizeof(*entries));
+	r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, cpuid);
+	free(cpuid);
+	return r;
+}
+
+int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages)
+{
+#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
+	int r;
+
+	r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION,
+		  KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
+	if (r > 0) {
+		r = kvm_vm_ioctl(kvm_state, KVM_SET_NR_MMU_PAGES, nrshadow_pages);
+		if (r < 0) {
+			fprintf(stderr, "kvm_set_shadow_pages: %m\n");
+			return r;
+		}
+		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 = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION,
+		  KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
+	if (r > 0) {
+		*nrshadow_pages = kvm_vm_ioctl(kvm_state, KVM_GET_NR_MMU_PAGES);
+		return 0;
+	}
+#endif
+	return -1;
+}
+
+#ifdef KVM_CAP_VAPIC
+
+static int tpr_access_reporting(CPUState *env, int enabled)
+{
+	int r;
+	struct kvm_tpr_access_ctl tac = {
+		.enabled = enabled,
+	};
+
+	r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_VAPIC);
+	if (r <= 0)
+		return -ENOSYS;
+	return kvm_vcpu_ioctl(env, KVM_TPR_ACCESS_REPORTING, &tac);
+}
+
+int kvm_enable_tpr_access_reporting(CPUState *env)
+{
+	return tpr_access_reporting(env, 1);
+}
+
+int kvm_disable_tpr_access_reporting(CPUState *env)
+{
+	return tpr_access_reporting(env, 0);
+}
+
+#endif
+
+#ifdef KVM_CAP_EXT_CPUID
+
+static struct kvm_cpuid2 *try_get_cpuid(kvm_context_t kvm, int max)
+{
+	struct kvm_cpuid2 *cpuid;
+	int r, size;
+
+	size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
+	cpuid = qemu_malloc(size);
+	cpuid->nent = max;
+	r = kvm_ioctl(kvm_state, KVM_GET_SUPPORTED_CPUID, cpuid);
+	if (r == 0 && cpuid->nent >= max)
+		r = -E2BIG;
+	if (r < 0) {
+		if (r == -E2BIG) {
+			free(cpuid);
+			return NULL;
+		} else {
+			fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
+				strerror(-r));
+			exit(1);
+		}
+	}
+	return cpuid;
+}
+
+#define R_EAX 0
+#define R_ECX 1
+#define R_EDX 2
+#define R_EBX 3
+#define R_ESP 4
+#define R_EBP 5
+#define R_ESI 6
+#define R_EDI 7
+
+uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg)
+{
+	struct kvm_cpuid2 *cpuid;
+	int i, max;
+	uint32_t ret = 0;
+	uint32_t cpuid_1_edx;
+
+	if (!kvm_check_extension(kvm_state, KVM_CAP_EXT_CPUID)) {
+		return -1U;
+	}
+
+	max = 1;
+	while ((cpuid = try_get_cpuid(kvm, max)) == NULL) {
+		max *= 2;
+	}
+
+	for (i = 0; i < cpuid->nent; ++i) {
+		if (cpuid->entries[i].function == function) {
+			switch (reg) {
+			case R_EAX:
+				ret = cpuid->entries[i].eax;
+				break;
+			case R_EBX:
+				ret = cpuid->entries[i].ebx;
+				break;
+			case R_ECX:
+				ret = cpuid->entries[i].ecx;
+				break;
+			case R_EDX:
+				ret = cpuid->entries[i].edx;
+                                if (function == 1) {
+                                    /* kvm misreports the following features
+                                     */
+                                    ret |= 1 << 12; /* MTRR */
+                                    ret |= 1 << 16; /* PAT */
+                                    ret |= 1 << 7;  /* MCE */
+                                    ret |= 1 << 14; /* MCA */
+                                }
+
+				/* On Intel, kvm returns cpuid according to
+				 * the Intel spec, so add missing bits
+				 * according to the AMD spec:
+				 */
+				if (function == 0x80000001) {
+					cpuid_1_edx = kvm_get_supported_cpuid(kvm, 1, R_EDX);
+					ret |= cpuid_1_edx & 0xdfeff7ff;
+				}
+				break;
+			}
+		}
+	}
+
+	free(cpuid);
+
+	return ret;
+}
+
+#else
+
+uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg)
+{
+	return -1U;
+}
+
+#endif
+int kvm_qemu_create_memory_alias(uint64_t phys_start,
+                                 uint64_t len,
+                                 uint64_t target_phys)
+{
+    return kvm_create_memory_alias(kvm_context, phys_start, len, target_phys);
+}
+
+int kvm_qemu_destroy_memory_alias(uint64_t phys_start)
+{
+	return kvm_destroy_memory_alias(kvm_context, phys_start);
+}
+
+#ifdef KVM_CAP_ADJUST_CLOCK
+static struct kvm_clock_data kvmclock_data;
+
+static void kvmclock_pre_save(void *opaque)
+{
+    struct kvm_clock_data *cl = opaque;
+
+    kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, cl);
+}
+
+static int kvmclock_post_load(void *opaque, int version_id)
+{
+    struct kvm_clock_data *cl = opaque;
+
+    return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, cl);
+}
+
+static const VMStateDescription vmstate_kvmclock= {
+    .name = "kvmclock",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvmclock_pre_save,
+    .post_load = kvmclock_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_U64(clock, struct kvm_clock_data),
+        VMSTATE_END_OF_LIST()
+    }
+};
+#endif
+
+int kvm_arch_qemu_create_context(void)
+{
+    int i;
+    struct utsname utsname;
+
+    uname(&utsname);
+    lm_capable_kernel = strcmp(utsname.machine, "x86_64") == 0;
+
+    if (kvm_shadow_memory)
+        kvm_set_shadow_pages(kvm_context, kvm_shadow_memory);
+
+    kvm_msr_list = kvm_get_msr_list(kvm_context);
+    if (!kvm_msr_list)
+		return -1;
+    for (i = 0; i < kvm_msr_list->nmsrs; ++i) {
+	if (kvm_msr_list->indices[i] == MSR_STAR)
+	    kvm_has_msr_star = 1;
+        if (kvm_msr_list->indices[i] == MSR_VM_HSAVE_PA)
+            kvm_has_vm_hsave_pa = 1;
+    }
+
+#ifdef KVM_CAP_ADJUST_CLOCK
+    if (kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK))
+        vmstate_register(0, &vmstate_kvmclock, &kvmclock_data);
+#endif
+    return 0;
+}
+
+static void set_msr_entry(struct kvm_msr_entry *entry, uint32_t index,
+                          uint64_t data)
+{
+    entry->index = index;
+    entry->data  = data;
+}
+
+/* returns 0 on success, non-0 on failure */
+static int get_msr_entry(struct kvm_msr_entry *entry, CPUState *env)
+{
+        switch (entry->index) {
+        case MSR_IA32_SYSENTER_CS:
+            env->sysenter_cs  = entry->data;
+            break;
+        case MSR_IA32_SYSENTER_ESP:
+            env->sysenter_esp = entry->data;
+            break;
+        case MSR_IA32_SYSENTER_EIP:
+            env->sysenter_eip = entry->data;
+            break;
+        case MSR_STAR:
+            env->star         = entry->data;
+            break;
+#ifdef TARGET_X86_64
+        case MSR_CSTAR:
+            env->cstar        = entry->data;
+            break;
+        case MSR_KERNELGSBASE:
+            env->kernelgsbase = entry->data;
+            break;
+        case MSR_FMASK:
+            env->fmask        = entry->data;
+            break;
+        case MSR_LSTAR:
+            env->lstar        = entry->data;
+            break;
+#endif
+        case MSR_IA32_TSC:
+            env->tsc          = entry->data;
+            break;
+        case MSR_VM_HSAVE_PA:
+            env->vm_hsave     = entry->data;
+            break;
+        case MSR_KVM_SYSTEM_TIME:
+            env->system_time_msr = entry->data;
+            break;
+        case MSR_KVM_WALL_CLOCK:
+            env->wall_clock_msr = entry->data;
+            break;
+        default:
+            printf("Warning unknown msr index 0x%x\n", entry->index);
+            return 1;
+        }
+        return 0;
+}
+
+static void set_v8086_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
+{
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->type = 3;
+    lhs->present = 1;
+    lhs->dpl = 3;
+    lhs->db = 0;
+    lhs->s = 1;
+    lhs->l = 0;
+    lhs->g = 0;
+    lhs->avl = 0;
+    lhs->unusable = 0;
+}
+
+static void set_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
+{
+    unsigned flags = rhs->flags;
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->type = (flags >> DESC_TYPE_SHIFT) & 15;
+    lhs->present = (flags & DESC_P_MASK) != 0;
+    lhs->dpl = rhs->selector & 3;
+    lhs->db = (flags >> DESC_B_SHIFT) & 1;
+    lhs->s = (flags & DESC_S_MASK) != 0;
+    lhs->l = (flags >> DESC_L_SHIFT) & 1;
+    lhs->g = (flags & DESC_G_MASK) != 0;
+    lhs->avl = (flags & DESC_AVL_MASK) != 0;
+    lhs->unusable = 0;
+}
+
+static void get_seg(SegmentCache *lhs, const struct kvm_segment *rhs)
+{
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->flags =
+	(rhs->type << DESC_TYPE_SHIFT)
+	| (rhs->present * DESC_P_MASK)
+	| (rhs->dpl << DESC_DPL_SHIFT)
+	| (rhs->db << DESC_B_SHIFT)
+	| (rhs->s * DESC_S_MASK)
+	| (rhs->l << DESC_L_SHIFT)
+	| (rhs->g * DESC_G_MASK)
+	| (rhs->avl * DESC_AVL_MASK);
+}
+
+void kvm_arch_load_regs(CPUState *env)
+{
+    struct kvm_regs regs;
+    struct kvm_fpu fpu;
+    struct kvm_sregs sregs;
+    struct kvm_msr_entry msrs[100];
+    int rc, n, i;
+
+    regs.rax = env->regs[R_EAX];
+    regs.rbx = env->regs[R_EBX];
+    regs.rcx = env->regs[R_ECX];
+    regs.rdx = env->regs[R_EDX];
+    regs.rsi = env->regs[R_ESI];
+    regs.rdi = env->regs[R_EDI];
+    regs.rsp = env->regs[R_ESP];
+    regs.rbp = env->regs[R_EBP];
+#ifdef TARGET_X86_64
+    regs.r8 = env->regs[8];
+    regs.r9 = env->regs[9];
+    regs.r10 = env->regs[10];
+    regs.r11 = env->regs[11];
+    regs.r12 = env->regs[12];
+    regs.r13 = env->regs[13];
+    regs.r14 = env->regs[14];
+    regs.r15 = env->regs[15];
+#endif
+
+    regs.rflags = env->eflags;
+    regs.rip = env->eip;
+
+    kvm_set_regs(env, &regs);
+
+    memset(&fpu, 0, sizeof fpu);
+    fpu.fsw = env->fpus & ~(7 << 11);
+    fpu.fsw |= (env->fpstt & 7) << 11;
+    fpu.fcw = env->fpuc;
+    for (i = 0; i < 8; ++i)
+	fpu.ftwx |= (!env->fptags[i]) << i;
+    memcpy(fpu.fpr, env->fpregs, sizeof env->fpregs);
+    memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs);
+    fpu.mxcsr = env->mxcsr;
+    kvm_set_fpu(env, &fpu);
+
+    memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
+    if (env->interrupt_injected >= 0) {
+        sregs.interrupt_bitmap[env->interrupt_injected / 64] |=
+                (uint64_t)1 << (env->interrupt_injected % 64);
+    }
+
+    if ((env->eflags & VM_MASK)) {
+	    set_v8086_seg(&sregs.cs, &env->segs[R_CS]);
+	    set_v8086_seg(&sregs.ds, &env->segs[R_DS]);
+	    set_v8086_seg(&sregs.es, &env->segs[R_ES]);
+	    set_v8086_seg(&sregs.fs, &env->segs[R_FS]);
+	    set_v8086_seg(&sregs.gs, &env->segs[R_GS]);
+	    set_v8086_seg(&sregs.ss, &env->segs[R_SS]);
+    } else {
+	    set_seg(&sregs.cs, &env->segs[R_CS]);
+	    set_seg(&sregs.ds, &env->segs[R_DS]);
+	    set_seg(&sregs.es, &env->segs[R_ES]);
+	    set_seg(&sregs.fs, &env->segs[R_FS]);
+	    set_seg(&sregs.gs, &env->segs[R_GS]);
+	    set_seg(&sregs.ss, &env->segs[R_SS]);
+
+	    if (env->cr[0] & CR0_PE_MASK) {
+		/* force ss cpl to cs cpl */
+		sregs.ss.selector = (sregs.ss.selector & ~3) |
+			(sregs.cs.selector & 3);
+		sregs.ss.dpl = sregs.ss.selector & 3;
+	    }
+    }
+
+    set_seg(&sregs.tr, &env->tr);
+    set_seg(&sregs.ldt, &env->ldt);
+
+    sregs.idt.limit = env->idt.limit;
+    sregs.idt.base = env->idt.base;
+    sregs.gdt.limit = env->gdt.limit;
+    sregs.gdt.base = env->gdt.base;
+
+    sregs.cr0 = env->cr[0];
+    sregs.cr2 = env->cr[2];
+    sregs.cr3 = env->cr[3];
+    sregs.cr4 = env->cr[4];
+
+    sregs.cr8 = cpu_get_apic_tpr(env);
+    sregs.apic_base = cpu_get_apic_base(env);
+
+    sregs.efer = env->efer;
+
+    kvm_set_sregs(env, &sregs);
+
+    /* msrs */
+    n = 0;
+    /* Remember to increase msrs size if you add new registers below */
+    set_msr_entry(&msrs[n++], MSR_IA32_SYSENTER_CS,  env->sysenter_cs);
+    set_msr_entry(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
+    set_msr_entry(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
+    if (kvm_has_msr_star)
+	set_msr_entry(&msrs[n++], MSR_STAR,              env->star);
+    if (kvm_has_vm_hsave_pa)
+        set_msr_entry(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
+#ifdef TARGET_X86_64
+    if (lm_capable_kernel) {
+        set_msr_entry(&msrs[n++], MSR_CSTAR,             env->cstar);
+        set_msr_entry(&msrs[n++], MSR_KERNELGSBASE,      env->kernelgsbase);
+        set_msr_entry(&msrs[n++], MSR_FMASK,             env->fmask);
+        set_msr_entry(&msrs[n++], MSR_LSTAR  ,           env->lstar);
+    }
+#endif
+    set_msr_entry(&msrs[n++], MSR_KVM_SYSTEM_TIME,  env->system_time_msr);
+    set_msr_entry(&msrs[n++], MSR_KVM_WALL_CLOCK,  env->wall_clock_msr);
+
+    rc = kvm_set_msrs(env, msrs, n);
+    if (rc == -1)
+        perror("kvm_set_msrs FAILED");
+}
+
+void kvm_load_tsc(CPUState *env)
+{
+    int rc;
+    struct kvm_msr_entry msr;
+
+    set_msr_entry(&msr, MSR_IA32_TSC, env->tsc);
+
+    rc = kvm_set_msrs(env, &msr, 1);
+    if (rc == -1)
+        perror("kvm_set_tsc FAILED.\n");
+}
+
+void kvm_arch_save_mpstate(CPUState *env)
+{
+#ifdef KVM_CAP_MP_STATE
+    int r;
+    struct kvm_mp_state mp_state;
+
+    r = kvm_get_mpstate(env, &mp_state);
+    if (r < 0)
+        env->mp_state = -1;
+    else
+        env->mp_state = mp_state.mp_state;
+#else
+    env->mp_state = -1;
+#endif
+}
+
+void kvm_arch_load_mpstate(CPUState *env)
+{
+#ifdef KVM_CAP_MP_STATE
+    struct kvm_mp_state mp_state = { .mp_state = env->mp_state };
+
+    /*
+     * -1 indicates that the host did not support GET_MP_STATE ioctl,
+     *  so don't touch it.
+     */
+    if (env->mp_state != -1)
+        kvm_set_mpstate(env, &mp_state);
+#endif
+}
+
+void kvm_arch_save_regs(CPUState *env)
+{
+    struct kvm_regs regs;
+    struct kvm_fpu fpu;
+    struct kvm_sregs sregs;
+    struct kvm_msr_entry msrs[100];
+    uint32_t hflags;
+    uint32_t i, n, rc, bit;
+
+    kvm_get_regs(env, &regs);
+
+    env->regs[R_EAX] = regs.rax;
+    env->regs[R_EBX] = regs.rbx;
+    env->regs[R_ECX] = regs.rcx;
+    env->regs[R_EDX] = regs.rdx;
+    env->regs[R_ESI] = regs.rsi;
+    env->regs[R_EDI] = regs.rdi;
+    env->regs[R_ESP] = regs.rsp;
+    env->regs[R_EBP] = regs.rbp;
+#ifdef TARGET_X86_64
+    env->regs[8] = regs.r8;
+    env->regs[9] = regs.r9;
+    env->regs[10] = regs.r10;
+    env->regs[11] = regs.r11;
+    env->regs[12] = regs.r12;
+    env->regs[13] = regs.r13;
+    env->regs[14] = regs.r14;
+    env->regs[15] = regs.r15;
+#endif
+
+    env->eflags = regs.rflags;
+    env->eip = regs.rip;
+
+    kvm_get_fpu(env, &fpu);
+    env->fpstt = (fpu.fsw >> 11) & 7;
+    env->fpus = fpu.fsw;
+    env->fpuc = fpu.fcw;
+    for (i = 0; i < 8; ++i)
+	env->fptags[i] = !((fpu.ftwx >> i) & 1);
+    memcpy(env->fpregs, fpu.fpr, sizeof env->fpregs);
+    memcpy(env->xmm_regs, fpu.xmm, sizeof env->xmm_regs);
+    env->mxcsr = fpu.mxcsr;
+
+    kvm_get_sregs(env, &sregs);
+
+    /* There can only be one pending IRQ set in the bitmap at a time, so try
+       to find it and save its number instead (-1 for none). */
+    env->interrupt_injected = -1;
+    for (i = 0; i < ARRAY_SIZE(sregs.interrupt_bitmap); i++) {
+        if (sregs.interrupt_bitmap[i]) {
+            bit = ctz64(sregs.interrupt_bitmap[i]);
+            env->interrupt_injected = i * 64 + bit;
+            break;
+        }
+    }
+
+    get_seg(&env->segs[R_CS], &sregs.cs);
+    get_seg(&env->segs[R_DS], &sregs.ds);
+    get_seg(&env->segs[R_ES], &sregs.es);
+    get_seg(&env->segs[R_FS], &sregs.fs);
+    get_seg(&env->segs[R_GS], &sregs.gs);
+    get_seg(&env->segs[R_SS], &sregs.ss);
+
+    get_seg(&env->tr, &sregs.tr);
+    get_seg(&env->ldt, &sregs.ldt);
+
+    env->idt.limit = sregs.idt.limit;
+    env->idt.base = sregs.idt.base;
+    env->gdt.limit = sregs.gdt.limit;
+    env->gdt.base = sregs.gdt.base;
+
+    env->cr[0] = sregs.cr0;
+    env->cr[2] = sregs.cr2;
+    env->cr[3] = sregs.cr3;
+    env->cr[4] = sregs.cr4;
+
+    cpu_set_apic_base(env, sregs.apic_base);
+
+    env->efer = sregs.efer;
+    //cpu_set_apic_tpr(env, sregs.cr8);
+
+#define HFLAG_COPY_MASK ~( \
+			HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \
+			HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \
+			HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
+			HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
+
+
+
+    hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+    hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
+    hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
+	    (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
+    hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
+    hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
+	    (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
+
+    if (env->efer & MSR_EFER_LMA) {
+        hflags |= HF_LMA_MASK;
+    }
+
+    if ((hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) {
+        hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
+    } else {
+        hflags |= (env->segs[R_CS].flags & DESC_B_MASK) >>
+		(DESC_B_SHIFT - HF_CS32_SHIFT);
+        hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >>
+		(DESC_B_SHIFT - HF_SS32_SHIFT);
+        if (!(env->cr[0] & CR0_PE_MASK) ||
+                   (env->eflags & VM_MASK) ||
+                   !(hflags & HF_CS32_MASK)) {
+                hflags |= HF_ADDSEG_MASK;
+            } else {
+                hflags |= ((env->segs[R_DS].base |
+                                env->segs[R_ES].base |
+                                env->segs[R_SS].base) != 0) <<
+                    HF_ADDSEG_SHIFT;
+            }
+    }
+    env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+
+    /* msrs */
+    n = 0;
+    /* Remember to increase msrs size if you add new registers below */
+    msrs[n++].index = MSR_IA32_SYSENTER_CS;
+    msrs[n++].index = MSR_IA32_SYSENTER_ESP;
+    msrs[n++].index = MSR_IA32_SYSENTER_EIP;
+    if (kvm_has_msr_star)
+	msrs[n++].index = MSR_STAR;
+    msrs[n++].index = MSR_IA32_TSC;
+    if (kvm_has_vm_hsave_pa)
+        msrs[n++].index = MSR_VM_HSAVE_PA;
+#ifdef TARGET_X86_64
+    if (lm_capable_kernel) {
+        msrs[n++].index = MSR_CSTAR;
+        msrs[n++].index = MSR_KERNELGSBASE;
+        msrs[n++].index = MSR_FMASK;
+        msrs[n++].index = MSR_LSTAR;
+    }
+#endif
+    msrs[n++].index = MSR_KVM_SYSTEM_TIME;
+    msrs[n++].index = MSR_KVM_WALL_CLOCK;
+
+    rc = kvm_get_msrs(env, msrs, n);
+    if (rc == -1) {
+        perror("kvm_get_msrs FAILED");
+    }
+    else {
+        n = rc; /* actual number of MSRs */
+        for (i=0 ; i<n; i++) {
+            if (get_msr_entry(&msrs[i], env))
+                return;
+        }
+    }
+    kvm_arch_save_mpstate(env);
+}
+
+static void do_cpuid_ent(struct kvm_cpuid_entry2 *e, uint32_t function,
+                         uint32_t count, CPUState *env)
+{
+    env->regs[R_EAX] = function;
+    env->regs[R_ECX] = count;
+    qemu_kvm_cpuid_on_env(env);
+    e->function = function;
+    e->flags = 0;
+    e->index = 0;
+    e->eax = env->regs[R_EAX];
+    e->ebx = env->regs[R_EBX];
+    e->ecx = env->regs[R_ECX];
+    e->edx = env->regs[R_EDX];
+}
+
+struct kvm_para_features {
+	int cap;
+	int feature;
+} para_features[] = {
+#ifdef KVM_CAP_CLOCKSOURCE
+	{ KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
+#endif
+#ifdef KVM_CAP_NOP_IO_DELAY
+	{ KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
+#endif
+#ifdef KVM_CAP_PV_MMU
+	{ KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
+#endif
+#ifdef KVM_CAP_CR3_CACHE
+	{ KVM_CAP_CR3_CACHE, KVM_FEATURE_CR3_CACHE },
+#endif
+	{ -1, -1 }
+};
+
+static int get_para_features(kvm_context_t kvm_context)
+{
+	int i, features = 0;
+
+	for (i = 0; i < ARRAY_SIZE(para_features)-1; i++) {
+		if (kvm_check_extension(kvm_state, para_features[i].cap))
+			features |= (1 << para_features[i].feature);
+	}
+
+	return features;
+}
+
+static void kvm_trim_features(uint32_t *features, uint32_t supported)
+{
+    int i;
+    uint32_t mask;
+
+    for (i = 0; i < 32; ++i) {
+        mask = 1U << i;
+        if ((*features & mask) && !(supported & mask)) {
+            *features &= ~mask;
+        }
+    }
+}
+
+int kvm_arch_init_vcpu(CPUState *cenv)
+{
+    struct kvm_cpuid_entry2 cpuid_ent[100];
+#ifdef KVM_CPUID_SIGNATURE
+    struct kvm_cpuid_entry2 *pv_ent;
+    uint32_t signature[3];
+#endif
+    int cpuid_nent = 0;
+    CPUState copy;
+    uint32_t i, j, limit;
+
+    qemu_kvm_load_lapic(cenv);
+
+    cenv->interrupt_injected = -1;
+
+#ifdef KVM_CPUID_SIGNATURE
+    /* Paravirtualization CPUIDs */
+    memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+    pv_ent = &cpuid_ent[cpuid_nent++];
+    memset(pv_ent, 0, sizeof(*pv_ent));
+    pv_ent->function = KVM_CPUID_SIGNATURE;
+    pv_ent->eax = 0;
+    pv_ent->ebx = signature[0];
+    pv_ent->ecx = signature[1];
+    pv_ent->edx = signature[2];
+
+    pv_ent = &cpuid_ent[cpuid_nent++];
+    memset(pv_ent, 0, sizeof(*pv_ent));
+    pv_ent->function = KVM_CPUID_FEATURES;
+    pv_ent->eax = get_para_features(kvm_context);
+#endif
+
+    kvm_trim_features(&cenv->cpuid_features,
+                      kvm_arch_get_supported_cpuid(cenv, 1, R_EDX));
+
+    /* prevent the hypervisor bit from being cleared by the kernel */
+    i = cenv->cpuid_ext_features & CPUID_EXT_HYPERVISOR;
+    kvm_trim_features(&cenv->cpuid_ext_features,
+                      kvm_arch_get_supported_cpuid(cenv, 1, R_ECX));
+    cenv->cpuid_ext_features |= i;
+
+    kvm_trim_features(&cenv->cpuid_ext2_features,
+                      kvm_arch_get_supported_cpuid(cenv, 0x80000001, R_EDX));
+    kvm_trim_features(&cenv->cpuid_ext3_features,
+                      kvm_arch_get_supported_cpuid(cenv, 0x80000001, R_ECX));
+
+    copy = *cenv;
+
+    copy.regs[R_EAX] = 0;
+    qemu_kvm_cpuid_on_env(&copy);
+    limit = copy.regs[R_EAX];
+
+    for (i = 0; i <= limit; ++i) {
+        if (i == 4 || i == 0xb || i == 0xd) {
+            for (j = 0; ; ++j) {
+                do_cpuid_ent(&cpuid_ent[cpuid_nent], i, j, &copy);
+
+                cpuid_ent[cpuid_nent].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                cpuid_ent[cpuid_nent].index = j;
+
+                cpuid_nent++;
+
+                if (i == 4 && copy.regs[R_EAX] == 0)
+                    break;
+                if (i == 0xb && !(copy.regs[R_ECX] & 0xff00))
+                    break;
+                if (i == 0xd && copy.regs[R_EAX] == 0)
+                    break;
+            }
+        } else
+            do_cpuid_ent(&cpuid_ent[cpuid_nent++], i, 0, &copy);
+    }
+
+    copy.regs[R_EAX] = 0x80000000;
+    qemu_kvm_cpuid_on_env(&copy);
+    limit = copy.regs[R_EAX];
+
+    for (i = 0x80000000; i <= limit; ++i)
+	do_cpuid_ent(&cpuid_ent[cpuid_nent++], i, 0, &copy);
+
+    kvm_setup_cpuid2(cenv, cpuid_nent, cpuid_ent);
+
+#ifdef KVM_CAP_MCE
+    if (((cenv->cpuid_version >> 8)&0xF) >= 6
+        && (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+        && kvm_check_extension(kvm_state, KVM_CAP_MCE) > 0) {
+        uint64_t mcg_cap;
+        int banks;
+
+        if (kvm_get_mce_cap_supported(kvm_context, &mcg_cap, &banks))
+            perror("kvm_get_mce_cap_supported FAILED");
+        else {
+            if (banks > MCE_BANKS_DEF)
+                banks = MCE_BANKS_DEF;
+            mcg_cap &= MCE_CAP_DEF;
+            mcg_cap |= banks;
+            if (kvm_setup_mce(cenv, &mcg_cap))
+                perror("kvm_setup_mce FAILED");
+            else
+                cenv->mcg_cap = mcg_cap;
+        }
+    }
+#endif
+
+#ifdef KVM_EXIT_TPR_ACCESS
+    kvm_tpr_vcpu_start(cenv);
+#endif
+    return 0;
+}
+
+int kvm_arch_halt(CPUState *env)
+{
+
+    if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+	  (env->eflags & IF_MASK)) &&
+	!(env->interrupt_request & CPU_INTERRUPT_NMI)) {
+            env->halted = 1;
+    }
+    return 1;
+}
+
+int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+{
+    if (env->update_vapic) {
+        kvm_tpr_enable_vapic(env);
+    }
+    if (!kvm_irqchip_in_kernel())
+	kvm_set_cr8(env, cpu_get_apic_tpr(env));
+    return 0;
+}
+
+int kvm_arch_has_work(CPUState *env)
+{
+    if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+	 (env->eflags & IF_MASK)) ||
+	(env->interrupt_request & CPU_INTERRUPT_NMI))
+	return 1;
+    return 0;
+}
+
+int kvm_arch_try_push_interrupts(void *opaque)
+{
+    CPUState *env = cpu_single_env;
+    int r, irq;
+
+    if (kvm_is_ready_for_interrupt_injection(env) &&
+        (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        (env->eflags & IF_MASK)) {
+            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+	    irq = cpu_get_pic_interrupt(env);
+	    if (irq >= 0) {
+		r = kvm_inject_irq(env, irq);
+		if (r < 0)
+		    printf("cpu %d fail inject %x\n", env->cpu_index, irq);
+	    }
+    }
+
+    return (env->interrupt_request & CPU_INTERRUPT_HARD) != 0;
+}
+
+#ifdef KVM_CAP_USER_NMI
+void kvm_arch_push_nmi(void *opaque)
+{
+    CPUState *env = cpu_single_env;
+    int r;
+
+    if (likely(!(env->interrupt_request & CPU_INTERRUPT_NMI)))
+        return;
+
+    env->interrupt_request &= ~CPU_INTERRUPT_NMI;
+    r = kvm_inject_nmi(env);
+    if (r < 0)
+        printf("cpu %d fail inject NMI\n", env->cpu_index);
+}
+#endif /* KVM_CAP_USER_NMI */
+
+void kvm_arch_cpu_reset(CPUState *env)
+{
+    env->interrupt_injected = -1;
+    kvm_arch_load_regs(env);
+    if (!cpu_is_bsp(env)) {
+	if (kvm_irqchip_in_kernel()) {
+#ifdef KVM_CAP_MP_STATE
+	    kvm_reset_mpstate(env);
+#endif
+	} else {
+	    env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+	    env->halted = 1;
+	}
+    }
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    uint8_t int3 = 0xcc;
+
+    if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) ||
+        cpu_memory_rw_debug(env, bp->pc, &int3, 1, 1))
+        return -EINVAL;
+    return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    uint8_t int3;
+
+    if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc ||
+        cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1))
+        return -EINVAL;
+    return 0;
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+static struct {
+    target_ulong addr;
+    int len;
+    int type;
+} hw_breakpoint[4];
+
+static int nb_hw_breakpoint;
+
+static int find_hw_breakpoint(target_ulong addr, int len, int type)
+{
+    int n;
+
+    for (n = 0; n < nb_hw_breakpoint; n++)
+	if (hw_breakpoint[n].addr == addr && hw_breakpoint[n].type == type &&
+	    (hw_breakpoint[n].len == len || len == -1))
+	    return n;
+    return -1;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+	len = 1;
+	break;
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_ACCESS:
+	switch (len) {
+	case 1:
+	    break;
+	case 2:
+	case 4:
+	case 8:
+	    if (addr & (len - 1))
+		return -EINVAL;
+	    break;
+	default:
+	    return -EINVAL;
+	}
+	break;
+    default:
+	return -ENOSYS;
+    }
+
+    if (nb_hw_breakpoint == 4)
+        return -ENOBUFS;
+
+    if (find_hw_breakpoint(addr, len, type) >= 0)
+        return -EEXIST;
+
+    hw_breakpoint[nb_hw_breakpoint].addr = addr;
+    hw_breakpoint[nb_hw_breakpoint].len = len;
+    hw_breakpoint[nb_hw_breakpoint].type = type;
+    nb_hw_breakpoint++;
+
+    return 0;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    int n;
+
+    n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type);
+    if (n < 0)
+        return -ENOENT;
+
+    nb_hw_breakpoint--;
+    hw_breakpoint[n] = hw_breakpoint[nb_hw_breakpoint];
+
+    return 0;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    nb_hw_breakpoint = 0;
+}
+
+static CPUWatchpoint hw_watchpoint;
+
+int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
+{
+    int handle = 0;
+    int n;
+
+    if (arch_info->exception == 1) {
+	if (arch_info->dr6 & (1 << 14)) {
+	    if (cpu_single_env->singlestep_enabled)
+		handle = 1;
+	} else {
+	    for (n = 0; n < 4; n++)
+		if (arch_info->dr6 & (1 << n))
+		    switch ((arch_info->dr7 >> (16 + n*4)) & 0x3) {
+		    case 0x0:
+			handle = 1;
+			break;
+		    case 0x1:
+			handle = 1;
+			cpu_single_env->watchpoint_hit = &hw_watchpoint;
+			hw_watchpoint.vaddr = hw_breakpoint[n].addr;
+			hw_watchpoint.flags = BP_MEM_WRITE;
+			break;
+		    case 0x3:
+			handle = 1;
+			cpu_single_env->watchpoint_hit = &hw_watchpoint;
+			hw_watchpoint.vaddr = hw_breakpoint[n].addr;
+			hw_watchpoint.flags = BP_MEM_ACCESS;
+			break;
+		    }
+	}
+    } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc))
+	handle = 1;
+
+    if (!handle)
+	kvm_update_guest_debug(cpu_single_env,
+			(arch_info->exception == 1) ?
+			KVM_GUESTDBG_INJECT_DB : KVM_GUESTDBG_INJECT_BP);
+
+    return handle;
+}
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
+{
+    const uint8_t type_code[] = {
+	[GDB_BREAKPOINT_HW] = 0x0,
+	[GDB_WATCHPOINT_WRITE] = 0x1,
+	[GDB_WATCHPOINT_ACCESS] = 0x3
+    };
+    const uint8_t len_code[] = {
+	[1] = 0x0, [2] = 0x1, [4] = 0x3, [8] = 0x2
+    };
+    int n;
+
+    if (kvm_sw_breakpoints_active(env))
+	dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+
+    if (nb_hw_breakpoint > 0) {
+	dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+	dbg->arch.debugreg[7] = 0x0600;
+	for (n = 0; n < nb_hw_breakpoint; n++) {
+	    dbg->arch.debugreg[n] = hw_breakpoint[n].addr;
+	    dbg->arch.debugreg[7] |= (2 << (n * 2)) |
+		(type_code[hw_breakpoint[n].type] << (16 + n*4)) |
+		(len_code[hw_breakpoint[n].len] << (18 + n*4));
+	}
+    }
+}
+#endif
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+void kvm_arch_do_ioperm(void *_data)
+{
+    struct ioperm_data *data = _data;
+    ioperm(data->start_port, data->num, data->turn_on);
+}
+#endif
+
+/*
+ * Setup x86 specific IRQ routing
+ */
+int kvm_arch_init_irq_routing(void)
+{
+    int i, r;
+
+    if (kvm_irqchip && kvm_has_gsi_routing(kvm_context)) {
+        kvm_clear_gsi_routes(kvm_context);
+        for (i = 0; i < 8; ++i) {
+            if (i == 2)
+                continue;
+            r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_PIC_MASTER, i);
+            if (r < 0)
+                return r;
+        }
+        for (i = 8; i < 16; ++i) {
+            r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+            if (r < 0)
+                return r;
+        }
+        for (i = 0; i < 24; ++i) {
+            if (i == 0) {
+                r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_IOAPIC, 2);
+            } else if (i != 2) {
+                r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_IOAPIC, i);
+            }
+            if (r < 0)
+                return r;
+        }
+        kvm_commit_irq_routes(kvm_context);
+    }
+    return 0;
+}
+
+uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
+                                      int reg)
+{
+    return kvm_get_supported_cpuid(kvm_context, function, reg);
+}
+
+void kvm_arch_process_irqchip_events(CPUState *env)
+{
+    if (env->interrupt_request & CPU_INTERRUPT_INIT) {
+        kvm_cpu_synchronize_state(env);
+        do_cpu_init(env);
+    }
+    if (env->interrupt_request & CPU_INTERRUPT_SIPI) {
+        kvm_cpu_synchronize_state(env);
+        do_cpu_sipi(env);
+    }
+}
diff --git a/qemu-kvm.c b/qemu-kvm.c
new file mode 100644
index 0000000..44e8b75
--- /dev/null
+++ b/qemu-kvm.c
@@ -0,0 +1,2659 @@
+/*
+ * qemu/kvm integration
+ *
+ * Copyright (C) 2006-2008 Qumranet Technologies
+ *
+ * Licensed under the terms of the GNU GPL version 2 or higher.
+ */
+#include "config.h"
+#include "config-host.h"
+
+#include <assert.h>
+#include <string.h>
+#include "hw/hw.h"
+#include "sysemu.h"
+#include "qemu-common.h"
+#include "console.h"
+#include "block.h"
+#include "compatfd.h"
+#include "gdbstub.h"
+
+#include "qemu-kvm.h"
+#include "libkvm.h"
+
+#include <pthread.h>
+#include <sys/utsname.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "compatfd.h"
+#include <sys/prctl.h>
+
+#define false 0
+#define true 1
+
+#ifndef PR_MCE_KILL
+#define PR_MCE_KILL 33
+#endif
+
+#ifndef BUS_MCEERR_AR
+#define BUS_MCEERR_AR 4
+#endif
+#ifndef BUS_MCEERR_AO
+#define BUS_MCEERR_AO 5
+#endif
+
+#define EXPECTED_KVM_API_VERSION 12
+
+#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
+#error libkvm: userspace and kernel version mismatch
+#endif
+
+int kvm_allowed = 1;
+int kvm_irqchip = 1;
+int kvm_pit = 1;
+int kvm_pit_reinject = 1;
+int kvm_nested = 0;
+
+
+KVMState *kvm_state;
+kvm_context_t kvm_context;
+
+pthread_mutex_t qemu_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t qemu_vcpu_cond = PTHREAD_COND_INITIALIZER;
+pthread_cond_t qemu_system_cond = PTHREAD_COND_INITIALIZER;
+pthread_cond_t qemu_pause_cond = PTHREAD_COND_INITIALIZER;
+pthread_cond_t qemu_work_cond = PTHREAD_COND_INITIALIZER;
+__thread CPUState *current_env;
+
+static int qemu_system_ready;
+
+#define SIG_IPI (SIGRTMIN+4)
+
+pthread_t io_thread;
+static int io_thread_fd = -1;
+static int io_thread_sigfd = -1;
+
+static CPUState *kvm_debug_cpu_requested;
+
+static uint64_t phys_ram_size;
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+/* The list of ioperm_data */
+static QLIST_HEAD(, ioperm_data) ioperm_head;
+#endif
+
+//#define DEBUG_MEMREG
+#ifdef	DEBUG_MEMREG
+#define DPRINTF(fmt, args...) \
+	do { fprintf(stderr, "%s:%d " fmt , __func__, __LINE__, ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1))
+
+int kvm_abi = EXPECTED_KVM_API_VERSION;
+int kvm_page_size;
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+static int kvm_debug(CPUState *env,
+                     struct kvm_debug_exit_arch *arch_info)
+{
+    int handle = kvm_arch_debug(arch_info);
+
+    if (handle) {
+        kvm_debug_cpu_requested = env;
+        env->stopped = 1;
+    }
+    return handle;
+}
+#endif
+
+static int handle_unhandled(uint64_t reason)
+{
+    fprintf(stderr, "kvm: unhandled exit %" PRIx64 "\n", reason);
+    return -EINVAL;
+}
+
+
+static inline void set_gsi(kvm_context_t kvm, unsigned int gsi)
+{
+    uint32_t *bitmap = kvm->used_gsi_bitmap;
+
+    if (gsi < kvm->max_gsi)
+        bitmap[gsi / 32] |= 1U << (gsi % 32);
+    else
+        DPRINTF("Invalid GSI %u\n", gsi);
+}
+
+static inline void clear_gsi(kvm_context_t kvm, unsigned int gsi)
+{
+    uint32_t *bitmap = kvm->used_gsi_bitmap;
+
+    if (gsi < kvm->max_gsi)
+        bitmap[gsi / 32] &= ~(1U << (gsi % 32));
+    else
+        DPRINTF("Invalid GSI %u\n", gsi);
+}
+
+struct slot_info {
+    unsigned long phys_addr;
+    unsigned long len;
+    unsigned long userspace_addr;
+    unsigned flags;
+    int logging_count;
+};
+
+struct slot_info slots[KVM_MAX_NUM_MEM_REGIONS];
+
+static void init_slots(void)
+{
+    int i;
+
+    for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i)
+        slots[i].len = 0;
+}
+
+static int get_free_slot(kvm_context_t kvm)
+{
+    int i;
+    int tss_ext;
+
+#if defined(KVM_CAP_SET_TSS_ADDR) && !defined(__s390__)
+    tss_ext = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
+#else
+    tss_ext = 0;
+#endif
+
+    /*
+     * on older kernels where the set tss ioctl is not supprted we must save
+     * slot 0 to hold the extended memory, as the vmx will use the last 3
+     * pages of this slot.
+     */
+    if (tss_ext > 0)
+        i = 0;
+    else
+        i = 1;
+
+    for (; i < KVM_MAX_NUM_MEM_REGIONS; ++i)
+        if (!slots[i].len)
+            return i;
+    return -1;
+}
+
+static void register_slot(int slot, unsigned long phys_addr,
+                          unsigned long len, unsigned long userspace_addr,
+                          unsigned flags)
+{
+    slots[slot].phys_addr = phys_addr;
+    slots[slot].len = len;
+    slots[slot].userspace_addr = userspace_addr;
+    slots[slot].flags = flags;
+}
+
+static void free_slot(int slot)
+{
+    slots[slot].len = 0;
+    slots[slot].logging_count = 0;
+}
+
+static int get_slot(unsigned long phys_addr)
+{
+    int i;
+
+    for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i) {
+        if (slots[i].len && slots[i].phys_addr <= phys_addr &&
+            (slots[i].phys_addr + slots[i].len - 1) >= phys_addr)
+            return i;
+    }
+    return -1;
+}
+
+/* Returns -1 if this slot is not totally contained on any other,
+ * and the number of the slot otherwise */
+static int get_container_slot(uint64_t phys_addr, unsigned long size)
+{
+    int i;
+
+    for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i)
+        if (slots[i].len && slots[i].phys_addr <= phys_addr &&
+            (slots[i].phys_addr + slots[i].len) >= phys_addr + size)
+            return i;
+    return -1;
+}
+
+int kvm_is_containing_region(kvm_context_t kvm, unsigned long phys_addr,
+                             unsigned long size)
+{
+    int slot = get_container_slot(phys_addr, size);
+    if (slot == -1)
+        return 0;
+    return 1;
+}
+
+/*
+ * dirty pages logging control
+ */
+static int kvm_dirty_pages_log_change(kvm_context_t kvm,
+                                      unsigned long phys_addr, unsigned flags,
+                                      unsigned mask)
+{
+    int r = -1;
+    int slot = get_slot(phys_addr);
+
+    if (slot == -1) {
+        fprintf(stderr, "BUG: %s: invalid parameters\n", __FUNCTION__);
+        return 1;
+    }
+
+    flags = (slots[slot].flags & ~mask) | flags;
+    if (flags == slots[slot].flags)
+        return 0;
+    slots[slot].flags = flags;
+
+    {
+        struct kvm_userspace_memory_region mem = {
+            .slot = slot,
+            .memory_size = slots[slot].len,
+            .guest_phys_addr = slots[slot].phys_addr,
+            .userspace_addr = slots[slot].userspace_addr,
+            .flags = slots[slot].flags,
+        };
+
+
+        DPRINTF("slot %d start %llx len %llx flags %x\n",
+                mem.slot, mem.guest_phys_addr, mem.memory_size, mem.flags);
+        r = kvm_vm_ioctl(kvm_state, KVM_SET_USER_MEMORY_REGION, &mem);
+        if (r < 0)
+            fprintf(stderr, "%s: %m\n", __FUNCTION__);
+    }
+    return r;
+}
+
+static int kvm_dirty_pages_log_change_all(kvm_context_t kvm,
+                                          int (*change)(kvm_context_t kvm,
+                                                        uint64_t start,
+                                                        uint64_t len))
+{
+    int i, r;
+
+    for (i = r = 0; i < KVM_MAX_NUM_MEM_REGIONS && r == 0; i++) {
+        if (slots[i].len)
+            r = change(kvm, slots[i].phys_addr, slots[i].len);
+    }
+    return r;
+}
+
+int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm, uint64_t phys_addr,
+                                    uint64_t len)
+{
+    int slot = get_slot(phys_addr);
+
+    DPRINTF("start %" PRIx64 " len %" PRIx64 "\n", phys_addr, len);
+    if (slot == -1) {
+        fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
+        return -EINVAL;
+    }
+
+    if (slots[slot].logging_count++)
+        return 0;
+
+    return kvm_dirty_pages_log_change(kvm, slots[slot].phys_addr,
+                                      KVM_MEM_LOG_DIRTY_PAGES,
+                                      KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+int kvm_dirty_pages_log_disable_slot(kvm_context_t kvm, uint64_t phys_addr,
+                                     uint64_t len)
+{
+    int slot = get_slot(phys_addr);
+
+    if (slot == -1) {
+        fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
+        return -EINVAL;
+    }
+
+    if (--slots[slot].logging_count)
+        return 0;
+
+    return kvm_dirty_pages_log_change(kvm, slots[slot].phys_addr, 0,
+                                      KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+/**
+ * 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_dirty_pages_log_enable_slot);
+}
+
+/**
+ * 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,
+                                          kvm_dirty_pages_log_disable_slot);
+}
+
+
+static int kvm_create_context(void);
+
+int kvm_init(int smp_cpus)
+{
+    int fd;
+    int r, gsi_count;
+
+
+    fd = open("/dev/kvm", O_RDWR);
+    if (fd == -1) {
+        perror("open /dev/kvm");
+        return -1;
+    }
+    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) {
+        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_page_size = getpagesize();
+    kvm_state = qemu_mallocz(sizeof(*kvm_state));
+    kvm_context = &kvm_state->kvm_context;
+
+    kvm_state->fd = fd;
+    kvm_state->vmfd = -1;
+    kvm_context->opaque = cpu_single_env;
+    kvm_context->dirty_pages_log_all = 0;
+    kvm_context->no_irqchip_creation = 0;
+    kvm_context->no_pit_creation = 0;
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    QTAILQ_INIT(&kvm_state->kvm_sw_breakpoints);
+#endif
+
+    gsi_count = kvm_get_gsi_count(kvm_context);
+    if (gsi_count > 0) {
+        int gsi_bits, i;
+
+        /* Round up so we can search ints using ffs */
+        gsi_bits = ALIGN(gsi_count, 32);
+        kvm_context->used_gsi_bitmap = qemu_mallocz(gsi_bits / 8);
+        kvm_context->max_gsi = gsi_bits;
+
+        /* Mark any over-allocated bits as already in use */
+        for (i = gsi_count; i < gsi_bits; i++)
+            set_gsi(kvm_context, i);
+    }
+
+    pthread_mutex_lock(&qemu_mutex);
+    return kvm_create_context();
+
+  out_close:
+    close(fd);
+    return -1;
+}
+
+static void kvm_finalize(KVMState *s)
+{
+    /* FIXME
+       if (kvm->vcpu_fd[0] != -1)
+           close(kvm->vcpu_fd[0]);
+       if (kvm->vm_fd != -1)
+           close(kvm->vm_fd);
+     */
+    close(s->fd);
+    free(s);
+}
+
+void kvm_disable_irqchip_creation(kvm_context_t kvm)
+{
+    kvm->no_irqchip_creation = 1;
+}
+
+void kvm_disable_pit_creation(kvm_context_t kvm)
+{
+    kvm->no_pit_creation = 1;
+}
+
+static void kvm_create_vcpu(CPUState *env, int id)
+{
+    long mmap_size;
+    int r;
+
+    r = kvm_vm_ioctl(kvm_state, KVM_CREATE_VCPU, id);
+    if (r < 0) {
+        fprintf(stderr, "kvm_create_vcpu: %m\n");
+        return;
+    }
+
+    env->kvm_fd = r;
+    env->kvm_state = kvm_state;
+
+    mmap_size = kvm_ioctl(kvm_state, KVM_GET_VCPU_MMAP_SIZE, 0);
+    if (mmap_size < 0) {
+        fprintf(stderr, "get vcpu mmap size: %m\n");
+        goto err_fd;
+    }
+    env->kvm_run =
+        mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, env->kvm_fd,
+             0);
+    if (env->kvm_run == MAP_FAILED) {
+        fprintf(stderr, "mmap vcpu area: %m\n");
+        goto err_fd;
+    }
+
+    return;
+  err_fd:
+    close(env->kvm_fd);
+}
+
+static int kvm_set_boot_vcpu_id(kvm_context_t kvm, uint32_t id)
+{
+#ifdef KVM_CAP_SET_BOOT_CPU_ID
+    int r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SET_BOOT_CPU_ID);
+    if (r > 0)
+        return kvm_vm_ioctl(kvm_state, KVM_SET_BOOT_CPU_ID, id);
+    return -ENOSYS;
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_create_vm(kvm_context_t kvm)
+{
+    int fd;
+#ifdef KVM_CAP_IRQ_ROUTING
+    kvm->irq_routes = qemu_mallocz(sizeof(*kvm->irq_routes));
+    kvm->nr_allocated_irq_routes = 0;
+#endif
+
+    fd = kvm_ioctl(kvm_state, KVM_CREATE_VM, 0);
+    if (fd < 0) {
+        fprintf(stderr, "kvm_create_vm: %m\n");
+        return -1;
+    }
+    kvm_state->vmfd = fd;
+    return 0;
+}
+
+static int kvm_create_default_phys_mem(kvm_context_t kvm,
+                                       unsigned long phys_mem_bytes,
+                                       void **vm_mem)
+{
+#ifdef KVM_CAP_USER_MEMORY
+    int r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
+    if (r > 0)
+        return 0;
+    fprintf(stderr,
+            "Hypervisor too old: KVM_CAP_USER_MEMORY extension not supported\n");
+#else
+#error Hypervisor too old: KVM_CAP_USER_MEMORY extension not supported
+#endif
+    return -1;
+}
+
+void kvm_create_irqchip(kvm_context_t kvm)
+{
+    int r;
+
+    kvm->irqchip_in_kernel = 0;
+#ifdef KVM_CAP_IRQCHIP
+    if (!kvm->no_irqchip_creation) {
+        r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP);
+        if (r > 0) {            /* kernel irqchip supported */
+            r = kvm_vm_ioctl(kvm_state, KVM_CREATE_IRQCHIP);
+            if (r >= 0) {
+                kvm->irqchip_inject_ioctl = KVM_IRQ_LINE;
+#if defined(KVM_CAP_IRQ_INJECT_STATUS) && defined(KVM_IRQ_LINE_STATUS)
+                r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION,
+                              KVM_CAP_IRQ_INJECT_STATUS);
+                if (r > 0)
+                    kvm->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+#endif
+                kvm->irqchip_in_kernel = 1;
+            } else
+                fprintf(stderr, "Create kernel PIC irqchip failed\n");
+        }
+    }
+#endif
+    kvm_state->irqchip_in_kernel = kvm->irqchip_in_kernel;
+}
+
+int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, void **vm_mem)
+{
+    int r;
+
+    r = kvm_create_vm(kvm);
+    if (r < 0)
+        return r;
+    r = kvm_arch_create(kvm, phys_mem_bytes, vm_mem);
+    if (r < 0)
+        return r;
+    init_slots();
+    r = kvm_create_default_phys_mem(kvm, phys_mem_bytes, vm_mem);
+    if (r < 0)
+        return r;
+    kvm_create_irqchip(kvm);
+
+    return 0;
+}
+
+
+int kvm_register_phys_mem(kvm_context_t kvm,
+                          unsigned long phys_start, void *userspace_addr,
+                          unsigned long len, int log)
+{
+
+    struct kvm_userspace_memory_region memory = {
+        .memory_size = len,
+        .guest_phys_addr = phys_start,
+        .userspace_addr = (unsigned long) (uintptr_t) userspace_addr,
+        .flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0,
+    };
+    int r;
+
+    memory.slot = get_free_slot(kvm);
+    DPRINTF
+        ("memory: gpa: %llx, size: %llx, uaddr: %llx, slot: %x, flags: %x\n",
+         memory.guest_phys_addr, memory.memory_size, memory.userspace_addr,
+         memory.slot, memory.flags);
+    r = kvm_vm_ioctl(kvm_state, KVM_SET_USER_MEMORY_REGION, &memory);
+    if (r < 0) {
+        fprintf(stderr, "create_userspace_phys_mem: %s\n", strerror(-r));
+        return -1;
+    }
+    register_slot(memory.slot, memory.guest_phys_addr, memory.memory_size,
+                  memory.userspace_addr, memory.flags);
+    return 0;
+}
+
+
+/* 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;
+    int r;
+    struct kvm_userspace_memory_region memory = {
+        .memory_size = 0,
+        .guest_phys_addr = phys_start,
+        .userspace_addr = 0,
+        .flags = 0,
+    };
+
+    slot = get_slot(phys_start);
+
+    if ((slot >= KVM_MAX_NUM_MEM_REGIONS) || (slot == -1)) {
+        fprintf(stderr, "BUG: %s: invalid parameters (slot=%d)\n", __FUNCTION__,
+                slot);
+        return;
+    }
+    if (phys_start != slots[slot].phys_addr) {
+        fprintf(stderr,
+                "WARNING: %s: phys_start is 0x%lx expecting 0x%lx\n",
+                __FUNCTION__, phys_start, slots[slot].phys_addr);
+        phys_start = slots[slot].phys_addr;
+    }
+
+    memory.slot = slot;
+    DPRINTF("slot %d start %llx len %llx flags %x\n",
+            memory.slot, memory.guest_phys_addr, memory.memory_size,
+            memory.flags);
+    r = kvm_vm_ioctl(kvm_state, KVM_SET_USER_MEMORY_REGION, &memory);
+    if (r < 0) {
+        fprintf(stderr, "destroy_userspace_phys_mem: %s", strerror(-r));
+        return;
+    }
+
+    free_slot(memory.slot);
+}
+
+void kvm_unregister_memory_area(kvm_context_t kvm, uint64_t phys_addr,
+                                unsigned long size)
+{
+
+    int slot = get_container_slot(phys_addr, size);
+
+    if (slot != -1) {
+        DPRINTF("Unregistering memory region %" PRIx64 " (%lx)\n", phys_addr, size);
+        kvm_destroy_phys_mem(kvm, phys_addr, size);
+        return;
+    }
+}
+
+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 = kvm_vm_ioctl(kvm_state, ioctl_num, &log);
+    if (r < 0)
+        return r;
+    return 0;
+}
+
+int kvm_get_dirty_pages(kvm_context_t kvm, unsigned long phys_addr, void *buf)
+{
+    int slot;
+
+    slot = get_slot(phys_addr);
+    return kvm_get_map(kvm, KVM_GET_DIRTY_LOG, slot, buf);
+}
+
+int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
+                              unsigned long len, void *opaque,
+                              int (*cb)(unsigned long start,
+                                        unsigned long len, void *bitmap,
+                                        void *opaque))
+{
+    int i;
+    int r;
+    unsigned long end_addr = phys_addr + len;
+    void *buf;
+
+    for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i) {
+        if ((slots[i].len && (uint64_t) slots[i].phys_addr >= phys_addr)
+            && ((uint64_t) slots[i].phys_addr + slots[i].len <= end_addr)) {
+            buf = qemu_malloc(BITMAP_SIZE(slots[i].len));
+            r = kvm_get_map(kvm, KVM_GET_DIRTY_LOG, i, buf);
+            if (r) {
+                qemu_free(buf);
+                return r;
+            }
+            r = cb(slots[i].phys_addr, slots[i].len, buf, opaque);
+            qemu_free(buf);
+            if (r)
+                return r;
+        }
+    }
+    return 0;
+}
+
+#ifdef KVM_CAP_IRQCHIP
+
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status)
+{
+    struct kvm_irq_level event;
+    int r;
+
+    if (!kvm->irqchip_in_kernel)
+        return 0;
+    event.level = level;
+    event.irq = irq;
+    r = kvm_vm_ioctl(kvm_state, kvm->irqchip_inject_ioctl, &event);
+    if (r < 0)
+        perror("kvm_set_irq_level");
+
+    if (status) {
+#ifdef KVM_CAP_IRQ_INJECT_STATUS
+        *status =
+            (kvm->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status;
+#else
+        *status = 1;
+#endif
+    }
+
+    return 1;
+}
+
+int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
+{
+    int r;
+
+    if (!kvm->irqchip_in_kernel)
+        return 0;
+    r = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip);
+    if (r < 0) {
+        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 = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip);
+    if (r < 0) {
+        perror("kvm_set_irqchip\n");
+    }
+    return r;
+}
+
+#endif
+
+static int handle_debug(CPUState *env)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    struct kvm_run *run = env->kvm_run;
+
+    return kvm_debug(env, &run->debug.arch);
+#else
+    return 0;
+#endif
+}
+
+int kvm_get_regs(CPUState *env, struct kvm_regs *regs)
+{
+    return kvm_vcpu_ioctl(env, KVM_GET_REGS, regs);
+}
+
+int kvm_set_regs(CPUState *env, struct kvm_regs *regs)
+{
+    return kvm_vcpu_ioctl(env, KVM_SET_REGS, regs);
+}
+
+int kvm_get_fpu(CPUState *env, struct kvm_fpu *fpu)
+{
+    return kvm_vcpu_ioctl(env, KVM_GET_FPU, fpu);
+}
+
+int kvm_set_fpu(CPUState *env, struct kvm_fpu *fpu)
+{
+    return kvm_vcpu_ioctl(env, KVM_SET_FPU, fpu);
+}
+
+int kvm_get_sregs(CPUState *env, struct kvm_sregs *sregs)
+{
+    return kvm_vcpu_ioctl(env, KVM_GET_SREGS, sregs);
+}
+
+int kvm_set_sregs(CPUState *env, struct kvm_sregs *sregs)
+{
+    return kvm_vcpu_ioctl(env, KVM_SET_SREGS, sregs);
+}
+
+#ifdef KVM_CAP_MP_STATE
+int kvm_get_mpstate(CPUState *env, struct kvm_mp_state *mp_state)
+{
+    int r;
+
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_MP_STATE);
+    if (r > 0)
+        return kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, mp_state);
+    return -ENOSYS;
+}
+
+int kvm_set_mpstate(CPUState *env, struct kvm_mp_state *mp_state)
+{
+    int r;
+
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_MP_STATE);
+    if (r > 0)
+        return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, mp_state);
+    return -ENOSYS;
+}
+#endif
+
+static int handle_mmio(CPUState *env)
+{
+    unsigned long addr = env->kvm_run->mmio.phys_addr;
+    struct kvm_run *kvm_run = env->kvm_run;
+    void *data = kvm_run->mmio.data;
+
+    /* hack: Red Hat 7.1 generates these weird accesses. */
+    if ((addr > 0xa0000 - 4 && addr <= 0xa0000) && kvm_run->mmio.len == 3)
+        return 0;
+
+    cpu_physical_memory_rw(addr, data, kvm_run->mmio.len, kvm_run->mmio.is_write);
+    return 0;
+}
+
+int handle_io_window(kvm_context_t kvm)
+{
+    return 1;
+}
+
+int handle_shutdown(kvm_context_t kvm, CPUState *env)
+{
+    /* stop the current vcpu from going back to guest mode */
+    env->stopped = 1;
+
+    qemu_system_reset_request();
+    return 1;
+}
+
+static inline void push_nmi(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_USER_NMI
+    kvm_arch_push_nmi(kvm->opaque);
+#endif                          /* KVM_CAP_USER_NMI */
+}
+
+void post_kvm_run(kvm_context_t kvm, CPUState *env)
+{
+    pthread_mutex_lock(&qemu_mutex);
+    kvm_arch_post_run(env, env->kvm_run);
+    cpu_single_env = env;
+}
+
+int pre_kvm_run(kvm_context_t kvm, CPUState *env)
+{
+    kvm_arch_pre_run(env, env->kvm_run);
+
+    if (env->kvm_cpu_state.regs_modified) {
+        kvm_arch_put_registers(env);
+        env->kvm_cpu_state.regs_modified = 0;
+    }
+
+    pthread_mutex_unlock(&qemu_mutex);
+    return 0;
+}
+
+int kvm_is_ready_for_interrupt_injection(CPUState *env)
+{
+    return env->kvm_run->ready_for_interrupt_injection;
+}
+
+static int kvm_handle_internal_error(kvm_context_t kvm,
+                                     CPUState *env,
+                                     struct kvm_run *run)
+{
+    fprintf(stderr, "KVM internal error. Suberror: %d\n",
+            run->internal.suberror);
+#ifdef KVM_CAP_INTERNAL_ERROR_DATA
+    if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
+        int i;
+
+        for (i = 0; i < run->internal.ndata; ++i) {
+            fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
+                    i, (uint64_t)run->internal.data[i]);
+        }
+    }
+#endif
+    kvm_show_regs(env);
+    if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION)
+        fprintf(stderr, "emulation failure, check dmesg for details\n");
+    vm_stop(0);
+    return 1;
+}
+
+int kvm_run(CPUState *env)
+{
+    int r;
+    kvm_context_t kvm = &env->kvm_state->kvm_context;
+    struct kvm_run *run = env->kvm_run;
+    int fd = env->kvm_fd;
+
+  again:
+    push_nmi(kvm);
+#if !defined(__s390__)
+    if (!kvm->irqchip_in_kernel)
+        run->request_interrupt_window = kvm_arch_try_push_interrupts(env);
+#endif
+
+    r = pre_kvm_run(kvm, env);
+    if (r)
+        return r;
+    r = ioctl(fd, KVM_RUN, 0);
+
+    if (r == -1 && errno != EINTR && errno != EAGAIN) {
+        r = -errno;
+        post_kvm_run(kvm, env);
+        fprintf(stderr, "kvm_run: %s\n", strerror(-r));
+        return r;
+    }
+
+    post_kvm_run(kvm, env);
+
+#if defined(KVM_CAP_COALESCED_MMIO)
+    if (kvm_state->coalesced_mmio) {
+        struct kvm_coalesced_mmio_ring *ring =
+            (void *) run + kvm_state->coalesced_mmio * PAGE_SIZE;
+        while (ring->first != ring->last) {
+            cpu_physical_memory_rw(ring->coalesced_mmio[ring->first].phys_addr,
+                           &ring->coalesced_mmio[ring->first].data[0],
+                           ring->coalesced_mmio[ring->first].len, 1);
+            smp_wmb();
+            ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+        }
+    }
+#endif
+
+#if !defined(__s390__)
+    if (r == -1) {
+        r = handle_io_window(kvm);
+        goto more;
+    }
+#endif
+    if (1) {
+        switch (run->exit_reason) {
+        case KVM_EXIT_UNKNOWN:
+            r = handle_unhandled(run->hw.hardware_exit_reason);
+            break;
+        case KVM_EXIT_FAIL_ENTRY:
+            r = handle_unhandled(run->fail_entry.hardware_entry_failure_reason);
+            break;
+        case KVM_EXIT_EXCEPTION:
+            fprintf(stderr, "exception %d (%x)\n", run->ex.exception,
+                    run->ex.error_code);
+            kvm_show_regs(env);
+            kvm_show_code(env);
+            abort();
+            break;
+        case KVM_EXIT_IO:
+            r = kvm_handle_io(run->io.port,
+                                (uint8_t *)run + run->io.data_offset,
+                                run->io.direction,
+                                run->io.size,
+                                run->io.count);
+            break;
+        case KVM_EXIT_DEBUG:
+            r = handle_debug(env);
+            break;
+        case KVM_EXIT_MMIO:
+            r = handle_mmio(env);
+            break;
+        case KVM_EXIT_HLT:
+            r = kvm_arch_halt(env);
+            break;
+        case KVM_EXIT_IRQ_WINDOW_OPEN:
+            break;
+        case KVM_EXIT_SHUTDOWN:
+            r = handle_shutdown(kvm, env);
+            break;
+#if defined(__s390__)
+        case KVM_EXIT_S390_SIEIC:
+            r = kvm_s390_handle_intercept(kvm, env, run);
+            break;
+        case KVM_EXIT_S390_RESET:
+            r = kvm_s390_handle_reset(kvm, env, run);
+            break;
+#endif
+	case KVM_EXIT_INTERNAL_ERROR:
+            r = kvm_handle_internal_error(kvm, env, run);
+	    break;
+        default:
+            if (kvm_arch_run(env)) {
+                fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason);
+                kvm_show_regs(env);
+                abort();
+            }
+            break;
+        }
+    }
+  more:
+    if (!r)
+        goto again;
+    return r;
+}
+
+int kvm_inject_irq(CPUState *env, unsigned irq)
+{
+    struct kvm_interrupt intr;
+
+    intr.irq = irq;
+    return kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr);
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
+{
+    return kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, dbg);
+}
+#endif
+
+int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
+{
+    struct kvm_signal_mask *sigmask;
+    int r;
+
+    if (!sigset) {
+        return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
+    }
+    sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
+
+    sigmask->len = 8;
+    memcpy(sigmask->sigset, sigset, sizeof(*sigset));
+    r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
+    free(sigmask);
+    return r;
+}
+
+int kvm_pit_in_kernel(kvm_context_t kvm)
+{
+    return kvm->pit_in_kernel;
+}
+
+int kvm_inject_nmi(CPUState *env)
+{
+#ifdef KVM_CAP_USER_NMI
+    return kvm_vcpu_ioctl(env, KVM_NMI);
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_init_coalesced_mmio(kvm_context_t kvm)
+{
+    int r = 0;
+    kvm_state->coalesced_mmio = 0;
+#ifdef KVM_CAP_COALESCED_MMIO
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+    if (r > 0) {
+        kvm_state->coalesced_mmio = r;
+        return 0;
+    }
+#endif
+    return r;
+}
+
+#ifdef KVM_CAP_DEVICE_ASSIGNMENT
+int kvm_assign_pci_device(kvm_context_t kvm,
+                          struct kvm_assigned_pci_dev *assigned_dev)
+{
+    return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_PCI_DEVICE, assigned_dev);
+}
+
+static int kvm_old_assign_irq(kvm_context_t kvm,
+                              struct kvm_assigned_irq *assigned_irq)
+{
+    return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_IRQ, assigned_irq);
+}
+
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+int kvm_assign_irq(kvm_context_t kvm, struct kvm_assigned_irq *assigned_irq)
+{
+    int ret;
+
+    ret = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_ASSIGN_DEV_IRQ);
+    if (ret > 0) {
+        return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_DEV_IRQ, assigned_irq);
+    }
+
+    return kvm_old_assign_irq(kvm, assigned_irq);
+}
+
+int kvm_deassign_irq(kvm_context_t kvm, struct kvm_assigned_irq *assigned_irq)
+{
+    return kvm_vm_ioctl(kvm_state, KVM_DEASSIGN_DEV_IRQ, assigned_irq);
+}
+#else
+int kvm_assign_irq(kvm_context_t kvm, struct kvm_assigned_irq *assigned_irq)
+{
+    return kvm_old_assign_irq(kvm, assigned_irq);
+}
+#endif
+#endif
+
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+int kvm_deassign_pci_device(kvm_context_t kvm,
+                            struct kvm_assigned_pci_dev *assigned_dev)
+{
+    return kvm_vm_ioctl(kvm_state, KVM_DEASSIGN_PCI_DEVICE, assigned_dev);
+}
+#endif
+
+int kvm_destroy_memory_region_works(kvm_context_t kvm)
+{
+    int ret = 0;
+
+#ifdef KVM_CAP_DESTROY_MEMORY_REGION_WORKS
+    ret =
+        kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION,
+                  KVM_CAP_DESTROY_MEMORY_REGION_WORKS);
+    if (ret <= 0)
+        ret = 0;
+#endif
+    return ret;
+}
+
+int kvm_reinject_control(kvm_context_t kvm, int pit_reinject)
+{
+#ifdef KVM_CAP_REINJECT_CONTROL
+    int r;
+    struct kvm_reinject_control control;
+
+    control.pit_reinject = pit_reinject;
+
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_REINJECT_CONTROL);
+    if (r > 0) {
+        return kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
+    }
+#endif
+    return -ENOSYS;
+}
+
+int kvm_has_gsi_routing(kvm_context_t kvm)
+{
+    int r = 0;
+
+#ifdef KVM_CAP_IRQ_ROUTING
+    r = kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+#endif
+    return r;
+}
+
+int kvm_get_gsi_count(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+#else
+    return -EINVAL;
+#endif
+}
+
+int kvm_clear_gsi_routes(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    kvm->irq_routes->nr = 0;
+    return 0;
+#else
+    return -EINVAL;
+#endif
+}
+
+int kvm_add_routing_entry(kvm_context_t kvm,
+                          struct kvm_irq_routing_entry *entry)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing *z;
+    struct kvm_irq_routing_entry *new;
+    int n, size;
+
+    if (kvm->irq_routes->nr == kvm->nr_allocated_irq_routes) {
+        n = kvm->nr_allocated_irq_routes * 2;
+        if (n < 64)
+            n = 64;
+        size = sizeof(struct kvm_irq_routing);
+        size += n * sizeof(*new);
+        z = realloc(kvm->irq_routes, size);
+        if (!z)
+            return -ENOMEM;
+        kvm->nr_allocated_irq_routes = n;
+        kvm->irq_routes = z;
+    }
+    n = kvm->irq_routes->nr++;
+    new = &kvm->irq_routes->entries[n];
+    memset(new, 0, sizeof(*new));
+    new->gsi = entry->gsi;
+    new->type = entry->type;
+    new->flags = entry->flags;
+    new->u = entry->u;
+
+    set_gsi(kvm, entry->gsi);
+
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing_entry e;
+
+    e.gsi = gsi;
+    e.type = KVM_IRQ_ROUTING_IRQCHIP;
+    e.flags = 0;
+    e.u.irqchip.irqchip = irqchip;
+    e.u.irqchip.pin = pin;
+    return kvm_add_routing_entry(kvm, &e);
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_del_routing_entry(kvm_context_t kvm,
+                          struct kvm_irq_routing_entry *entry)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing_entry *e, *p;
+    int i, gsi, found = 0;
+
+    gsi = entry->gsi;
+
+    for (i = 0; i < kvm->irq_routes->nr; ++i) {
+        e = &kvm->irq_routes->entries[i];
+        if (e->type == entry->type && e->gsi == gsi) {
+            switch (e->type) {
+            case KVM_IRQ_ROUTING_IRQCHIP:{
+                    if (e->u.irqchip.irqchip ==
+                        entry->u.irqchip.irqchip
+                        && e->u.irqchip.pin == entry->u.irqchip.pin) {
+                        p = &kvm->irq_routes->entries[--kvm->irq_routes->nr];
+                        *e = *p;
+                        found = 1;
+                    }
+                    break;
+                }
+            case KVM_IRQ_ROUTING_MSI:{
+                    if (e->u.msi.address_lo ==
+                        entry->u.msi.address_lo
+                        && e->u.msi.address_hi ==
+                        entry->u.msi.address_hi
+                        && e->u.msi.data == entry->u.msi.data) {
+                        p = &kvm->irq_routes->entries[--kvm->irq_routes->nr];
+                        *e = *p;
+                        found = 1;
+                    }
+                    break;
+                }
+            default:
+                break;
+            }
+            if (found) {
+                /* If there are no other users of this GSI
+                 * mark it available in the bitmap */
+                for (i = 0; i < kvm->irq_routes->nr; i++) {
+                    e = &kvm->irq_routes->entries[i];
+                    if (e->gsi == gsi)
+                        break;
+                }
+                if (i == kvm->irq_routes->nr)
+                    clear_gsi(kvm, gsi);
+
+                return 0;
+            }
+        }
+    }
+    return -ESRCH;
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_update_routing_entry(kvm_context_t kvm,
+                             struct kvm_irq_routing_entry *entry,
+                             struct kvm_irq_routing_entry *newentry)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing_entry *e;
+    int i;
+
+    if (entry->gsi != newentry->gsi || entry->type != newentry->type) {
+        return -EINVAL;
+    }
+
+    for (i = 0; i < kvm->irq_routes->nr; ++i) {
+        e = &kvm->irq_routes->entries[i];
+        if (e->type != entry->type || e->gsi != entry->gsi) {
+            continue;
+        }
+        switch (e->type) {
+        case KVM_IRQ_ROUTING_IRQCHIP:
+            if (e->u.irqchip.irqchip == entry->u.irqchip.irqchip &&
+                e->u.irqchip.pin == entry->u.irqchip.pin) {
+                memcpy(&e->u.irqchip, &newentry->u.irqchip,
+                       sizeof e->u.irqchip);
+                return 0;
+            }
+            break;
+        case KVM_IRQ_ROUTING_MSI:
+            if (e->u.msi.address_lo == entry->u.msi.address_lo &&
+                e->u.msi.address_hi == entry->u.msi.address_hi &&
+                e->u.msi.data == entry->u.msi.data) {
+                memcpy(&e->u.msi, &newentry->u.msi, sizeof e->u.msi);
+                return 0;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    return -ESRCH;
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing_entry e;
+
+    e.gsi = gsi;
+    e.type = KVM_IRQ_ROUTING_IRQCHIP;
+    e.flags = 0;
+    e.u.irqchip.irqchip = irqchip;
+    e.u.irqchip.pin = pin;
+    return kvm_del_routing_entry(kvm, &e);
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_commit_irq_routes(kvm_context_t kvm)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+    kvm->irq_routes->flags = 0;
+    return kvm_vm_ioctl(kvm_state, KVM_SET_GSI_ROUTING, kvm->irq_routes);
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_get_irq_route_gsi(kvm_context_t kvm)
+{
+    int i, bit;
+    uint32_t *buf = kvm->used_gsi_bitmap;
+
+    /* Return the lowest unused GSI in the bitmap */
+    for (i = 0; i < kvm->max_gsi / 32; i++) {
+        bit = ffs(~buf[i]);
+        if (!bit)
+            continue;
+
+        return bit - 1 + i * 32;
+    }
+
+    return -ENOSPC;
+}
+
+#ifdef KVM_CAP_DEVICE_MSIX
+int kvm_assign_set_msix_nr(kvm_context_t kvm,
+                           struct kvm_assigned_msix_nr *msix_nr)
+{
+    return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_SET_MSIX_NR, msix_nr);
+}
+
+int kvm_assign_set_msix_entry(kvm_context_t kvm,
+                              struct kvm_assigned_msix_entry *entry)
+{
+    return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_SET_MSIX_ENTRY, entry);
+}
+#endif
+
+#if defined(KVM_CAP_IRQFD) && defined(CONFIG_EVENTFD)
+
+#include <sys/eventfd.h>
+
+static int _kvm_irqfd(kvm_context_t kvm, int fd, int gsi, int flags)
+{
+    struct kvm_irqfd data = {
+        .fd = fd,
+        .gsi = gsi,
+        .flags = flags,
+    };
+
+    return kvm_vm_ioctl(kvm_state, KVM_IRQFD, &data);
+}
+
+int kvm_irqfd(kvm_context_t kvm, int gsi, int flags)
+{
+    int r;
+    int fd;
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_IRQFD))
+        return -ENOENT;
+
+    fd = eventfd(0, 0);
+    if (fd < 0)
+        return -errno;
+
+    r = _kvm_irqfd(kvm, fd, gsi, 0);
+    if (r < 0) {
+        close(fd);
+        return -errno;
+    }
+
+    return fd;
+}
+
+#else                           /* KVM_CAP_IRQFD */
+
+int kvm_irqfd(kvm_context_t kvm, int gsi, int flags)
+{
+    return -ENOSYS;
+}
+
+#endif                          /* KVM_CAP_IRQFD */
+static inline unsigned long kvm_get_thread_id(void)
+{
+    return syscall(SYS_gettid);
+}
+
+static void qemu_cond_wait(pthread_cond_t *cond)
+{
+    CPUState *env = cpu_single_env;
+
+    pthread_cond_wait(cond, &qemu_mutex);
+    cpu_single_env = env;
+}
+
+static void sig_ipi_handler(int n)
+{
+}
+
+static void hardware_memory_error(void)
+{
+    fprintf(stderr, "Hardware memory error!\n");
+    exit(1);
+}
+
+static void sigbus_reraise(void)
+{
+    sigset_t set;
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = SIG_DFL;
+    if (!sigaction(SIGBUS, &action, NULL)) {
+        raise(SIGBUS);
+        sigemptyset(&set);
+        sigaddset(&set, SIGBUS);
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
+    }
+    perror("Failed to re-raise SIGBUS!\n");
+    abort();
+}
+
+static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
+                           void *ctx)
+{
+#if defined(KVM_CAP_MCE) && defined(TARGET_I386)
+    if (first_cpu->mcg_cap && siginfo->ssi_addr
+        && siginfo->ssi_code == BUS_MCEERR_AO) {
+        uint64_t status;
+        unsigned long paddr;
+        CPUState *cenv;
+
+        /* Hope we are lucky for AO MCE */
+        if (do_qemu_ram_addr_from_host((void *)(intptr_t)siginfo->ssi_addr,
+				       &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!: %llx\n",
+                    (unsigned long long)siginfo->ssi_addr);
+            return;
+        }
+        status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+            | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+            | 0xc0;
+        kvm_inject_x86_mce(first_cpu, 9, status,
+                           MCG_STATUS_MCIP | MCG_STATUS_RIPV, paddr,
+                           (MCM_ADDR_PHYS << 6) | 0xc, 1);
+        for (cenv = first_cpu->next_cpu; cenv != NULL; cenv = cenv->next_cpu)
+            kvm_inject_x86_mce(cenv, 1, MCI_STATUS_VAL | MCI_STATUS_UC,
+                               MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0, 1);
+    } else
+#endif
+    {
+        if (siginfo->ssi_code == BUS_MCEERR_AO)
+            return;
+        else if (siginfo->ssi_code == BUS_MCEERR_AR)
+            hardware_memory_error();
+        else
+            sigbus_reraise();
+    }
+}
+
+static void on_vcpu(CPUState *env, void (*func)(void *data), void *data)
+{
+    struct qemu_work_item wi;
+
+    if (env == current_env) {
+        func(data);
+        return;
+    }
+
+    wi.func = func;
+    wi.data = data;
+    if (!env->kvm_cpu_state.queued_work_first)
+        env->kvm_cpu_state.queued_work_first = &wi;
+    else
+        env->kvm_cpu_state.queued_work_last->next = &wi;
+    env->kvm_cpu_state.queued_work_last = &wi;
+    wi.next = NULL;
+    wi.done = false;
+
+    pthread_kill(env->kvm_cpu_state.thread, SIG_IPI);
+    while (!wi.done)
+        qemu_cond_wait(&qemu_work_cond);
+}
+
+void kvm_arch_get_registers(CPUState *env)
+{
+	kvm_arch_save_regs(env);
+}
+
+static void do_kvm_cpu_synchronize_state(void *_env)
+{
+    CPUState *env = _env;
+    if (!env->kvm_cpu_state.regs_modified) {
+        kvm_arch_get_registers(env);
+        env->kvm_cpu_state.regs_modified = 1;
+    }
+}
+
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+    if (!env->kvm_cpu_state.regs_modified)
+        on_vcpu(env, do_kvm_cpu_synchronize_state, env);
+}
+
+static void inject_interrupt(void *data)
+{
+    cpu_interrupt(current_env, (long) data);
+}
+
+void kvm_inject_interrupt(CPUState *env, int mask)
+{
+    on_vcpu(env, inject_interrupt, (void *) (long) mask);
+}
+
+void kvm_update_interrupt_request(CPUState *env)
+{
+    int signal = 0;
+
+    if (env) {
+        if (!current_env || !current_env->created)
+            signal = 1;
+        /*
+         * Testing for created here is really redundant
+         */
+        if (current_env && current_env->created &&
+            env != current_env && !env->kvm_cpu_state.signalled)
+            signal = 1;
+
+        if (signal) {
+            env->kvm_cpu_state.signalled = 1;
+            if (env->kvm_cpu_state.thread)
+                pthread_kill(env->kvm_cpu_state.thread, SIG_IPI);
+        }
+    }
+}
+
+static void kvm_do_load_registers(void *_env)
+{
+    CPUState *env = _env;
+
+    kvm_arch_load_regs(env);
+}
+
+void kvm_load_registers(CPUState *env)
+{
+    if (kvm_enabled() && qemu_system_ready)
+        on_vcpu(env, kvm_do_load_registers, env);
+}
+
+static void kvm_do_save_registers(void *_env)
+{
+    CPUState *env = _env;
+
+    kvm_arch_save_regs(env);
+}
+
+void kvm_save_registers(CPUState *env)
+{
+    if (kvm_enabled())
+        on_vcpu(env, kvm_do_save_registers, env);
+}
+
+static void kvm_do_load_mpstate(void *_env)
+{
+    CPUState *env = _env;
+
+    kvm_arch_load_mpstate(env);
+}
+
+void kvm_load_mpstate(CPUState *env)
+{
+    if (kvm_enabled() && qemu_system_ready)
+        on_vcpu(env, kvm_do_load_mpstate, env);
+}
+
+static void kvm_do_save_mpstate(void *_env)
+{
+    CPUState *env = _env;
+
+    kvm_arch_save_mpstate(env);
+#ifdef KVM_CAP_MP_STATE
+    if (kvm_irqchip_in_kernel())
+        env->halted = (env->mp_state == KVM_MP_STATE_HALTED);
+#endif
+}
+
+void kvm_save_mpstate(CPUState *env)
+{
+    if (kvm_enabled())
+        on_vcpu(env, kvm_do_save_mpstate, env);
+}
+
+int kvm_cpu_exec(CPUState *env)
+{
+    int r;
+
+    r = kvm_run(env);
+    if (r < 0) {
+        printf("kvm_run returned %d\n", r);
+        vm_stop(0);
+    }
+
+    return 0;
+}
+
+static int is_cpu_stopped(CPUState *env)
+{
+    return !vm_running || env->stopped;
+}
+
+static void flush_queued_work(CPUState *env)
+{
+    struct qemu_work_item *wi;
+
+    if (!env->kvm_cpu_state.queued_work_first)
+        return;
+
+    while ((wi = env->kvm_cpu_state.queued_work_first)) {
+        env->kvm_cpu_state.queued_work_first = wi->next;
+        wi->func(wi->data);
+        wi->done = true;
+    }
+    env->kvm_cpu_state.queued_work_last = NULL;
+    pthread_cond_broadcast(&qemu_work_cond);
+}
+
+static void kvm_on_sigbus(CPUState *env, siginfo_t *siginfo)
+{
+#if defined(KVM_CAP_MCE) && defined(TARGET_I386)
+    struct kvm_x86_mce mce = {
+            .bank = 9,
+    };
+    unsigned long paddr;
+    int r;
+
+    if (env->mcg_cap && siginfo->si_addr
+        && (siginfo->si_code == BUS_MCEERR_AR
+            || siginfo->si_code == BUS_MCEERR_AO)) {
+        if (siginfo->si_code == BUS_MCEERR_AR) {
+            /* Fake an Intel architectural Data Load SRAR UCR */
+            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                | MCI_STATUS_AR | 0x134;
+            mce.misc = (MCM_ADDR_PHYS << 6) | 0xc;
+            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
+        } else {
+            /* Fake an Intel architectural Memory scrubbing UCR */
+            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                | 0xc0;
+            mce.misc = (MCM_ADDR_PHYS << 6) | 0xc;
+            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+        }
+        if (do_qemu_ram_addr_from_host((void *)siginfo->si_addr, &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instaed of guest system!\n");
+            /* Hope we are lucky for AO MCE */
+            if (siginfo->si_code == BUS_MCEERR_AO)
+                return;
+            else
+                hardware_memory_error();
+        }
+        mce.addr = paddr;
+        r = kvm_set_mce(env, &mce);
+        if (r < 0) {
+            fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
+            abort();
+        }
+    } else
+#endif
+    {
+        if (siginfo->si_code == BUS_MCEERR_AO)
+            return;
+        else if (siginfo->si_code == BUS_MCEERR_AR)
+            hardware_memory_error();
+        else
+            sigbus_reraise();
+    }
+}
+
+static void kvm_main_loop_wait(CPUState *env, int timeout)
+{
+    struct timespec ts;
+    int r, e;
+    siginfo_t siginfo;
+    sigset_t waitset;
+    sigset_t chkset;
+
+    ts.tv_sec = timeout / 1000;
+    ts.tv_nsec = (timeout % 1000) * 1000000;
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
+
+    do {
+        pthread_mutex_unlock(&qemu_mutex);
+
+        r = sigtimedwait(&waitset, &siginfo, &ts);
+        e = errno;
+
+        pthread_mutex_lock(&qemu_mutex);
+
+        if (r == -1 && !(e == EAGAIN || e == EINTR)) {
+            printf("sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+            kvm_on_sigbus(env, &siginfo);
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            printf("sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
+
+    cpu_single_env = env;
+    flush_queued_work(env);
+
+    if (env->stop) {
+        env->stop = 0;
+        env->stopped = 1;
+        pthread_cond_signal(&qemu_pause_cond);
+    }
+
+    env->kvm_cpu_state.signalled = 0;
+}
+
+static int all_threads_paused(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        if (penv->stop)
+            return 0;
+        penv = (CPUState *) penv->next_cpu;
+    }
+
+    return 1;
+}
+
+static void pause_all_threads(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        if (penv != cpu_single_env) {
+            penv->stop = 1;
+            pthread_kill(penv->kvm_cpu_state.thread, SIG_IPI);
+        } else {
+            penv->stop = 0;
+            penv->stopped = 1;
+            cpu_exit(penv);
+        }
+        penv = (CPUState *) penv->next_cpu;
+    }
+
+    while (!all_threads_paused())
+        qemu_cond_wait(&qemu_pause_cond);
+}
+
+static void resume_all_threads(void)
+{
+    CPUState *penv = first_cpu;
+
+    assert(!cpu_single_env);
+
+    while (penv) {
+        penv->stop = 0;
+        penv->stopped = 0;
+        pthread_kill(penv->kvm_cpu_state.thread, SIG_IPI);
+        penv = (CPUState *) penv->next_cpu;
+    }
+}
+
+static void kvm_vm_state_change_handler(void *context, int running, int reason)
+{
+    if (running)
+        resume_all_threads();
+    else
+        pause_all_threads();
+}
+
+static void setup_kernel_sigmask(CPUState *env)
+{
+    sigset_t set;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR2);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    sigprocmask(SIG_BLOCK, &set, NULL);
+
+    sigprocmask(SIG_BLOCK, NULL, &set);
+    sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
+
+    kvm_set_signal_mask(env, &set);
+}
+
+static void qemu_kvm_system_reset(void)
+{
+    CPUState *penv = first_cpu;
+
+    pause_all_threads();
+
+    qemu_system_reset();
+
+    while (penv) {
+        kvm_arch_cpu_reset(penv);
+        penv = (CPUState *) penv->next_cpu;
+    }
+
+    resume_all_threads();
+}
+
+static void process_irqchip_events(CPUState *env)
+{
+    kvm_arch_process_irqchip_events(env);
+    if (kvm_arch_has_work(env))
+        env->halted = 0;
+}
+
+static int kvm_main_loop_cpu(CPUState *env)
+{
+    while (1) {
+        int run_cpu = !is_cpu_stopped(env);
+        if (run_cpu && !kvm_irqchip_in_kernel()) {
+            process_irqchip_events(env);
+            run_cpu = !env->halted;
+        }
+        if (run_cpu) {
+            kvm_cpu_exec(env);
+            kvm_main_loop_wait(env, 0);
+        } else {
+            kvm_main_loop_wait(env, 1000);
+        }
+    }
+    pthread_mutex_unlock(&qemu_mutex);
+    return 0;
+}
+
+static void *ap_main_loop(void *_env)
+{
+    CPUState *env = _env;
+    sigset_t signals;
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+    struct ioperm_data *data = NULL;
+#endif
+
+    current_env = env;
+    env->thread_id = kvm_get_thread_id();
+    sigfillset(&signals);
+    sigprocmask(SIG_BLOCK, &signals, NULL);
+    kvm_create_vcpu(env, env->cpu_index);
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+    /* do ioperm for io ports of assigned devices */
+    QLIST_FOREACH(data, &ioperm_head, entries)
+        on_vcpu(env, kvm_arch_do_ioperm, data);
+#endif
+
+    setup_kernel_sigmask(env);
+
+    pthread_mutex_lock(&qemu_mutex);
+    cpu_single_env = env;
+
+    kvm_arch_init_vcpu(env);
+
+    kvm_arch_load_regs(env);
+
+    /* signal VCPU creation */
+    current_env->created = 1;
+    pthread_cond_signal(&qemu_vcpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready)
+        qemu_cond_wait(&qemu_system_cond);
+
+    /* re-initialize cpu_single_env after re-acquiring qemu_mutex */
+    cpu_single_env = env;
+
+    kvm_main_loop_cpu(env);
+    return NULL;
+}
+
+void kvm_init_vcpu(CPUState *env)
+{
+    pthread_create(&env->kvm_cpu_state.thread, NULL, ap_main_loop, env);
+
+    while (env->created == 0)
+        qemu_cond_wait(&qemu_vcpu_cond);
+}
+
+int kvm_vcpu_inited(CPUState *env)
+{
+    return env->created;
+}
+
+#ifdef TARGET_I386
+void kvm_hpet_disable_kpit(void)
+{
+    struct kvm_pit_state2 ps2;
+
+    kvm_get_pit2(kvm_context, &ps2);
+    ps2.flags |= KVM_PIT_FLAGS_HPET_LEGACY;
+    kvm_set_pit2(kvm_context, &ps2);
+}
+
+void kvm_hpet_enable_kpit(void)
+{
+    struct kvm_pit_state2 ps2;
+
+    kvm_get_pit2(kvm_context, &ps2);
+    ps2.flags &= ~KVM_PIT_FLAGS_HPET_LEGACY;
+    kvm_set_pit2(kvm_context, &ps2);
+}
+#endif
+
+int kvm_init_ap(void)
+{
+    struct sigaction action;
+
+    qemu_add_vm_change_state_handler(kvm_vm_state_change_handler, NULL);
+
+    signal(SIG_IPI, sig_ipi_handler);
+
+    memset(&action, 0, sizeof(action));
+    action.sa_flags = SA_SIGINFO;
+    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+    sigaction(SIGBUS, &action, NULL);
+    prctl(PR_MCE_KILL, 1, 1);
+    return 0;
+}
+
+void qemu_kvm_notify_work(void)
+{
+    uint64_t value = 1;
+    char buffer[8];
+    size_t offset = 0;
+
+    if (io_thread_fd == -1)
+        return;
+
+    memcpy(buffer, &value, sizeof(value));
+
+    while (offset < 8) {
+        ssize_t len;
+
+        len = write(io_thread_fd, buffer + offset, 8 - offset);
+        if (len == -1 && errno == EINTR)
+            continue;
+
+        /* In case we have a pipe, there is not reason to insist writing
+         * 8 bytes
+         */
+        if (len == -1 && errno == EAGAIN)
+            break;
+
+        if (len <= 0)
+            break;
+
+        offset += len;
+    }
+}
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them.  We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+
+static void sigfd_handler(void *opaque)
+{
+    int fd = (unsigned long) opaque;
+    struct qemu_signalfd_siginfo info;
+    struct sigaction action;
+    ssize_t len;
+
+    while (1) {
+        do {
+            len = read(fd, &info, sizeof(info));
+        } while (len == -1 && errno == EINTR);
+
+        if (len == -1 && errno == EAGAIN)
+            break;
+
+        if (len != sizeof(info)) {
+            printf("read from sigfd returned %zd: %m\n", len);
+            return;
+        }
+
+        sigaction(info.ssi_signo, NULL, &action);
+        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction)
+            action.sa_sigaction(info.ssi_signo,
+                                (siginfo_t *)&info, NULL);
+	else if (action.sa_handler)
+            action.sa_handler(info.ssi_signo);
+
+    }
+}
+
+/* Used to break IO thread out of select */
+static void io_thread_wakeup(void *opaque)
+{
+    int fd = (unsigned long) opaque;
+    char buffer[4096];
+
+    /* Drain the pipe/(eventfd) */
+    while (1) {
+        ssize_t len;
+
+        len = read(fd, buffer, sizeof(buffer));
+        if (len == -1 && errno == EINTR)
+            continue;
+
+        if (len <= 0)
+            break;
+    }
+}
+
+int kvm_main_loop(void)
+{
+    int fds[2];
+    sigset_t mask;
+    int sigfd;
+
+    io_thread = pthread_self();
+    qemu_system_ready = 1;
+
+    if (qemu_eventfd(fds) == -1) {
+        fprintf(stderr, "failed to create eventfd\n");
+        return -errno;
+    }
+
+    fcntl(fds[0], F_SETFL, O_NONBLOCK);
+    fcntl(fds[1], F_SETFL, O_NONBLOCK);
+
+    qemu_set_fd_handler2(fds[0], NULL, io_thread_wakeup, NULL,
+                         (void *)(unsigned long) fds[0]);
+
+    io_thread_fd = fds[1];
+
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGIO);
+    sigaddset(&mask, SIGALRM);
+    sigaddset(&mask, SIGBUS);
+    sigprocmask(SIG_BLOCK, &mask, NULL);
+
+    sigfd = qemu_signalfd(&mask);
+    if (sigfd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
+        return -errno;
+    }
+
+    fcntl(sigfd, F_SETFL, O_NONBLOCK);
+
+    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+                         (void *)(unsigned long) sigfd);
+
+    pthread_cond_broadcast(&qemu_system_cond);
+
+    io_thread_sigfd = sigfd;
+    cpu_single_env = NULL;
+
+    while (1) {
+        main_loop_wait(1000);
+        if (qemu_shutdown_requested()) {
+            if (qemu_no_shutdown()) {
+                vm_stop(0);
+            } else
+                break;
+        } else if (qemu_powerdown_requested())
+            qemu_irq_raise(qemu_system_powerdown);
+        else if (qemu_reset_requested())
+            qemu_kvm_system_reset();
+        else if (kvm_debug_cpu_requested) {
+            gdb_set_stop_cpu(kvm_debug_cpu_requested);
+            vm_stop(EXCP_DEBUG);
+            kvm_debug_cpu_requested = NULL;
+        }
+    }
+
+    pause_all_threads();
+    pthread_mutex_unlock(&qemu_mutex);
+
+    return 0;
+}
+
+#ifdef TARGET_I386
+static int destroy_region_works = 0;
+#endif
+
+
+#if !defined(TARGET_I386)
+int kvm_arch_init_irq_routing(void)
+{
+    return 0;
+}
+#endif
+
+extern int no_hpet;
+
+static int kvm_create_context(void)
+{
+    int r;
+
+    if (!kvm_irqchip) {
+        kvm_disable_irqchip_creation(kvm_context);
+    }
+    if (!kvm_pit) {
+        kvm_disable_pit_creation(kvm_context);
+    }
+    if (kvm_create(kvm_context, 0, NULL) < 0) {
+        kvm_finalize(kvm_state);
+        return -1;
+    }
+    r = kvm_arch_qemu_create_context();
+    if (r < 0)
+        kvm_finalize(kvm_state);
+    if (kvm_pit && !kvm_pit_reinject) {
+        if (kvm_reinject_control(kvm_context, 0)) {
+            fprintf(stderr, "failure to disable in-kernel PIT reinjection\n");
+            return -1;
+        }
+    }
+#ifdef TARGET_I386
+    destroy_region_works = kvm_destroy_memory_region_works(kvm_context);
+#endif
+
+    r = kvm_arch_init_irq_routing();
+    if (r < 0) {
+        return r;
+    }
+
+    kvm_init_ap();
+    if (kvm_irqchip) {
+        if (!qemu_kvm_has_gsi_routing()) {
+            irq0override = 0;
+#ifdef TARGET_I386
+            /* if kernel can't do irq routing, interrupt source
+             * override 0->2 can not be set up as required by hpet,
+             * so disable hpet.
+             */
+            no_hpet = 1;
+        } else if (!qemu_kvm_has_pit_state2()) {
+            no_hpet = 1;
+        }
+#else
+        }
+#endif
+    }
+
+    return 0;
+}
+
+#ifdef TARGET_I386
+static int must_use_aliases_source(target_phys_addr_t addr)
+{
+    if (destroy_region_works)
+        return false;
+    if (addr == 0xa0000 || addr == 0xa8000)
+        return true;
+    return false;
+}
+
+static int must_use_aliases_target(target_phys_addr_t addr)
+{
+    if (destroy_region_works)
+        return false;
+    if (addr >= 0xe0000000 && addr < 0x100000000ull)
+        return true;
+    return false;
+}
+
+static struct mapping {
+    target_phys_addr_t phys;
+    ram_addr_t ram;
+    ram_addr_t len;
+} mappings[50];
+static int nr_mappings;
+
+static struct mapping *find_ram_mapping(ram_addr_t ram_addr)
+{
+    struct mapping *p;
+
+    for (p = mappings; p < mappings + nr_mappings; ++p) {
+        if (p->ram <= ram_addr && ram_addr < p->ram + p->len) {
+            return p;
+        }
+    }
+    return NULL;
+}
+
+static struct mapping *find_mapping(target_phys_addr_t start_addr)
+{
+    struct mapping *p;
+
+    for (p = mappings; p < mappings + nr_mappings; ++p) {
+        if (p->phys <= start_addr && start_addr < p->phys + p->len) {
+            return p;
+        }
+    }
+    return NULL;
+}
+
+static void drop_mapping(target_phys_addr_t start_addr)
+{
+    struct mapping *p = find_mapping(start_addr);
+
+    if (p)
+        *p = mappings[--nr_mappings];
+}
+#endif
+
+void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
+                      ram_addr_t phys_offset)
+{
+    int r = 0;
+    unsigned long area_flags;
+#ifdef TARGET_I386
+    struct mapping *p;
+#endif
+
+    if (start_addr + size > phys_ram_size) {
+        phys_ram_size = start_addr + size;
+    }
+
+    phys_offset &= ~IO_MEM_ROM;
+    area_flags = phys_offset & ~TARGET_PAGE_MASK;
+
+    if (area_flags != IO_MEM_RAM) {
+#ifdef TARGET_I386
+        if (must_use_aliases_source(start_addr)) {
+            kvm_destroy_memory_alias(kvm_context, start_addr);
+            return;
+        }
+        if (must_use_aliases_target(start_addr))
+            return;
+#endif
+        while (size > 0) {
+            p = find_mapping(start_addr);
+            if (p) {
+                kvm_unregister_memory_area(kvm_context, p->phys, p->len);
+                drop_mapping(p->phys);
+            }
+            start_addr += TARGET_PAGE_SIZE;
+            if (size > TARGET_PAGE_SIZE) {
+                size -= TARGET_PAGE_SIZE;
+            } else {
+                size = 0;
+            }
+        }
+        return;
+    }
+
+    r = kvm_is_containing_region(kvm_context, start_addr, size);
+    if (r)
+        return;
+
+    if (area_flags >= TLB_MMIO)
+        return;
+
+#ifdef TARGET_I386
+    if (must_use_aliases_source(start_addr)) {
+        p = find_ram_mapping(phys_offset);
+        if (p) {
+            kvm_create_memory_alias(kvm_context, start_addr, size,
+                                    p->phys + (phys_offset - p->ram));
+        }
+        return;
+    }
+#endif
+
+    r = kvm_register_phys_mem(kvm_context, start_addr,
+                              qemu_get_ram_ptr(phys_offset), size, 0);
+    if (r < 0) {
+        printf("kvm_cpu_register_physical_memory: failed\n");
+        exit(1);
+    }
+#ifdef TARGET_I386
+    drop_mapping(start_addr);
+    p = &mappings[nr_mappings++];
+    p->phys = start_addr;
+    p->ram = phys_offset;
+    p->len = size;
+#endif
+
+    return;
+}
+
+int kvm_setup_guest_memory(void *area, unsigned long size)
+{
+    int ret = 0;
+
+#ifdef MADV_DONTFORK
+    if (kvm_enabled() && !kvm_has_sync_mmu())
+        ret = madvise(area, size, MADV_DONTFORK);
+#endif
+
+    if (ret)
+        perror("madvise");
+
+    return ret;
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+
+struct kvm_set_guest_debug_data {
+    struct kvm_guest_debug dbg;
+    int err;
+};
+
+static void kvm_invoke_set_guest_debug(void *data)
+{
+    struct kvm_set_guest_debug_data *dbg_data = data;
+
+    if (cpu_single_env->kvm_cpu_state.regs_modified) {
+        kvm_arch_put_registers(cpu_single_env);
+        cpu_single_env->kvm_cpu_state.regs_modified = 0;
+    }
+    dbg_data->err =
+        kvm_set_guest_debug(cpu_single_env,
+                            &dbg_data->dbg);
+}
+
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
+{
+    struct kvm_set_guest_debug_data data;
+
+    data.dbg.control = 0;
+    if (env->singlestep_enabled)
+        data.dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+
+    kvm_arch_update_guest_debug(env, &data.dbg);
+    data.dbg.control |= reinject_trap;
+
+    on_vcpu(env, kvm_invoke_set_guest_debug, &data);
+    return data.err;
+}
+
+#endif
+
+/*
+ * dirty pages logging
+ */
+/* FIXME: use unsigned long pointer instead of unsigned char */
+unsigned char *kvm_dirty_bitmap = NULL;
+int kvm_physical_memory_set_dirty_tracking(int enable)
+{
+    int r = 0;
+
+    if (!kvm_enabled())
+        return 0;
+
+    if (enable) {
+        if (!kvm_dirty_bitmap) {
+            unsigned bitmap_size = BITMAP_SIZE(phys_ram_size);
+            kvm_dirty_bitmap = qemu_malloc(bitmap_size);
+            r = kvm_dirty_pages_log_enable_all(kvm_context);
+        }
+    } else {
+        if (kvm_dirty_bitmap) {
+            r = kvm_dirty_pages_log_reset(kvm_context);
+            qemu_free(kvm_dirty_bitmap);
+            kvm_dirty_bitmap = NULL;
+        }
+    }
+    return r;
+}
+
+/* get kvm's dirty pages bitmap and update qemu's */
+static int kvm_get_dirty_pages_log_range(unsigned long start_addr,
+                                         unsigned char *bitmap,
+                                         unsigned long offset,
+                                         unsigned long mem_size)
+{
+    unsigned int i, j, n = 0;
+    unsigned char c;
+    unsigned long page_number, addr, addr1;
+    ram_addr_t ram_addr;
+    unsigned int len = ((mem_size / TARGET_PAGE_SIZE) + 7) / 8;
+
+    /* 
+     * bitmap-traveling is faster than memory-traveling (for addr...) 
+     * especially when most of the memory is not dirty.
+     */
+    for (i = 0; i < len; i++) {
+        c = bitmap[i];
+        while (c > 0) {
+            j = ffsl(c) - 1;
+            c &= ~(1u << j);
+            page_number = i * 8 + j;
+            addr1 = page_number * TARGET_PAGE_SIZE;
+            addr = offset + addr1;
+            ram_addr = cpu_get_physical_page_desc(addr);
+            cpu_physical_memory_set_dirty(ram_addr);
+            n++;
+        }
+    }
+    return 0;
+}
+
+static int kvm_get_dirty_bitmap_cb(unsigned long start, unsigned long len,
+                                   void *bitmap, void *opaque)
+{
+    return kvm_get_dirty_pages_log_range(start, bitmap, start, len);
+}
+
+/* 
+ * get kvm's dirty pages bitmap and update qemu's
+ * we only care about physical ram, which resides in slots 0 and 3
+ */
+int kvm_update_dirty_pages_log(void)
+{
+    int r = 0;
+
+
+    r = kvm_get_dirty_pages_range(kvm_context, 0, -1UL, NULL,
+                                  kvm_get_dirty_bitmap_cb);
+    return r;
+}
+
+void kvm_qemu_log_memory(target_phys_addr_t start, target_phys_addr_t size,
+                         int log)
+{
+    if (log)
+        kvm_dirty_pages_log_enable_slot(kvm_context, start, size);
+    else {
+#ifdef TARGET_I386
+        if (must_use_aliases_target(start))
+            return;
+#endif
+        kvm_dirty_pages_log_disable_slot(kvm_context, start, size);
+    }
+}
+
+#ifdef KVM_CAP_IRQCHIP
+
+int kvm_set_irq(int irq, int level, int *status)
+{
+    return kvm_set_irq_level(kvm_context, irq, level, status);
+}
+
+#endif
+
+int qemu_kvm_get_dirty_pages(unsigned long phys_addr, void *buf)
+{
+    return kvm_get_dirty_pages(kvm_context, phys_addr, buf);
+}
+
+void kvm_mutex_unlock(void)
+{
+    assert(!cpu_single_env);
+    pthread_mutex_unlock(&qemu_mutex);
+}
+
+void kvm_mutex_lock(void)
+{
+    pthread_mutex_lock(&qemu_mutex);
+    cpu_single_env = NULL;
+}
+
+void qemu_mutex_unlock_iothread(void)
+{
+    if (kvm_enabled())
+        kvm_mutex_unlock();
+}
+
+void qemu_mutex_lock_iothread(void)
+{
+    if (kvm_enabled())
+        kvm_mutex_lock();
+}
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+void kvm_add_ioperm_data(struct ioperm_data *data)
+{
+    QLIST_INSERT_HEAD(&ioperm_head, data, entries);
+}
+
+void kvm_remove_ioperm_data(unsigned long start_port, unsigned long num)
+{
+    struct ioperm_data *data;
+
+    data = QLIST_FIRST(&ioperm_head);
+    while (data) {
+        struct ioperm_data *next = QLIST_NEXT(data, entries);
+
+        if (data->start_port == start_port && data->num == num) {
+            QLIST_REMOVE(data, entries);
+            qemu_free(data);
+        }
+
+        data = next;
+    }
+}
+
+void kvm_ioperm(CPUState *env, void *data)
+{
+    if (kvm_enabled() && qemu_system_ready)
+        on_vcpu(env, kvm_arch_do_ioperm, data);
+}
+
+#endif
+
+int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+#ifndef TARGET_IA64
+
+#ifdef TARGET_I386
+    if (must_use_aliases_source(start_addr))
+        return 0;
+#endif
+
+    kvm_get_dirty_pages_range(kvm_context, start_addr,
+                              end_addr - start_addr, NULL,
+                              kvm_get_dirty_bitmap_cb);
+#endif
+    return 0;
+}
+
+int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t len)
+{
+#ifdef TARGET_I386
+    if (must_use_aliases_source(phys_addr))
+        return 0;
+#endif
+
+#ifndef TARGET_IA64
+    kvm_qemu_log_memory(phys_addr, len, 1);
+#endif
+    return 0;
+}
+
+int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t len)
+{
+#ifdef TARGET_I386
+    if (must_use_aliases_source(phys_addr))
+        return 0;
+#endif
+
+#ifndef TARGET_IA64
+    kvm_qemu_log_memory(phys_addr, len, 0);
+#endif
+    return 0;
+}
+
+int kvm_set_boot_cpu_id(uint32_t id)
+{
+    return kvm_set_boot_vcpu_id(kvm_context, id);
+}
+
+#ifdef TARGET_I386
+#ifdef KVM_CAP_MCE
+struct kvm_x86_mce_data {
+    CPUState *env;
+    struct kvm_x86_mce *mce;
+    int abort_on_error;
+};
+
+static void kvm_do_inject_x86_mce(void *_data)
+{
+    struct kvm_x86_mce_data *data = _data;
+    int r;
+
+    r = kvm_set_mce(data->env, data->mce);
+    if (r < 0) {
+        perror("kvm_set_mce FAILED");
+        if (data->abort_on_error)
+            abort();
+    }
+}
+#endif
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error)
+{
+#ifdef KVM_CAP_MCE
+    struct kvm_x86_mce mce = {
+        .bank = bank,
+        .status = status,
+        .mcg_status = mcg_status,
+        .addr = addr,
+        .misc = misc,
+    };
+    struct kvm_x86_mce_data data = {
+        .env = cenv,
+        .mce = &mce,
+        .abort_on_error = abort_on_error,
+    };
+
+    if (!cenv->mcg_cap) {
+        fprintf(stderr, "MCE support is not enabled!\n");
+        return;
+    }
+    on_vcpu(cenv, kvm_do_inject_x86_mce, &data);
+#else
+    if (abort_on_error)
+        abort();
+#endif
+}
+#endif
diff --git a/qemu-kvm.h b/qemu-kvm.h
new file mode 100644
index 0000000..6b3e5a1
--- /dev/null
+++ b/qemu-kvm.h
@@ -0,0 +1,1169 @@
+/*
+ * qemu/kvm integration
+ *
+ * Copyright (C) 2006-2008 Qumranet Technologies
+ *
+ * Licensed under the terms of the GNU GPL version 2 or higher.
+ */
+#ifndef THE_ORIGINAL_AND_TRUE_QEMU_KVM_H
+#define THE_ORIGINAL_AND_TRUE_QEMU_KVM_H
+
+#ifndef QEMU_KVM_NO_CPU
+#include "cpu.h"
+#endif
+
+#include <signal.h>
+#include <stdlib.h>
+
+#ifdef CONFIG_KVM
+
+#if defined(__s390__)
+#include <asm/ptrace.h>
+#endif
+
+#include <stdint.h>
+
+#ifndef __user
+#define __user       /* temporary, until installed via make headers_install */
+#endif
+
+#include <linux/kvm.h>
+
+#include <signal.h>
+
+/* FIXME: share this number with kvm */
+/* FIXME: or dynamically alloc/realloc regions */
+#ifdef __s390__
+#define KVM_MAX_NUM_MEM_REGIONS 1u
+#define MAX_VCPUS 64
+#define LIBKVM_S390_ORIGIN (0UL)
+#elif defined(__ia64__)
+#define KVM_MAX_NUM_MEM_REGIONS 32u
+#define MAX_VCPUS 256
+#else
+#define KVM_MAX_NUM_MEM_REGIONS 32u
+#define MAX_VCPUS 16
+#endif
+
+/* kvm abi verison variable */
+extern int kvm_abi;
+
+/**
+ * \brief The KVM context
+ *
+ * The verbose KVM context
+ */
+
+struct kvm_context {
+    void *opaque;
+    /// is dirty pages logging enabled for all regions or not
+    int dirty_pages_log_all;
+    /// do not create in-kernel irqchip if set
+    int no_irqchip_creation;
+    /// in-kernel irqchip status
+    int irqchip_in_kernel;
+    /// ioctl to use to inject interrupts
+    int irqchip_inject_ioctl;
+    /// do not create in-kernel pit if set
+    int no_pit_creation;
+    /// in-kernel pit status
+    int pit_in_kernel;
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing *irq_routes;
+    int nr_allocated_irq_routes;
+#endif
+    void *used_gsi_bitmap;
+    int max_gsi;
+};
+
+typedef struct kvm_context *kvm_context_t;
+
+#include "kvm.h"
+int kvm_alloc_kernel_memory(kvm_context_t kvm, unsigned long memory,
+                            void **vm_mem);
+int kvm_alloc_userspace_memory(kvm_context_t kvm, unsigned long memory,
+                               void **vm_mem);
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+                    void **vm_mem);
+
+int kvm_arch_run(CPUState *env);
+
+
+void kvm_show_code(CPUState *env);
+
+int handle_halt(CPUState *env);
+
+#ifndef QEMU_KVM_NO_CPU
+
+int handle_shutdown(kvm_context_t kvm, CPUState *env);
+void post_kvm_run(kvm_context_t kvm, CPUState *env);
+int pre_kvm_run(kvm_context_t kvm, CPUState *env);
+int handle_io_window(kvm_context_t kvm);
+int try_push_interrupts(kvm_context_t kvm);
+
+#if defined(__x86_64__) || defined(__i386__)
+struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
+int kvm_get_msrs(CPUState *env, struct kvm_msr_entry *msrs, int n);
+int kvm_set_msrs(CPUState *env, struct kvm_msr_entry *msrs, int n);
+int kvm_get_mce_cap_supported(kvm_context_t, uint64_t *mce_cap,
+                              int *max_banks);
+int kvm_setup_mce(CPUState *env, uint64_t *mcg_cap);
+struct kvm_x86_mce;
+int kvm_set_mce(CPUState *env, struct kvm_x86_mce *mce);
+#endif
+
+#endif
+
+/*!
+ * \brief Create new KVM context
+ *
+ * This creates a new kvm_context. A KVM context is a small area of data that
+ * holds information about the KVM instance that gets created by this call.\n
+ * This should always be your first call to KVM.
+ *
+ * \param opaque Not used
+ * \return NULL on failure
+ */
+int kvm_init(int smp_cpus);
+
+/*!
+ * \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 Disable the in-kernel PIT creation
+ *
+ * In-kernel pit is enabled by default. If userspace pit is to be used,
+ * this should be called prior to kvm_create().
+ *
+ *  \param kvm Pointer to the kvm_context
+ */
+void kvm_disable_pit_creation(kvm_context_t kvm);
+
+/*!
+ * \brief Create new virtual machine
+ *
+ * This creates a new virtual machine, maps physical RAM to it, and creates a
+ * virtual CPU for it.\n
+ * \n
+ * Memory gets mapped for addresses 0->0xA0000, 0xC0000->phys_mem_bytes
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param phys_mem_bytes The amount of physical ram you want the VM to have
+ * \param phys_mem This pointer will be set to point to the memory that
+ * kvm_create allocates for physical RAM
+ * \return 0 on success
+ */
+int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+               void **phys_mem);
+int kvm_create_vm(kvm_context_t kvm);
+void kvm_create_irqchip(kvm_context_t kvm);
+
+/*!
+ * \brief Start the VCPU
+ *
+ * This starts the VCPU and virtualization is started.\n
+ * \n
+ * This function will not return until any of these conditions are met:
+ * - An IO/MMIO handler does not return "0"
+ * - An exception that neither the guest OS, nor KVM can handle occurs
+ *
+ * \note This function will call the callbacks registered in kvm_init()
+ * to emulate those functions
+ * \note If you at any point want to interrupt the VCPU, kvm_run() will
+ * listen to the EINTR signal. This allows you to simulate external interrupts
+ * and asyncronous IO.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should be started
+ * \return 0 on success, but you really shouldn't expect this function to
+ * return except for when an error has occured, or when you have sent it
+ * an EINTR signal.
+ */
+int kvm_run(CPUState *env);
+
+/*!
+ * \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(CPUState *env);
+
+/*!
+ * \brief Read VCPU registers
+ *
+ * This gets the GP registers from the VCPU and outputs them
+ * into a kvm_regs structure
+ *
+ * \note This function returns a \b copy of the VCPUs registers.\n
+ * If you wish to modify the VCPUs GP registers, you should call kvm_set_regs()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_regs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_get_regs(CPUState *env, struct kvm_regs *regs);
+
+/*!
+ * \brief Write VCPU registers
+ *
+ * This sets the GP registers on the VCPU from a kvm_regs structure
+ *
+ * \note When this function returns, the regs pointer and the data it points to
+ * can be discarded
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_regs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_set_regs(CPUState *env, struct kvm_regs *regs);
+/*!
+ * \brief Read VCPU fpu registers
+ *
+ * This gets the FPU registers from the VCPU and outputs them
+ * into a kvm_fpu structure
+ *
+ * \note This function returns a \b copy of the VCPUs registers.\n
+ * If you wish to modify the VCPU FPU registers, you should call kvm_set_fpu()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param fpu Pointer to a kvm_fpu which will be populated with the VCPUs
+ * fpu registers values
+ * \return 0 on success
+ */
+int kvm_get_fpu(CPUState *env, struct kvm_fpu *fpu);
+
+/*!
+ * \brief Write VCPU fpu registers
+ *
+ * This sets the FPU registers on the VCPU from a kvm_fpu structure
+ *
+ * \note When this function returns, the fpu pointer and the data it points to
+ * can be discarded
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param fpu Pointer to a kvm_fpu which holds the new vcpu fpu state
+ * \return 0 on success
+ */
+int kvm_set_fpu(CPUState *env, struct kvm_fpu *fpu);
+
+/*!
+ * \brief Read VCPU system registers
+ *
+ * This gets the non-GP registers from the VCPU and outputs them
+ * into a kvm_sregs structure
+ *
+ * \note This function returns a \b copy of the VCPUs registers.\n
+ * If you wish to modify the VCPUs non-GP registers, you should call
+ * kvm_set_sregs()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_sregs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_get_sregs(CPUState *env, struct kvm_sregs *regs);
+
+/*!
+ * \brief Write VCPU system registers
+ *
+ * This sets the non-GP registers on the VCPU from a kvm_sregs structure
+ *
+ * \note When this function returns, the regs pointer and the data it points to
+ * can be discarded
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \param regs Pointer to a kvm_sregs which will be populated with the VCPUs
+ * registers values
+ * \return 0 on success
+ */
+int kvm_set_sregs(CPUState *env, struct kvm_sregs *regs);
+
+#ifdef KVM_CAP_MP_STATE
+/*!
+ *  * \brief Read VCPU MP state
+ *
+ */
+int kvm_get_mpstate(CPUState *env, struct kvm_mp_state *mp_state);
+
+/*!
+ *  * \brief Write VCPU MP state
+ *
+ */
+int kvm_set_mpstate(CPUState *env, struct kvm_mp_state *mp_state);
+/*!
+ *  * \brief Reset VCPU MP state
+ *
+ */
+static inline int kvm_reset_mpstate(CPUState *env)
+{
+    struct kvm_mp_state mp_state = {.mp_state = KVM_MP_STATE_UNINITIALIZED
+    };
+    return kvm_set_mpstate(env, &mp_state);
+}
+#endif
+
+/*!
+ * \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(CPUState *env, unsigned irq);
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * \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(CPUState *env, int nent,
+                    struct kvm_cpuid_entry *entries);
+
+/*!
+ * \brief Setup a vcpu's cpuid instruction emulation
+ *
+ * Set up a table of cpuid function to cpuid outputs.
+ * This call replaces the older kvm_setup_cpuid interface by adding a few
+ * parameters to support cpuid functions that have sub-leaf values.
+ *
+ * \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_cpuid2(CPUState *env, int nent,
+                     struct kvm_cpuid_entry2 *entries);
+
+/*!
+ * \brief Setting the number of shadow pages to be allocated to the vm
+ *
+ * \param kvm pointer to kvm_context
+ * \param nrshadow_pages number of pages to be allocated
+ */
+int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages);
+
+/*!
+ * \brief Getting the number of shadow pages that are allocated to the vm
+ *
+ * \param kvm pointer to kvm_context
+ * \param nrshadow_pages number of pages to be allocated
+ */
+int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages);
+
+#endif
+
+/*!
+ * \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(CPUState *env, const sigset_t *sigset);
+
+/*!
+ * \brief Dump VCPU registers
+ *
+ * This dumps some of the information that KVM has about a virtual CPU, namely:
+ * - GP Registers
+ *
+ * A much more verbose version of this is available as kvm_dump_vcpu()
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return 0 on success
+ */
+void kvm_show_regs(CPUState *env);
+
+
+void *kvm_create_phys_mem(kvm_context_t, unsigned long phys_start,
+                          unsigned long len, int log, int writable);
+void kvm_destroy_phys_mem(kvm_context_t, unsigned long phys_start,
+                          unsigned long len);
+void kvm_unregister_memory_area(kvm_context_t, uint64_t phys_start,
+                                unsigned long len);
+
+int kvm_is_containing_region(kvm_context_t kvm, unsigned long phys_start,
+                             unsigned long size);
+int kvm_register_phys_mem(kvm_context_t kvm, unsigned long phys_start,
+                          void *userspace_addr, unsigned long len, int log);
+int kvm_get_dirty_pages(kvm_context_t, unsigned long phys_addr, void *buf);
+int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
+                              unsigned long end_addr, void *opaque,
+                              int (*cb)(unsigned long start,
+                                        unsigned long len, void *bitmap,
+                                        void *opaque));
+int kvm_register_coalesced_mmio(kvm_context_t kvm, uint64_t addr,
+                                uint32_t size);
+int kvm_unregister_coalesced_mmio(kvm_context_t kvm, uint64_t addr,
+                                  uint32_t size);
+
+/*!
+ * \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, 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, uint64_t phys_start);
+
+/*!
+ * \brief Get a bitmap of guest ram pages which are allocated to the guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param phys_addr Memory slot phys addr
+ * \param bitmap Long aligned address of a big enough bitmap (one bit per page)
+ */
+int kvm_get_mem_map(kvm_context_t kvm, unsigned long phys_addr, void *bitmap);
+int kvm_get_mem_map_range(kvm_context_t kvm, unsigned long phys_addr,
+                          unsigned long len, void *buf, void *opaque,
+                          int (*cb)(unsigned long start,
+                                    unsigned long len, void *bitmap,
+                                    void *opaque));
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status);
+
+int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm, uint64_t phys_start,
+                                    uint64_t len);
+int kvm_dirty_pages_log_disable_slot(kvm_context_t kvm, uint64_t phys_start,
+                                     uint64_t len);
+/*!
+ * \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);
+
+#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);
+
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * \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(CPUState *env, 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(CPUState *env, struct kvm_lapic_state *s);
+
+#endif
+
+/*!
+ * \brief Simulate an NMI
+ *
+ * This allows you to simulate a non-maskable interrupt.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return 0 on success
+ */
+int kvm_inject_nmi(CPUState *env);
+
+#endif
+
+/*!
+ * \brief Simulate an x86 MCE
+ *
+ * This allows you to simulate a x86 MCE.
+ *
+ * \param cenv Which virtual CPU should get MCE injected
+ * \param bank Bank number
+ * \param status MSR_MCI_STATUS
+ * \param mcg_status MSR_MCG_STATUS
+ * \param addr MSR_MCI_ADDR
+ * \param misc MSR_MCI_MISC
+ * \param abort_on_error abort on error
+ */
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error);
+
+/*!
+ * \brief Query wheather in kernel pit is used
+ *
+ *  \param kvm Pointer to the current kvm_context
+ */
+int kvm_pit_in_kernel(kvm_context_t kvm);
+
+/*!
+ * \brief Initialize coalesced MMIO
+ *
+ * Check for coalesced MMIO capability and store in context
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_init_coalesced_mmio(kvm_context_t kvm);
+
+#ifdef KVM_CAP_PIT
+
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * \brief Get in kernel PIT of the virtual domain
+ *
+ * Save the PIT state.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param s PIT state of the virtual domain
+ */
+int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s);
+
+/*!
+ * \brief Set in kernel PIT of the virtual domain
+ *
+ * Restore the PIT state.
+ * Timer would be retriggerred after restored.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param s PIT state of the virtual domain
+ */
+int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s);
+
+int kvm_reinject_control(kvm_context_t kvm, int pit_reinject);
+
+#ifdef KVM_CAP_PIT_STATE2
+/*!
+ * \brief Check for kvm support of kvm_pit_state2
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \return 0 on success
+ */
+int kvm_has_pit_state2(kvm_context_t kvm);
+
+/*!
+ * \brief Set in kernel PIT state2 of the virtual domain
+ *
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param ps2 PIT state2 of the virtual domain
+ * \return 0 on success
+ */
+int kvm_set_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2);
+
+/*!
+ * \brief Get in kernel PIT state2 of the virtual domain
+ *
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param ps2 PIT state2 of the virtual domain
+ * \return 0 on success
+ */
+int kvm_get_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2);
+
+#endif
+#endif
+#endif
+
+#ifdef KVM_CAP_VAPIC
+
+/*!
+ * \brief Enable kernel tpr access reporting
+ *
+ * When tpr access reporting is enabled, the kernel will call the
+ * ->tpr_access() callback every time the guest vcpu accesses the tpr.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu vcpu to enable tpr access reporting on
+ */
+int kvm_enable_tpr_access_reporting(CPUState *env);
+
+/*!
+ * \brief Disable kernel tpr access reporting
+ *
+ * Undoes the effect of kvm_enable_tpr_access_reporting().
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu vcpu to disable tpr access reporting on
+ */
+int kvm_disable_tpr_access_reporting(CPUState *env);
+
+int kvm_enable_vapic(CPUState *env, uint64_t vapic);
+
+#endif
+
+#if defined(__s390__)
+int kvm_s390_initial_reset(kvm_context_t kvm, int slot);
+int kvm_s390_interrupt(kvm_context_t kvm, int slot,
+                       struct kvm_s390_interrupt *kvmint);
+int kvm_s390_set_initial_psw(kvm_context_t kvm, int slot, psw_t psw);
+int kvm_s390_store_status(kvm_context_t kvm, int slot, unsigned long addr);
+#endif
+
+#ifdef KVM_CAP_DEVICE_ASSIGNMENT
+/*!
+ * \brief Notifies host kernel about a PCI device to be assigned to a guest
+ *
+ * Used for PCI device assignment, this function notifies the host
+ * kernel about the assigning of the physical PCI device to a guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_dev Parameters, like bus, devfn number, etc
+ */
+int kvm_assign_pci_device(kvm_context_t kvm,
+                          struct kvm_assigned_pci_dev *assigned_dev);
+
+/*!
+ * \brief Assign IRQ for an assigned device
+ *
+ * Used for PCI device assignment, this function assigns IRQ numbers for
+ * an physical device and guest IRQ handling.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_irq Parameters, like dev id, host irq, guest irq, etc
+ */
+int kvm_assign_irq(kvm_context_t kvm, struct kvm_assigned_irq *assigned_irq);
+
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+/*!
+ * \brief Deassign IRQ for an assigned device
+ *
+ * Used for PCI device assignment, this function deassigns IRQ numbers
+ * for an assigned device.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_irq Parameters, like dev id, host irq, guest irq, etc
+ */
+int kvm_deassign_irq(kvm_context_t kvm, struct kvm_assigned_irq *assigned_irq);
+#endif
+#endif
+
+/*!
+ * \brief Determines whether destroying memory regions is allowed
+ *
+ * KVM before 2.6.29 had a bug when destroying memory regions.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_destroy_memory_region_works(kvm_context_t kvm);
+
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+/*!
+ * \brief Notifies host kernel about a PCI device to be deassigned from a guest
+ *
+ * Used for hot remove PCI device, this function notifies the host
+ * kernel about the deassigning of the physical PCI device from a guest.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param assigned_dev Parameters, like bus, devfn number, etc
+ */
+int kvm_deassign_pci_device(kvm_context_t kvm,
+                            struct kvm_assigned_pci_dev *assigned_dev);
+#endif
+
+/*!
+ * \brief Checks whether the generic irq routing capability is present
+ *
+ * Checks whether kvm can reroute interrupts among the various interrupt
+ * controllers.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_has_gsi_routing(kvm_context_t kvm);
+
+/*!
+ * \brief Determines the number of gsis that can be routed
+ *
+ * Returns the number of distinct gsis that can be routed by kvm.  This is
+ * also the number of distinct routes (if a gsi has two routes, than another
+ * gsi cannot be used...)
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_get_gsi_count(kvm_context_t kvm);
+
+/*!
+ * \brief Clears the temporary irq routing table
+ *
+ * Clears the temporary irq routing table.  Nothing is committed to the
+ * running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_clear_gsi_routes(kvm_context_t kvm);
+
+/*!
+ * \brief Adds an irq route to the temporary irq routing table
+ *
+ * Adds an irq route to the temporary irq routing table.  Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
+
+/*!
+ * \brief Removes an irq route from the temporary irq routing table
+ *
+ * Adds an irq route to the temporary irq routing table.  Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
+
+struct kvm_irq_routing_entry;
+/*!
+ * \brief Adds a routing entry to the temporary irq routing table
+ *
+ * Adds a filled routing entry to the temporary irq routing table. Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_add_routing_entry(kvm_context_t kvm,
+                          struct kvm_irq_routing_entry *entry);
+
+/*!
+ * \brief Removes a routing from the temporary irq routing table
+ *
+ * Remove a routing to the temporary irq routing table.  Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_del_routing_entry(kvm_context_t kvm,
+                          struct kvm_irq_routing_entry *entry);
+
+/*!
+ * \brief Updates a routing in the temporary irq routing table
+ *
+ * Update a routing in the temporary irq routing table
+ * with a new value. entry type and GSI can not be changed.
+ * Nothing is committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_update_routing_entry(kvm_context_t kvm,
+                             struct kvm_irq_routing_entry *entry,
+                             struct kvm_irq_routing_entry *newentry);
+
+/*!
+ * \brief Commit the temporary irq routing table
+ *
+ * Commit the temporary irq routing table to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_commit_irq_routes(kvm_context_t kvm);
+
+/*!
+ * \brief Get unused GSI number for irq routing table
+ *
+ * Get unused GSI number for irq routing table
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_get_irq_route_gsi(kvm_context_t kvm);
+
+/*!
+ * \brief Create a file descriptor for injecting interrupts
+ *
+ * Creates an eventfd based file-descriptor that maps to a specific GSI
+ * in the guest.  eventfd compliant signaling (write() from userspace, or
+ * eventfd_signal() from kernelspace) will cause the GSI to inject
+ * itself into the guest at the next available window.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param gsi GSI to assign to this fd
+ * \param flags reserved, must be zero
+ */
+int kvm_irqfd(kvm_context_t kvm, int gsi, int flags);
+
+#ifdef KVM_CAP_DEVICE_MSIX
+int kvm_assign_set_msix_nr(kvm_context_t kvm,
+                           struct kvm_assigned_msix_nr *msix_nr);
+int kvm_assign_set_msix_entry(kvm_context_t kvm,
+                              struct kvm_assigned_msix_entry *entry);
+#endif
+
+uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg);
+
+#else                           /* !CONFIG_KVM */
+
+typedef struct kvm_context *kvm_context_t;
+typedef struct kvm_vcpu_context *kvm_vcpu_context_t;
+
+struct kvm_pit_state {
+};
+
+static inline int kvm_init(int smp_cpus)
+{
+    return 0;
+}
+
+#ifndef QEMU_KVM_NO_CPU
+
+static inline void kvm_inject_x86_mce(CPUState *cenv, int bank,
+                                      uint64_t status, uint64_t mcg_status,
+                                      uint64_t addr, uint64_t misc,
+                                      int abort_on_error)
+{
+    if (abort_on_error)
+        abort();
+}
+
+#endif
+
+extern int kvm_allowed;
+
+#endif                          /* !CONFIG_KVM */
+
+
+int kvm_main_loop(void);
+int kvm_init_ap(void);
+#ifndef QEMU_KVM_NO_CPU
+int kvm_vcpu_inited(CPUState *env);
+void kvm_load_registers(CPUState *env);
+void kvm_save_registers(CPUState *env);
+void kvm_load_mpstate(CPUState *env);
+void kvm_save_mpstate(CPUState *env);
+int kvm_cpu_exec(CPUState *env);
+int kvm_insert_breakpoint(CPUState * current_env, target_ulong addr,
+                          target_ulong len, int type);
+int kvm_remove_breakpoint(CPUState * current_env, target_ulong addr,
+                          target_ulong len, int type);
+void kvm_remove_all_breakpoints(CPUState * current_env);
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap);
+void kvm_apic_init(CPUState *env);
+/* called from vcpu initialization */
+void qemu_kvm_load_lapic(CPUState *env);
+#endif
+
+void kvm_hpet_enable_kpit(void);
+void kvm_hpet_disable_kpit(void);
+int kvm_set_irq(int irq, int level, int *status);
+
+int kvm_physical_memory_set_dirty_tracking(int enable);
+int kvm_update_dirty_pages_log(void);
+
+#ifndef QEMU_KVM_NO_CPU
+void qemu_kvm_call_with_env(void (*func)(void *), void *data, CPUState *env);
+void qemu_kvm_cpuid_on_env(CPUState *env);
+void kvm_inject_interrupt(CPUState *env, int mask);
+void kvm_update_after_sipi(CPUState *env);
+void kvm_update_interrupt_request(CPUState *env);
+#endif
+void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
+                      ram_addr_t phys_offset);
+void *kvm_cpu_create_phys_mem(target_phys_addr_t start_addr, unsigned long size,
+                              int log, int writable);
+
+void kvm_cpu_destroy_phys_mem(target_phys_addr_t start_addr,
+                              unsigned long size);
+void kvm_qemu_log_memory(target_phys_addr_t start, target_phys_addr_t size,
+                         int log);
+int kvm_setup_guest_memory(void *area, unsigned long size);
+int kvm_qemu_create_memory_alias(uint64_t phys_start, uint64_t len,
+                                 uint64_t target_phys);
+int kvm_qemu_destroy_memory_alias(uint64_t phys_start);
+
+int kvm_arch_qemu_create_context(void);
+
+#ifndef QEMU_KVM_NO_CPU
+void kvm_arch_save_regs(CPUState *env);
+void kvm_arch_load_regs(CPUState *env);
+void kvm_arch_load_mpstate(CPUState *env);
+void kvm_arch_save_mpstate(CPUState *env);
+int kvm_arch_init_vcpu(CPUState *cenv);
+int kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
+int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
+int kvm_arch_has_work(CPUState *env);
+void kvm_arch_process_irqchip_events(CPUState *env);
+int kvm_arch_try_push_interrupts(void *opaque);
+void kvm_arch_push_nmi(void *opaque);
+void kvm_arch_cpu_reset(CPUState *env);
+int kvm_set_boot_cpu_id(uint32_t id);
+
+struct kvm_guest_debug;
+struct kvm_debug_exit_arch;
+
+struct kvm_sw_breakpoint {
+    target_ulong pc;
+    target_ulong saved_insn;
+    int use_count;
+    QTAILQ_ENTRY(kvm_sw_breakpoint) entry;
+};
+
+QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint);
+
+int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info);
+int kvm_sw_breakpoints_active(CPUState *env);
+struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
+                                                 target_ulong pc);
+int kvm_arch_insert_sw_breakpoint(CPUState * current_env,
+                                  struct kvm_sw_breakpoint *bp);
+int kvm_arch_remove_sw_breakpoint(CPUState * current_env,
+                                  struct kvm_sw_breakpoint *bp);
+int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len,
+                                  int type);
+int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len,
+                                  int type);
+void kvm_arch_remove_all_hw_breakpoints(void);
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
+
+#endif
+
+void qemu_kvm_aio_wait_start(void);
+void qemu_kvm_aio_wait(void);
+void qemu_kvm_aio_wait_end(void);
+
+void qemu_kvm_notify_work(void);
+
+#ifndef QEMU_KVM_NO_CPU
+void kvm_tpr_opt_setup(void);
+void kvm_tpr_access_report(CPUState *env, uint64_t rip, int is_write);
+void kvm_tpr_vcpu_start(CPUState *env);
+#endif
+
+int qemu_kvm_get_dirty_pages(unsigned long phys_addr, void *buf);
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
+
+int kvm_arch_init_irq_routing(void);
+
+int kvm_mmio_read(void *opaque, uint64_t addr, uint8_t * data, int len);
+int kvm_mmio_write(void *opaque, uint64_t addr, uint8_t * data, int len);
+
+#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+struct ioperm_data;
+
+void kvm_ioperm(CPUState *env, void *data);
+void kvm_add_ioperm_data(struct ioperm_data *data);
+void kvm_remove_ioperm_data(unsigned long start_port, unsigned long num);
+void kvm_arch_do_ioperm(void *_data);
+#endif
+
+#define ALIGN(x, y)  (((x)+(y)-1) & ~((y)-1))
+#ifndef QEMU_KVM_NO_CPU
+#define BITMAP_SIZE(m) (ALIGN(((m)>>TARGET_PAGE_BITS), HOST_LONG_BITS) / 8)
+#endif
+
+#ifdef CONFIG_KVM
+#include "qemu-queue.h"
+
+extern int kvm_allowed;
+extern int kvm_irqchip;
+extern int kvm_pit;
+extern int kvm_pit_reinject;
+extern int kvm_nested;
+extern kvm_context_t kvm_context;
+
+struct ioperm_data {
+    unsigned long start_port;
+    unsigned long num;
+    int turn_on;
+    QLIST_ENTRY(ioperm_data) entries;
+};
+
+void qemu_kvm_cpu_stop(CPUState *env);
+int kvm_arch_halt(CPUState *env);
+int handle_tpr_access(void *opaque, CPUState *env, uint64_t rip,
+                      int is_write);
+int kvm_has_sync_mmu(void);
+
+#define kvm_enabled() (kvm_allowed)
+#define qemu_kvm_pit_in_kernel() kvm_pit_in_kernel(kvm_context)
+#define qemu_kvm_has_gsi_routing() kvm_has_gsi_routing(kvm_context)
+#ifdef TARGET_I386
+#define qemu_kvm_has_pit_state2() kvm_has_pit_state2(kvm_context)
+#endif
+void kvm_init_vcpu(CPUState *env);
+void kvm_load_tsc(CPUState *env);
+#else
+#define kvm_has_sync_mmu() (0)
+#define kvm_enabled() (0)
+#define kvm_nested 0
+#define qemu_kvm_pit_in_kernel() (0)
+#define qemu_kvm_has_gsi_routing() (0)
+#ifndef QEMU_KVM_NO_CPU
+#ifdef TARGET_I386
+#define qemu_kvm_has_pit_state2() (0)
+#endif
+#define kvm_load_registers(env) do {} while(0)
+#define kvm_save_registers(env) do {} while(0)
+#define kvm_save_mpstate(env)   do {} while(0)
+#define qemu_kvm_cpu_stop(env) do {} while(0)
+static inline void kvm_init_vcpu(CPUState *env)
+{
+}
+
+static inline void kvm_load_tsc(CPUState *env)
+{
+}
+#endif
+#endif
+
+void kvm_mutex_unlock(void);
+void kvm_mutex_lock(void);
+
+int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr);
+
+int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t len);
+int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t len);
+
+
+static inline int kvm_sync_vcpus(void)
+{
+    return 0;
+}
+
+#ifndef QEMU_KVM_NO_CPU
+void kvm_arch_get_registers(CPUState *env);
+
+static inline void kvm_arch_put_registers(CPUState *env)
+{
+    kvm_load_registers(env);
+}
+
+void kvm_cpu_synchronize_state(CPUState *env);
+
+static inline void cpu_synchronize_state(CPUState *env)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_state(env);
+    }
+}
+
+uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
+                                      int reg);
+
+
+#endif
+
+static inline int kvm_set_migration_log(int enable)
+{
+    return kvm_physical_memory_set_dirty_tracking(enable);
+}
+
+
+int kvm_irqchip_in_kernel(void);
+#ifdef CONFIG_KVM
+
+typedef struct KVMSlot {
+    target_phys_addr_t start_addr;
+    ram_addr_t memory_size;
+    ram_addr_t phys_offset;
+    int slot;
+    int flags;
+} KVMSlot;
+
+typedef struct kvm_dirty_log KVMDirtyLog;
+
+typedef struct KVMState {
+    KVMSlot slots[32];
+    int fd;
+    int vmfd;
+    int coalesced_mmio;
+    int broken_set_mem_region;
+    int migration_log;
+    int vcpu_events;
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
+#endif
+    int irqchip_in_kernel;
+
+    struct kvm_context kvm_context;
+} KVMState;
+
+extern KVMState *kvm_state;
+
+int kvm_ioctl(KVMState *s, int type, ...);
+int kvm_vm_ioctl(KVMState *s, int type, ...);
+int kvm_vcpu_ioctl(CPUState *env, int type, ...);
+int kvm_check_extension(KVMState *s, unsigned int ext);
+
+int kvm_tpr_enable_vapic(CPUState *env);
+
+#endif
+
+#endif
diff --git a/qemu-lock.h b/qemu-lock.h
index 9a3e6ac..bc8f91a 100644
--- a/qemu-lock.h
+++ b/qemu-lock.h
@@ -184,11 +184,11 @@
 
 #elif defined(__ia64)
 
-#include <ia64intrin.h>
+#include "ia64intrin.h"
 
 static inline int testandset (int *p)
 {
-    return __sync_lock_test_and_set (p, 1);
+    return (int)cmpxchg_acq(p,0,1);
 }
 #elif defined(__mips__)
 static inline int testandset (int *p)
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index 1aa7818..9e3ea3c 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -807,7 +807,7 @@
     {
         .name       = "pci_add",
         .args_type  = "pci_addr:s,type:s,opts:s?",
-        .params     = "auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...",
+        .params     = "auto|[[<domain>:]<bus>:]<slot> nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]",
         .help       = "hot-add PCI device",
         .user_print = pci_device_hot_add_print,
         .mhandler.cmd_new = pci_device_hot_add,
@@ -1062,6 +1062,19 @@
 Set the encrypted device @var{device} password to @var{password}
 ETEXI
 
+    {
+        .name       = "cpu_set",
+        .args_type  = "cpu:i,state:s",
+        .params     = "cpu [online|offline]",
+        .help       = "change cpu state",
+        .mhandler.cmd  = do_cpu_set_nr,
+    },
+
+STEXI
+@item cpu_set @var{cpu} [online|offline]
+Set CPU @var{cpu} online or offline.
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/qemu-options.hx b/qemu-options.hx
index b8cc375..812d067 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -104,6 +104,7 @@
     "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
     "       [,cache=writethrough|writeback|none][,format=f][,serial=s]\n"
     "       [,addr=A][,id=name][,aio=threads|native]\n"
+    "       [,boot=on|off]\n"
     "                use 'file' as a drive image\n")
 DEF("set", HAS_ARG, QEMU_OPTION_set,
     "-set group.id.arg=value\n"
@@ -1937,3 +1938,34 @@
 DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig,
     "-writeconfig <file>\n"
     "                read/write config file")
+
+DEF("no-kvm", 0, QEMU_OPTION_no_kvm,
+    "-no-kvm         disable KVM hardware virtualization\n")
+DEF("no-kvm-irqchip", 0, QEMU_OPTION_no_kvm_irqchip,
+    "-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC\n")
+DEF("no-kvm-pit", 0, QEMU_OPTION_no_kvm_pit,
+    "-no-kvm-pit     disable KVM kernel mode PIT\n")
+DEF("no-kvm-pit-reinjection", 0, QEMU_OPTION_no_kvm_pit_reinjection,
+    "-no-kvm-pit-reinjection disable KVM kernel mode PIT interrupt reinjection\n")
+#if defined(TARGET_I386) || defined(TARGET_X86_64) || defined(TARGET_IA64) || defined(__linux__)
+DEF("pcidevice", HAS_ARG, QEMU_OPTION_pcidevice,
+    "-pcidevice host=bus:dev.func[,dma=none][,name=string]\n"
+    "                expose a PCI device to the guest OS.\n"
+    "                dma=none: don't perform any dma translations (default is to use an iommu)\n"
+    "                'string' is used in log output.\n")
+#endif
+DEF("enable-nesting", 0, QEMU_OPTION_enable_nesting,
+    "-enable-nesting enable support for running a VM inside the VM (AMD only)\n")
+DEF("nvram", HAS_ARG, QEMU_OPTION_nvram,
+    "-nvram FILE          provide ia64 nvram contents\n")
+DEF("tdf", 0, QEMU_OPTION_tdf,
+    "-tdf                 enable guest time drift compensation\n")
+DEF("kvm-shadow-memory", HAS_ARG, QEMU_OPTION_kvm_shadow_memory,
+    "-kvm-shadow-memory MEGABYTES\n"
+    "                     allocate MEGABYTES for kvm mmu shadowing\n")
+DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath,
+    "-mem-path FILE       provide backing storage for guest RAM\n")
+#ifdef MAP_POPULATE
+DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc,
+    "-mem-prealloc        preallocate guest memory (use with -mempath)\n")
+#endif
diff --git a/qemu/pc-bios/extboot.bin b/qemu/pc-bios/extboot.bin
new file mode 100644
index 0000000..e1ffe96
--- /dev/null
+++ b/qemu/pc-bios/extboot.bin
Binary files differ
diff --git a/savevm.c b/savevm.c
index aefe052..3992dfd 100644
--- a/savevm.c
+++ b/savevm.c
@@ -872,6 +872,29 @@
     .put  = put_uint64,
 };
 
+/* 64 bit linux kernel unsigned int */
+
+#ifdef __linux__
+static int get_u64(QEMUFile *f, void *pv, size_t size)
+{
+    uint64_t *v = pv;
+    qemu_get_be64s(f, v);
+    return 0;
+}
+
+static void put_u64(QEMUFile *f, void *pv, size_t size)
+{
+    uint64_t *v = pv;
+    qemu_put_be64s(f, v);
+}
+
+const VMStateInfo vmstate_info_u64 = {
+    .name = "__u64",
+    .get  = get_u64,
+    .put  = put_u64,
+};
+#endif /* __linux__ */
+
 /* 8 bit int. See that the received value is the same than the one
    in the field */
 
diff --git a/sysemu.h b/sysemu.h
index 9d80bb2..a545a2b 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -47,6 +47,7 @@
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
+int qemu_no_shutdown(void);
 int qemu_shutdown_requested(void);
 int qemu_reset_requested(void);
 int qemu_powerdown_requested(void);
@@ -141,6 +142,7 @@
 extern int old_param;
 extern int boot_menu;
 extern QEMUClock *rtc_clock;
+extern long hpagesize;
 
 #define MAX_NODES 64
 extern int nb_numa_nodes;
@@ -192,6 +194,7 @@
 
 extern QTAILQ_HEAD(drivelist, DriveInfo) drives;
 extern QTAILQ_HEAD(driveoptlist, DriveOpt) driveopts;
+extern DriveInfo *extboot_drive;
 
 extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
 extern DriveInfo *drive_get_by_id(const char *id);
@@ -207,6 +210,9 @@
 extern QemuOpts *drive_add(const char *file, const char *fmt, ...);
 extern DriveInfo *drive_init(QemuOpts *arg, void *machine, int *fatal_error);
 
+/* acpi */
+void qemu_system_cpu_hot_add(int cpu, int state);
+
 /* device-hotplug */
 
 DriveInfo *add_init_drive(const char *opts);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index f3834b3..0df6f1d 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -250,16 +250,32 @@
 #define PG_ERROR_RSVD_MASK 0x08
 #define PG_ERROR_I_D_MASK  0x10
 
-#define MCG_CTL_P	(1UL<<8)   /* MCG_CAP register available */
+#define MCG_CTL_P	(1ULL<<8)   /* MCG_CAP register available */
+#define MCG_SER_P	(1ULL<<24) /* MCA recovery/new status bits */
 
-#define MCE_CAP_DEF	MCG_CTL_P
+#define MCE_CAP_DEF	(MCG_CTL_P|MCG_SER_P)
 #define MCE_BANKS_DEF	10
 
+#define MCG_STATUS_RIPV	(1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV	(1ULL<<1)   /* ip points to correct instruction */
 #define MCG_STATUS_MCIP	(1ULL<<2)   /* machine check in progress */
 
 #define MCI_STATUS_VAL	(1ULL<<63)  /* valid error */
 #define MCI_STATUS_OVER	(1ULL<<62)  /* previous errors lost */
 #define MCI_STATUS_UC	(1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN	(1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC	(1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S	(1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR	(1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF	0	/* segment offset */
+#define MCM_ADDR_LINEAR	1	/* linear address */
+#define MCM_ADDR_PHYS	2	/* physical address */
+#define MCM_ADDR_MEM	3	/* memory address */
+#define MCM_ADDR_GENERIC 7	/* generic */
 
 #define MSR_IA32_TSC                    0x10
 #define MSR_IA32_APICBASE               0x1b
@@ -717,6 +733,8 @@
     uint16_t fpus_vmstate;
     uint16_t fptag_vmstate;
     uint16_t fpregs_format_vmstate;
+
+    int update_vapic;
 } CPUX86State;
 
 CPUX86State *cpu_x86_init(const char *cpu_model);
@@ -877,7 +895,7 @@
 #define cpu_signal_handler cpu_x86_signal_handler
 #define cpu_list x86_cpu_list
 
-#define CPU_SAVE_VERSION 11
+#define CPU_SAVE_VERSION 12
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-i386/fake-exec.c b/target-i386/fake-exec.c
new file mode 100644
index 0000000..dfa202d
--- /dev/null
+++ b/target-i386/fake-exec.c
@@ -0,0 +1,50 @@
+/*
+ * fake-exec.c
+ *
+ * This is a file for stub functions so that compilation is possible
+ * when TCG CPU emulation is disabled during compilation.
+ *
+ * Copyright 2007 IBM Corporation.
+ * Added by & Authors:
+ * 	Jerone Young <jyoung5@us.ibm.com>
+ * This work is licensed under the GNU GPL licence version 2 or later.
+ *
+ */
+#include "exec.h"
+#include "cpu.h"
+
+int code_copy_enabled = 0;
+
+CCTable cc_table[CC_OP_NB];
+
+void cpu_dump_statistics (CPUState *env, FILE*f,
+                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                          int flags)
+{
+}
+
+unsigned long code_gen_max_block_size(void)
+{
+    return 32;
+}
+
+void cpu_gen_init(void)
+{
+}
+
+int cpu_restore_state(TranslationBlock *tb,
+                      CPUState *env, unsigned long searched_pc,
+                      void *puc)
+
+{
+    return 0;
+}
+
+int cpu_x86_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
+{
+    return 0;
+}
+
+void optimize_flags_init(void)
+{
+}
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 730e396..b58fd82 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -28,6 +28,8 @@
 #include "qemu-common.h"
 #include "kvm.h"
 
+#include "qemu-kvm.h"
+
 //#define DEBUG_MMU
 
 /* feature flags taken from "Intel Processor Identification and the CPUID
@@ -42,7 +44,7 @@
 static const char *ext_feature_name[] = {
     "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
     "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
-    NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
+    NULL, NULL, "dca", NULL, NULL, "x2apic", NULL, "popcnt",
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor",
 };
 static const char *ext2_feature_name[] = {
@@ -516,7 +518,7 @@
         env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2;
         env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
     }
-    env->cpuid_vendor_override = def->vendor_override;
+    env->cpuid_vendor_override = def->vendor_override || kvm_enabled();
     env->cpuid_level = def->level;
     if (def->family > 0x0f)
         env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20);
@@ -1546,6 +1548,11 @@
     unsigned bank_num = mcg_cap & 0xff;
     uint64_t *banks = cenv->mce_banks;
 
+    if (kvm_enabled()) {
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0);
+        return;
+    }
+
     if (bank >= bank_num || !(status & MCI_STATUS_VAL))
         return;
 
@@ -1609,7 +1616,7 @@
                        uint32_t *eax, uint32_t *ebx,
                        uint32_t *ecx, uint32_t *edx)
 {
-#if defined(CONFIG_KVM)
+#if defined(CONFIG_KVM) || defined(USE_KVM)
     uint32_t vec[4];
 
 #ifdef __x86_64__
@@ -1785,8 +1792,32 @@
         }
 
         if (kvm_enabled()) {
-            /* Nested SVM not yet supported in upstream QEMU */
-            *ecx &= ~CPUID_EXT3_SVM;
+            uint32_t h_eax, h_edx;
+
+            host_cpuid(index, 0, &h_eax, NULL, NULL, &h_edx);
+
+            /* disable CPU features that the host does not support */
+
+            /* long mode */
+            if ((h_edx & 0x20000000) == 0 /* || !lm_capable_kernel */)
+                *edx &= ~0x20000000;
+            /* syscall */
+            if ((h_edx & 0x00000800) == 0)
+                *edx &= ~0x00000800;
+            /* nx */
+            if ((h_edx & 0x00100000) == 0)
+                *edx &= ~0x00100000;
+
+            /* disable CPU features that KVM cannot support */
+
+            /* svm */
+            if (!kvm_nested)
+                *ecx &= ~CPUID_EXT3_SVM;
+            /* 3dnow */
+            *edx &= ~0xc0000000;
+        } else {
+            /* AMD 3DNow! is not supported in QEMU */
+            *edx &= ~(CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT);
         }
         break;
     case 0x80000002:
@@ -1901,8 +1932,6 @@
     }
     mce_init(env);
 
-    qemu_init_vcpu(env);
-
     return env;
 }
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index de79eb7..8584507 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -25,6 +25,7 @@
 #include "gdbstub.h"
 #include "host-utils.h"
 
+#ifdef KVM_UPSTREAM
 //#define DEBUG_KVM
 
 #ifdef DEBUG_KVM
@@ -490,6 +491,7 @@
     if (kvm_has_msr_star(env))
 	kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
+    kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
 #ifdef TARGET_X86_64
     /* FIXME if lm capable */
     kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
@@ -633,6 +635,7 @@
     if (kvm_has_msr_star(env))
 	msrs[n++].index = MSR_STAR;
     msrs[n++].index = MSR_IA32_TSC;
+    msrs[n++].index = MSR_VM_HSAVE_PA;
 #ifdef TARGET_X86_64
     /* FIXME lm_capable_kernel */
     msrs[n++].index = MSR_CSTAR;
@@ -685,6 +688,9 @@
         case MSR_KVM_WALL_CLOCK:
             env->wall_clock_msr = msrs[i].data;
             break;
+        case MSR_VM_HSAVE_PA:
+            env->vm_hsave = msrs[i].data;
+            break;
         }
     }
 
@@ -873,6 +879,7 @@
 
     return 0;
 }
+#endif
 
 int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
@@ -887,6 +894,7 @@
     return 0;
 }
 
+#ifdef KVM_UPSTREAM
 static int kvm_handle_halt(CPUState *env)
 {
     if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -1084,3 +1092,6 @@
     }
 }
 #endif /* KVM_CAP_SET_GUEST_DEBUG */
+#endif
+
+#include "qemu-kvm-x86.c"
diff --git a/target-i386/libkvm.h b/target-i386/libkvm.h
new file mode 100644
index 0000000..d85b6a1
--- /dev/null
+++ b/target-i386/libkvm.h
@@ -0,0 +1,28 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for x86.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * derived from libkvm.c
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_X86_H
+#define KVM_X86_H
+
+#define PAGE_SIZE 4096ul
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr);
+
+#define smp_wmb()   asm volatile("" ::: "memory")
+
+#endif
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 8770491..47ca6e8 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -5,6 +5,7 @@
 
 #include "exec-all.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 static const VMStateDescription vmstate_segment = {
     .name = "segment",
@@ -322,6 +323,7 @@
     int i;
 
     cpu_synchronize_state(env);
+    kvm_save_mpstate(env);
 
     /* FPU */
     env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
@@ -364,6 +366,16 @@
         hw_breakpoint_insert(env, i);
 
     tlb_flush(env, 1);
+
+    if (kvm_enabled()) {
+        /* when in-kernel irqchip is used, env->halted causes deadlock
+           because no userspace IRQs will ever clear this flag */
+        env->halted = 0;
+
+        kvm_load_tsc(env);
+        kvm_load_mpstate(env);
+    }
+
     return 0;
 }
 
diff --git a/target-ia64/cpu.h b/target-ia64/cpu.h
new file mode 100644
index 0000000..fb51463
--- /dev/null
+++ b/target-ia64/cpu.h
@@ -0,0 +1,85 @@
+/*
+ * IA64 virtual CPU header
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  Copyright (c) 2007 Intel Corporation
+ *  Zhang xiantao <xiantao.zhang@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef CPU_IA64_H
+#define CPU_IA64_H
+#include "config.h"
+#include "ia64intrin.h"
+
+#include<string.h>
+
+#define TARGET_LONG_BITS 64
+
+#define TARGET_PAGE_BITS 16
+
+#define ELF_MACHINE	EM_IA_64
+
+#define NB_MMU_MODES 2
+#define CPU_PAL_HALT 1
+#define HF_HALTED_MASK       (1 << CPU_PAL_HALT)
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define CPUState struct CPUIA64State
+
+typedef struct CPUIA64State {
+    CPU_COMMON;
+    uint32_t hflags;
+    int mp_state;
+} CPUIA64State;
+
+#define cpu_gen_code cpu_ia64_gen_code
+#define cpu_init cpu_ia64_init
+#define cpu_signal_handler cpu_ia64_signal_handler
+
+extern struct CPUIA64State *env;
+int cpu_get_pic_interrupt(CPUIA64State *s);
+int cpu_exec(CPUState *env1);
+CPUState *cpu_ia64_init(const char * cpu_model);
+
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return 0;
+}
+
+#define CPU_PC_FROM_TB(env, tb) do{}while(0)
+
+#include "cpu-all.h"
+
+/*
+ * These ones really should go to the appropriate tcg header file, if/when
+ * tcg support is added for ia64.
+ */
+void tcg_dump_info(FILE *f,
+                   int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = 0;
+    *cs_base = 0;
+    *flags = 0;
+}
+
+#endif
diff --git a/target-ia64/exec.h b/target-ia64/exec.h
new file mode 100644
index 0000000..060d9c3
--- /dev/null
+++ b/target-ia64/exec.h
@@ -0,0 +1,61 @@
+/*
+ *  IA64 execution defines
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *  Copyright (c) 2007 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __IA64_H__
+#define __IA64_H__
+
+//#include "dyngen-exec.h"
+#include "config.h"
+
+#include "dyngen-exec.h"
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#define tcg_qemu_tb_exec(tb_ptr) 0
+
+register struct CPUIA64State *env asm(AREG0);
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+void do_interrupt (CPUState *env);
+
+void cpu_lock(void);
+void cpu_unlock(void);
+
+static inline int cpu_halted(CPUState *env) {
+    /* handle exit of HALTED state */
+    if (!(env->hflags & HF_HALTED_MASK))
+        return 0;
+    return EXCP_HALTED;
+}
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return (env->interrupt_request & (CPU_INTERRUPT_HARD));
+}
+
+#endif
diff --git a/target-ia64/fake-exec.c b/target-ia64/fake-exec.c
new file mode 100644
index 0000000..8d6ded0
--- /dev/null
+++ b/target-ia64/fake-exec.c
@@ -0,0 +1,50 @@
+/*
+ * fake-exec.c for ia64.
+ *
+ * This is a file for stub functions so that compilation is possible
+ * when TCG CPU emulation is disabled during compilation.
+ *
+ * Copyright 2007 IBM Corporation.
+ * Added by & Authors:
+ * 	Jerone Young <jyoung5@us.ibm.com>
+ *
+ * Copyright 2008 Intel Corporation.
+ * Added by Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This work is licensed under the GNU GPL licence version 2 or later.
+ *
+ */
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+int code_copy_enabled = 0;
+
+void cpu_gen_init(void)
+{
+}
+
+unsigned long code_gen_max_block_size(void)
+{
+    return 32;
+}
+
+int cpu_ia64_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
+{
+    return 0;
+}
+
+void tcg_dump_info(FILE *f,
+                   int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+    return;
+}
+
+int cpu_restore_state(TranslationBlock *tb,
+                      CPUState *env, unsigned long searched_pc,
+                      void *puc)
+
+{
+    return 0;
+}
diff --git a/target-ia64/firmware.c b/target-ia64/firmware.c
new file mode 100644
index 0000000..79f8464
--- /dev/null
+++ b/target-ia64/firmware.c
@@ -0,0 +1,715 @@
+/*
+ * firmware.c : Firmware build logic for ia64 platform.
+ *
+ * Ported from Xen 3.0 Source.
+ * Copyright (c) 2007, Intel Corporation.
+ * Zhang Xiantao <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <zlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "cpu.h"
+
+#include "firmware.h"
+
+#include "qemu-common.h"
+
+typedef struct {
+    unsigned long signature;
+    unsigned int  type;
+    unsigned int  length;
+} HOB_GENERIC_HEADER;
+
+/*
+ * INFO HOB is the first data data in one HOB list
+ * it contains the control information of the HOB list
+ */
+typedef struct {
+    HOB_GENERIC_HEADER  header;
+    unsigned long       length;    // current length of hob
+    unsigned long       cur_pos;   // current poisiton of hob
+    unsigned long       buf_size;  // size of hob buffer
+} HOB_INFO;
+
+typedef struct{
+    unsigned long start;
+    unsigned long size;
+} hob_mem_t;
+
+typedef enum {
+    HOB_TYPE_INFO=0,
+    HOB_TYPE_TERMINAL,
+    HOB_TYPE_MEM,
+    HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
+    HOB_TYPE_PAL_CACHE_SUMMARY,
+    HOB_TYPE_PAL_MEM_ATTRIB,
+    HOB_TYPE_PAL_CACHE_INFO,
+    HOB_TYPE_PAL_CACHE_PROT_INFO,
+    HOB_TYPE_PAL_DEBUG_INFO,
+    HOB_TYPE_PAL_FIXED_ADDR,
+    HOB_TYPE_PAL_FREQ_BASE,
+    HOB_TYPE_PAL_FREQ_RATIOS,
+    HOB_TYPE_PAL_HALT_INFO,
+    HOB_TYPE_PAL_PERF_MON_INFO,
+    HOB_TYPE_PAL_PROC_GET_FEATURES,
+    HOB_TYPE_PAL_PTCE_INFO,
+    HOB_TYPE_PAL_REGISTER_INFO,
+    HOB_TYPE_PAL_RSE_INFO,
+    HOB_TYPE_PAL_TEST_INFO,
+    HOB_TYPE_PAL_VM_SUMMARY,
+    HOB_TYPE_PAL_VM_INFO,
+    HOB_TYPE_PAL_VM_PAGE_SIZE,
+    HOB_TYPE_NR_VCPU,
+    HOB_TYPE_NR_NVRAM,
+    HOB_TYPE_MAX
+} hob_type_t;
+
+static int hob_init(void  *buffer ,unsigned long buf_size);
+static int add_pal_hob(void* hob_buf);
+static int add_mem_hob(void* hob_buf, unsigned long dom_mem_size);
+static int add_vcpus_hob(void* hob_buf, unsigned long nr_vcpu);
+static int add_nvram_hob(void *hob_buf, unsigned long nvram_addr);
+static int build_hob(void *hob_buf, unsigned long hob_buf_size,
+                     unsigned long dom_mem_size, unsigned long vcpus,
+                     unsigned long nvram_addr);
+static int load_hob(void *hob_buf, unsigned long dom_mem_size);
+
+int
+kvm_ia64_build_hob(unsigned long memsize, unsigned long vcpus,
+                   unsigned long nvram_addr)
+{
+    char   *hob_buf;
+
+    hob_buf = malloc(GFW_HOB_SIZE);
+    if (hob_buf == NULL) {
+        Hob_Output("Hob: Could not allocate hob");
+        return -1;
+    }
+
+    if (build_hob(hob_buf, GFW_HOB_SIZE, memsize, vcpus, nvram_addr) < 0) {
+        free(hob_buf);
+        Hob_Output("Could not build hob");
+        return -1;
+    }
+
+    if (load_hob(hob_buf, memsize) < 0) {
+        free(hob_buf);
+        Hob_Output("Could not load hob");
+        return -1;
+    }
+    free(hob_buf);
+
+    return 0;
+}
+
+static int
+hob_init(void *buffer, unsigned long buf_size)
+{
+    HOB_INFO *phit;
+    HOB_GENERIC_HEADER *terminal;
+
+    if (sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER) > buf_size) {
+        // buffer too small
+        return -1;
+    }
+
+    phit = (HOB_INFO*)buffer;
+    phit->header.signature = HOB_SIGNATURE;
+    phit->header.type = HOB_TYPE_INFO;
+    phit->header.length = sizeof(HOB_INFO);
+    phit->length = sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER);
+    phit->cur_pos = 0;
+    phit->buf_size = buf_size;
+
+    terminal = (HOB_GENERIC_HEADER*)(buffer + sizeof(HOB_INFO));
+    terminal->signature = HOB_SIGNATURE;
+    terminal->type = HOB_TYPE_TERMINAL;
+    terminal->length = sizeof(HOB_GENERIC_HEADER);
+
+    return 0;
+}
+
+/*
+ *  Add a new HOB to the HOB List.
+ *
+ *  hob_start  -  start address of hob buffer
+ *  type       -  type of the hob to be added
+ *  data       -  data of the hob to be added
+ *  data_size  -  size of the data
+ */
+static int
+hob_add(void* hob_start, int type, void* data, int data_size)
+{
+    HOB_INFO *phit;
+    HOB_GENERIC_HEADER *newhob, *tail;
+
+    phit = (HOB_INFO*)hob_start;
+
+    if (phit->length + data_size > phit->buf_size) {
+        // no space for new hob
+        return -1;
+    }
+
+    //append new HOB
+    newhob = (HOB_GENERIC_HEADER*)(hob_start + phit->length -
+                                   sizeof(HOB_GENERIC_HEADER));
+    newhob->signature = HOB_SIGNATURE;
+    newhob->type = type;
+    newhob->length = data_size + sizeof(HOB_GENERIC_HEADER);
+    memcpy((void*)newhob + sizeof(HOB_GENERIC_HEADER), data, data_size);
+
+    // append terminal HOB
+    tail = (HOB_GENERIC_HEADER*)(hob_start + phit->length + data_size);
+    tail->signature = HOB_SIGNATURE;
+    tail->type = HOB_TYPE_TERMINAL;
+    tail->length = sizeof(HOB_GENERIC_HEADER);
+
+    // adjust HOB list length
+    phit->length += sizeof(HOB_GENERIC_HEADER) + data_size;
+
+    return 0;
+}
+
+static int
+get_hob_size(void* hob_buf)
+{
+    HOB_INFO *phit = (HOB_INFO*)hob_buf;
+
+    if (phit->header.signature != HOB_SIGNATURE) {
+        Hob_Output("xc_get_hob_size:Incorrect signature");
+        return -1;
+    }
+    return phit->length;
+}
+
+static  int
+add_max_hob_entry(void* hob_buf)
+{
+    long max_hob = 0;
+    return hob_add(hob_buf, HOB_TYPE_MAX, &max_hob, sizeof(long));
+}
+
+static int
+build_hob(void* hob_buf, unsigned long hob_buf_size,
+          unsigned long dom_mem_size, unsigned long vcpus,
+          unsigned long nvram_addr)
+{
+    //Init HOB List
+    if (hob_init(hob_buf, hob_buf_size) < 0) {
+        Hob_Output("buffer too small");
+        goto err_out;
+    }
+
+    if (add_mem_hob(hob_buf,dom_mem_size) < 0) {
+        Hob_Output("Add memory hob failed, buffer too small");
+        goto err_out;
+    }
+
+    if (add_vcpus_hob(hob_buf, vcpus) < 0) {
+        Hob_Output("Add NR_VCPU hob failed, buffer too small");
+        goto err_out;
+    }
+
+    if (add_pal_hob(hob_buf) < 0) {
+        Hob_Output("Add PAL hob failed, buffer too small");
+        goto err_out;
+    }
+
+    if (add_nvram_hob(hob_buf, nvram_addr) < 0) {
+	    Hob_Output("Add nvram hob failed, buffer too small");
+	    goto err_out;
+	}
+
+    if (add_max_hob_entry(hob_buf) < 0) {
+        Hob_Output("Add max hob entry failed, buffer too small");
+        goto err_out;
+    }
+    return 0;
+
+err_out:
+    return -1;
+}
+static int
+load_hob(void *hob_buf, unsigned long dom_mem_size)
+{
+    int hob_size;
+
+    hob_size = get_hob_size(hob_buf);
+    if (hob_size < 0) {
+        Hob_Output("Invalid hob data");
+        return -1;
+    }
+
+    if (hob_size > GFW_HOB_SIZE) {
+        Hob_Output("No enough memory for hob data");
+        return -1;
+    }
+
+    cpu_physical_memory_write(GFW_HOB_START, hob_buf, hob_size);
+
+    return 0;
+}
+
+static int
+add_mem_hob(void* hob_buf, unsigned long dom_mem_size)
+{
+    hob_mem_t memhob;
+
+    // less than 3G
+    memhob.start = 0;
+    memhob.size = MIN(dom_mem_size, 0xC0000000);
+
+    if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
+        return -1;
+
+    if (dom_mem_size > 0xC0000000) {
+        // 4G ~ 4G+remain
+        memhob.start = 0x100000000; //4G
+        memhob.size = dom_mem_size - 0xC0000000;
+        if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
+            return -1;
+    }
+    return 0;
+}
+
+static int
+add_vcpus_hob(void* hob_buf, unsigned long vcpus)
+{
+    return hob_add(hob_buf, HOB_TYPE_NR_VCPU, &vcpus, sizeof(vcpus));
+}
+
+static int
+add_nvram_hob(void *hob_buf, unsigned long nvram_addr)
+{
+    return hob_add(hob_buf, HOB_TYPE_NR_NVRAM,
+                   &nvram_addr, sizeof(nvram_addr));
+}
+
+static const unsigned char config_pal_bus_get_features_data[24] = {
+    0, 0, 0, 32, 0, 0, 240, 189, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_cache_summary[16] = {
+    3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_mem_attrib[8] = {
+    241, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_cache_info[152] = {
+    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    6, 4, 6, 7, 255, 1, 0, 1, 0, 64, 0, 0, 12, 12,
+    49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 7, 0, 1,
+    0, 1, 0, 64, 0, 0, 12, 12, 49, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 6, 8, 7, 7, 255, 7, 0, 11, 0, 0, 16, 0,
+    12, 17, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
+    7, 7, 5, 9, 11, 0, 0, 4, 0, 12, 15, 49, 0, 254, 255,
+    255, 255, 255, 255, 255, 255, 2, 8, 7, 7, 7, 5, 9,
+    11, 0, 0, 4, 0, 12, 15, 49, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 3, 12, 7, 7, 7, 14, 1, 3, 0, 0, 192, 0, 12, 20, 49, 0
+};
+
+static const unsigned char config_pal_cache_prot_info[200] = {
+    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    45, 0, 16, 8, 0, 76, 12, 64, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    8, 0, 16, 4, 0, 76, 44, 68, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,
+    0, 16, 8, 0, 81, 44, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0,
+    112, 12, 0, 79, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255,
+    32, 0, 112, 12, 0, 79, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 160,
+    12, 0, 84, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0
+};
+
+static const unsigned char config_pal_debug_info[16] = {
+    2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_fixed_addr[8] = {
+    0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_freq_base[8] = {
+    109, 219, 182, 13, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_freq_ratios[24] = {
+    11, 1, 0, 0, 77, 7, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 4,
+    0, 0, 0, 7, 0, 0, 0
+};
+
+static const unsigned char config_pal_halt_info[64] = {
+    0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_perf_mon_info[136] = {
+    12, 47, 18, 8, 0, 0, 0, 0, 241, 255, 0, 0, 255, 7, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 0, 0, 223, 0, 255, 255,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_proc_get_features[104] = {
+    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 64, 6, 64, 49, 0, 0, 0, 0, 64, 6, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
+    231, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0,
+    63, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_ptce_info[24] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_register_info[64] = {
+    255, 0, 47, 127, 17, 17, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+    255, 208, 128, 238, 238, 0, 0, 248, 255, 255, 255, 255, 255, 0, 0, 7, 3,
+    251, 3, 0, 0, 0, 0, 255, 7, 3, 0, 0, 0, 0, 0, 248, 252, 4,
+    252, 255, 255, 255, 255, 2, 248, 252, 255, 255, 255, 255, 255
+};
+
+static const unsigned char config_pal_rse_info[16] = {
+    96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_test_info[48] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_vm_summary[16] = {
+    101, 18, 15, 2, 7, 7, 4, 2, 59, 18, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_vm_info[104] = {
+    2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+    32, 32, 0, 0, 0, 0, 0, 0, 112, 85, 21, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 1, 32, 32, 0, 0, 0, 0, 0, 0, 112, 85,
+    21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 128, 128, 0,
+    4, 0, 0, 0, 0, 112, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 1, 128, 128, 0, 4, 0, 0, 0, 0, 112, 85, 0, 0, 0, 0, 0
+};
+
+static const unsigned char config_pal_vm_page_size[16] = {
+    0, 112, 85, 21, 0, 0, 0, 0, 0, 112, 85, 21, 0, 0, 0, 0
+};
+
+typedef struct{
+    hob_type_t type;
+    void* data;
+    unsigned long size;
+} hob_batch_t;
+
+static const hob_batch_t hob_batch[]={
+    {   HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
+        &config_pal_bus_get_features_data,
+        sizeof(config_pal_bus_get_features_data)
+    },
+    {   HOB_TYPE_PAL_CACHE_SUMMARY,
+        &config_pal_cache_summary,
+        sizeof(config_pal_cache_summary)
+    },
+    {   HOB_TYPE_PAL_MEM_ATTRIB,
+        &config_pal_mem_attrib,
+        sizeof(config_pal_mem_attrib)
+    },
+    {   HOB_TYPE_PAL_CACHE_INFO,
+        &config_pal_cache_info,
+        sizeof(config_pal_cache_info)
+    },
+    {   HOB_TYPE_PAL_CACHE_PROT_INFO,
+        &config_pal_cache_prot_info,
+        sizeof(config_pal_cache_prot_info)
+    },
+    {   HOB_TYPE_PAL_DEBUG_INFO,
+        &config_pal_debug_info,
+        sizeof(config_pal_debug_info)
+    },
+    {   HOB_TYPE_PAL_FIXED_ADDR,
+        &config_pal_fixed_addr,
+        sizeof(config_pal_fixed_addr)
+    },
+    {   HOB_TYPE_PAL_FREQ_BASE,
+        &config_pal_freq_base,
+        sizeof(config_pal_freq_base)
+    },
+    {   HOB_TYPE_PAL_FREQ_RATIOS,
+        &config_pal_freq_ratios,
+        sizeof(config_pal_freq_ratios)
+    },
+    {   HOB_TYPE_PAL_HALT_INFO,
+        &config_pal_halt_info,
+        sizeof(config_pal_halt_info)
+    },
+    {   HOB_TYPE_PAL_PERF_MON_INFO,
+        &config_pal_perf_mon_info,
+        sizeof(config_pal_perf_mon_info)
+    },
+    {   HOB_TYPE_PAL_PROC_GET_FEATURES,
+        &config_pal_proc_get_features,
+        sizeof(config_pal_proc_get_features)
+    },
+    {   HOB_TYPE_PAL_PTCE_INFO,
+        &config_pal_ptce_info,
+        sizeof(config_pal_ptce_info)
+    },
+    {   HOB_TYPE_PAL_REGISTER_INFO,
+        &config_pal_register_info,
+        sizeof(config_pal_register_info)
+    },
+    {   HOB_TYPE_PAL_RSE_INFO,
+        &config_pal_rse_info,
+        sizeof(config_pal_rse_info)
+    },
+    {   HOB_TYPE_PAL_TEST_INFO,
+        &config_pal_test_info,
+        sizeof(config_pal_test_info)
+    },
+    {   HOB_TYPE_PAL_VM_SUMMARY,
+        &config_pal_vm_summary,
+        sizeof(config_pal_vm_summary)
+    },
+    {   HOB_TYPE_PAL_VM_INFO,
+        &config_pal_vm_info,
+        sizeof(config_pal_vm_info)
+    },
+    {   HOB_TYPE_PAL_VM_PAGE_SIZE,
+        &config_pal_vm_page_size,
+        sizeof(config_pal_vm_page_size)
+    },
+};
+
+static int
+add_pal_hob(void* hob_buf)
+{
+    int i;
+    for (i = 0; i < sizeof(hob_batch)/sizeof(hob_batch_t); i++) {
+        if (hob_add(hob_buf, hob_batch[i].type, hob_batch[i].data,
+                    hob_batch[i].size) < 0)
+            return -1;
+    }
+    return 0;
+}
+
+uint8_t *read_image(const char *filename, unsigned long *size)
+{
+    int kernel_fd = -1;
+    gzFile kernel_gfd = NULL;
+    uint8_t *image = NULL, *tmp;
+    unsigned int bytes;
+
+    if ((filename == NULL) || (size == NULL))
+        return NULL;
+
+    kernel_fd = open(filename, O_RDONLY);
+    if (kernel_fd < 0) {
+        Hob_Output("Could not open kernel image\n");
+        goto out_1;
+    }
+
+    if ((kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL) {
+        Hob_Output("Could not allocate decompression state for state file\n");
+        goto out_1;
+    }
+
+    *size = 0;
+
+#define CHUNK 1*1024*1024
+    while(1)
+    {
+        if ((tmp = realloc(image, *size + CHUNK)) == NULL) {
+            Hob_Output("Could not allocate memory for kernel image");
+            free(image);
+            image = NULL;
+            goto out;
+        }
+        image = tmp;
+
+        bytes = gzread(kernel_gfd, image + *size, CHUNK);
+        switch (bytes) {
+        case -1:
+            Hob_Output("Error reading kernel image");
+            free(image);
+            image = NULL;
+            goto out;
+        case 0: /* EOF */
+            goto out;
+        default:
+            *size += bytes;
+            break;
+        }
+    }
+#undef CHUNK
+
+out:
+    if (*size == 0) {
+        Hob_Output("Could not read kernel image");
+        free(image);
+        image = NULL;
+    } else if (image) {
+        /* Shrink allocation to fit image. */
+        tmp = realloc(image, *size);
+        if (tmp)
+            image = tmp;
+    }
+
+    if (kernel_gfd != NULL)
+        gzclose(kernel_gfd);
+    else if (kernel_fd >= 0)
+        close(kernel_fd);
+    return image;
+
+out_1:
+    return NULL;
+}
+
+int kvm_ia64_nvram_init(unsigned long type)
+{
+    unsigned long nvram_fd;
+    char nvram_path[PATH_MAX];
+    unsigned long i;
+
+    if (nvram) {
+        if (strlen(nvram) > PATH_MAX) {
+            goto out;
+        }
+        if (type == READ_FROM_NVRAM) {
+            if (access(nvram, R_OK | W_OK | X_OK) == -1)
+                goto out;
+            nvram_fd = open(nvram, O_RDONLY);
+            return nvram_fd;
+        }
+        else { /* write from gfw to nvram file */
+            i = access(nvram, R_OK | W_OK | X_OK);
+            if ((i == -1) && (errno != ENOENT))
+               goto out;
+            nvram_fd = open(nvram, O_CREAT|O_RDWR, 0777);
+            return nvram_fd;
+        }
+    }
+    else {
+        strcpy(nvram_path, "nvram.dat");
+        if (type == READ_FROM_NVRAM) {
+            if (access(nvram_path, R_OK | W_OK | X_OK) == -1)
+                goto out;
+            nvram_fd = open(nvram_path, O_RDONLY);
+            return nvram_fd;
+        }
+        else { /* write from gfw to nvram file */
+            i = access(nvram_path, R_OK | W_OK | X_OK);
+            if ((i == -1) && (errno != ENOENT))
+               goto out;
+            nvram_fd = open(nvram_path, O_CREAT|O_RDWR, 0777);
+            return nvram_fd;
+        }
+    }
+out:
+    return -1;
+}
+
+int
+kvm_ia64_copy_from_nvram_to_GFW(unsigned long nvram_fd)
+{
+    struct stat file_stat;
+    uint8_t *nvram_buf;
+    int r = 0;
+
+    nvram_buf = malloc(NVRAM_SIZE);
+
+    if ((fstat(nvram_fd, &file_stat) < 0) ||
+        (NVRAM_SIZE  != file_stat.st_size) ||
+        (read(nvram_fd, nvram_buf, NVRAM_SIZE) != NVRAM_SIZE)) {
+        r = -1;
+        goto out;
+    }
+
+    cpu_physical_memory_write(NVRAM_START, nvram_buf, NVRAM_SIZE);
+
+ out:
+    free(nvram_buf);
+    return r;
+}
+
+int
+kvm_ia64_copy_from_GFW_to_nvram()
+{
+    struct nvram_save_addr nvram_addr_buf;
+    uint8_t *nvram_buf;
+    unsigned long nvram_fd;
+    unsigned long type = WRITE_TO_NVRAM;
+    int ret = -1;
+
+    nvram_buf = malloc(NVRAM_SIZE);
+    if (!nvram_buf)
+        goto out_free;
+
+    cpu_physical_memory_read(NVRAM_START, (uint8_t *)&nvram_addr_buf,
+                             sizeof(struct nvram_save_addr));
+    if (nvram_addr_buf.signature != NVRAM_VALID_SIG) {
+        goto out_free;
+    }
+
+    cpu_physical_memory_read(nvram_addr_buf.addr, nvram_buf, NVRAM_SIZE);
+
+    nvram_fd = kvm_ia64_nvram_init(type);
+    if (nvram_fd  == -1)
+        goto out;
+
+    lseek(nvram_fd, 0, SEEK_SET);
+    if (write(nvram_fd, nvram_buf, NVRAM_SIZE) != NVRAM_SIZE)
+        goto out;
+
+    ret = 0;
+ out:
+    close(nvram_fd);
+ out_free:
+    free(nvram_buf);
+    return ret;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/target-ia64/firmware.h b/target-ia64/firmware.h
new file mode 100644
index 0000000..a47db67
--- /dev/null
+++ b/target-ia64/firmware.h
@@ -0,0 +1,62 @@
+/*
+ * firmwar.h: Firmware build logic head file
+ *
+ * Copyright (c) 2007, Intel Corporation.
+ * Zhang Xiantao <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __FIRM_WARE_H
+#define  __FIRM_WARE_
+#include "cpu.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <zlib.h>
+
+#define GFW_SIZE                (16UL<<20)
+#define GFW_START               ((4UL<<30) - GFW_SIZE)
+
+#define HOB_SIGNATURE           0x3436474953424f48        // "HOBSIG64"
+#define GFW_HOB_START           ((4UL<<30) - (14UL<<20))    // 4G - 14M
+#define GFW_HOB_SIZE            (1UL<<20)                 // 1M
+#define HOB_OFFSET              (GFW_HOB_START-GFW_START)
+
+#define Hob_Output(s)           fprintf(stderr, s)
+
+#define NVRAM_START  (GFW_START + NVRAM_OFFSET)
+#define NVRAM_OFFSET (10 * (1UL << 20))
+#define NVRAM_SIZE   (64 * (1UL << 10))
+#define NVRAM_VALID_SIG  0x4650494e45584948 /* "HIXENIPF" */
+#define VALIDATE_NVRAM_FD(x) ((1UL<<(sizeof(x)*8 - 1)) | x)
+#define IS_VALID_NVRAM_FD(x) ((uint64_t)x >> (sizeof(x)*8 - 1))
+#define READ_FROM_NVRAM 0
+#define WRITE_TO_NVRAM 1
+
+struct nvram_save_addr {
+    unsigned long addr;
+    unsigned long signature;
+};
+
+extern const char *nvram;
+extern int kvm_ia64_build_hob(unsigned long memsize, unsigned long vcpus,
+                              unsigned long nvram_addr);
+extern uint8_t *read_image(const char *filename, unsigned long *size);
+
+extern int kvm_ia64_copy_from_GFW_to_nvram(void);
+extern int kvm_ia64_nvram_init(unsigned long type);
+extern int kvm_ia64_copy_from_nvram_to_GFW(unsigned long nvram_fd);
+#endif //__FIRM_WARE_
diff --git a/target-ia64/helper.c b/target-ia64/helper.c
new file mode 100644
index 0000000..4a94dca
--- /dev/null
+++ b/target-ia64/helper.c
@@ -0,0 +1,5 @@
+
+/*
+ *  IA64 emulation helpers for qemu. (Leave it as blank now.)
+ *
+ */
diff --git a/target-ia64/libkvm.c b/target-ia64/libkvm.c
new file mode 100644
index 0000000..bf9dded
--- /dev/null
+++ b/target-ia64/libkvm.c
@@ -0,0 +1,82 @@
+/*
+ * libkvm-ia64.c :Kernel-based Virtual Machine control library for ia64.
+ *
+ * This library provides an API to control the kvm hardware virtualization
+ * module.
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ * Authors:
+ *
+ *  Avi Kivity <avi@qumranet.com>
+ *  Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * Copyright (C) 2007 Intel
+ * Added by : Zhang Xiantao <xiantao.zhang@intel.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ *
+ */
+
+#include "libkvm-all.h"
+#include "libkvm.h"
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+			void **vm_mem)
+{
+	int r;
+
+	r = kvm_init_coalesced_mmio(kvm);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+int kvm_arch_run(kvm_vcpu_context_t vcpu)
+{
+	int r = 0;
+
+	switch (vcpu->run->exit_reason) {
+		default:
+			r = 1;
+			break;
+	}
+
+	return r;
+}
+
+void kvm_show_code(kvm_vcpu_context_t vcpu)
+{
+	fprintf(stderr, "kvm_show_code not supported yet!\n");
+}
+
+void kvm_show_regs(kvm_vcpu_context_t vcpu)
+{
+	fprintf(stderr,"kvm_show_regs not supportted today!\n");
+}
+
+int kvm_create_memory_alias(kvm_context_t kvm,
+			    uint64_t phys_start,
+			    uint64_t len,
+			    uint64_t target_phys)
+{
+    return 0;
+}
+
+int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start)
+{
+	return 0;
+}
diff --git a/target-ia64/libkvm.h b/target-ia64/libkvm.h
new file mode 100644
index 0000000..417f7f1
--- /dev/null
+++ b/target-ia64/libkvm.h
@@ -0,0 +1,31 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for x86.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * derived from libkvm.c
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_IA64_H
+#define KVM_IA64_H
+
+#include "libkvm-all.h"
+
+extern int kvm_page_size;
+
+#define PAGE_SIZE kvm_page_size
+#define PAGE_MASK (~(kvm_page_size - 1))
+
+#define ia64_mf()	asm volatile ("mf" ::: "memory")
+#define smp_wmb()	ia64_mf()
+
+#endif
diff --git a/target-ia64/machine.c b/target-ia64/machine.c
new file mode 100644
index 0000000..70ef379
--- /dev/null
+++ b/target-ia64/machine.c
@@ -0,0 +1,35 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+#include "exec-all.h"
+#include "qemu-kvm.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    CPUState *env = opaque;
+
+    if (kvm_enabled()) {
+        kvm_save_registers(env);
+        kvm_arch_save_mpstate(env);
+    }
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+
+    if (kvm_enabled()) {
+        kvm_load_registers(env);
+        kvm_arch_load_mpstate(env);
+    }
+    return 0;
+}
+
+extern QEMUMachine ipf_machine;
+
+static void ipf_machine_init(void)
+{
+    qemu_register_machine(&ipf_machine);
+}
+
+machine_init(ipf_machine_init);
diff --git a/target-ia64/op.c b/target-ia64/op.c
new file mode 100644
index 0000000..f7301c6
--- /dev/null
+++ b/target-ia64/op.c
@@ -0,0 +1,22 @@
+/*
+ *  IA64 micro operations
+ *
+ *  Leave it blank for future implementation
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
diff --git a/target-ia64/op_helper.c b/target-ia64/op_helper.c
new file mode 100644
index 0000000..d51525a
--- /dev/null
+++ b/target-ia64/op_helper.c
@@ -0,0 +1,104 @@
+/*
+ * op_helper.c:  IA64 emulation cpu micro-operations helpers for qemu.
+ *
+ * Copyright (c) 2007 Intel Corporation
+ * Zhang Xiantao <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#include "qemu-kvm.h"
+#include "qemu-common.h"
+
+void cpu_ia64_set_model(CPUIA64State *env, uint32_t id);
+void cpu_ia64_close(CPUIA64State *env);
+void switch_mode(CPUState *env, int mode);
+void do_interrupt(CPUIA64State *env);
+int cpu_ia64_handle_mmu_fault (CPUState *env, target_ulong address,
+                               int access_type, int is_user, int is_softmmu);
+CPUState *cpu_ia64_init(const char *cpu_model)
+{
+    CPUState *env;
+    env = qemu_mallocz(sizeof(CPUState));
+    if (!env)
+        return NULL;
+    cpu_exec_init(env);
+    cpu_reset(env);
+    if (kvm_enabled()) {
+        kvm_qemu_init_env(env);
+        kvm_init_vcpu(env);
+    }
+    return env;
+}
+
+void cpu_reset(CPUIA64State *env)
+{
+}
+
+static inline void set_feature(CPUIA64State *env, int feature)
+{
+}
+
+void cpu_ia64_set_model(CPUIA64State *env, uint32_t id)
+{
+}
+
+void cpu_ia64_close(CPUIA64State *env)
+{
+    free(env);
+}
+
+extern int semihosting_enabled;
+
+void switch_mode(CPUState *env, int mode)
+{
+}
+
+/* Handle a CPU exception.  */
+void do_interrupt(CPUIA64State *env)
+{
+    if (kvm_enabled()) {
+        printf("%s: unexpect\n", __FUNCTION__);
+        exit(-1);
+    }
+}
+
+int cpu_ia64_handle_mmu_fault (CPUState *env, target_ulong address,
+                               int access_type, int is_user, int is_softmmu)
+{
+    return 1;
+}
+
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return -1;
+}
+
+void cpu_dump_state(CPUState *env, FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+    return;
+}
+
+void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+    return;
+}
diff --git a/target-ia64/translate.c b/target-ia64/translate.c
new file mode 100644
index 0000000..86f48f5
--- /dev/null
+++ b/target-ia64/translate.c
@@ -0,0 +1,39 @@
+/*
+ *  translation.c : IA64 translation code.
+ *  Just put it as blank now, and implement it later.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+static uint16_t *gen_opc_ptr;
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "gen-op.h"
+
+int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    return 0;
+}
+int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    return 0;
+}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2535cbc..339468e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -36,9 +36,10 @@
 #if defined(TARGET_PPCEMB)
 /* Specific definitions for PowerPC embedded */
 /* BookE have 36 bits physical address space */
-#if defined(CONFIG_USER_ONLY)
+#if defined(CONFIG_USER_ONLY) || defined(USE_KVM)
 /* It looks like a lot of Linux programs assume page size
  * is 4kB long. This is evil, but we have to deal with it...
+ * Also kvm for embedded powerpc needs (atm) 4kB aligned pages
  */
 #define TARGET_PAGE_BITS 12
 #else /* defined(CONFIG_USER_ONLY) */
@@ -1602,4 +1603,11 @@
 #endif
 }
 
+/* hidden flags (hflags) - used internally by qemu to represent additional
+ * cpu states.
+ */
+#define HF_HALTED_SHIFT 1
+
+#define HF_HALTED_MASK 1<<HF_HALTED_SHIFT
+
 #endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/fake-exec.c b/target-ppc/fake-exec.c
new file mode 100644
index 0000000..259e06d
--- /dev/null
+++ b/target-ppc/fake-exec.c
@@ -0,0 +1,104 @@
+/*
+ * fake-exec.c
+ *
+ * This is a file for stub functions so that compilation is possible
+ * when TCG CPU emulation is disabled during compilation.
+ *
+ * Copyright 2007 IBM Corporation.
+ * Added by & Authors:
+ * 	Jerone Young <jyoung5@us.ibm.com>
+ * This work is licensed under the GNU GPL licence version 2 or later.
+ *
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+
+struct ppc_def_t {
+    const unsigned char *name;
+    uint32_t pvr;
+    uint32_t svr;
+    uint64_t insns_flags;
+    uint64_t msr_mask;
+    powerpc_mmu_t   mmu_model;
+    powerpc_excp_t  excp_model;
+    powerpc_input_t bus_model;
+    uint32_t flags;
+    int bfd_mach;
+    void (*init_proc)(CPUPPCState *env);
+    int  (*check_pow)(CPUPPCState *env);
+};
+
+int code_copy_enabled = 0;
+
+void cpu_dump_state (CPUState *env, FILE *f,
+                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                     int flags)
+{
+}
+
+void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+}
+
+void cpu_dump_statistics (CPUState *env, FILE*f,
+                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                          int flags)
+{
+}
+
+unsigned long code_gen_max_block_size(void)
+{
+    return 32;
+}
+
+void cpu_gen_init(void)
+{
+}
+
+int cpu_restore_state(TranslationBlock *tb,
+                      CPUState *env, unsigned long searched_pc,
+                      void *puc)
+
+{
+    return 0;
+}
+
+int cpu_ppc_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
+{
+    return 0;
+}
+
+void init_proc_ppc440ep_kvm(CPUPPCState *env)
+{
+    ppc40x_irq_init(env);
+}
+
+static ppc_def_t ppc440ep_kvm = {
+    .name = "440EP KVM",
+    .mmu_model = POWERPC_MMU_SOFT_4xx, /*XXX needed for GDB stub */
+    .init_proc = init_proc_ppc440ep_kvm,
+};
+
+const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name)
+{
+    return &ppc440ep_kvm;
+}
+
+int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
+{
+    env->mmu_model = def->mmu_model;
+    (*def->init_proc)(env);
+    return 0;
+}
+
+void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index b233d4f..d619737 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -28,6 +28,7 @@
 #include "helper_regs.h"
 #include "qemu-common.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_BATS
diff --git a/target-ppc/libkvm.c b/target-ppc/libkvm.c
new file mode 100644
index 0000000..da93026
--- /dev/null
+++ b/target-ppc/libkvm.c
@@ -0,0 +1,102 @@
+/*
+ * This file contains the powerpc specific implementation for the
+ * architecture dependent functions defined in kvm-common.h and
+ * libkvm.h
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *      Avi Kivity   <avi@qumranet.com>
+ *      Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * Copyright IBM Corp. 2007,2008
+ * Authors:
+ * 	Jerone Young <jyoung5@us.ibm.com>
+ * 	Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#include "libkvm-all.h"
+#include "libkvm.h"
+#include <errno.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+int handle_dcr(kvm_vcpu_context_t vcpu)
+{
+	int ret = 0;
+	struct kvm_run *run = vcpu->run;
+	kvm_context_t kvm = vcpu->kvm;
+
+	if (run->dcr.is_write)
+		ret = kvm->callbacks->powerpc_dcr_write(vcpu,
+							run->dcr.dcrn,
+							run->dcr.data);
+	else
+		ret = kvm->callbacks->powerpc_dcr_read(vcpu,
+							run->dcr.dcrn,
+							&(run->dcr.data));
+
+	return ret;
+}
+
+void kvm_show_code(kvm_vcpu_context_t vcpu)
+{
+	fprintf(stderr, "%s: Operation not supported\n", __FUNCTION__);
+}
+
+void kvm_show_regs(kvm_vcpu_context_t vcpu)
+{
+	struct kvm_regs regs;
+	int i;
+
+	if (kvm_get_regs(vcpu, &regs))
+		return;
+
+	fprintf(stderr,"guest vcpu #%d\n", vcpu);
+	fprintf(stderr,"pc:   %016"PRIx64" msr:  %016"PRIx64"\n",
+	        regs.pc, regs.msr);
+	fprintf(stderr,"lr:   %016"PRIx64" ctr:  %016"PRIx64"\n",
+	        regs.lr, regs.ctr);
+	fprintf(stderr,"srr0: %016"PRIx64" srr1: %016"PRIx64"\n",
+	        regs.srr0, regs.srr1);
+	for (i=0; i<32; i+=4)
+	{
+		fprintf(stderr, "gpr%02d: %016"PRIx64" %016"PRIx64" %016"PRIx64
+		        " %016"PRIx64"\n", i,
+			regs.gpr[i],
+			regs.gpr[i+1],
+			regs.gpr[i+2],
+			regs.gpr[i+3]);
+	}
+
+	fflush(stdout);
+}
+
+int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
+			 void **vm_mem)
+{
+	int r;
+
+	r = kvm_init_coalesced_mmio(kvm);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+int kvm_arch_run(kvm_vcpu_context_t vcpu)
+{
+	int ret = 0;
+
+	switch (vcpu->run->exit_reason){
+	case KVM_EXIT_DCR:
+		ret = handle_dcr(vcpu);
+		break;
+	default:
+		ret = 1;
+		break;
+	}
+	return ret;
+}
diff --git a/target-ppc/libkvm.h b/target-ppc/libkvm.h
new file mode 100644
index 0000000..80b6b06
--- /dev/null
+++ b/target-ppc/libkvm.h
@@ -0,0 +1,36 @@
+/*
+ * This header is for functions & variables that will ONLY be
+ * used inside libkvm for powerpc.
+ * THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
+ * WITHIN LIBKVM.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *	Avi Kivity   <avi@qumranet.com>
+ *	Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * Copyright 2007 IBM Corporation.
+ * Added by: Jerone Young <jyoung5@us.ibm.com>
+ *
+ * This work is licensed under the GNU LGPL license, version 2.
+ */
+
+#ifndef KVM_POWERPC_H
+#define KVM_POWERPC_H
+
+#include "libkvm-all.h"
+
+extern int kvm_page_size;
+
+#define PAGE_SIZE kvm_page_size
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+static inline void eieio(void)
+{
+	asm volatile("eieio" : : : "memory");
+}
+
+#define smp_wmb()	eieio()
+
+#endif
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 4897c8a..ead38e1 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -1,6 +1,7 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 void cpu_save(QEMUFile *f, void *opaque)
 {
diff --git a/vl.c b/vl.c
index ee9c3f9..5d713d9 100644
--- a/vl.c
+++ b/vl.c
@@ -157,6 +157,8 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "qemu-objects.h"
+#include "qemu-kvm.h"
+#include "hw/device-assignment.h"
 
 #include "disas.h"
 
@@ -179,6 +181,7 @@
    to store the VM snapshots */
 struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
 struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts);
+DriveInfo *extboot_drive = NULL;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 static DisplayState *display_state;
 DisplayType display_type = DT_DEFAULT;
@@ -215,13 +218,17 @@
 #endif
 int usb_enabled = 0;
 int singlestep = 0;
+const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE];
+int assigned_devices_index;
 int smp_cpus = 1;
 int max_cpus = 0;
 int smp_cores = 1;
 int smp_threads = 1;
 const char *vnc_display;
 int acpi_enabled = 1;
+#ifdef TARGET_I386
 int no_hpet = 0;
+#endif
 int fd_bootchk = 1;
 int no_reboot = 0;
 int no_shutdown = 0;
@@ -235,6 +242,12 @@
 const char *option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
 int semihosting_enabled = 0;
+int time_drift_fix = 0;
+unsigned int kvm_shadow_memory = 0;
+const char *mem_path = NULL;
+#ifdef MAP_POPULATE
+int mem_prealloc = 1;	/* force preallocation of physical target memory */
+#endif
 #ifdef TARGET_ARM
 int old_param = 0;
 #endif
@@ -245,6 +258,7 @@
 unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 #endif
+const char *nvram = NULL;
 int boot_menu;
 
 int nb_numa_nodes;
@@ -2109,6 +2123,7 @@
     int on_read_error, on_write_error;
     const char *devaddr;
     DriveInfo *dinfo;
+    int is_extboot = 0;
     int snapshot = 0;
 
     *fatal_error = 1;
@@ -2267,6 +2282,12 @@
         }
     }
 
+    is_extboot = qemu_opt_get_bool(opts, "boot", 0);
+    if (is_extboot && extboot_drive) {
+        fprintf(stderr, "qemu: two bootable drives specified\n");
+        return NULL;
+    }
+
     on_write_error = BLOCK_ERR_STOP_ENOSPC;
     if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
         if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) {
@@ -2378,6 +2399,9 @@
     if (serial)
         strncpy(dinfo->serial, serial, sizeof(serial));
     QTAILQ_INSERT_TAIL(&drives, dinfo, next);
+    if (is_extboot) {
+        extboot_drive = dinfo;
+    }
 
     switch(type) {
     case IF_IDE:
@@ -2851,6 +2875,7 @@
         ioh->opaque = opaque;
         ioh->deleted = 0;
     }
+    qemu_notify_event();
     return 0;
 }
 
@@ -2973,6 +2998,15 @@
     int found = 0;
 
     while (addr < last_ram_offset) {
+        if (kvm_enabled() && current_addr == 0) {
+            int r;
+            r = kvm_update_dirty_pages_log();
+            if (r) {
+                fprintf(stderr, "%s: update dirty pages log failed %d\n", __FUNCTION__, r);
+                qemu_file_set_error(f);
+                return 0;
+            }
+        }
         if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
             uint8_t *p;
 
@@ -3277,6 +3311,13 @@
 static int debug_requested;
 static int vmstop_requested;
 
+int qemu_no_shutdown(void)
+{
+    int r = no_shutdown;
+    no_shutdown = 0;
+    return r;
+}
+
 int qemu_shutdown_requested(void)
 {
     int r = shutdown_requested;
@@ -3361,6 +3402,9 @@
     } else {
         reset_requested = 1;
     }
+    if (cpu_single_env) {
+        cpu_single_env->stopped = 1;
+    }
     qemu_notify_event();
 }
 
@@ -3513,13 +3557,19 @@
 {
     CPUState *env = cpu_single_env;
 
+    if (kvm_enabled()) {
+        qemu_kvm_notify_work();
+        return;
+    }
     if (env) {
         cpu_exit(env);
     }
 }
 
+#if defined(KVM_UPSTREAM) || !defined(CONFIG_KVM)
 void qemu_mutex_lock_iothread(void) {}
 void qemu_mutex_unlock_iothread(void) {}
+#endif
 
 void vm_stop(int reason)
 {
@@ -3947,6 +3997,8 @@
         for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
             if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
                 ioh->fd_read(ioh->opaque);
+                if (!(ioh->fd_read_poll && ioh->fd_read_poll(ioh->opaque)))
+                    FD_CLR(ioh->fd, &rfds);
             }
             if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
                 ioh->fd_write(ioh->opaque);
@@ -4153,6 +4205,12 @@
 {
     int r;
 
+    if (kvm_enabled()) {
+        kvm_main_loop();
+        cpu_disable_ticks();
+        return;
+    }
+
 #ifdef CONFIG_IOTHREAD
     qemu_system_ready = 1;
     qemu_cond_broadcast(&qemu_system_cond);
@@ -4930,6 +4988,8 @@
         node_cpumask[i] = 0;
     }
 
+    assigned_devices_index = 0;
+
     nb_numa_nodes = 0;
     nb_nics = 0;
 
@@ -5437,9 +5497,41 @@
                 break;
 #endif
 #ifdef CONFIG_KVM
+#ifdef KVM_UPSTREAM
             case QEMU_OPTION_enable_kvm:
                 kvm_allowed = 1;
+#endif
                 break;
+	    case QEMU_OPTION_no_kvm:
+		kvm_allowed = 0;
+		break;
+	    case QEMU_OPTION_no_kvm_irqchip: {
+		kvm_irqchip = 0;
+		kvm_pit = 0;
+		break;
+	    }
+	    case QEMU_OPTION_no_kvm_pit: {
+		kvm_pit = 0;
+		break;
+	    }
+            case QEMU_OPTION_no_kvm_pit_reinjection: {
+                kvm_pit_reinject = 0;
+                break;
+            }
+	    case QEMU_OPTION_enable_nesting: {
+		kvm_nested = 1;
+		break;
+	    }
+#if defined(TARGET_I386) || defined(TARGET_X86_64) || defined(TARGET_IA64) || defined(__linux__)
+            case QEMU_OPTION_pcidevice:
+		if (assigned_devices_index >= MAX_DEV_ASSIGN_CMDLINE) {
+                    fprintf(stderr, "Too many assigned devices\n");
+                    exit(1);
+		}
+		assigned_devices[assigned_devices_index] = optarg;
+		assigned_devices_index++;
+                break;
+#endif
 #endif
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
@@ -5521,6 +5613,20 @@
                 semihosting_enabled = 1;
                 break;
 #endif
+            case QEMU_OPTION_tdf:
+                time_drift_fix = 1;
+		break;
+            case QEMU_OPTION_kvm_shadow_memory:
+                kvm_shadow_memory = (int64_t)atoi(optarg) * 1024 * 1024 / 4096;
+                break;
+            case QEMU_OPTION_mempath:
+		mem_path = optarg;
+		break;
+#ifdef MAP_POPULATE
+            case QEMU_OPTION_mem_prealloc:
+		mem_prealloc = !mem_prealloc;
+		break;
+#endif
             case QEMU_OPTION_name:
                 qemu_name = qemu_strdup(optarg);
 		 {
@@ -5599,6 +5705,9 @@
             case QEMU_OPTION_runas:
                 run_as = optarg;
                 break;
+            case QEMU_OPTION_nvram:
+                nvram = optarg;
+                break;
 #endif
 #ifdef CONFIG_XEN
             case QEMU_OPTION_xen_domid:
@@ -5788,8 +5897,12 @@
 
         ret = kvm_init(smp_cpus);
         if (ret < 0) {
+#if defined(KVM_UPSTREAM) || defined(CONFIG_NO_CPU_EMULATION)
             fprintf(stderr, "failed to initialize KVM\n");
             exit(1);
+#endif
+            fprintf(stderr, "Could not initialize KVM, will disable KVM support\n");
+            kvm_allowed = 0;
         }
     }