Merge commit 'v0.11.1' into stable-0.11

* commit 'v0.11.1':
  Update version and changelog for 0.11.1 release
  fix I2C slave addressing
  Revert "vga: do not resize the screen on hw_invalidate"
  slirp: fix use-after-free
  Fix sparc.ld
  ELF codedump build failures
  kvm: Move KVM mp_state accessors to i386-specific code
  this patch fixes a typo where armv4l was incorrectly spelled arm4l,
  net: disable draining tap queue in one go
  pcnet: Restart poll timer on pcnet_start
  Sparc32: Fix lance
  mac99: fix segmentation fault on startup
  usb-linux.c: fix buffer overflow
  ARM host: fix generated blocks linking
  qemu serial: lost tx irqs (affecting FreeBSD's new uart(4) driver)
  exec-all.h: increase MAX_OP_PER_INSTR to 96 from 64

Conflicts:
	net.c

Signed-off-by: Avi Kivity <avi@redhat.com>
diff --git a/Makefile b/Makefile
index e4f9498..f2b8885 100644
--- a/Makefile
+++ b/Makefile
@@ -51,6 +51,18 @@
 SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
 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-%:
 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 
@@ -90,6 +102,10 @@
 
 block-obj-y +=  $(addprefix block/, $(block-nested-y))
 
+ifdef CONFIG_AIO
+block-obj-y += compatfd.o
+endif
+
 ######################################################################
 # libqemu_common.a: Target independent part of system emulation. The
 # long term path is to suppress *all* target specific code in case of
@@ -263,6 +279,7 @@
 pxe-ne2k_pci.bin pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin \
 bamboo.dtb petalogix-s3adsp1800.dtb \
 multiboot.bin
+BLOBS += extboot.bin
 else
 BLOBS=
 endif
@@ -285,7 +302,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"
@@ -295,6 +317,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
@@ -412,6 +437,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 \
@@ -420,3 +446,10 @@
 
 # Include automatically generated dependency files
 -include $(wildcard *.d audio/*.d slirp/*.d block/*.d)
+
+build-targets-i386 = $(build-targets-x86)
+build-targets-x86_64 = $(build-targets-x86)
+build-targets-x86  =
+build-targets-ia64 =
+
+all: $(build-targets-$(ARCH))
diff --git a/Makefile.target b/Makefile.target
index f9cd42a..72f14f6 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -1,6 +1,11 @@
+CFLAGS=
+LDFLAGS=
+
 include config.mak
 include $(SRC_PATH)/rules.mak
 
+LDFLAGS_BASE:=$(LDFLAGS)
+
 TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
 VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
 CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MT $@ -MP -DNEED_CPU_H
@@ -54,6 +59,7 @@
 
 CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 CPPFLAGS+=-U_FORTIFY_SOURCE
+CPPFLAGS+=-D__user=
 LIBS+=-lm
 ifdef CONFIG_WIN32
 LIBS+=-lwinmm -lws2_32 -liphlpapi
@@ -70,20 +76,30 @@
 kvm.o: CFLAGS+=$(KVM_CFLAGS)
 kvm-all.o: CFLAGS+=$(KVM_CFLAGS)
 
+CFLAGS += $(KVM_CFLAGS)
+
 all: $(PROGS)
 # Dummy command so that make thinks it has done something
 	@true
 
 #########################################################
 # cpu emulator library
-libobj-y = exec.o translate-all.o cpu-exec.o translate.o host-utils.o
+libobj-y = exec.o cpu-exec.o host-utils.o
+ifeq ($(NO_CPU_EMULATION), 1)
+libobj-y += fack-exec.o
+else
+libobj-y += translate-all.o translate.o 
+endif
 libobj-$(CONFIG_KQEMU) += kqemu.o
 # TCG code generator
+ifneq ($(NO_CPU_EMULATION), 1)
 libobj-y += tcg/tcg.o tcg/tcg-runtime.o
 CPPFLAGS+=-I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/$(ARCH)
+endif
 ifeq ($(ARCH),sparc64)
 CPPFLAGS+=-I$(SRC_PATH)/tcg/sparc
 endif
+
 ifdef CONFIG_SOFTFLOAT
 libobj-y += fpu/softfloat.o
 else
@@ -92,6 +108,18 @@
 CPPFLAGS+=-I$(SRC_PATH)/fpu
 libobj-y += op_helper.o helper.o
 
+ifeq ($(TARGET_BASE_ARCH), i386)
+libobj-y += helper.o
+libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
+libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
+endif
+
+libobj-y += op_helper.o
+
+ifneq ($(TARGET_ARCH), ia64)
+libobj-y += helper.o
+endif
+
 ifeq ($(TARGET_BASE_ARCH), arm)
 libobj-y += neon_helper.o iwmmxt_helper.o
 endif
@@ -100,6 +128,11 @@
 libobj-y += alpha_palcode.o
 endif
 
+ifeq ($(TARGET_BASE_ARCH), ia64)
+libobj-y += op_helper.o firmware.o
+libobj-$(CONFIG_KVM) += qemu-kvm-ia64.o
+endif
+
 ifeq ($(TARGET_BASE_ARCH), cris)
 libobj-y += cris-dis.o
 
@@ -108,6 +141,7 @@
 endif
 endif
 
+
 # NOTE: the disassembler code is only needed for debugging
 libobj-y += disas.o
 ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -167,6 +201,9 @@
 
 cpu-exec.o: CFLAGS += $(HELPER_CFLAGS)
 
+qemu-kvm-helper.o: qemu-kvm-helper.c
+	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
 #########################################################
 # Linux user emulator target
 
@@ -494,13 +531,33 @@
 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
+obj-i386-y += extboot.o
+ifeq ($(USE_KVM_PIT), 1)
+obj-i386-y += i8254-kvm.o
+endif
+ifeq ($(USE_KVM_DEVICE_ASSIGNMENT), 1)
+obj-i386-y += device-assignment.o
+LIBS+=-lpci
+endif
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
 
+# 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
+
+ifeq ($(USE_KVM_DEVICE_ASSIGNMENT), 1)
+obj-ia64-y += device-assignment.o
+LIBS+=-lpci
+endif
+
 # shared objects
 obj-ppc-y = ppc.o ide.o vga.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
@@ -650,6 +707,10 @@
 LDFLAGS+=-p
 main.o: CFLAGS+=-p
 endif
+ifeq ($(TARGET_ARCH), ia64)
+firmware.o: firmware.c
+	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+endif
 
 vl.o: CFLAGS+=$(SDL_CFLAGS)
 
@@ -660,6 +721,9 @@
 LIBS += $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS) $(VDE_LIBS) $(CURL_LIBS)
 ARLIBS=../libqemu_common.a libqemu.a $(HWLIB)
 
+$(QEMU_PROG): ARLIBS += $(DEPLIBS)
+$(QEMU_PROG): $(DEPLIBS)
+
 endif # !CONFIG_USER_ONLY
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(ARLIBS)
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 3e1a875..7482150 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>
 #ifdef CONFIG_AIO
 #include "posix-aio-compat.h"
 #endif
@@ -502,7 +504,7 @@
 
 typedef struct PosixAioState
 {
-    int rfd, wfd;
+    int fd;
     RawAIOCB *first_aio;
 } PosixAioState;
 
@@ -511,18 +513,29 @@
     PosixAioState *s = opaque;
     RawAIOCB *acb, **pacb;
     int ret;
-    ssize_t len;
+    size_t offset;
+    union {
+        struct qemu_signalfd_siginfo siginfo;
+        char buf[128];
+    } sig;
 
-    /* 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;
     }
 
     for(;;) {
@@ -569,22 +582,10 @@
 
 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 int posix_aio_init(void)
 {
-    struct sigaction act;
+    sigset_t mask;
     PosixAioState *s;
-    int fds[2];
     struct qemu_paioinit ai;
   
     if (posix_aio_state)
@@ -592,24 +593,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 (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 -errno;
     }
 
-    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, s);
+    qemu_aio_set_fd_handler(s->fd, posix_aio_read, NULL, posix_aio_flush, s);
 
     memset(&ai, 0, sizeof(ai));
     ai.aio_threads = 64;
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/compatfd.c b/compatfd.c
new file mode 100644
index 0000000..36e37e5
--- /dev/null
+++ b/compatfd.c
@@ -0,0 +1,131 @@
+/*
+ * 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;
+    }
+
+    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)
+        return ret;
+#endif
+
+    return qemu_signalfd_compat(mask);
+}
+
+int qemu_eventfd(int *fds)
+{
+#if defined(CONFIG_eventfd)
+    int ret;
+
+    ret = syscall(SYS_eventfd, 0);
+    if (ret >= 0) {
+        fds[0] = ret;
+        if ((fds[1] = dup(ret)) == -1) {
+            close(ret);
+            return -1;
+        }
+        return 0;
+    }
+#endif
+
+    return pipe(fds);
+}
diff --git a/compatfd.h b/compatfd.h
new file mode 100644
index 0000000..55a111a
--- /dev/null
+++ b/compatfd.h
@@ -0,0 +1,28 @@
+/*
+ * 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;
+    uint8_t pad[124];
+};
+
+int qemu_signalfd(const sigset_t *mask);
+
+int qemu_eventfd(int *fds);
+
+#endif
diff --git a/configure b/configure
index d58d19b..35ce2e1 100755
--- a/configure
+++ b/configure
@@ -102,7 +102,7 @@
   cpu=`uname -m`
 fi
 
-target_list=""
+target_list="x86_64-softmmu"
 case "$cpu" in
   i386|i486|i586|i686|i86pc|BePC)
     cpu="i386"
@@ -159,6 +159,17 @@
     cpu="unknown"
   ;;
 esac
+
+kvm_version() {
+    local fname="$(dirname "$0")/KVM_VERSION"
+
+    if test -f "$fname"; then
+        cat "$fname"
+    else
+        echo "kvm-devel"
+    fi
+}
+
 gprof="no"
 debug_tcg="no"
 debug="no"
@@ -195,6 +206,9 @@
 mixemu="no"
 bluez="yes"
 kvm="no"
+kvm_trace="no"
+kvm_cap_pit="no"
+kvm_cap_device_assignment="no"
 kerneldir=""
 aix="no"
 blobs="yes"
@@ -202,7 +216,11 @@
 sdl="yes"
 sdl_x11="no"
 xen="yes"
-pkgversion=""
+pkgversion=" ($(kvm_version))"
+signalfd="no"
+eventfd="no"
+cpu_emulation="yes"
+kvm_kmod="no"
 
 # OS specific
 if check_define __linux__ ; then
@@ -245,6 +263,7 @@
 audio_possible_drivers="oss sdl esd pa"
 if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
     kqemu="yes"
+    kvm="yes"
 fi
 ;;
 DragonFly)
@@ -337,6 +356,19 @@
 if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
     kqemu="yes"
     audio_possible_drivers="$audio_possible_drivers fmod"
+    kvm="yes"
+    kqemu="no"
+fi
+if [ "$cpu" = "ia64" ] ; then
+     kvm="yes"
+     xen="no"
+     target_list="ia64-softmmu"
+     cpu_emulation="no"
+     gdbstub="no"
+     slirp="no"
+fi
+if [ "$cpu" = "powerpc" ]; then
+     kvm="yes"
 fi
 ;;
 esac
@@ -501,10 +533,14 @@
   ;;
   --kerneldir=*) kerneldir="$optarg"
   ;;
+  --with-kvm-trace) kvm_trace="yes"
+  ;;
   --with-pkgversion=*) pkgversion=" ($optarg)"
   ;;
   --disable-docs) build_docs="no"
   ;;
+  --disable-cpu-emulation) cpu_emulation="no"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -528,6 +564,8 @@
     else
         werror="no"
     fi
+    # disable default werror for kvm
+    werror="no"
 fi
 
 if test "$werror" = "yes" ; then
@@ -652,6 +690,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
@@ -830,6 +870,75 @@
 fi
 
 ##########################################
+# KVM probe
+
+case "$cpu" in
+    i386 | x86_64)
+	kvm_arch="x86"
+	;;
+    ppc)
+        kvm_arch="powerpc"
+        ;;
+    *)
+	kvm_arch="$cpu"
+	;;
+esac
+
+kvm_cflags=""
+
+if test "$kvm" = "yes" ; then
+
+kvm_cflags="-I$source_path/kvm/include"
+kvm_cflags="$kvm_cflags -I$source_path/kvm/include/$kvm_arch"
+
+# test for KVM_CAP_PIT
+
+cat > $TMPC <<EOF
+#include <linux/kvm.h>
+#ifndef KVM_CAP_PIT
+#error "kvm no pit capability"
+#endif
+int main(void) { return 0; }
+EOF
+    if $cc $ARCH_CFLAGS $CFLAGS $kvm_cflags -o $TMPE ${OS_CFLAGS} $TMPC 2> /dev/null ; then
+	kvm_cap_pit="yes"
+    fi
+
+# test for KVM_CAP_DEVICE_ASSIGNMENT
+
+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 $cc $ARCH_CFLAGS $CFLAGS $kvm_cflags -o $TMPE ${OS_CFLAGS} $TMPC 2> /dev/null ; then
+	kvm_cap_device_assignment="yes"
+    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) { return 0; }
+EOF
+    if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC 2>/dev/null ; then
+        :
+    else
+        echo
+        echo "Error: libpci check failed"
+        echo "Disable KVM Device Assignment capability."
+        echo
+        kvm_cap_device_assignment="no"
+    fi
+fi
+
+##########################################
 # zlib check
 
 cat > $TMPC << EOF
@@ -1152,19 +1261,6 @@
 #endif
 int main(void) { return 0; }
 EOF
-  if test "$kerneldir" != "" ; then
-      kvm_cflags=-I"$kerneldir"/include
-      if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) \
-         -a -d "$kerneldir/arch/x86/include" ; then
-            kvm_cflags="$kvm_cflags -I$kerneldir/arch/x86/include"
-	elif test "$cpu" = "ppc" -a -d "$kerneldir/arch/powerpc/include" ; then
-	    kvm_cflags="$kvm_cflags -I$kerneldir/arch/powerpc/include"
-        elif test -d "$kerneldir/arch/$cpu/include" ; then
-            kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
-      fi
-  else
-      kvm_cflags=""
-  fi
   if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $kvm_cflags $TMPC \
       > /dev/null 2>/dev/null ; then
     :
@@ -1347,6 +1443,33 @@
   splice=yes
 fi
 
+##########################################
+# signalfd probe
+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
+
+##########################################
+# eventfd probe
+cat > $TMPC << EOF
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+int main(void) { return syscall(SYS_eventfd, 0); }
+EOF
+
+if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+  eventfd=yes
+fi
+
 # Check if tools are available to build documentation.
 if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then
   build_docs="no"
@@ -1390,6 +1513,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"
@@ -1441,6 +1578,7 @@
 fi
 echo "kqemu support     $kqemu"
 echo "xen support       $xen"
+echo "CPU emulation     $cpu_emulation"
 echo "brlapi support    $brlapi"
 echo "Documentation     $build_docs"
 [ ! -z "$uname_release" ] && \
@@ -1451,6 +1589,7 @@
 echo "IO thread         $io_thread"
 echo "Install blobs     $blobs"
 echo -e "KVM support       $kvm"
+echo "KVM trace support $kvm_trace"
 echo "fdt support       $fdt"
 echo "preadv support    $preadv"
 
@@ -1738,6 +1877,12 @@
   echo "#define HAVE_FDT 1" >> $config_host_h
   echo "FDT_LIBS=-lfdt" >> $config_host_mak
 fi
+if test "$signalfd" = "yes" ; then
+  echo "#define CONFIG_signalfd 1" >> $config_host_h
+fi
+if test "$eventfd" = "yes" ; then
+  echo "#define CONFIG_eventfd 1" >> $config_host_h
+fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
@@ -1797,6 +1942,13 @@
     echo "CONFIG_XEN=y" >> $config_host_mak
 fi
 
+# this is a temp hack needed for kvm
+if test "$kvm" = "yes" ; then
+    echo "KVM_CFLAGS=$kvm_cflags" >> $config_host_mak
+fi
+
+echo "KVM_KMOD=$kvm_kmod" >> $config_host_mak
+
 tools=
 if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
   tools="qemu-img\$(EXESUF) $tools"
@@ -1890,6 +2042,28 @@
 echo "CONFIG_QEMU_PREFIX=\"$interp_prefix1\"" >> $config_mak
 gdb_xml_files=""
 
+disable_cpu_emulation() {
+  if test $cpu_emulation = "no"; then
+    echo "#define NO_CPU_EMULATION 1" >> $config_host_h
+    echo "NO_CPU_EMULATION=1" >> $config_host_mak
+  fi
+}
+
+configure_kvm() {
+  if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
+          \( "$cpu" = "i386" -o "$cpu" = "x86_64" -o "$cpu" = "ia64" -o "$cpu" = "powerpc" \); then
+    echo "CONFIG_KVM=y" >> $config_mak
+    echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
+    if test $kvm_cap_pit = "yes" ; then
+	echo "USE_KVM_PIT=1" >> $config_mak
+    fi
+    if test $kvm_cap_device_assignment = "yes" ; then
+	echo "USE_KVM_DEVICE_ASSIGNMENT=1" >> $config_mak
+    fi
+    disable_cpu_emulation
+  fi
+}
+
 TARGET_ARCH="$target_arch2"
 TARGET_BASE_ARCH=""
 TARGET_ABI_DIR=""
@@ -1902,6 +2076,12 @@
     TARGET_BASE_ARCH=i386
     target_phys_bits=64
   ;;
+  ia64)
+    echo "TARGET_ARCH=ia64" >> $config_host_mak
+    echo "#define TARGET_ARCH \"ia64\"" >> $config_host_h
+    echo "#define TARGET_IA64 1" >> $config_host_h
+    target_phys_bits=64
+  ;;
   alpha)
     target_phys_bits=64
   ;;
@@ -2028,6 +2208,7 @@
       \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then
       echo "CONFIG_KVM=y" >> $config_mak
       echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
+      configure_kvm
     fi
 esac
 echo "HWLIB=../libhw$target_phys_bits/libqemuhw$target_phys_bits.a" >> $config_mak
diff --git a/cpu-all.h b/cpu-all.h
index 1166786..3381125 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -844,6 +844,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-defs.h b/cpu-defs.h
index d73ec0a..db17bd0 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 "sys-queue.h"
 #include "targphys.h"
@@ -134,6 +135,16 @@
     TAILQ_ENTRY(CPUWatchpoint) entry;
 } CPUWatchpoint;
 
+/* forward decleration */
+struct qemu_work_item;
+
+struct KVMCPUState {
+    pthread_t thread;
+    int signalled;
+    void *vcpu_ctx;
+    struct qemu_work_item *queued_work_first, *queued_work_last;
+};
+
 #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. */   \
@@ -186,6 +195,7 @@
     uint32_t host_tid; /* host thread ID */                             \
     int numa_node; /* NUMA node this cpu is belonging to  */            \
     int running; /* Nonzero if cpu is currently running(usermode).  */  \
+    int thread_id;							\
     /* user data */                                                     \
     void *opaque;                                                       \
                                                                         \
@@ -195,6 +205,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 2385d56..e6709dc 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(HOST_SOLARIS)
 // Work around ugly bugs in glibc that mangle global register contents
 #undef env
@@ -249,6 +253,7 @@
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
+#elif defined(TARGET_IA64)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -316,6 +321,8 @@
                     do_interrupt(env);
 #elif defined(TARGET_M68K)
                     do_interrupt(0);
+#elif defined(TARGET_IA64)
+		    do_interrupt(env);
 #endif
 #endif
                 }
@@ -710,6 +717,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)
     /* XXXXX */
diff --git a/create_config b/create_config
index cac0edb..b7b33bb 100755
--- a/create_config
+++ b/create_config
@@ -50,6 +50,9 @@
     name=${line%=*}
     echo "#define $name 1"
     ;;
+ USE_KVM_*)
+    echo "#define $(echo "$line" | sed 's/=/ /')"
+    ;;
 esac
 
 done # read
diff --git a/cutils.c b/cutils.c
index bd9a019..c8d5326 100644
--- a/cutils.c
+++ b/cutils.c
@@ -177,6 +177,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 65257d8..0655b4b 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) && !defined(CONFIG_KQEMU)
 #define TARGET_PHYS_ADDR_SPACE_BITS 36
+#elif defined(TARGET_IA64)
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
 #else
 /* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
@@ -112,6 +120,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 {
@@ -413,6 +422,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;
@@ -577,6 +589,11 @@
     env->numa_node = 0;
     TAILQ_INIT(&env->breakpoints);
     TAILQ_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();
@@ -1542,6 +1559,8 @@
 
     old_mask = env->interrupt_request;
     env->interrupt_request |= mask;
+    if (kvm_enabled() && !qemu_kvm_irqchip_in_kernel())
+	kvm_update_interrupt_request(env);
 
 #ifndef CONFIG_USER_ONLY
     /*
@@ -1892,7 +1911,6 @@
 
 int cpu_physical_memory_set_dirty_tracking(int enable)
 {
-    in_migration = enable;
     if (kvm_enabled()) {
         return kvm_set_migration_log(enable);
     }
@@ -2438,6 +2456,113 @@
 }
 #endif
 
+#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;
@@ -2451,7 +2576,10 @@
     size = TARGET_PAGE_ALIGN(size);
     new_block = qemu_malloc(sizeof(*new_block));
 
-    new_block->host = qemu_vmalloc(size);
+    new_block->host = file_ram_alloc(size, mem_path);
+    if (!new_block->host) {
+        new_block->host = qemu_vmalloc(size);
+    }
     new_block->offset = last_ram_offset;
     new_block->length = size;
 
@@ -3156,6 +3284,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 &&
@@ -3348,6 +3481,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);
@@ -3365,7 +3500,9 @@
                 }
                 addr1 += l;
                 access_len -= l;
-            }
+	    }
+	    dma_flush_range((unsigned long)buffer,
+			    (unsigned long)buffer + flush_len);
         }
         return;
     }
diff --git a/gdbstub.c b/gdbstub.c
index bb38971..dc6d398 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 056e4c6..9d6d78b 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
 
@@ -519,6 +521,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);
 
@@ -567,12 +576,14 @@
 #endif
 
 #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 {
@@ -595,6 +606,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);
@@ -637,6 +652,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);
@@ -713,22 +732,72 @@
 #endif
 }
 
+static const char *model;
+
 static void piix4_device_hot_add(int bus, int slot, int state);
 
-void piix4_acpi_system_hot_add_init(void)
+void piix4_acpi_system_hot_add_init(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, NULL);
     register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, NULL);
 
+    model = cpu_model;
+
     qemu_system_device_hot_add_register(piix4_device_hot_add);
 }
 
+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));
+}
+
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+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 1927811..3d641e0 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() && qemu_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);
@@ -864,11 +874,103 @@
     }
 }
 
+#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->kvm_cpu_state.vcpu_ctx, 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->kvm_cpu_state.vcpu_ctx, klapic);
+}
+
+#endif
+
+void qemu_kvm_load_lapic(CPUState *env)
+{
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && kvm_vcpu_inited(env) && qemu_kvm_irqchip_in_kernel()) {
+        kvm_kernel_lapic_load_from_user(env->apic_state);
+    }
+#endif
+}
+
 static void apic_save(QEMUFile *f, void *opaque)
 {
     APICState *s = opaque;
     int i;
 
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+        kvm_kernel_lapic_save_to_user(s);
+    }
+#endif
+
     qemu_put_be32s(f, &s->apicbase);
     qemu_put_8s(f, &s->id);
     qemu_put_8s(f, &s->arb_id);
@@ -931,6 +1033,9 @@
 
     if (version_id >= 2)
         qemu_get_timer(f, s->timer);
+
+    qemu_kvm_load_lapic(s->cpu_env);
+
     return 0;
 }
 
@@ -953,8 +1058,8 @@
          */
         s->lvt[APIC_LVT_LINT0] = 0x700;
     }
-
     cpu_synchronize_state(s->cpu_env, 1);
+    qemu_kvm_load_lapic(s->cpu_env);
 }
 
 static CPUReadMemoryFunc *apic_mem_read[3] = {
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 0460f97..9e775a9 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"
 
 /*
  * TODO:
@@ -2587,6 +2588,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;
@@ -2596,13 +2598,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((VGAState *)s);
         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,
@@ -2614,17 +2622,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 */
@@ -3265,6 +3277,8 @@
 {
     CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
 
+    vga_dirty_log_stop((VGAState *)s);
+
     /* XXX: add byte swapping apertures */
     cpu_register_physical_memory(addr, s->vga.vram_size,
 				 s->cirrus_linear_io_addr);
@@ -3296,10 +3310,14 @@
     PCICirrusVGAState *pvs = container_of(d, PCICirrusVGAState, dev);
     CirrusVGAState *s = &pvs->cirrus_vga;
 
+    vga_dirty_log_stop((VGAState *)s);
+
     pci_default_write_config(d, address, val, len);
     if (s->vga.map_addr && pvs->dev.io_regions[0].addr == -1)
         s->vga.map_addr = 0;
     cirrus_update_memory_access(s);
+
+    vga_dirty_log_start((VGAState *)s);
 }
 
 void pci_cirrus_vga_init(PCIBus *bus)
diff --git a/hw/device-assignment.c b/hw/device-assignment.c
new file mode 100644
index 0000000..75db546
--- /dev/null
+++ b/hw/device-assignment.c
@@ -0,0 +1,1442 @@
+/*
+ * 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 <pci/pci.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"
+
+/* 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 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,
+                                   uint32_t e_phys, uint32_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];
+    uint32_t old_ephys = region->e_physbase;
+    uint32_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,
+                                    uint32_t addr, uint32_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_ADDRESS_SPACE_MEM_PREFETCH
+                : PCI_ADDRESS_SPACE_MEM;
+
+            /* 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_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, sizeof(pci_dev->dev.config));
+    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 LIST_HEAD(, AssignedDevInfo) adev_head;
+
+#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(AssignedDevInfo *adev)
+{
+    AssignedDevice *dev = adev->assigned_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;
+        }
+
+        pci_unregister_device(&dev->dev, 1);
+#ifdef KVM_CAP_IRQ_ROUTING
+        free_dev_irq_entries(dev);
+#endif
+        adev->assigned_dev = dev = NULL;
+    }
+
+    LIST_REMOVE(adev, next);
+    qemu_free(adev);
+}
+
+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(AssignedDevInfo *adev)
+{
+    struct kvm_assigned_pci_dev assigned_dev_data;
+    AssignedDevice *dev = adev->assigned_dev;
+    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 && !adev->disable_iommu)
+	assigned_dev_data.flags |= KVM_DEV_ASSIGN_ENABLE_IOMMU;
+#endif
+
+    r = kvm_assign_pci_device(kvm_context, &assigned_dev_data);
+    if (r < 0)
+	fprintf(stderr, "Failed to assign device \"%s\" : %s\n",
+                adev->name, strerror(-r));
+    return r;
+}
+
+static int assign_irq(AssignedDevInfo *adev)
+{
+    struct kvm_assigned_irq assigned_irq_data;
+    AssignedDevice *dev = adev->assigned_dev;
+    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",
+                adev->name, 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(AssignedDevInfo *adev)
+{
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+    struct kvm_assigned_pci_dev assigned_dev_data;
+    AssignedDevice *dev = adev->assigned_dev;
+    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",
+                adev->name, strerror(-r));
+#endif
+}
+
+void remove_assigned_device(AssignedDevInfo *adev)
+{
+    deassign_device(adev);
+    free_assigned_device(adev);
+}
+
+AssignedDevInfo *get_assigned_device(int pcibus, int slot)
+{
+    AssignedDevice *assigned_dev = NULL;
+    AssignedDevInfo *adev = NULL;
+
+    LIST_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;
+}
+
+/* The pci config space got updated. Check if irq numbers have changed
+ * for our devices
+ */
+void assigned_dev_update_irqs()
+{
+    AssignedDevInfo *adev;
+
+    adev = LIST_FIRST(&adev_head);
+    while (adev) {
+        AssignedDevInfo *next = LIST_NEXT(adev, next);
+        int r;
+
+        r = assign_irq(adev);
+        if (r < 0)
+            remove_assigned_device(adev);
+
+        adev = 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;
+}
+
+struct PCIDevice *init_assigned_device(AssignedDevInfo *adev,
+                                       const char *devaddr)
+{
+    PCIBus *bus;
+    int devfn;
+    int r;
+    AssignedDevice *dev;
+    PCIDevice *pci_dev;
+    struct pci_access *pacc;
+    uint8_t e_device, e_intx;
+
+    DEBUG("Registering real physical device %s (bus=%x dev=%x func=%x)\n",
+          adev->name, adev->bus, adev->dev, adev->func);
+
+    bus = pci_get_bus_devfn(&devfn, devaddr);
+    pci_dev = pci_register_device(bus, adev->name,
+              sizeof(AssignedDevice), devfn, assigned_dev_pci_read_config,
+              assigned_dev_pci_write_config);
+    dev = container_of(pci_dev, AssignedDevice, dev);
+
+    if (NULL == dev) {
+        fprintf(stderr, "%s: Error: Couldn't register real device %s\n",
+                __func__, adev->name);
+        return NULL;
+    }
+
+    adev->assigned_dev = dev;
+
+    if (get_real_device(dev, adev->bus, adev->dev, adev->func)) {
+        fprintf(stderr, "%s: Error: Couldn't get real device (%s)!\n",
+                __func__, adev->name);
+        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 = adev->bus;
+    dev->h_devfn = PCI_DEVFN(adev->dev, adev->func);
+
+    pacc = pci_alloc();
+    pci_init(pacc);
+    dev->pdev = pci_get_dev(pacc, 0, adev->bus, adev->dev, adev->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(adev);
+    if (r < 0)
+        goto assigned_out;
+
+    /* assign irq for the device */
+    r = assign_irq(adev);
+    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))
+            return NULL;
+
+    return &dev->dev;
+
+assigned_out:
+    deassign_device(adev);
+out:
+    free_assigned_device(adev);
+    return NULL;
+}
+
+/*
+ * 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.
+ */
+AssignedDevInfo *add_assigned_device(const char *arg)
+{
+    char device[16];
+    char dma[6];
+    int r;
+    AssignedDevInfo *adev;
+
+    adev = qemu_mallocz(sizeof(AssignedDevInfo));
+    if (adev == NULL) {
+        fprintf(stderr, "%s: Out of memory\n", __func__);
+        return NULL;
+    }
+    r = get_param_value(device, sizeof(device), "host", arg);
+    if (!r)
+         goto bad;
+
+    r = pci_parse_host_devaddr(device, &adev->bus, &adev->dev, &adev->func);
+    if (r)
+        goto bad;
+
+    r = get_param_value(adev->name, sizeof(adev->name), "name", arg);
+    if (!r)
+	snprintf(adev->name, sizeof(adev->name), "%s", device);
+
+#ifdef KVM_CAP_IOMMU
+    r = get_param_value(dma, sizeof(dma), "dma", arg);
+    if (r && !strncmp(dma, "none", 4))
+        adev->disable_iommu = 1;
+#endif
+
+    LIST_INSERT_HEAD(&adev_head, adev, next);
+    return adev;
+bad:
+    fprintf(stderr, "pcidevice argument parse error; "
+            "please check the help text for usage\n");
+    qemu_free(adev);
+    return NULL;
+}
+
+void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices)
+{
+    int i;
+
+    for (i = 0; i < n_devices; i++) {
+        struct AssignedDevInfo *adev;
+
+        adev = add_assigned_device(devices[i]);
+        if (!adev) {
+            fprintf(stderr, "Could not add assigned device %s\n", devices[i]);
+            exit(1);
+        }
+
+        if (!init_assigned_device(adev, NULL)) {
+            fprintf(stderr, "Failed to initialize assigned device %s\n",
+                    devices[i]);
+            exit(1);
+        }
+    }
+}
+
+/* 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 int scan_option_rom(uint8_t devfn, void *roms, ram_addr_t offset)
+{
+    int i, size, total_size;
+    uint8_t csum;
+    ram_addr_t addr;
+    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 0;
+
+ found:
+    /* The size should be both 2K-aligned and page-aligned */
+    total_size = (TARGET_PAGE_SIZE < 2048)
+                  ? OPTION_ROM_ALIGN(size + 1)
+                  : TARGET_PAGE_ALIGN(size + 1);
+
+    /* Size of all available ram space is 0x10000 (0xd0000 to 0xe0000) */
+    if ((offset + total_size) > 0x10000u) {
+        fprintf(stderr, "Option ROM size %x exceeds available space\n", size);
+        return 0;
+    }
+
+    addr = qemu_ram_alloc(total_size);
+    cpu_register_physical_memory(0xd0000 + offset, total_size, addr | IO_MEM_ROM);
+
+    /* Write ROM data and devfn to phys_addr */
+    cpu_physical_memory_write_rom(0xd0000 + offset, (uint8_t *)rom, size);
+    cpu_physical_memory_write_rom(0xd0000 + offset + size, &devfn, 1);
+
+    return total_size;
+}
+
+/*
+ * 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.
+ */
+ram_addr_t assigned_dev_load_option_roms(ram_addr_t rom_base_offset)
+{
+    ram_addr_t offset = rom_base_offset;
+    AssignedDevInfo *adev;
+
+    LIST_FOREACH(adev, &adev_head, next) {
+        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",
+                 adev->bus, adev->dev, adev->func);
+
+        if (access(rom_file, F_OK))
+            continue;
+
+        /* Write something to the ROM file to enable it */
+        fp = fopen(rom_file, "wb");
+        if (fp == NULL)
+            continue;
+        len = fwrite(&i, 1, 1, fp);
+        fclose(fp);
+        if (len != 1)
+            continue;
+
+        /* The file has to be closed and reopened, otherwise it won't work */
+        fp = fopen(rom_file, "rb");
+        if (fp == NULL)
+            continue;
+
+        fseek(fp, 0, SEEK_END);
+        size = ftell(fp);
+        fseek(fp, 0, SEEK_SET);
+
+        buf = malloc(size);
+        if (buf == NULL) {
+            fclose(fp);
+            continue;
+        }
+
+        fread(buf, size, 1, fp);
+        if (!feof(fp) || ferror(fp)) {
+            free(buf);
+            fclose(fp);
+            continue;
+        }
+
+        /* Copy ROM contents into the space backing the ROM BAR */
+        if (adev->assigned_dev->v_addrs[PCI_ROM_SLOT].r_size >= size &&
+            adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase) {
+            mprotect(adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+                     size, PROT_READ | PROT_WRITE);
+            memcpy(adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+                   buf, size);
+            mprotect(adev->assigned_dev->v_addrs[PCI_ROM_SLOT].u.r_virtbase,
+                     size, PROT_READ);
+        }
+
+        /* Scan the buffer for suitable ROMs and increase the offset */
+        offset += scan_option_rom(adev->assigned_dev->dev.devfn, buf, offset);
+
+        free(buf);
+        fclose(fp);
+    }
+
+    return offset;
+}
diff --git a/hw/device-assignment.h b/hw/device-assignment.h
new file mode 100644
index 0000000..0be62f4
--- /dev/null
+++ b/hw/device-assignment.h
@@ -0,0 +1,124 @@
+/*
+ * 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 "sys-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 {
+    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 {
+    target_phys_addr_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[] */
+    uint32_t e_size;    /* emulated size of region in bytes */
+    uint32_t r_size;    /* real size of region in bytes */
+} AssignedDevRegion;
+
+typedef struct {
+    PCIDevice dev;
+    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;
+} AssignedDevice;
+
+typedef struct AssignedDevInfo AssignedDevInfo;
+
+struct AssignedDevInfo {
+    char name[15];
+    int bus;
+    int dev;
+    int func;
+    AssignedDevice *assigned_dev;
+    LIST_ENTRY(AssignedDevInfo) next;
+    int disable_iommu;
+};
+
+PCIDevice *init_assigned_device(AssignedDevInfo *adev, const char *devaddr);
+AssignedDevInfo *add_assigned_device(const char *arg);
+void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices);
+void remove_assigned_device(AssignedDevInfo *adev);
+AssignedDevInfo *get_assigned_device(int pcibus, int slot);
+ram_addr_t assigned_dev_load_option_roms(ram_addr_t rom_base_offset);
+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 01b10aa..a740df5 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -205,6 +205,9 @@
             qemu_get_timer(f, s->timer[i].qemu_timer);
         }
     }
+    if (hpet_in_legacy_mode()) {
+        hpet_disable_pit();
+    }
     return 0;
 }
 
@@ -474,9 +477,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:
@@ -560,7 +565,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/i8254-kvm.c b/hw/i8254-kvm.c
new file mode 100644
index 0000000..c54052c
--- /dev/null
+++ b/hw/i8254-kvm.c
@@ -0,0 +1,117 @@
+/*
+ * 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"
+
+static PITState pit_state;
+
+static void kvm_pit_save(QEMUFile *f, void *opaque)
+{
+    PITState *s = 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;
+    }
+
+    pit_save(f, s);
+}
+
+static int kvm_pit_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PITState *s = opaque;
+    struct kvm_pit_state2 pit2;
+    struct kvm_pit_channel_state *c;
+    struct PITChannelState *sc;
+    int i;
+
+    pit_load(f, s, version_id);
+
+    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;
+}
+
+PITState *kvm_pit_init(int base, qemu_irq irq)
+{
+    PITState *pit = &pit_state;
+
+    register_savevm(PIT_SAVEVM_NAME, base, PIT_SAVEVM_VERSION,
+		    kvm_pit_save, kvm_pit_load, pit);
+
+    qemu_register_reset(pit_reset, pit);
+    pit_reset(pit);
+
+    return pit;
+}
diff --git a/hw/i8254.c b/hw/i8254.c
index 44e4531..34a716c 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);
@@ -224,13 +197,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 */
@@ -290,17 +268,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;
         }
@@ -360,6 +338,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;
@@ -370,16 +353,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) / 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)
@@ -389,12 +391,13 @@
     pit_irq_timer_update(s, s->next_transition_time);
 }
 
-static void pit_save(QEMUFile *f, void *opaque)
+void pit_save(QEMUFile *f, void *opaque)
 {
     PITState *pit = opaque;
     PITChannelState *s;
     int i;
 
+    qemu_put_be32(f, pit->flags);
     for(i = 0; i < 3; i++) {
         s = &pit->channels[i];
         qemu_put_be32(f, s->count);
@@ -417,15 +420,16 @@
     }
 }
 
-static int pit_load(QEMUFile *f, void *opaque, int version_id)
+int pit_load(QEMUFile *f, void *opaque, int version_id)
 {
     PITState *pit = opaque;
     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,44 +450,71 @@
             qemu_get_timer(f, s->irq_timer);
         }
     }
+
     return 0;
 }
 
-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)
 {
@@ -495,7 +526,8 @@
     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
     s->irq = irq;
 
-    register_savevm("i8254", base, 1, pit_save, pit_load, pit);
+    register_savevm(PIT_SAVEVM_NAME, base, PIT_SAVEVM_VERSION,
+		    pit_save, pit_load, pit);
 
     qemu_register_reset(pit_reset, pit);
     register_ioport_write(base, 4, 1, pit_ioport_write, pit);
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 0b9fab5..19c9d17 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
 
@@ -184,7 +186,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)
@@ -218,18 +219,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) {
@@ -451,7 +469,7 @@
     return s->elcr;
 }
 
-static void pic_save(QEMUFile *f, void *opaque)
+static void pic_save_common(QEMUFile *f, void *opaque)
 {
     PicState *s = opaque;
 
@@ -473,7 +491,12 @@
     qemu_put_8s(f, &s->elcr);
 }
 
-static int pic_load(QEMUFile *f, void *opaque, int version_id)
+static void pic_save(QEMUFile *f, void *opaque)
+{
+    pic_save_common(f, opaque);
+}
+
+static int pic_load_common(QEMUFile *f, void *opaque, int version_id)
 {
     PicState *s = opaque;
 
@@ -496,9 +519,15 @@
     qemu_get_8s(f, &s->init4);
     qemu_get_8s(f, &s->single_mode);
     qemu_get_8s(f, &s->elcr);
+
     return 0;
 }
 
+static int pic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return pic_load_common(f, opaque, version_id);
+}
+
 /* XXX: add generic master/slave system */
 static void pic_init1(int io_addr, int elcr_addr, PicState *s)
 {
@@ -569,3 +598,118 @@
     s->alt_irq_func = alt_irq_func;
     s->alt_irq_opaque = alt_irq_opaque;
 }
+
+#ifdef KVM_CAP_IRQCHIP
+static void kvm_kernel_pic_save_to_user(PicState *s)
+{
+#if defined(TARGET_I386)
+    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 void kvm_kernel_pic_load_from_user(PicState *s)
+{
+#if defined(TARGET_I386)
+    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
+}
+
+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_save(QEMUFile *f, void *opaque)
+{
+    PicState *s = opaque;
+
+    kvm_kernel_pic_save_to_user(s);
+    pic_save_common(f, opaque);
+}
+
+static int kvm_pic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PicState *s = opaque;
+    int r = pic_load_common(f, s, version_id);
+    if (r == 0)
+        kvm_kernel_pic_load_from_user(s);
+    return r;
+}
+
+static void kvm_pic_init1(int io_addr, PicState *s)
+{
+    register_savevm("i8259", io_addr, 1, kvm_pic_save, kvm_pic_load, 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, 16);
+}
+#endif
+
+
diff --git a/hw/ioapic.c b/hw/ioapic.c
index a5cdd5d..32019de 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,13 +197,62 @@
     }
 }
 
+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_save(QEMUFile *f, void *opaque)
 {
     IOAPICState *s = opaque;
     int i;
 
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+        kvm_kernel_ioapic_save_to_user(s);
+    }
+
     qemu_put_8s(f, &s->id);
     qemu_put_8s(f, &s->ioregsel);
+    qemu_put_be64s(f, &s->base_address);
+    qemu_put_be32s(f, &s->irr);
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
         qemu_put_be64s(f, &s->ioredtbl[i]);
     }
@@ -208,14 +263,29 @@
     IOAPICState *s = opaque;
     int i;
 
-    if (version_id != 1)
+    if (version_id < 1 || version_id > 2)
         return -EINVAL;
 
     qemu_get_8s(f, &s->id);
     qemu_get_8s(f, &s->ioregsel);
+    if (version_id == 2) {
+      /* for version 2, we get this data off of the wire */
+      qemu_get_be64s(f, &s->base_address);
+      qemu_get_be32s(f, &s->irr);
+    }
+    else {
+      /* in case we are doing version 1, we just set these to sane values */
+      s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
+      s->irr = 0;
+    }
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
         qemu_get_be64s(f, &s->ioredtbl[i]);
     }
+
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+        kvm_kernel_ioapic_load_from_user(s);
+    }
+
     return 0;
 }
 
@@ -225,8 +295,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() && qemu_kvm_irqchip_in_kernel()) {
+        kvm_kernel_ioapic_load_from_user(s);
+    }
+#endif
 }
 
 static CPUReadMemoryFunc *ioapic_mem_read[3] = {
@@ -253,7 +329,7 @@
                                        ioapic_mem_write, s);
     cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
 
-    register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
+    register_savevm("ioapic", 0, 2, ioapic_save, ioapic_load, s);
     qemu_register_reset(ioapic_reset, s);
 
     return s;
diff --git a/hw/ipf.c b/hw/ipf.c
new file mode 100644
index 0000000..04b7b2c
--- /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 USE_KVM_DEVICE_ASSIGNMENT
+    if (kvm_enabled())
+	add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
+#endif /* USE_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 c954d47..b6c3f17 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -14,6 +14,7 @@
 #include "hw.h"
 #include "msix.h"
 #include "pci.h"
+#include "qemu-kvm.h"
 
 /* Declaration from linux/pci_regs.h */
 #define  PCI_CAP_ID_MSIX 0x11 /* MSI-X */
@@ -62,6 +63,110 @@
 /* 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;
+
+    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.
@@ -109,6 +214,9 @@
 static void msix_free_irq_entries(PCIDevice *dev)
 {
     int vector;
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+        kvm_msix_free(dev);
+    }
 
     for (vector = 0; vector < dev->msix_entries_nr; ++vector)
         dev->msix_entry_used[vector] = 0;
@@ -181,7 +289,11 @@
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1);
     int vector = offset / MSIX_ENTRY_SIZE;
+    int was_masked = msix_is_masked(dev, vector);
     memcpy(dev->msix_table_page + offset, &val, 4);
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+        kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
+    }
     if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
         msix_clr_pending(dev, vector);
         msix_notify(dev, vector);
@@ -234,6 +346,12 @@
     if (nentries > MSIX_MAX_ENTRIES)
         return -EINVAL;
 
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && qemu_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);
 
@@ -279,6 +397,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;
 }
@@ -287,10 +407,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);
 }
@@ -300,6 +423,9 @@
 {
     unsigned n = dev->msix_entries_nr;
 
+    if (!msix_supported)
+        return;
+
     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
         return;
     }
@@ -344,6 +470,13 @@
         return;
     }
 
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && qemu_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);
@@ -370,15 +503,29 @@
 /* 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() && qemu_kvm_irqchip_in_kernel()) {
+        ret = kvm_msix_add(dev, vector);
+        if (ret) {
+            return ret;
+        }
+    }
+    ++dev->msix_entry_used[vector];
     return 0;
 }
 
 /* Mark vector as unused. */
 void msix_vector_unuse(PCIDevice *dev, unsigned vector)
 {
-    if (vector < dev->msix_entries_nr && dev->msix_entry_used[vector])
+    if (vector < dev->msix_entries_nr && dev->msix_entry_used[vector]) {
         --dev->msix_entry_used[vector];
+        if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+            kvm_msix_del(dev, vector);
+        }
+    }
 }
diff --git a/hw/pc.c b/hw/pc.c
index d262b76..bcd2989 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,6 +36,9 @@
 #include "hpet_emul.h"
 #include "watchdog.h"
 #include "smbios.h"
+#include "device-assignment.h"
+
+#include "qemu-kvm.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -46,6 +49,7 @@
 #define BIOS_FILENAME "bios.bin"
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
+#define EXTBOOT_FILENAME "extboot.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
 
@@ -54,6 +58,7 @@
 #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)
 
 #define MAX_IDE_BUS 2
 
@@ -476,6 +481,7 @@
     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
                      acpi_tables_len);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
 
     smbios_table = smbios_get_table(&smbios_len);
     if (smbios_table)
@@ -1081,22 +1087,25 @@
 	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;
+        CPUState *env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find x86 CPU definition\n");
+            exit(1);
+        }
+        if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
+            env->cpuid_apic_id = env->cpu_index;
+            /* APIC reset callback resets cpu */
+            apic_init(env);
+        } else {
+            qemu_register_reset((QEMUResetHandler*)cpu_reset, env);
+        }
 
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to find x86 CPU definition\n");
-        exit(1);
-    }
-    if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
-        env->cpuid_apic_id = env->cpu_index;
-        /* APIC reset callback resets cpu */
-        apic_init(env);
-    } 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;
 }
 
@@ -1114,6 +1123,7 @@
     ram_addr_t ram_addr, bios_offset, option_rom_offset;
     ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
     int bios_size, isa_bios_size, oprom_area_size;
+    int pci_option_rom_offset = 0;
     PCIBus *pci_bus;
     PCIDevice *pci_dev;
     int piix3_devfn = -1;
@@ -1144,6 +1154,9 @@
 #endif
     }
 
+    if (kvm_enabled()) {
+        kvm_set_boot_cpu_id(0);
+    }
     for (i = 0; i < smp_cpus; i++) {
         env = pc_new_cpu(cpu_model);
     }
@@ -1151,18 +1164,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) {
@@ -1204,11 +1210,16 @@
     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 != -1) {
+        option_rom[nb_option_roms++] = qemu_strdup(EXTBOOT_FILENAME);
+    }
 
     option_rom_offset = qemu_ram_alloc(0x20000);
     oprom_area_size = 0;
@@ -1223,6 +1234,7 @@
             vgabios_filename = VGABIOS_FILENAME;
         }
         oprom_area_size = load_option_rom(vgabios_filename, 0xc0000, 0xe0000);
+        pci_option_rom_offset = oprom_area_size;
     }
     /* Although video roms can grow larger than 0x8000, the area between
      * 0xc0000 - 0xc8000 is reserved for them. It means we won't be looking
@@ -1255,7 +1267,7 @@
             continue;
 
         if (model == NULL)
-            model = "ne2k_pci";
+            model = "rtl8139";
         snprintf(nic_oprom, sizeof(nic_oprom), "pxe-%s.bin", model);
 
         oprom_area_size += load_option_rom(nic_oprom, 0xc0000 + oprom_area_size,
@@ -1263,7 +1275,12 @@
     }
 
     cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
-    i8259 = i8259_init(cpu_irq[0]);
+#ifdef KVM_CAP_IRQCHIP
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel()) {
+        i8259 = kvm_i8259_init(cpu_irq[0]);
+    } else
+#endif
+        i8259 = i8259_init(cpu_irq[0]);
     ferr_irq = i8259[13];
 
     if (pci_enabled) {
@@ -1307,7 +1324,12 @@
     if (pci_enabled) {
         ioapic = ioapic_init();
     }
-    pit = pit_init(0x40, i8259[0]);
+#ifdef USE_KVM_PIT
+    if (kvm_enabled() && qemu_kvm_pit_in_kernel())
+	pit = kvm_pit_init(0x40, i8259[0]);
+    else
+#endif
+	pit = pit_init(0x40, i8259[0]);
     pcspk_init(pit);
     if (!no_hpet) {
         hpet_init(i8259);
@@ -1338,10 +1360,10 @@
         if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
             pc_init_ne2k_isa(nd, i8259);
         else
-            pci_nic_init(nd, "ne2k_pci", NULL);
+            pci_nic_init(nd, "rtl8139", NULL);
     }
 
-    piix4_acpi_system_hot_add_init();
+    piix4_acpi_system_hot_add_init(cpu_model);
 
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
         fprintf(stderr, "qemu: too many IDE bus\n");
@@ -1428,6 +1450,18 @@
         }
     }
 
+    if (extboot_drive != -1) {
+	DriveInfo *info = &drives_table[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 balloon device */
     if (pci_enabled && virtio_balloon) {
         pci_dev = pci_create("virtio-balloon-pci", virtio_balloon_devaddr);
@@ -1442,6 +1476,13 @@
             }
         }
     }
+
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+    if (kvm_enabled()) {
+        add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
+        assigned_dev_load_option_roms(pci_option_rom_offset);
+    }
+#endif /* USE_KVM_DEVICE_ASSIGNMENT */
 }
 
 static void pc_init_pci(ram_addr_t ram_size,
diff --git a/hw/pc.h b/hw/pc.h
index 9fbae20..26bf616 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -32,6 +32,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);
 void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
                           void *alt_irq_opaque);
 int pic_read_irq(PicState2 *s);
@@ -54,6 +55,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 */
 
@@ -68,8 +70,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);
@@ -102,6 +108,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;
@@ -115,7 +122,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(void);
+void piix4_acpi_system_hot_add_init(const char *model);
 
 /* hpet.c */
 extern int no_hpet;
@@ -125,6 +132,9 @@
 int pcspk_audio_init(qemu_irq *pic);
 
 /* piix_pci.c */
+/* config space register for IRQ routing */
+#define PIIX_CONFIG_IRQ_ROUTE 0x60
+
 PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic);
 void i440fx_set_smm(PCIDevice *d, int val);
 int piix3_init(PCIBus *bus, int devfn);
@@ -133,6 +143,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,
@@ -165,5 +179,10 @@
 
 void isa_ne2000_init(int base, qemu_irq 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 d0f2911..1180758 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -31,6 +31,7 @@
 #include "monitor.h"
 #include "block_int.h"
 #include "virtio-blk.h"
+#include "device-assignment.h"
 
 #if defined(TARGET_I386) || defined(TARGET_X86_64)
 static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
@@ -143,6 +144,45 @@
     return dev;
 }
 
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+static PCIDevice *qemu_pci_hot_assign_device(Monitor *mon,
+                                             const char *devaddr,
+                                             const char *opts)
+{
+    AssignedDevInfo *adev;
+    PCIDevice *ret;
+
+    adev = add_assigned_device(opts);
+    if (adev == NULL) {
+        monitor_printf(mon, "Error adding device; check syntax\n");
+        return NULL;
+    }
+
+    ret = init_assigned_device(adev, devaddr);
+    if (ret == NULL) {
+        monitor_printf(mon, "Failed to assign device\n");
+        return NULL;
+    }
+
+    monitor_printf(mon,
+                   "Registered host PCI device %02x:%02x.%1x "
+                   "(\"%s\") as guest device %s\n",
+                   adev->bus, adev->dev, adev->func, adev->name, devaddr);
+
+    return ret;
+}
+
+static void qemu_pci_hot_deassign_device(Monitor *mon, AssignedDevInfo *adev)
+{
+    remove_assigned_device(adev);
+
+    monitor_printf(mon,
+                   "Unregister host PCI device %02x:%02x.%1x "
+                   "(\"%s\") from guest\n",
+                   adev->bus, adev->dev, adev->func, adev->name);
+}
+#endif /* USE_KVM_DEVICE_ASSIGNMENT */
+
 void pci_device_hot_add(Monitor *mon, const char *pci_addr, const char *type,
                         const char *opts)
 {
@@ -164,6 +204,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 USE_KVM_DEVICE_ASSIGNMENT
+    else if (strcmp(type, "host") == 0)
+        dev = qemu_pci_hot_assign_device(mon, pci_addr, opts);
+#endif /* USE_KVM_DEVICE_ASSIGNMENT */
     else
         monitor_printf(mon, "invalid type: %s\n", type);
 
@@ -212,12 +256,23 @@
 {
     PCIDevice *d = pci_find_device(pcibus, slot, 0);
     int class_code;
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+    AssignedDevInfo *adev;
+#endif
 
     if (!d) {
         monitor_printf(cur_mon, "invalid slot %d\n", slot);
         return;
     }
 
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+    adev = get_assigned_device(pcibus, slot);
+    if (adev) {
+        qemu_pci_hot_deassign_device(cur_mon, adev);
+        return;
+    }
+#endif /* USE_KVM_DEVICE_ASSIGNMENT */
+
     class_code = d->config_read(d, PCI_CLASS_DEVICE+1, 1);
 
     switch(class_code) {
@@ -229,6 +284,6 @@
         break;
     }
 
-    pci_unregister_device(d);
+    pci_unregister_device(d, 0);
 }
 
diff --git a/hw/pci.c b/hw/pci.c
index 3b5a947..a575d4a 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -26,6 +26,9 @@
 #include "monitor.h"
 #include "net.h"
 #include "sysemu.h"
+#include "pc.h"
+#include "qemu-kvm.h"
+#include "device-assignment.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -206,6 +209,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)
@@ -254,6 +258,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)
 {
@@ -268,7 +321,7 @@
     return 0;
 }
 
-static PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
+PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
 {
     int dom, bus;
     unsigned slot;
@@ -380,7 +433,7 @@
     }
 }
 
-int pci_unregister_device(PCIDevice *pci_dev)
+int pci_unregister_device(PCIDevice *pci_dev, int assigned)
 {
     int ret = 0;
 
@@ -393,7 +446,11 @@
 
     qemu_free_irqs(pci_dev->irq);
     pci_dev->bus->devices[pci_dev->devfn] = NULL;
-    qdev_free(&pci_dev->qdev);
+
+    if (assigned)
+        qemu_free(pci_dev);
+    else
+        qdev_free(&pci_dev->qdev);
     return 0;
 }
 
@@ -513,8 +570,8 @@
     }
 }
 
-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;
 
@@ -539,21 +596,74 @@
     return val;
 }
 
+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);
+}
+
+uint32_t pci_default_read_config(PCIDevice *d,
+                                 uint32_t address, int len)
+{
+    if (pci_access_cap_config(d, address, len))
+        return d->cap.config_read(d, address, len);
+
+    return pci_read_config(d, address, len);
+}
+
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
     uint8_t orig[PCI_CONFIG_SPACE_SIZE];
     int i;
 
+    if (pci_access_cap_config(d, addr, l)) {
+        d->cap.config_write(d, addr, val, l);
+        return;
+    }
+
     /* not efficient, but simple */
     memcpy(orig, d->config, PCI_CONFIG_SPACE_SIZE);
     for(i = 0; i < l && addr < PCI_CONFIG_SPACE_SIZE; val >>= 8, ++i, ++addr) {
         uint8_t wmask = d->wmask[addr];
         d->config[addr] = (d->config[addr] & ~wmask) | (val & wmask);
     }
+
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+    if (kvm_enabled() && qemu_kvm_irqchip_in_kernel() &&
+        addr >= PIIX_CONFIG_IRQ_ROUTE &&
+	addr < PIIX_CONFIG_IRQ_ROUTE + 4)
+        assigned_dev_update_irqs();
+#endif /* USE_KVM_DEVICE_ASSIGNMENT */
+
     if (memcmp(orig + PCI_BASE_ADDRESS_0, d->config + PCI_BASE_ADDRESS_0, 24)
         || ((orig[PCI_COMMAND] ^ d->config[PCI_COMMAND])
             & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)))
         pci_update_mappings(d);
+
 }
 
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
@@ -636,6 +746,11 @@
         return;
 
     pci_dev->irq_state[irq_num] = level;
+
+#if defined(TARGET_IA64)
+    ioapic_set_irq(pci_dev, irq_num, level);
+#endif
+
     for (;;) {
         bus = pci_dev->bus;
         irq_num = bus->map_irq(pci_dev, irq_num);
@@ -647,6 +762,11 @@
     bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
 }
 
+int pci_map_irq(PCIDevice *pci_dev, int pin)
+{
+    return pci_dev->bus->map_irq(pci_dev, pin);
+}
+
 /***********************************************************/
 /* monitor info on PCI */
 
@@ -936,6 +1056,37 @@
     return (PCIDevice *)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 offset = PCI_CONFIG_HEADER_SIZE;
diff --git a/hw/pci.h b/hw/pci.h
index cbfea6a..7ca3ba9 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))
@@ -78,6 +83,12 @@
                                 uint32_t addr, uint32_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);
+
 #define PCI_ADDRESS_SPACE_MEM		0x00
 #define PCI_ADDRESS_SPACE_IO		0x01
 #define PCI_ADDRESS_SPACE_MEM_PREFETCH	0x08
@@ -133,10 +144,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 | \
@@ -160,6 +180,11 @@
     QEMU_PCI_CAP_MSIX = 0x1,
 };
 
+#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 */
@@ -209,18 +234,35 @@
     unsigned *msix_entry_used;
     /* Region including the MSI-X table */
     uint32_t msix_bar_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,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write);
-int pci_unregister_device(PCIDevice *pci_dev);
+int pci_unregister_device(PCIDevice *pci_dev, int assigned);
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
                             uint32_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);
@@ -229,13 +271,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)(qemu_irq *pic, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
@@ -255,6 +301,10 @@
 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);
+PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
+
 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..3d3eba4 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 USE_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 fce01d4..2a5fb01 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -26,6 +26,8 @@
 #include "pc.h"
 #include "pci.h"
 
+#include "qemu-kvm.h"
+
 typedef uint32_t pci_addr_t;
 #include "pci_host.h"
 
@@ -91,6 +93,10 @@
     int i, r;
     uint32_t smram, addr;
 
+    if (kvm_enabled()) {
+        /* FIXME: Support remappings and protection changes. */
+        return;
+    }
     update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3);
     for(i = 0; i < 12; i++) {
         r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
@@ -232,6 +238,16 @@
     }
 }
 
+int piix_get_irq(int pin)
+{
+    if (piix3_dev)
+        return piix3_dev->config[0x60+pin];
+    if (piix4_dev)
+        return piix4_dev->config[0x60+pin];
+
+    return 0;
+}
+
 static void piix3_reset(void *opaque)
 {
     PCIDevice *d = opaque;
diff --git a/hw/ppc440.c b/hw/ppc440.c
index 5171988..aefc019 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -19,6 +19,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 d9ef3ec..c74aa2f 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -22,6 +22,7 @@
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "device_tree.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 c0e367d..db52cdd 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -29,6 +29,7 @@
 #include "device_tree.h"
 #include "openpic.h"
 #include "ppce500.h"
+#include "qemu-kvm.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
diff --git a/hw/vga.c b/hw/vga.c
index c5abd299..31bf369 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -29,6 +29,7 @@
 #include "pixel_ops.h"
 #include "qemu-timer.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
@@ -1281,6 +1282,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;
@@ -1579,6 +1582,7 @@
         cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
         cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
     }
+    vga_dirty_log_start(s);
 }
 
 /*
@@ -1810,6 +1814,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)];
@@ -1854,6 +1859,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:
@@ -2226,17 +2234,48 @@
     VGAState vga_state;
 } PCIVGAState;
 
+static int s1, s2;
+
+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(VGAState *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;
     }
 }
 
+void vga_dirty_log_stop(VGAState *s)
+{
+    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 && s2) {
+        kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
+        kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
+    }
+    s1 = s2 = 0;
+}
+
 static void vga_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
 {
@@ -2246,10 +2285,12 @@
         cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
     } else {
         cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
-        s->map_addr = addr;
-        s->map_end = addr + s->vram_size;
-        vga_dirty_log_start(s);
     }
+
+    s->map_addr = addr;
+    s->map_end = addr + VGA_RAM_SIZE;
+
+    vga_dirty_log_start(s);
 }
 
 void vga_common_init(VGAState *s, int vga_ram_size)
@@ -2477,9 +2518,11 @@
     PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
     VGAState *s = &pvs->vga_state;
 
+    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);
 }
 
 int pci_vga_init(PCIBus *bus,
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 631b1b0..1aaf5c5 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -30,8 +30,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
@@ -194,6 +194,7 @@
 void vga_reset(void *s);
 
 void vga_dirty_log_start(VGAState *s);
+void vga_dirty_log_stop(VGAState *s);
 
 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
@@ -216,5 +217,5 @@
 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)
 
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 04f8873..663c8b9 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/virtio-net.c b/hw/virtio-net.c
index 7a7eafe..ce8e6cb 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -15,6 +15,11 @@
 #include "net.h"
 #include "qemu-timer.h"
 #include "virtio-net.h"
+#ifdef CONFIG_KVM
+#include "qemu-kvm.h"
+#endif
+
+#define TAP_VNET_HDR
 
 #define VIRTIO_NET_VM_VERSION    10
 
@@ -130,6 +135,25 @@
                         (1 << VIRTIO_NET_F_CTRL_VLAN) |
                         (1 << VIRTIO_NET_F_CTRL_RX_EXTRA);
 
+#ifdef TAP_VNET_HDR
+    VirtIONet *n = to_virtio_net(vdev);
+    VLANClientState *host = n->vc->vlan->first_client;
+
+    if (tap_has_vnet_hdr(host)) {
+        tap_using_vnet_hdr(host, 1);
+        features |= (1 << VIRTIO_NET_F_CSUM);
+        features |= (1 << VIRTIO_NET_F_GUEST_CSUM);
+        features |= (1 << VIRTIO_NET_F_GUEST_TSO4);
+        features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
+        features |= (1 << VIRTIO_NET_F_GUEST_ECN);
+        features |= (1 << VIRTIO_NET_F_HOST_TSO4);
+        features |= (1 << VIRTIO_NET_F_HOST_TSO6);
+        features |= (1 << VIRTIO_NET_F_HOST_ECN);
+        features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
+        /* Kernel can't actually handle UFO in software currently. */
+    }
+#endif
+
     return features;
 }
 
@@ -151,8 +175,22 @@
 static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
 {
     VirtIONet *n = to_virtio_net(vdev);
+#ifdef TAP_VNET_HDR
+    VLANClientState *host = n->vc->vlan->first_client;
+#endif
 
     n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
+
+#ifdef TAP_VNET_HDR
+    if (!tap_has_vnet_hdr(host) || !host->set_offload)
+        return;
+
+    host->set_offload(host,
+                      (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                      (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                      (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                      (features >> VIRTIO_NET_F_GUEST_ECN)  & 1);
+#endif
 }
 
 static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
@@ -305,6 +343,10 @@
     VirtIONet *n = to_virtio_net(vdev);
 
     qemu_flush_queued_packets(n->vc);
+
+    /* We now have RX buffers, signal to the IO thread to break out of the
+     * select to re-poll the tap file descriptor */
+    qemu_notify_event();
 }
 
 static int do_virtio_net_can_receive(VirtIONet *n, int bufsize)
@@ -331,6 +373,36 @@
     return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);
 }
 
+#ifdef TAP_VNET_HDR
+/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
+ * it never finds out that the packets don't have valid checksums.  This
+ * causes dhclient to get upset.  Fedora's carried a patch for ages to
+ * fix this with Xen but it hasn't appeared in an upstream release of
+ * dhclient yet.
+ *
+ * To avoid breaking existing guests, we catch udp packets and add
+ * checksums.  This is terrible but it's better than hacking the guest
+ * kernels.
+ *
+ * N.B. if we introduce a zero-copy API, this operation is no longer free so
+ * we should provide a mechanism to disable it to avoid polluting the host
+ * cache.
+ */
+static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
+                                        const uint8_t *buf, size_t size)
+{
+    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
+        (size > 27 && size < 1500) && /* normal sized MTU */
+        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
+        (buf[23] == 17) && /* ip.protocol == UDP */
+        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
+        /* FIXME this cast is evil */
+        net_checksum_calculate((uint8_t *)buf, size);
+        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
+    }
+}
+#endif
+
 static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
 {
     int offset, i;
@@ -347,7 +419,7 @@
 }
 
 static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
-                          const void *buf, size_t size, size_t hdr_len)
+                          const void *buf, size_t size, size_t hdr_len, int raw)
 {
     struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base;
     int offset = 0;
@@ -355,6 +427,18 @@
     hdr->flags = 0;
     hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
 
+#ifdef TAP_VNET_HDR
+    if (tap_has_vnet_hdr(n->vc->vlan->first_client)) {
+        if (!raw) {
+            memcpy(hdr, buf, sizeof(*hdr));
+        } else {
+            memset(hdr, 0, sizeof(*hdr));
+        }
+        offset = sizeof(*hdr);
+        work_around_broken_dhclient(hdr, buf + offset, size - offset);
+    }
+#endif
+
     /* We only ever receive a struct virtio_net_hdr from the tapfd,
      * but we may be passing along a larger header to the guest.
      */
@@ -374,6 +458,11 @@
     if (n->promisc)
         return 1;
 
+#ifdef TAP_VNET_HDR
+    if (tap_has_vnet_hdr(n->vc->vlan->first_client))
+        ptr += sizeof(struct virtio_net_hdr);
+#endif
+
     if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
         int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
         if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
@@ -413,7 +502,7 @@
     return 0;
 }
 
-static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+static ssize_t virtio_net_receive2(VLANClientState *vc, const uint8_t *buf, size_t size, int raw)
 {
     VirtIONet *n = vc->opaque;
     struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
@@ -463,7 +552,7 @@
                 mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
 
             offset += receive_header(n, sg, elem.in_num,
-                                     buf + offset, size - offset, hdr_len);
+                                     buf + offset, size - offset, hdr_len, raw);
             total += hdr_len;
         }
 
@@ -502,11 +591,25 @@
     virtio_net_flush_tx(n, n->tx_vq);
 }
 
+static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    return virtio_net_receive2(vc, buf, size, 0);
+}
+
+static ssize_t virtio_net_receive_raw(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    return virtio_net_receive2(vc, buf, size, 1);
+}
+
 /* TX */
 static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
 {
     VirtQueueElement elem;
+#ifdef TAP_VNET_HDR
+    int has_vnet_hdr = tap_has_vnet_hdr(n->vc->vlan->first_client);
+#else
     int has_vnet_hdr = 0;
+#endif
 
     if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
         return;
@@ -606,7 +709,13 @@
     qemu_put_be32(f, n->mac_table.in_use);
     qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
     qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
-    qemu_put_be32(f, 0); /* vnet-hdr placeholder */
+
+#ifdef TAP_VNET_HDR
+    qemu_put_be32(f, tap_has_vnet_hdr(n->vc->vlan->first_client));
+#else
+    qemu_put_be32(f, 0);
+#endif
+
     qemu_put_byte(f, n->mac_table.multi_overflow);
     qemu_put_byte(f, n->mac_table.uni_overflow);
     qemu_put_byte(f, n->alluni);
@@ -659,9 +768,13 @@
         qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
 
     if (version_id >= 7 && qemu_get_be32(f)) {
+#ifdef TAP_VNET_HDR
+        tap_using_vnet_hdr(n->vc->vlan->first_client, 1);
+#else
         fprintf(stderr,
                 "virtio-net: saved image requires vnet header support\n");
         exit(1);
+#endif
     }
 
     if (version_id >= 9) {
@@ -734,6 +847,7 @@
                                  virtio_net_receive, NULL,
                                  virtio_net_cleanup, n);
     n->vc->link_status_changed = virtio_net_set_link_status;
+    n->vc->receive_raw = virtio_net_receive_raw;
 
     qemu_format_nic_info_str(n->vc, n->mac);
 
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 8d2ede2..23c940d 100644
--- a/ia64.ld
+++ b/ia64.ld
@@ -9,7 +9,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 f4c51f6..5d9d0b6 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
 
@@ -362,6 +363,7 @@
     return ret;
 }
 
+#endif
 int kvm_check_extension(KVMState *s, unsigned int extension)
 {
     int ret;
@@ -373,6 +375,7 @@
 
     return ret;
 }
+#ifdef KVM_UPSTREAM
 
 int kvm_init(int smp_cpus)
 {
@@ -772,6 +775,7 @@
     }
 }
 
+#endif
 int kvm_ioctl(KVMState *s, int type, ...)
 {
     int ret;
@@ -806,6 +810,7 @@
     return ret;
 }
 
+#ifdef KVM_UPSTREAM
 int kvm_vcpu_ioctl(CPUState *env, int type, ...)
 {
     int ret;
@@ -852,6 +857,8 @@
     }
 }
 
+#endif /* KVM_UPSTREAM */
+
 #ifdef KVM_CAP_SET_GUEST_DEBUG
 struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
                                                  target_ulong pc)
@@ -870,6 +877,7 @@
     return !TAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
 }
 
+#ifdef KVM_UPSTREAM
 int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
 {
     struct kvm_guest_debug dbg;
@@ -883,6 +891,7 @@
 
     return kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg);
 }
+#endif
 
 int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
                           target_ulong len, int type)
@@ -1007,3 +1016,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..f7b6f3b
--- /dev/null
+++ b/kvm-tpr-opt.c
@@ -0,0 +1,390 @@
+/*
+ * 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->kvm_cpu_state.vcpu_ctx, &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->kvm_cpu_state.vcpu_ctx, &sregs);
+    stb_phys(map_addr(&sregs, virt, NULL), b);
+}
+
+static __u64 kvm_rsp_read(CPUState *env)
+{
+    struct kvm_regs regs;
+
+    kvm_get_regs(env->kvm_cpu_state.vcpu_ctx, &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 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;
+
+    if (bios_enabled)
+	return 1;
+
+    kvm_get_sregs(env->kvm_cpu_state.vcpu_ctx, &sregs);
+
+    probe = (rip & 0xf0000000) + 0xe0000;
+    phys = map_addr(&sregs, probe, &perms);
+    if (phys != 0xe0000)
+	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;
+
+    kvm_save_registers(env);
+
+    if (cpu_memory_rw_debug(env, env->segs[R_FS].base + 0x51, &b, 1, 0) < 0)
+	    return -1;
+
+    return (int)b;
+}
+
+static int 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->kvm_cpu_state.vcpu_ctx, vapic_phys + (pcr_cpu << 7));
+    cpu_physical_memory_rw(vapic_phys + (pcr_cpu << 7) + 4, &one, 1, 1);
+    bios_enabled = 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 (!enable_vapic(env))
+	return;
+    patch_instruction(env, rip);
+}
+
+void kvm_tpr_vcpu_start(CPUState *env)
+{
+    kvm_enable_tpr_access_reporting(env->kvm_cpu_state.vcpu_ctx);
+    if (bios_enabled)
+	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_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->kvm_cpu_state.vcpu_ctx, &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->kvm_cpu_state.vcpu_ctx, &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();
+    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);
+}
+
diff --git a/kvm.h b/kvm.h
index 5da8502..c4f21ec 100644
--- a/kvm.h
+++ b/kvm.h
@@ -16,6 +16,9 @@
 
 #include "config.h"
 #include "sys-queue.h"
+#include "qemu-kvm.h"
+
+#ifdef KVM_UPSTREAM
 
 #ifdef CONFIG_KVM
 extern int kvm_allowed;
@@ -136,3 +139,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/bios/.cvsignore b/kvm/bios/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/kvm/bios/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/kvm/bios/Makefile b/kvm/bios/Makefile
new file mode 100644
index 0000000..434d64e
--- /dev/null
+++ b/kvm/bios/Makefile
@@ -0,0 +1,136 @@
+# Copyright (C) 2001  MandrakeSoft S.A.
+#
+#   MandrakeSoft S.A.
+#   43, rue d'Aboukir
+#   75002 Paris - France
+#   http://www.linux-mandrake.com/
+#   http://www.mandrakesoft.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
+
+# Makefile for the BIOS component of bochs
+
+
+.SUFFIXES: .cc
+
+srcdir = .
+
+
+SHELL = /bin/sh
+
+CXX = g++
+CXXFLAGS = -g -O2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES
+
+# cc-option, copied from user/Makefile
+# 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 = -m32
+CFLAGS += $(call cc-option, -fno-stack-protector, "")
+CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
+
+LDFLAGS = 
+LIBS =  -lm
+RANLIB = ranlib
+
+BCC = bcc
+GCC = gcc $(CFLAGS)
+HOST_CC = gcc
+AS86 = as86
+
+BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev
+LOCAL_CXXFLAGS =
+
+BUILDDATE = `date '+%m/%d/%y'`
+BIOS_BUILD_DATE = "-DBIOS_BUILD_DATE=\"$(BUILDDATE)\""
+#
+# -------- end configurable options --------------------------
+#
+
+
+.cc.o:
+	$(CXX) -c $(BX_INCDIRS) $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@
+
+
+bios: biossums BIOS-bochs-latest BIOS-bochs-legacy 
+
+clean:
+	rm -f  *.o *.a *.s _rombios*_.c rombios*.txt rombios*.sym
+	rm -f  usage biossums rombios16.bin
+	rm -f  rombios32.bin rombios32.out acpi-dsdt.hex acpi-ssdt.hex
+
+dist-clean: clean
+	rm -f  Makefile
+
+bios-clean:
+	rm -f  BIOS-bochs-*
+
+BIOS-bochs-legacy: rombios.c apmbios.S biossums rombios.h
+	$(GCC) $(BIOS_BUILD_DATE) -DLEGACY -E -P $< > _rombiosl_.c
+	$(BCC) -o rombiosl.s -C-c -D__i86__ -0 -S _rombiosl_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' rombiosl.s > _rombiosl_.s
+	$(AS86) _rombiosl_.s -b tmpl.bin -u- -w- -g -0 -j -O -l rombiosl.txt
+	-perl ${srcdir}/makesym.perl < rombiosl.txt > rombiosl.sym
+	mv tmpl.bin $@
+	./biossums $@
+	rm -f  _rombiosl_.s
+
+
+rombios16.bin: rombios.c apmbios.S biossums rombios.h
+	$(GCC) $(BIOS_BUILD_DATE) -E -P $< > _rombios_.c
+	$(BCC) -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s
+	$(AS86) _rombios_.s -b tmp.bin -u- -w- -g -0 -j -O -l rombios.txt
+	-perl ${srcdir}/makesym.perl < rombios.txt > rombios.sym
+	mv tmp.bin rombios16.bin
+	./biossums rombios16.bin
+	rm -f  _rombios_.s
+
+
+rombios32.bin: rombios32.out rombios.h
+	objcopy -O binary $< $@
+	./biossums -pad $@
+
+rombios32.out: rombios32start.o rombios32.o vapic.o rombios32.ld
+	ld -o $@ -T rombios32.ld rombios32start.o vapic.o rombios32.o
+
+rombios32.o: rombios32.c acpi-dsdt.hex acpi-ssdt.hex
+	$(GCC) -m32 -O2 -Wall -c -o $@ $<
+
+acpi-dsdt.hex: acpi-dsdt.dsl
+	cpp -P $< $<.i
+	iasl -tc -p $@ $<.i
+	sed -i -e's/^unsigned char AmlCode/const unsigned char DSDTCode/' $@
+	rm $<.i
+
+acpi-ssdt.hex: acpi-ssdt.dsl
+	cpp -P $< $<.i
+	iasl -tc -p $@ $<.i
+	sed -i -e's/^unsigned char AmlCode/const unsigned char SSDTCode/' $@
+	rm $<.i
+
+rombios32start.o: rombios32start.S
+	$(GCC) -m32 -c -o $@ $<
+
+vapic.o: vapic.S
+	$(GCC) -m32 -c -o $@ $<
+
+BIOS-bochs-latest: rombios16.bin rombios32.bin
+	cat rombios32.bin rombios16.bin > $@
+
+biossums: biossums.c
+	$(HOST_CC) -o biossums biossums.c
diff --git a/kvm/bios/Makefile.in b/kvm/bios/Makefile.in
new file mode 100644
index 0000000..28ada75
--- /dev/null
+++ b/kvm/bios/Makefile.in
@@ -0,0 +1,120 @@
+# Copyright (C) 2001  MandrakeSoft S.A.
+#
+#   MandrakeSoft S.A.
+#   43, rue d'Aboukir
+#   75002 Paris - France
+#   http://www.linux-mandrake.com/
+#   http://www.mandrakesoft.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+# Makefile for the BIOS component of bochs
+
+
+@SUFFIX_LINE@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@
+
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+RANLIB = @RANLIB@
+
+BCC = bcc
+GCC = gcc
+GCC32 = gcc -m32 -fno-stack-protector
+AS86 = as86
+
+BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev
+LOCAL_CXXFLAGS =
+
+BUILDDATE = `date '+%m/%d/%y'`
+BIOS_BUILD_DATE = "-DBIOS_BUILD_DATE=\"$(BUILDDATE)\""
+#
+# -------- end configurable options --------------------------
+#
+
+
+.@CPP_SUFFIX@.o:
+	$(CXX) -c $(BX_INCDIRS) $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
+
+
+bios: biossums BIOS-bochs-latest BIOS-bochs-legacy
+
+clean:
+	@RMCOMMAND@ *.o *.a *.s _rombios*_.c rombios*.txt rombios*.sym
+	@RMCOMMAND@ usage biossums rombios16.bin
+	@RMCOMMAND@ rombios32.bin rombios32.out
+
+dist-clean: clean
+	@RMCOMMAND@ Makefile
+
+bios-clean:
+	@RMCOMMAND@ BIOS-bochs-*
+
+BIOS-bochs-legacy: rombios.c apmbios.S biossums rombios.h
+	$(GCC32) $(BIOS_BUILD_DATE) -DLEGACY -E -P $< > _rombiosl_.c
+	$(BCC) -o rombiosl.s -C-c -D__i86__ -0 -S _rombiosl_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' rombiosl.s > _rombiosl_.s
+	$(AS86) _rombiosl_.s -b tmpl.bin -u- -w- -g -0 -j -O -l rombiosl.txt
+	-perl ${srcdir}/makesym.perl < rombiosl.txt > rombiosl.sym
+	mv tmpl.bin $@
+	./biossums $@
+	@RMCOMMAND@ _rombiosl_.s
+
+
+rombios16.bin: rombios.c apmbios.S biossums rombios.h
+	$(GCC32) $(BIOS_BUILD_DATE) -E -P $< > _rombios_.c
+	$(BCC) -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s
+	$(AS86) _rombios_.s -b tmp.bin -u- -w- -g -0 -j -O -l rombios.txt
+	-perl ${srcdir}/makesym.perl < rombios.txt > rombios.sym
+	mv tmp.bin rombios16.bin
+	./biossums rombios16.bin
+	@RMCOMMAND@ _rombios_.s
+
+
+rombios32.bin: rombios32.out rombios.h
+	objcopy -O binary $< $@
+	./biossums -pad $@
+
+rombios32.out: rombios32start.o rombios32.o rombios32.ld
+	ld -o $@ -T $(srcdir)/rombios32.ld rombios32start.o rombios32.o
+
+rombios32.o: rombios32.c acpi-dsdt.hex
+	$(GCC32) -O2 -Wall -c -o $@ $<
+
+ifeq ("1", "0")
+acpi-dsdt.hex: acpi-dsdt.dsl
+	cpp -P $< $<.i
+	iasl -tc -p $@ $<.i
+	rm $<.i
+	sed -i -e's/^unsigned/const unsigned/' $@
+endif
+
+rombios32start.o: rombios32start.S
+	$(GCC32) -c -o $@ $<
+
+BIOS-bochs-latest: rombios16.bin rombios32.bin
+	cat rombios32.bin rombios16.bin > $@
+
+biossums: biossums.o
diff --git a/kvm/bios/acpi-dsdt.dsl b/kvm/bios/acpi-dsdt.dsl
new file mode 100755
index 0000000..26fc7ad
--- /dev/null
+++ b/kvm/bios/acpi-dsdt.dsl
@@ -0,0 +1,747 @@
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+DefinitionBlock (
+    "acpi-dsdt.aml",    // Output Filename
+    "DSDT",             // Signature
+    0x01,               // DSDT Compliance Revision
+    "BXPC",             // OEMID
+    "BXDSDT",           // TABLE ID
+    0x1                 // OEM Revision
+    )
+{
+    Scope (\)
+    {
+        /* Debug Output */
+        OperationRegion (DBG, SystemIO, 0xb044, 0x04)
+        Field (DBG, DWordAcc, NoLock, Preserve)
+        {
+            DBGL,   32,
+        }
+    }
+
+
+    /* PCI Bus definition */
+    Scope(\_SB) {
+        Device(PCI0) {
+            Name (_HID, EisaId ("PNP0A03"))
+            Name (_ADR, 0x00)
+            Name (_UID, 1)
+            Name(_PRT, Package() {
+                /* PCI IRQ routing table, example from ACPI 2.0a specification,
+                   section 6.2.8.1 */
+                /* Note: we provide the same info as the PCI routing
+                   table of the Bochs BIOS */
+
+#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
+	Package() { nr##ffff, 0, lnk0, 0 }, \
+	Package() { nr##ffff, 1, lnk1, 0 }, \
+	Package() { nr##ffff, 2, lnk2, 0 }, \
+	Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
+
+		prt_slot0(0x0000),
+		prt_slot1(0x0001),
+		prt_slot2(0x0002),
+		prt_slot3(0x0003),
+		prt_slot0(0x0004),
+		prt_slot1(0x0005),
+		prt_slot2(0x0006),
+		prt_slot3(0x0007),
+		prt_slot0(0x0008),
+		prt_slot1(0x0009),
+		prt_slot2(0x000a),
+		prt_slot3(0x000b),
+		prt_slot0(0x000c),
+		prt_slot1(0x000d),
+		prt_slot2(0x000e),
+		prt_slot3(0x000f),
+		prt_slot0(0x0010),
+		prt_slot1(0x0011),
+		prt_slot2(0x0012),
+		prt_slot3(0x0013),
+		prt_slot0(0x0014),
+		prt_slot1(0x0015),
+		prt_slot2(0x0016),
+		prt_slot3(0x0017),
+		prt_slot0(0x0018),
+		prt_slot1(0x0019),
+		prt_slot2(0x001a),
+		prt_slot3(0x001b),
+		prt_slot0(0x001c),
+		prt_slot1(0x001d),
+		prt_slot2(0x001e),
+		prt_slot3(0x001f),
+            })
+
+            OperationRegion(PCST, SystemIO, 0xae00, 0x08)
+            Field (PCST, DWordAcc, NoLock, WriteAsZeros)
+	    {
+		PCIU, 32,
+		PCID, 32,
+	    }
+
+            OperationRegion(SEJ, SystemIO, 0xae08, 0x04)
+            Field (SEJ, DWordAcc, NoLock, WriteAsZeros)
+            {
+                B0EJ, 32,
+            }
+
+#define hotplug_slot(name, nr) \
+            Device (S##name) {                    \
+               Name (_ADR, nr##0000)              \
+               Method (_EJ0,1) {                  \
+                    Store(ShiftLeft(1, nr), B0EJ) \
+                    Return (0x0)                  \
+               }                                  \
+               Name (_SUN, name)                  \
+            }
+
+	    hotplug_slot(1, 0x0001)
+	    hotplug_slot(2, 0x0002)
+	    hotplug_slot(3, 0x0003)
+	    hotplug_slot(4, 0x0004)
+	    hotplug_slot(5, 0x0005)
+	    hotplug_slot(6, 0x0006)
+	    hotplug_slot(7, 0x0007)
+	    hotplug_slot(8, 0x0008)
+	    hotplug_slot(9, 0x0009)
+	    hotplug_slot(10, 0x000a)
+	    hotplug_slot(11, 0x000b)
+	    hotplug_slot(12, 0x000c)
+	    hotplug_slot(13, 0x000d)
+	    hotplug_slot(14, 0x000e)
+	    hotplug_slot(15, 0x000f)
+	    hotplug_slot(16, 0x0010)
+	    hotplug_slot(17, 0x0011)
+	    hotplug_slot(18, 0x0012)
+	    hotplug_slot(19, 0x0013)
+	    hotplug_slot(20, 0x0014)
+	    hotplug_slot(21, 0x0015)
+	    hotplug_slot(22, 0x0016)
+	    hotplug_slot(23, 0x0017)
+	    hotplug_slot(24, 0x0018)
+	    hotplug_slot(25, 0x0019)
+	    hotplug_slot(26, 0x001a)
+	    hotplug_slot(27, 0x001b)
+	    hotplug_slot(28, 0x001c)
+	    hotplug_slot(29, 0x001d)
+	    hotplug_slot(30, 0x001e)
+	    hotplug_slot(31, 0x001f)
+
+            Name (_CRS, ResourceTemplate ()
+            {
+                WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
+                    0x0000,             // Address Space Granularity
+                    0x0000,             // Address Range Minimum
+                    0x00FF,             // Address Range Maximum
+                    0x0000,             // Address Translation Offset
+                    0x0100,             // Address Length
+                    ,, )
+                IO (Decode16,
+                    0x0CF8,             // Address Range Minimum
+                    0x0CF8,             // Address Range Maximum
+                    0x01,               // Address Alignment
+                    0x08,               // Address Length
+                    )
+                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+                    0x0000,             // Address Space Granularity
+                    0x0000,             // Address Range Minimum
+                    0x0CF7,             // Address Range Maximum
+                    0x0000,             // Address Translation Offset
+                    0x0CF8,             // Address Length
+                    ,, , TypeStatic)
+                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+                    0x0000,             // Address Space Granularity
+                    0x0D00,             // Address Range Minimum
+                    0xFFFF,             // Address Range Maximum
+                    0x0000,             // Address Translation Offset
+                    0xF300,             // Address Length
+                    ,, , TypeStatic)
+                DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+                    0x00000000,         // Address Space Granularity
+                    0x000A0000,         // Address Range Minimum
+                    0x000BFFFF,         // Address Range Maximum
+                    0x00000000,         // Address Translation Offset
+                    0x00020000,         // Address Length
+                    ,, , AddressRangeMemory, TypeStatic)
+                DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
+                    0x00000000,         // Address Space Granularity
+                    0xE0000000,         // Address Range Minimum
+                    0xFEBFFFFF,         // Address Range Maximum
+                    0x00000000,         // Address Translation Offset
+                    0x1EC00000,         // Address Length
+                    ,, , AddressRangeMemory, TypeStatic)
+            })
+        }
+#ifdef BX_QEMU
+        Device(HPET) {
+            Name(_HID,  EISAID("PNP0103"))
+            Name(_UID, 0)
+            Method (_STA, 0, NotSerialized) {
+                    Return(0x0F)
+            }
+            Name(_CRS, ResourceTemplate() {
+                DWordMemory(
+                    ResourceConsumer, PosDecode, MinFixed, MaxFixed,
+                    NonCacheable, ReadWrite,
+                    0x00000000,
+                    0xFED00000,
+                    0xFED003FF,
+                    0x00000000,
+                    0x00000400 /* 1K memory: FED00000 - FED003FF */
+                )
+            })
+        }
+#endif
+    }
+
+    Scope(\_SB.PCI0) {
+        Device (VGA) {
+                 Name (_ADR, 0x00020000)
+                 Method (_S1D, 0, NotSerialized)
+                 {
+                         Return (0x00)
+                 }
+                 Method (_S2D, 0, NotSerialized)
+                 {
+                         Return (0x00)
+                 }
+                 Method (_S3D, 0, NotSerialized)
+                 {
+                         Return (0x00)
+                 }
+        }
+
+	/* PIIX3 ISA bridge */
+        Device (ISA) {
+            Name (_ADR, 0x00010000)
+
+            /* PIIX PCI to ISA irq remapping */
+            OperationRegion (P40C, PCI_Config, 0x60, 0x04)
+
+            /* Real-time clock */
+            Device (RTC)
+            {
+                Name (_HID, EisaId ("PNP0B00"))
+                Name (_CRS, ResourceTemplate ()
+                {
+                    IO (Decode16, 0x0070, 0x0070, 0x10, 0x02)
+                    IRQNoFlags () {8}
+                    IO (Decode16, 0x0072, 0x0072, 0x02, 0x06)
+                })
+            }
+
+            /* Keyboard seems to be important for WinXP install */
+            Device (KBD)
+            {
+                Name (_HID, EisaId ("PNP0303"))
+                Method (_STA, 0, NotSerialized)
+                {
+                    Return (0x0f)
+                }
+
+                Method (_CRS, 0, NotSerialized)
+                {
+                     Name (TMP, ResourceTemplate ()
+                     {
+                    IO (Decode16,
+                        0x0060,             // Address Range Minimum
+                        0x0060,             // Address Range Maximum
+                        0x01,               // Address Alignment
+                        0x01,               // Address Length
+                        )
+                    IO (Decode16,
+                        0x0064,             // Address Range Minimum
+                        0x0064,             // Address Range Maximum
+                        0x01,               // Address Alignment
+                        0x01,               // Address Length
+                        )
+                    IRQNoFlags ()
+                        {1}
+                    })
+                    Return (TMP)
+                }
+            }
+
+	    /* PS/2 mouse */
+            Device (MOU)
+            {
+                Name (_HID, EisaId ("PNP0F13"))
+                Method (_STA, 0, NotSerialized)
+                {
+                    Return (0x0f)
+                }
+
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (TMP, ResourceTemplate ()
+                    {
+                         IRQNoFlags () {12}
+                    })
+                    Return (TMP)
+                }
+            }
+
+	    /* PS/2 floppy controller */
+	    Device (FDC0)
+	    {
+	        Name (_HID, EisaId ("PNP0700"))
+		Method (_STA, 0, NotSerialized)
+		{
+		    Return (0x0F)
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+                        IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+                        IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+                        IRQNoFlags () {6}
+                        DMA (Compatibility, NotBusMaster, Transfer8) {2}
+                    })
+		    Return (BUF0)
+		}
+	    }
+
+	    /* Parallel port */
+	    Device (LPT)
+	    {
+	        Name (_HID, EisaId ("PNP0400"))
+		Method (_STA, 0, NotSerialized)
+		{
+		    Store (\_SB.PCI0.PX13.DRSA, Local0)
+		    And (Local0, 0x80000000, Local0)
+		    If (LEqual (Local0, 0))
+		    {
+			Return (0x00)
+		    }
+		    Else
+		    {
+			Return (0x0F)
+		    }
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+			IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
+			IRQNoFlags () {7}
+		    })
+		    Return (BUF0)
+		}
+	    }
+
+	    /* Serial Ports */
+	    Device (COM1)
+	    {
+	        Name (_HID, EisaId ("PNP0501"))
+		Name (_UID, 0x01)
+		Method (_STA, 0, NotSerialized)
+		{
+		    Store (\_SB.PCI0.PX13.DRSC, Local0)
+		    And (Local0, 0x08000000, Local0)
+		    If (LEqual (Local0, 0))
+		    {
+			Return (0x00)
+		    }
+		    Else
+		    {
+			Return (0x0F)
+		    }
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+			IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+                	IRQNoFlags () {4}
+		    })
+		    Return (BUF0)
+		}
+	    }
+
+	    Device (COM2)
+	    {
+	        Name (_HID, EisaId ("PNP0501"))
+		Name (_UID, 0x02)
+		Method (_STA, 0, NotSerialized)
+		{
+		    Store (\_SB.PCI0.PX13.DRSC, Local0)
+		    And (Local0, 0x80000000, Local0)
+		    If (LEqual (Local0, 0))
+		    {
+			Return (0x00)
+		    }
+		    Else
+		    {
+			Return (0x0F)
+		    }
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+			IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+                	IRQNoFlags () {3}
+		    })
+		    Return (BUF0)
+		}
+	    }
+        }
+
+	/* PIIX4 PM */
+        Device (PX13) {
+	    Name (_ADR, 0x00010003)
+
+	    OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
+	    Field (P13C, DWordAcc, NoLock, Preserve)
+	    {
+		DRSA, 32,
+		DRSB, 32,
+		DRSC, 32,
+		DRSE, 32,
+		DRSF, 32,
+		DRSG, 32,
+		DRSH, 32,
+		DRSI, 32,
+		DRSJ, 32
+	    }
+	}
+    }
+
+    /* PCI IRQs */
+    Scope(\_SB) {
+         Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
+         {
+             PRQ0,   8,
+             PRQ1,   8,
+             PRQ2,   8,
+             PRQ3,   8
+         }
+
+        Device(LNKA){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 1)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ0, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ0, 0x80, PRQ0)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ0, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ0)
+                }
+        }
+        Device(LNKB){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 2)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ1, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ1, 0x80, PRQ1)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ1, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ1)
+                }
+        }
+        Device(LNKC){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 3)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ2, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ2, 0x80, PRQ2)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ2, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ2)
+                }
+        }
+        Device(LNKD){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 4)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ3, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ3, 0x80, PRQ3)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ3, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ3)
+                }
+        }
+    }
+
+    /*
+     * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes:
+     * must match piix4 emulation.
+     */
+    Name (\_S3, Package (0x04)
+    {
+        0x01,  /* PM1a_CNT.SLP_TYP */
+        0x01,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+    Name (\_S4, Package (0x04)
+    {
+        Zero,  /* PM1a_CNT.SLP_TYP */
+        Zero,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+    Name (\_S5, Package (0x04)
+    {
+        Zero,  /* PM1a_CNT.SLP_TYP */
+        Zero,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+
+    Scope (\_GPE)
+    {
+	Name(_HID, "ACPI0006")
+
+        Method(_L00) {
+            Return(0x01)
+        }
+
+#define gen_pci_hotplug(nr)                                       \
+            If (And(\_SB.PCI0.PCIU, ShiftLeft(1, nr))) {          \
+                Notify(\_SB.PCI0.S##nr, 1)                        \
+            }                                                     \
+            If (And(\_SB.PCI0.PCID, ShiftLeft(1, nr))) {          \
+                Notify(\_SB.PCI0.S##nr, 3)                        \
+            }
+
+        Method(_L01) {
+	    gen_pci_hotplug(1)
+	    gen_pci_hotplug(2)
+	    gen_pci_hotplug(3)
+	    gen_pci_hotplug(4)
+	    gen_pci_hotplug(5)
+	    gen_pci_hotplug(6)
+	    gen_pci_hotplug(7)
+	    gen_pci_hotplug(8)
+	    gen_pci_hotplug(9)
+	    gen_pci_hotplug(10)
+	    gen_pci_hotplug(11)
+	    gen_pci_hotplug(12)
+	    gen_pci_hotplug(13)
+	    gen_pci_hotplug(14)
+	    gen_pci_hotplug(15)
+	    gen_pci_hotplug(16)
+	    gen_pci_hotplug(17)
+	    gen_pci_hotplug(18)
+	    gen_pci_hotplug(19)
+	    gen_pci_hotplug(20)
+	    gen_pci_hotplug(21)
+	    gen_pci_hotplug(22)
+	    gen_pci_hotplug(23)
+	    gen_pci_hotplug(24)
+	    gen_pci_hotplug(25)
+	    gen_pci_hotplug(26)
+	    gen_pci_hotplug(27)
+	    gen_pci_hotplug(28)
+	    gen_pci_hotplug(29)
+	    gen_pci_hotplug(30)
+	    gen_pci_hotplug(31)
+
+            Return(0x01)
+        }
+
+	/*
+         * Method _02 will be provided by the SSDT as it needs to call
+         * into the Processor methods (_PR.PRSC()).
+         */
+
+        Method(_L03) {
+            Return(0x01)
+        }
+        Method(_L04) {
+            Return(0x01)
+        }
+        Method(_L05) {
+            Return(0x01)
+        }
+        Method(_L06) {
+            Return(0x01)
+        }
+        Method(_L07) {
+            Return(0x01)
+        }
+        Method(_L08) {
+            Return(0x01)
+        }
+        Method(_L09) {
+            Return(0x01)
+        }
+        Method(_L0A) {
+            Return(0x01)
+        }
+        Method(_L0B) {
+            Return(0x01)
+        }
+        Method(_L0C) {
+            Return(0x01)
+        }
+        Method(_L0D) {
+            Return(0x01)
+        }
+        Method(_L0E) {
+            Return(0x01)
+        }
+        Method(_L0F) {
+            Return(0x01)
+        }
+    }
+}
diff --git a/kvm/bios/acpi-ssdt.dsl b/kvm/bios/acpi-ssdt.dsl
new file mode 100644
index 0000000..d998867
--- /dev/null
+++ b/kvm/bios/acpi-ssdt.dsl
@@ -0,0 +1,140 @@
+/*
+ * Bochs/QEMU ACPI SSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2009 SGI, Jes Sorensen <jes@sgi.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+DefinitionBlock (
+    "acpi-ssdt.aml",    // Output Filename
+    "SSDT",             // Signature
+    0x01,               // DSDT Compliance Revision
+    "BXPC",             // OEMID
+    "BXSSDT",           // TABLE ID
+    0x1                 // OEM Revision
+    )
+{
+   Scope (\_PR)
+   {
+	/* pointer to first element of MADT APIC structures */
+	OperationRegion(ATPR, SystemMemory, 0x0514, 4)
+	Field (ATPR, DwordAcc, NoLock, Preserve)
+	{
+		ATP, 32
+	}
+
+#define madt_addr(nr)  Add (ATP, Multiply(nr, 8))
+
+#define gen_processor(nr, name) 				            \
+	Processor (C##name, nr, 0x0000b010, 0x06) {                       \
+	    OperationRegion (MATR, SystemMemory, madt_addr(nr), 8)          \
+	    Field (MATR, ByteAcc, NoLock, Preserve)                         \
+	    {                                                               \
+	        MAT, 64                                                     \
+	    }                                                               \
+	    Field (MATR, ByteAcc, NoLock, Preserve)                         \
+	    {                                                               \
+	        Offset(4),                                                  \
+	        FLG, 1                                                      \
+	    }                                                               \
+            Method(_MAT, 0) {                                               \
+		Return(MAT)                                                 \
+            }                                                               \
+            Method (_STA) {                                                 \
+                If (FLG) { Return(0xF) } Else { Return(0x9) }               \
+            }                                                               \
+        }                                                                   \
+
+
+	gen_processor(0, 0)
+	gen_processor(1, 1)
+	gen_processor(2, 2)
+	gen_processor(3, 3)
+	gen_processor(4, 4)
+	gen_processor(5, 5)
+	gen_processor(6, 6)
+	gen_processor(7, 7)
+	gen_processor(8, 8)
+	gen_processor(9, 9)
+	gen_processor(10, A)
+	gen_processor(11, B)
+	gen_processor(12, C)
+	gen_processor(13, D)
+	gen_processor(14, E)
+
+	Method (NTFY, 2) {
+#define gen_ntfy(nr)                                        \
+	If (LEqual(Arg0, 0x##nr)) {                         \
+		If (LNotEqual(Arg1, \_PR.C##nr.FLG)) {      \
+			Store (Arg1, \_PR.C##nr.FLG)        \
+			If (LEqual(Arg1, 1)) {              \
+				Notify(C##nr, 1)            \
+			} Else {                            \
+				Notify(C##nr, 3)            \
+			}                                   \
+		}                                           \
+	}
+		gen_ntfy(0)
+		gen_ntfy(1)
+		gen_ntfy(2)
+		gen_ntfy(3)
+		gen_ntfy(4)
+		gen_ntfy(5)
+		gen_ntfy(6)
+		gen_ntfy(7)
+		gen_ntfy(8)
+		gen_ntfy(9)
+		gen_ntfy(A)
+		gen_ntfy(B)
+		gen_ntfy(C)
+		gen_ntfy(D)
+		gen_ntfy(E)
+		Return(One)
+	}
+
+	OperationRegion(PRST, SystemIO, 0xaf00, 32)
+	Field (PRST, ByteAcc, NoLock, Preserve)
+	{
+		PRS, 256
+	}
+
+	Method(PRSC, 0) {
+		Store(PRS, Local3)
+		Store(Zero, Local0)
+		While(LLess(Local0, 32)) {
+			Store(Zero, Local1)
+			Store(DerefOf(Index(Local3, Local0)), Local2)
+			While(LLess(Local1, 8)) {
+				NTFY(Add(Multiply(Local0, 8), Local1),
+						And(Local2, 1))
+				ShiftRight(Local2, 1, Local2)
+				Increment(Local1)
+			}
+			Increment(Local0)
+		}
+		Return(One)
+	}
+    }
+
+    /*
+     * Add the missing _L02 method for CPU notification
+     */
+    Scope (\_GPE)
+    {
+        Method(_L02) {
+	    Return(\_PR.PRSC())
+        }
+    }
+}
diff --git a/kvm/bios/apmbios.S b/kvm/bios/apmbios.S
new file mode 100644
index 0000000..41c9e7e
--- /dev/null
+++ b/kvm/bios/apmbios.S
@@ -0,0 +1,365 @@
+//  APM BIOS support for the Bochs BIOS
+//  Copyright (C) 2004 Fabrice Bellard
+//
+//  Debugging extensions, 16-bit interface and extended power options
+//  Copyright (C) 2005 Struan Bartlett
+//
+//  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 St, Fifth Floor, Boston, MA  02110-1301 USA
+
+#if defined(APM_REAL)
+#define APMSYM(s) apmreal_ ## s
+#elif defined(APM_PROT16)
+#define APMSYM(s) apm16_ ## s
+#elif defined(APM_PROT32)
+#define APMSYM(s) apm32_ ## s
+#else
+#error unsupported APM mode
+#endif
+
+APMSYM(out_str):
+  push eax
+  push ebx
+  mov ebx, eax
+APMSYM(out_str1):
+  SEG CS
+  mov al, byte ptr [bx]
+  cmp al, #0
+  je APMSYM(out_str2)
+  outb dx, al
+  inc ebx
+  jmp APMSYM(out_str1)
+APMSYM(out_str2):
+  pop ebx
+  pop eax
+  ret
+
+APMSYM(07_poweroff_str):
+  .ascii "Shutdown"
+  db 0
+APMSYM(07_suspend_str):
+  .ascii "Suspend"
+  db 0
+APMSYM(07_standby_str):
+  .ascii "Standby"
+  db 0
+
+#if DEBUG_APM
+APMSYM(put_str):
+  push edx
+  mov dx, #INFO_PORT
+  call APMSYM(out_str)
+  pop edx
+  ret
+
+; print the hex number in eax
+APMSYM(put_num):
+  push eax
+  push ebx
+  push ecx
+  push edx
+  mov ecx, eax
+  mov bx, #8
+  mov dx, #INFO_PORT
+APMSYM(put_num1):
+  mov eax, ecx
+  shr eax, #28
+  add al, #0x30
+  cmp al, #0x39
+  jbe APMSYM(put_num2)
+  add al, #0x27
+APMSYM(put_num2):
+  outb dx, al
+  shl ecx, #4
+  dec bx
+  jne APMSYM(put_num1)
+  pop edx
+  pop ecx
+  pop ebx
+  pop eax
+  ret
+
+APMSYM(put_reg):
+  outb dx, al
+  shr eax, #8
+  outb dx, al
+  shr eax, #8
+  outb dx, al
+  shr eax, #8
+  outb dx, al
+
+  mov eax,ebx
+  call APMSYM(put_num)
+
+  mov al, #0x3b
+  outb dx,al
+  mov al, #0x20
+  outb dx,al
+  ret
+
+APMSYM(put_regs):
+  push eax
+  push edx
+  push ebx
+  mov dx, #INFO_PORT
+
+  mov ebx, eax
+  mov eax, #0x3d584145 // 'EAX='
+  call APMSYM(put_reg)
+  pop ebx
+  push ebx
+  mov eax, #0x3d584245 // 'EBX='
+  call APMSYM(put_reg)
+  mov ebx, ecx
+  mov eax, #0x3d584345 // 'ECX='
+  call APMSYM(put_reg)
+  mov ebx, edx
+  mov eax, #0x3d584445 // 'EDX='
+  call APMSYM(put_reg)
+  mov ebx, esi
+  mov eax, #0x3d495345 // 'ESI='
+  call APMSYM(put_reg)
+  mov ebx, edi
+  mov eax, #0x3d494445 // 'EDI='
+  call APMSYM(put_reg)
+
+  mov al, #0x0a
+  outb dx, al
+  pop ebx
+  pop edx
+  pop eax
+  ret
+#endif
+
+#if defined(APM_PROT32)
+_apm32_entry:
+#endif
+#if defined(APM_PROT16)
+_apm16_entry:
+#endif
+  pushf
+
+#if defined(APM_REAL)
+_apmreal_entry:
+#endif
+
+#if DEBUG_APM
+  call APMSYM(put_regs)
+#endif
+
+#if defined(APM_REAL)
+;-----------------
+; APM installation check
+APMSYM(00):
+  cmp al, #0x00
+  jne APMSYM(01)
+
+  mov ah, #1 // APM major version
+  mov al, #2 // APM minor version
+
+  mov bh, #0x50 // 'P'
+  mov bl, #0x4d // 'M'
+
+  // bit 0 : 16 bit interface supported
+  // bit 1 : 32 bit interface supported
+  mov cx, #0x3
+  jmp APMSYM(ok)
+
+;-----------------
+; APM real mode interface connect
+APMSYM(01):
+  cmp al, #0x01
+  jne APMSYM(02)
+  jmp APMSYM(ok)
+
+;-----------------
+; APM 16 bit protected mode interface connect
+APMSYM(02):
+  cmp al, #0x02
+  jne APMSYM(03)
+
+  mov bx, #_apm16_entry
+
+  mov ax, #0xf000 // 16 bit code segment base
+  mov si, #0xfff0 // 16 bit code segment size
+  mov cx, #0xf000 // data segment address
+  mov di, #0xfff0 // data segment length
+  jmp APMSYM(ok)
+
+;-----------------
+; APM 32 bit protected mode interface connect
+APMSYM(03):
+  cmp al, #0x03
+  jne APMSYM(04)
+  mov ax, #0xf000 // 32 bit code segment base
+  mov ebx, #_apm32_entry
+  mov cx, #0xf000 // 16 bit code segment base
+  // 32 bit code segment size (low 16 bits)
+  // 16 bit code segment size (high 16 bits)
+  mov esi, #0xfff0fff0
+  mov dx, #0xf000 // data segment address
+  mov di, #0xfff0 // data segment length
+  jmp APMSYM(ok)
+#endif
+
+;-----------------
+; APM interface disconnect
+APMSYM(04):
+  cmp al, #0x04
+  jne APMSYM(05)
+  jmp APMSYM(ok)
+
+;-----------------
+; APM cpu idle
+APMSYM(05):
+  cmp al, #0x05
+  jne APMSYM(07)
+  sti
+  hlt
+  jmp APMSYM(ok)
+
+;-----------------
+; APM Set Power State
+APMSYM(07):
+  cmp al, #0x07
+  jne APMSYM(08)
+
+  cmp bx, #1
+  jne APMSYM(ok)
+
+  cmp cx, #3
+  je APMSYM(07_poweroff)
+
+  cmp cx, #2
+  je APMSYM(07_suspend)
+
+  cmp cx, #1
+  je APMSYM(07_standby)
+
+  jne APMSYM(ok)
+
+APMSYM(07_poweroff):
+  // send power off event to emulator
+  cli
+  mov dx, #0x8900
+  mov ax, #APMSYM(07_poweroff_str)
+  call APMSYM(out_str)
+
+APMSYM(07_1):
+  hlt
+  jmp APMSYM(07_1)
+
+APMSYM(07_suspend):
+  push edx
+  mov dx, #0x8900
+  mov ax, #APMSYM(07_suspend_str)
+  call APMSYM(out_str)
+  pop edx
+  jmp APMSYM(ok)
+
+APMSYM(07_standby):
+  push edx
+  mov dx, #0x8900
+  mov ax, #APMSYM(07_standby_str)
+  call APMSYM(out_str)
+  pop edx
+  jmp APMSYM(ok)
+
+;-----------------
+; APM Enable / Disable
+APMSYM(08):
+  cmp al, #0x08
+  jne APMSYM(0a)
+
+  jmp APMSYM(ok)
+
+;-----------------
+; Get Power Status
+APMSYM(0a):
+  cmp al, #0x0a
+  jne APMSYM(0b)
+  mov bh, #0x01 // on line
+  // mov bh, #0x02 // battery
+  mov bl, #0xff // unknown battery status
+  // mov bl, #0x03 // charging
+  mov ch, #0x80 // no system battery
+  // mov ch, #0x8 // charging
+  mov cl, #0xff // unknown remaining time
+  // mov cl, #50
+  mov dx, #0xffff // unknown remaining time
+  mov si, #0      // zero battery
+  // mov si, #1      // one battery
+  jmp APMSYM(ok)
+
+;-----------------
+; Get PM Event
+APMSYM(0b):
+  cmp al, #0x0b
+  jne APMSYM(0e)
+  mov ah, #0x80 // no event pending
+  jmp APMSYM(error)
+
+;-----------------
+; APM Driver Version
+APMSYM(0e):
+  cmp al, #0x0e
+  jne APMSYM(0f)
+
+  mov ah, #1
+  mov al, #2
+
+  jmp APMSYM(ok)
+
+;-----------------
+; APM Engage / Disengage
+APMSYM(0f):
+  cmp al, #0x0f
+  jne APMSYM(10)
+
+  jmp APMSYM(ok)
+
+;-----------------
+; APM Get Capabilities
+APMSYM(10):
+  cmp al, #0x10
+  jne APMSYM(unimplemented)
+
+  mov bl, #0
+  mov cx, #0
+
+  jmp APMSYM(ok)
+
+;-----------------
+APMSYM(ok):
+  popf
+  clc
+#if defined(APM_REAL)
+  jmp iret_modify_cf
+#else
+  retf
+#endif
+APMSYM(unimplemented):
+APMSYM(error):
+  popf
+  stc
+#if defined(APM_REAL)
+  jmp iret_modify_cf
+#else
+  retf
+#endif
+
+#undef APM_PROT32
+#undef APM_PROT16
+#undef APM_REAL
+#undef APMSYM
diff --git a/kvm/bios/bios_usage b/kvm/bios/bios_usage
new file mode 100644
index 0000000..8019ef6
--- /dev/null
+++ b/kvm/bios/bios_usage
@@ -0,0 +1,4 @@
+#!/bin/csh -f
+gcc -E rombios.c | grep "^\.org" | sed -e 's/\.org //' | sed -e 's/ .*//' | sort >! temp.usage
+usage rombios.bin temp.usage
+/bin/rm temp.usage
diff --git a/kvm/bios/biossums.c b/kvm/bios/biossums.c
new file mode 100644
index 0000000..032ac23
--- /dev/null
+++ b/kvm/bios/biossums.c
@@ -0,0 +1,504 @@
+/*
+ * $Id: biossums.c,v 1.4 2007/05/28 08:09:13 vruppert Exp $
+ *
+ *  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
+ */
+
+/* biossums.c  --- written by Eike W. for the Bochs BIOS */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef unsigned char byte;
+
+void check( int value, char* message );
+
+#define LEN_BIOS_DATA 0x10000
+#define MAX_OFFSET    (LEN_BIOS_DATA - 1)
+
+
+#define BIOS_OFFSET 0xFFFF
+
+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 _32__LEN         9
+#define _32__CHKSUM     10
+
+#define _32__MINHDR     16
+
+long chksum__32__get_offset( byte* data, long offset );
+byte chksum__32__calc_value( byte* data, long offset );
+byte chksum__32__get_value(  byte* data, long offset );
+void chksum__32__set_value(  byte* data, long offset, byte value );
+
+
+#define _MP__LEN         8
+#define _MP__CHKSUM     10
+
+#define _MP__MINHDR     16
+
+long chksum__mp__get_offset( byte* data, long offset );
+byte chksum__mp__calc_value( byte* data, long offset );
+byte chksum__mp__get_value(  byte* data, long offset );
+void chksum__mp__set_value(  byte* data, long offset, byte value );
+
+
+#define PCMP_BASELEN     4
+#define PCMP_CHKSUM      7
+#define PCMP_EXT_LEN    40
+#define PCMP_EXT_CHKSUM 42
+
+#define PCMP_MINHDR     42
+
+long chksum_pcmp_get_offset( byte* data, long offset );
+byte chksum_pcmp_calc_value( byte* data, long offset );
+byte chksum_pcmp_get_value(  byte* data, long offset );
+void chksum_pcmp_set_value(  byte* data, long offset, byte value );
+
+
+#define _PIR_LEN         6
+#define _PIR_CHKSUM     31
+
+#define _PIR_MINHDR     32
+
+long chksum__pir_get_offset( byte *data, long offset );
+byte chksum__pir_calc_value( byte* data, long offset );
+byte chksum__pir_get_value(  byte* data, long offset );
+void chksum__pir_set_value(  byte* data, long offset, byte value );
+
+
+byte bios_data[LEN_BIOS_DATA];
+long bios_len;
+
+
+int main(int argc, char* argv[]) {
+
+  FILE* stream;
+  long  offset, tmp_offset;
+  byte  cur_val = 0, new_val = 0;
+  int   arg = 1, hits, pad = 0;
+
+
+  if ((argc == 3) && (!strcmp(argv[1], "-pad"))) {
+    pad = 1;
+    arg = 2;
+  } else if (argc != 2) {
+    printf("Error. Need a file-name as an argument.\n");
+    exit(EXIT_FAILURE);
+  }
+  memset(bios_data, 0xff, LEN_BIOS_DATA);
+
+  if ((stream = fopen(argv[arg], "rb")) == NULL) {
+    printf("Error opening %s for reading.\n", argv[arg]);
+    exit(EXIT_FAILURE);
+  }
+  bios_len = fread(bios_data, 1, LEN_BIOS_DATA, stream);
+  if ((bios_len < LEN_BIOS_DATA) && (pad == 0)) {
+    printf("Error reading 64KBytes from %s.\n", argv[arg]);
+    fclose(stream);
+    exit(EXIT_FAILURE);
+  }
+  fclose(stream);
+  if (pad == 1) goto write_bios;
+
+  hits   = 0;
+  offset = 0L;
+  while( (tmp_offset = chksum__32__get_offset( bios_data, offset )) != -1L ) {
+    offset  = tmp_offset;
+    cur_val = chksum__32__get_value(  bios_data, offset );
+    new_val = chksum__32__calc_value( bios_data, offset );
+    printf( "\n\nPCI-Bios header 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__32__set_value( bios_data, offset, new_val );
+  }
+  if( hits >= 2 ) {
+    printf( "Multiple PCI headers! No checksum set." );
+  }
+  if( hits ) {
+    printf( "\n" );
+  }
+
+
+  hits   = 0;
+  offset = 0L;
+  while( (tmp_offset = chksum__mp__get_offset( bios_data, offset )) != -1L ) {
+    offset  = tmp_offset;
+    cur_val = chksum__mp__get_value(  bios_data, offset );
+    new_val = chksum__mp__calc_value( bios_data, offset );
+    printf( "\n\nMP header 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__mp__set_value( bios_data, offset, new_val );
+  }
+  if( hits >= 2 ) {
+    printf( "Warning! Multiple MP headers. No checksum set." );
+  }
+  if( hits ) {
+    printf( "\n" );
+  }
+
+
+  hits   = 0;
+  offset = 0L;
+  while( (tmp_offset = chksum_pcmp_get_offset( bios_data, offset )) != -1L ) {
+    offset  = tmp_offset;
+    cur_val = chksum_pcmp_get_value(  bios_data, offset );
+    new_val = chksum_pcmp_calc_value( bios_data, offset );
+    printf( "\n\nPCMP header 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_pcmp_set_value( bios_data, offset, new_val );
+  }
+  if( hits >= 2 ) {
+    printf( "Warning! Multiple PCMP headers. No checksum set." );
+  }
+  if( hits ) {
+    printf( "\n" );
+  }
+
+
+  hits   = 0;
+  offset = 0L;
+  while( (tmp_offset = chksum__pir_get_offset( bios_data, offset )) != -1L ) {
+    offset  = tmp_offset;
+    cur_val = chksum__pir_get_value(  bios_data, offset );
+    new_val = chksum__pir_calc_value( bios_data, offset );
+    printf( "\n\n$PIR header at:     0x%4lX\n", offset  );
+    printf( "Current checksum:     0x%02X\n",   cur_val );
+    printf( "Calculated checksum:  0x%02X\n  ",  new_val );
+    hits++;
+  }
+  if( hits == 1 && cur_val != new_val ) {
+    printf( "Setting checksum." );
+    chksum__pir_set_value( bios_data, offset, new_val );
+  }
+  if( hits >= 2 ) {
+    printf( "Warning! Multiple $PIR headers. No checksum set." );
+  }
+  if( hits ) {
+    printf( "\n" );
+  }
+
+
+  offset  = 0L;
+  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 );
+  printf( "\n\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 );
+  }
+  printf( "\n" );
+
+write_bios:
+  if ((stream = fopen(argv[arg], "wb")) == NULL) {
+    printf("Error opening %s for writing.\n", argv[arg]);
+    exit(EXIT_FAILURE);
+  }
+  if (fwrite(bios_data, 1, LEN_BIOS_DATA, stream) < LEN_BIOS_DATA) {
+    printf("Error writing 64KBytes to %s.\n", argv[arg]);
+    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_OFFSET );
+}
+
+
+byte chksum_bios_calc_value( byte* data, long offset ) {
+
+  int   i;
+  byte  sum;
+
+  sum = 0;
+  for( i = 0; i < MAX_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 + BIOS_OFFSET ) );
+}
+
+
+void chksum_bios_set_value( byte* data, long offset, byte value ) {
+
+  *( data + BIOS_OFFSET ) = value;
+}
+
+
+byte chksum__32__calc_value( byte* data, long offset ) {
+
+  int           i;
+  int           len;
+  byte sum;
+
+  check( offset + _32__MINHDR <= MAX_OFFSET, "_32_ header out of bounds" );
+  len = *( data + offset + _32__LEN ) << 4;
+  check( offset + len <= MAX_OFFSET, "_32_ header-length out of bounds" );
+  sum = 0;
+  for( i = 0; i < len; i++ ) {
+    if( i != _32__CHKSUM ) {
+      sum = sum + *( data + offset + i );
+    }
+  }
+  sum = -sum;
+  return( sum );
+}
+
+
+long chksum__32__get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  offset = offset + 0x0F;
+  offset = offset & ~( 0x0F );
+  while( offset + 16 < MAX_OFFSET ) {
+    offset = offset + 16;
+    if( *( data + offset + 0 ) == '_' && \
+        *( data + offset + 1 ) == '3' && \
+        *( data + offset + 2 ) == '2' && \
+        *( data + offset + 3 ) == '_' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
+
+
+byte chksum__32__get_value( byte* data, long offset ) {
+
+  check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
+  return(  *( data + offset + _32__CHKSUM ) );
+}
+
+
+void chksum__32__set_value( byte* data, long offset, byte value ) {
+
+  check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
+  *( data + offset + _32__CHKSUM ) = value;
+}
+
+
+byte chksum__mp__calc_value( byte* data, long offset ) {
+
+  int   i;
+  int   len;
+  byte  sum;
+
+  check( offset + _MP__MINHDR <= MAX_OFFSET, "_MP_ header out of bounds" );
+  len = *( data + offset + _MP__LEN ) << 4;
+  check( offset + len <= MAX_OFFSET, "_MP_ header-length out of bounds" );
+  sum = 0;
+  for( i = 0; i < len; i++ ) {
+    if( i != _MP__CHKSUM ) {
+      sum = sum + *( data + offset + i );
+    }
+  }
+  sum = -sum;
+  return( sum );
+}
+
+
+long chksum__mp__get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  offset = offset + 0x0F;
+  offset = offset & ~( 0x0F );
+  while( offset + 16 < MAX_OFFSET ) {
+    offset = offset + 16;
+    if( *( data + offset + 0 ) == '_' && \
+        *( data + offset + 1 ) == 'M' && \
+        *( data + offset + 2 ) == 'P' && \
+        *( data + offset + 3 ) == '_' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
+
+
+byte chksum__mp__get_value( byte* data, long offset ) {
+
+  check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
+  return( *( data + offset + _MP__CHKSUM ) );
+}
+
+
+void chksum__mp__set_value( byte* data, long offset, byte value ) {
+
+  check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
+  *( data + offset + _MP__CHKSUM ) = value;
+}
+
+
+byte chksum_pcmp_calc_value( byte* data, long offset ) {
+
+  int   i;
+  int   len;
+  byte  sum;
+
+  check( offset + PCMP_MINHDR <= MAX_OFFSET, "PCMP header out of bounds" );
+  len  =   *( data + offset + PCMP_BASELEN )      + \
+         ( *( data + offset + PCMP_BASELEN + 1 ) << 8 );
+  check( offset + len <= MAX_OFFSET, "PCMP header-length out of bounds" );
+  if( *( data + offset + PCMP_EXT_LEN )     | \
+      *( data + offset + PCMP_EXT_LEN + 1 ) | \
+      *( data + offset + PCMP_EXT_CHKSUM ) ) {
+    check( 0, "PCMP header indicates extended tables (unsupported)" );
+  }
+  sum = 0;
+  for( i = 0; i < len; i++ ) {
+    if( i != PCMP_CHKSUM ) {
+      sum = sum + *( data + offset + i );
+    }
+  }
+  sum = -sum;
+  return( sum );
+}
+
+
+long chksum_pcmp_get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  offset = offset + 0x0F;
+  offset = offset & ~( 0x0F );
+  while( offset + 16 < MAX_OFFSET ) {
+    offset = offset + 16;
+    if( *( data + offset + 0 ) == 'P' && \
+        *( data + offset + 1 ) == 'C' && \
+        *( data + offset + 2 ) == 'M' && \
+        *( data + offset + 3 ) == 'P' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
+
+
+byte chksum_pcmp_get_value( byte* data, long offset ) {
+
+  check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
+  return( *( data + offset + PCMP_CHKSUM ) );
+}
+
+
+void chksum_pcmp_set_value( byte* data, long offset, byte value ) {
+
+  check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
+  *( data + offset + PCMP_CHKSUM ) = value;
+}
+
+
+byte chksum__pir_calc_value( byte* data, long offset ) {
+
+  int   i;
+  int   len;
+  byte  sum;
+
+  check( offset + _PIR_MINHDR <= MAX_OFFSET, "$PIR header out of bounds" );
+  len  =   *( data + offset + _PIR_LEN )      + \
+         ( *( data + offset + _PIR_LEN + 1 ) << 8 );
+  check( offset + len <= MAX_OFFSET, "$PIR header-length out of bounds" );
+  sum = 0;
+  for( i = 0; i < len; i++ ) {
+    if( i != _PIR_CHKSUM ) {
+      sum = sum + *( data + offset + i );
+    }
+  }
+  sum = -sum;
+  return( sum );
+}
+
+
+long chksum__pir_get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  offset = offset + 0x0F;
+  offset = offset & ~( 0x0F );
+  while( offset + 16 < MAX_OFFSET ) {
+    offset = offset + 16;
+    if( *( data + offset + 0 ) == '$' && \
+        *( data + offset + 1 ) == 'P' && \
+        *( data + offset + 2 ) == 'I' && \
+        *( data + offset + 3 ) == 'R' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
+
+
+byte chksum__pir_get_value( byte* data, long offset ) {
+
+  check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
+  return(  *( data + offset + _PIR_CHKSUM ) );
+}
+
+
+void chksum__pir_set_value( byte* data, long offset, byte value ) {
+
+  check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
+  *( data + offset + _PIR_CHKSUM ) = value;
+}
+
diff --git a/kvm/bios/makesym.perl b/kvm/bios/makesym.perl
new file mode 100755
index 0000000..6312654
--- /dev/null
+++ b/kvm/bios/makesym.perl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+#
+# $Id: makesym.perl,v 1.1 2002/11/24 22:45:40 bdenney Exp $
+#
+# Read output file from as86 (e.g. rombios.txt) and write out a symbol
+# table suitable for the Bochs debugger.
+#
+
+$WHERE_BEFORE_SYM_TABLE = 0;
+$WHERE_IN_SYM_TABLE = 1;
+$WHERE_AFTER_SYM_TABLE = 2;
+
+$where = $WHERE_BEFORE_SYM_TABLE;
+while (<STDIN>) {
+  chop;
+  if ($where == WHERE_BEFORE_SYM_TABLE && /^Symbols:/) {
+    $where = $WHERE_IN_SYM_TABLE;
+  } elsif ($where == $WHERE_IN_SYM_TABLE && /^$/) {
+    $where = $WHERE_AFTER_SYM_TABLE;
+  }
+  if ($where == $WHERE_IN_SYM_TABLE) {
+    @F = split (/\s+/);
+    ($name[0], $junk, $addr[0], $junk, $name[1], $junk, $addr[1]) = @F;
+    foreach $col (0,1) {
+      next if length $addr[$col] < 1;
+      $addr[$col] =~ tr/A-Z/a-z/;
+      $addr[$col] = "000f" . $addr[$col];
+      print "$addr[$col] $name[$col]\n";
+    }
+  }
+}
diff --git a/kvm/bios/notes b/kvm/bios/notes
new file mode 100644
index 0000000..ae1073e
--- /dev/null
+++ b/kvm/bios/notes
@@ -0,0 +1,44 @@
+####################
+# Read Disk Sector #
+####################
+
+System programming:
+-------------------
+
+(Int 13h, ah=2)
+in 1f7 until BSY cleared
+out 1f2, AL                            # number of sectors
+out 1f3, cl (bits 0-5)                 # starting sector number
+out 1f4, ch                            # cylinder number bits 0..7, 0 based
+out 1f5, cl (bits 6,7) & dh (bits 6,7) # cyl, bits 8..9, 10..11
+out 1f6, dh (bits 0..3) --> bits 0..3  # head number
+         dh (bits 4..5) --> ???        # head number
+         dl (bit 0) --> bit 4          # drive number
+out 1f7, 0x20                          # read sectors command normal
+
+
+
+Drive response:
+---------------
+
+* drive sets the busy bit in Status Reg to 1
+* if command parameters are wrong:
+  > drive sets the aborted-command bit in the Error register and
+    error bit in the Status register to 1.
+  > Drive also sets the busy bit in the Status register to 0.
+  > Drive then generates an interrupt to the system.
+* else:
+  > drive executes an implied seek to desired track and
+    reads sectors into sector buffer
+  > when sector buffer is filled and the data is ready to be
+    transferred, the drive sets the data-request bit to 1, sets
+    the busy bit to 0, and generates an interrupt.
+  > on a single-sector transfer, after the system has transferred
+    the data, the drive sets the data-request bit and the busy bit to 0.
+  > on a multiple-sector transfer, after the system has transferred
+    the first sector of data, the drive sets the data-request bit to 0,
+    and the busy bit to 1.  When each subsequent sector is ready to be
+    transferred, the drive sets the data-request bit to 1, the busy bit to 0,
+    and generates an interrupt.  When the system has tranferred the last sector,
+    the drive sets the data-request bit and busy bit to 0.
+
diff --git a/kvm/bios/rombios.c b/kvm/bios/rombios.c
new file mode 100644
index 0000000..6e1d446
--- /dev/null
+++ b/kvm/bios/rombios.c
@@ -0,0 +1,11456 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rombios.c,v 1.182 2007/08/01 17:09:51 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+
+// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+
+
+// ROM BIOS compatability entry points:
+// ===================================
+// $e05b ; POST Entry Point
+// $e2c3 ; NMI Handler Entry Point
+// $e3fe ; INT 13h Fixed Disk Services Entry Point
+// $e401 ; Fixed Disk Parameter Table
+// $e6f2 ; INT 19h Boot Load Service Entry Point
+// $e6f5 ; Configuration Data Table
+// $e729 ; Baud Rate Generator Table
+// $e739 ; INT 14h Serial Communications Service Entry Point
+// $e82e ; INT 16h Keyboard Service Entry Point
+// $e987 ; INT 09h Keyboard Service Entry Point
+// $ec59 ; INT 13h Diskette Service Entry Point
+// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
+// $efc7 ; Diskette Controller Parameter Table
+// $efd2 ; INT 17h Printer Service Entry Point
+// $f045 ; INT 10 Functions 0-Fh Entry Point
+// $f065 ; INT 10h Video Support Service Entry Point
+// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
+// $f841 ; INT 12h Memory Size Service Entry Point
+// $f84d ; INT 11h Equipment List Service Entry Point
+// $f859 ; INT 15h System Services Entry Point
+// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+// $fe6e ; INT 1Ah Time-of-day Service Entry Point
+// $fea5 ; INT 08h System Timer ISR Entry Point
+// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
+// $ff53 ; IRET Instruction for Dummy Interrupt Handler
+// $ff54 ; INT 05h Print Screen Service Entry Point
+// $fff0 ; Power-up Entry Point
+// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
+// $fffe ; System Model ID
+
+// NOTES for ATA/ATAPI driver (cbbochs@free.fr)
+//   Features
+//     - supports up to 4 ATA interfaces
+//     - device/geometry detection
+//     - 16bits/32bits device access
+//     - pchs/lba access
+//     - datain/dataout/packet command support
+//
+// NOTES for El-Torito Boot (cbbochs@free.fr)
+//   - CD-ROM booting is only available if ATA/ATAPI Driver is available
+//   - Current code is only able to boot mono-session cds
+//   - Current code can not boot and emulate a hard-disk
+//     the bios will panic otherwise
+//   - Current code also use memory in EBDA segement.
+//   - I used cmos byte 0x3D to store extended information on boot-device
+//   - Code has to be modified modified to handle multiple cdrom drives
+//   - Here are the cdrom boot failure codes:
+//       1 : no atapi device found
+//       2 : no atapi cdrom found
+//       3 : can not read cd - BRVD
+//       4 : cd is not eltorito (BRVD)
+//       5 : cd is not eltorito (ISO TAG)
+//       6 : cd is not eltorito (ELTORITO TAG)
+//       7 : can not read cd - boot catalog
+//       8 : boot catalog : bad header
+//       9 : boot catalog : bad platform
+//      10 : boot catalog : bad signature
+//      11 : boot catalog : bootable flag not set
+//      12 : can not read cd - boot image
+//
+//   ATA driver
+//   - EBDA segment.
+//     I used memory starting at 0x121 in the segment
+//   - the translation policy is defined in cmos regs 0x39 & 0x3a
+//
+// TODO :
+//
+//   int74
+//     - needs to be reworked.  Uses direct [bp] offsets. (?)
+//
+//   int13:
+//     - f04 (verify sectors) isn't complete  (?)
+//     - f02/03/04 should set current cyl,etc in BDA  (?)
+//     - rewrite int13_relocated & clean up int13 entry code
+//
+//   NOTES:
+//   - NMI access (bit7 of addr written to 70h)
+//
+//   ATA driver
+//   - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
+//   - could send the multiple-sector read/write commands
+//
+//   El-Torito
+//   - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
+//   - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
+//   - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
+//   - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
+//     This is ok. But DL should be reincremented afterwards.
+//   - Fix all "FIXME ElTorito Various"
+//   - should be able to boot any cdrom instead of the first one
+//
+//   BCC Bug: find a generic way to handle the bug of #asm after an "if"  (fixed in 0.16.7)
+
+#include "rombios.h"
+
+#define DEBUG_ATA          0
+#define DEBUG_INT13_HD     0
+#define DEBUG_INT13_CD     0
+#define DEBUG_INT13_ET     0
+#define DEBUG_INT13_FL     0
+#define DEBUG_INT15        0
+#define DEBUG_INT16        0
+#define DEBUG_INT1A        0
+#define DEBUG_INT74        0
+#define DEBUG_APM          0
+
+#define BX_CPU           3
+#define BX_USE_PS2_MOUSE 1
+#define BX_CALL_INT15_4F 1
+#define BX_USE_EBDA      1
+#define BX_SUPPORT_FLOPPY 1
+#define BX_FLOPPY_ON_CNT 37   /* 2 seconds */
+#define BX_PCIBIOS       1
+#define BX_APM           1
+
+#define BX_USE_ATADRV    1
+#define BX_ELTORITO_BOOT 1
+
+#define BX_MAX_ATA_INTERFACES   4
+#define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
+
+#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
+#define BX_DEBUG_SERIAL  0 /* output to COM1 */
+
+   /* model byte 0xFC = AT */
+#define SYS_MODEL_ID     0xFC
+#define SYS_SUBMODEL_ID  0x00
+#define BIOS_REVISION    1
+#define BIOS_CONFIG_TABLE 0xe6f5
+
+#ifndef BIOS_BUILD_DATE
+#  define BIOS_BUILD_DATE "06/23/99"
+#endif
+
+  // 1K of base memory used for Extended Bios Data Area (EBDA)
+  // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
+#define EBDA_SEG           0x9FC0
+#define EBDA_SIZE          1              // In KiB
+#define BASE_MEM_IN_K   (640 - EBDA_SIZE)
+
+/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
+#define IPL_SEG              0x9ff0
+#define IPL_TABLE_OFFSET     0x0000
+#define IPL_TABLE_ENTRIES    8
+#define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
+#define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
+#define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
+#define IPL_SIZE             0xff
+#define IPL_TYPE_FLOPPY      0x01
+#define IPL_TYPE_HARDDISK    0x02
+#define IPL_TYPE_CDROM       0x03
+#define IPL_TYPE_BEV         0x80
+
+  // Sanity Checks
+#if BX_USE_ATADRV && BX_CPU<3
+#    error The ATA/ATAPI Driver can only to be used with a 386+ cpu
+#endif
+#if BX_USE_ATADRV && !BX_USE_EBDA
+#    error ATA/ATAPI Driver can only be used if EBDA is available
+#endif
+#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
+#    error El-Torito Boot can only be use if ATA/ATAPI Driver is available
+#endif
+#if BX_PCIBIOS && BX_CPU<3
+#    error PCI BIOS can only be used with 386+ cpu
+#endif
+#if BX_APM && BX_CPU<3
+#    error APM BIOS can only be used with 386+ cpu
+#endif
+
+// define this if you want to make PCIBIOS working on a specific bridge only
+// undef enables PCIBIOS when at least one PCI device is found
+// i440FX is emulated by Bochs and QEMU
+#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
+
+// #20  is dec 20
+// #$20 is hex 20 = 32
+// #0x20 is hex 20 = 32
+// LDA  #$20
+// JSR  $E820
+// LDD  .i,S
+// JSR  $C682
+// mov al, #$20
+
+// all hex literals should be prefixed with '0x'
+//   grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
+// no mov SEG-REG, #value, must mov register into seg-reg
+//   grep -i "mov[ ]*.s" rombios.c
+
+// This is for compiling with gcc2 and gcc3
+#define ASM_START #asm
+#define ASM_END #endasm
+
+ASM_START
+.rom
+
+.org 0x0000
+
+#if BX_CPU >= 3
+use16 386
+#else
+use16 286
+#endif
+
+MACRO HALT
+  ;; the HALT macro is called with the line number of the HALT call.
+  ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
+  ;; to print a BX_PANIC message.  This will normally halt the simulation
+  ;; with a message such as "BIOS panic at rombios.c, line 4091".
+  ;; However, users can choose to make panics non-fatal and continue.
+#if BX_VIRTUAL_PORTS
+  mov dx,#PANIC_PORT
+  mov ax,#?1
+  out dx,ax
+#else
+  mov dx,#0x80
+  mov ax,#?1
+  out dx,al
+#endif
+MEND
+
+MACRO JMP_AP
+  db 0xea
+  dw ?2
+  dw ?1
+MEND
+
+MACRO SET_INT_VECTOR
+  mov ax, ?3
+  mov ?1*4, ax
+  mov ax, ?2
+  mov ?1*4+2, ax
+MEND
+
+ASM_END
+
+typedef unsigned char  Bit8u;
+typedef unsigned short Bit16u;
+typedef unsigned short bx_bool;
+typedef unsigned long  Bit32u;
+
+
+  void memsetb(seg,offset,value,count);
+  void memcpyb(dseg,doffset,sseg,soffset,count);
+  void memcpyd(dseg,doffset,sseg,soffset,count);
+
+  // memset of count bytes
+    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
+      test cx, cx
+      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
+  }
+
+  // memcpy of count bytes
+    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
+      test cx, cx
+      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
+  }
+
+  // memcpy of count dword
+    void
+  memcpyd(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
+      test cx, cx
+      je   memcpyd_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
+       movsd
+
+  memcpyd_end:
+      pop si
+      pop ds
+      pop di
+      pop es
+      pop cx
+      pop ax
+
+    pop bp
+  ASM_END
+  }
+
+  // read_dword and write_dword functions
+  static Bit32u         read_dword();
+  static void           write_dword();
+
+    Bit32u
+  read_dword(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]
+      add  bx, #2
+      mov  dx, [bx]
+      ;; ax = return value (word)
+      ;; dx = return value (word)
+      pop  ds
+      pop  bx
+
+    pop  bp
+  ASM_END
+  }
+
+    void
+  write_dword(seg, offset, data)
+    Bit16u seg;
+    Bit16u offset;
+    Bit32u 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
+      add  bx, #2
+      mov  ax, 10[bp] ; data word
+      mov  [bx], ax  ; write data word
+      pop  ds
+      pop  bx
+      pop  ax
+
+    pop  bp
+  ASM_END
+  }
+
+  // Bit32u (unsigned long) and long helper functions
+  ASM_START
+
+  ;; and function
+  landl:
+  landul:
+    SEG SS
+      and ax,[di]
+    SEG SS
+      and bx,2[di]
+    ret
+
+  ;; add function
+  laddl:
+  laddul:
+    SEG SS
+      add ax,[di]
+    SEG SS
+      adc bx,2[di]
+    ret
+
+  ;; cmp function
+  lcmpl:
+  lcmpul:
+    and eax, #0x0000FFFF
+    shl ebx, #16
+    or  eax, ebx
+    shr ebx, #16
+    SEG SS
+      cmp eax, dword ptr [di]
+    ret
+
+  ;; sub function
+  lsubl:
+  lsubul:
+    SEG SS
+    sub ax,[di]
+    SEG SS
+    sbb bx,2[di]
+    ret
+
+  ;; mul function
+  lmull:
+  lmulul:
+    and eax, #0x0000FFFF
+    shl ebx, #16
+    or  eax, ebx
+    SEG SS
+    mul eax, dword ptr [di]
+    mov ebx, eax
+    shr ebx, #16
+    ret
+
+  ;; dec function
+  ldecl:
+  ldecul:
+    SEG SS
+    dec dword ptr [bx]
+    ret
+
+  ;; or function
+  lorl:
+  lorul:
+    SEG SS
+    or  ax,[di]
+    SEG SS
+    or  bx,2[di]
+    ret
+
+  ;; inc function
+  lincl:
+  lincul:
+    SEG SS
+    inc dword ptr [bx]
+    ret
+
+  ;; tst function
+  ltstl:
+  ltstul:
+    and eax, #0x0000FFFF
+    shl ebx, #16
+    or  eax, ebx
+    shr ebx, #16
+    test eax, eax
+    ret
+
+  ;; sr function
+  lsrul:
+    mov  cx,di
+    jcxz lsr_exit
+    and  eax, #0x0000FFFF
+    shl  ebx, #16
+    or   eax, ebx
+  lsr_loop:
+    shr  eax, #1
+    loop lsr_loop
+    mov  ebx, eax
+    shr  ebx, #16
+  lsr_exit:
+    ret
+
+  ;; sl function
+  lsll:
+  lslul:
+    mov  cx,di
+    jcxz lsl_exit
+    and  eax, #0x0000FFFF
+    shl  ebx, #16
+    or   eax, ebx
+  lsl_loop:
+    shl  eax, #1
+    loop lsl_loop
+    mov  ebx, eax
+    shr  ebx, #16
+  lsl_exit:
+    ret
+
+  idiv_:
+    cwd
+    idiv bx
+    ret
+
+  idiv_u:
+    xor dx,dx
+    div bx
+    ret
+
+  ldivul:
+    and  eax, #0x0000FFFF
+    shl  ebx, #16
+    or   eax, ebx
+    xor  edx, edx
+    SEG SS
+    mov  bx,  2[di]
+    shl  ebx, #16
+    SEG SS
+    mov  bx,  [di]
+    div  ebx
+    mov  ebx, eax
+    shr  ebx, #16
+    ret
+
+  ASM_END
+
+// for access to RAM area which is used by interrupt vectors
+// and BIOS Data Area
+
+typedef struct {
+  unsigned char filler1[0x400];
+  unsigned char filler2[0x6c];
+  Bit16u ticks_low;
+  Bit16u ticks_high;
+  Bit8u  midnight_flag;
+  } bios_data_t;
+
+#define BiosData ((bios_data_t  *) 0)
+
+#if BX_USE_ATADRV
+  typedef struct {
+    Bit16u heads;      // # heads
+    Bit16u cylinders;  // # cylinders
+    Bit16u spt;        // # sectors / track
+    } chs_t;
+
+  // DPTE definition
+  typedef struct {
+    Bit16u iobase1;
+    Bit16u iobase2;
+    Bit8u  prefix;
+    Bit8u  unused;
+    Bit8u  irq;
+    Bit8u  blkcount;
+    Bit8u  dma;
+    Bit8u  pio;
+    Bit16u options;
+    Bit16u reserved;
+    Bit8u  revision;
+    Bit8u  checksum;
+    } dpte_t;
+
+  typedef struct {
+    Bit8u  iface;        // ISA or PCI
+    Bit16u iobase1;      // IO Base 1
+    Bit16u iobase2;      // IO Base 2
+    Bit8u  irq;          // IRQ
+    } ata_channel_t;
+
+  typedef struct {
+    Bit8u  type;         // Detected type of ata (ata/atapi/none/unknown)
+    Bit8u  device;       // Detected type of attached devices (hd/cd/none)
+    Bit8u  removable;    // Removable device flag
+    Bit8u  lock;         // Locks for removable devices
+    Bit8u  mode;         // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
+    Bit16u blksize;      // block size
+
+    Bit8u  translation;  // type of translation
+    chs_t  lchs;         // Logical CHS
+    chs_t  pchs;         // Physical CHS
+
+    Bit32u sectors_low;  // Total sectors count
+    Bit32u sectors_high;
+    } ata_device_t;
+
+  typedef struct {
+    // ATA channels info
+    ata_channel_t channels[BX_MAX_ATA_INTERFACES];
+
+    // ATA devices info
+    ata_device_t  devices[BX_MAX_ATA_DEVICES];
+    //
+    // map between (bios hd id - 0x80) and ata channels
+    Bit8u  hdcount, hdidmap[BX_MAX_ATA_DEVICES];
+
+    // map between (bios cd id - 0xE0) and ata channels
+    Bit8u  cdcount, cdidmap[BX_MAX_ATA_DEVICES];
+
+    // Buffer for DPTE table
+    dpte_t dpte;
+
+    // Count of transferred sectors and bytes
+    Bit16u trsfsectors;
+    Bit32u trsfbytes;
+
+    } ata_t;
+
+#if BX_ELTORITO_BOOT
+  // ElTorito Device Emulation data
+  typedef struct {
+    Bit8u  active;
+    Bit8u  media;
+    Bit8u  emulated_drive;
+    Bit8u  controller_index;
+    Bit16u device_spec;
+    Bit32u ilba;
+    Bit16u buffer_segment;
+    Bit16u load_segment;
+    Bit16u sector_count;
+
+    // Virtual device
+    chs_t  vdevice;
+    } cdemu_t;
+#endif // BX_ELTORITO_BOOT
+
+  // for access to EBDA area
+  //     The EBDA structure should conform to
+  //     http://www.frontiernet.net/~fys/rombios.htm document
+  //     I made the ata and cdemu structs begin at 0x121 in the EBDA seg
+  // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot
+  // device tables are at IPL_SEG
+  typedef struct {
+    unsigned char filler1[0x3D];
+
+    // FDPT - Can be splitted in data members if needed
+    unsigned char fdpt0[0x10];
+    unsigned char fdpt1[0x10];
+
+    unsigned char filler2[0xC4];
+
+    // ATA Driver data
+    ata_t   ata;
+
+#if BX_ELTORITO_BOOT
+    // El Torito Emulation data
+    cdemu_t cdemu;
+#endif // BX_ELTORITO_BOOT
+
+    } ebda_data_t;
+
+  #define EbdaData ((ebda_data_t *) 0)
+
+  // for access to the int13ext structure
+  typedef struct {
+    Bit8u  size;
+    Bit8u  reserved;
+    Bit16u count;
+    Bit16u offset;
+    Bit16u segment;
+    Bit32u lba1;
+    Bit32u lba2;
+    } int13ext_t;
+
+  #define Int13Ext ((int13ext_t *) 0)
+
+  // Disk Physical Table definition
+  typedef struct {
+    Bit16u  size;
+    Bit16u  infos;
+    Bit32u  cylinders;
+    Bit32u  heads;
+    Bit32u  spt;
+    Bit32u  sector_count1;
+    Bit32u  sector_count2;
+    Bit16u  blksize;
+    Bit16u  dpte_offset;
+    Bit16u  dpte_segment;
+    Bit16u  key;
+    Bit8u   dpi_length;
+    Bit8u   reserved1;
+    Bit16u  reserved2;
+    Bit8u   host_bus[4];
+    Bit8u   iface_type[8];
+    Bit8u   iface_path[8];
+    Bit8u   device_path[8];
+    Bit8u   reserved3;
+    Bit8u   checksum;
+    } dpt_t;
+
+  #define Int13DPT ((dpt_t *) 0)
+
+#endif // BX_USE_ATADRV
+
+typedef struct {
+  union {
+    struct {
+      Bit16u di, si, bp, sp;
+      Bit16u bx, dx, cx, ax;
+      } r16;
+    struct {
+      Bit16u filler[4];
+      Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
+      } r8;
+    } u;
+  } pusha_regs_t;
+
+typedef struct {
+ union {
+  struct {
+    Bit32u edi, esi, ebp, esp;
+    Bit32u ebx, edx, ecx, eax;
+    } r32;
+  struct {
+    Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
+    Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
+    } r16;
+  struct {
+    Bit32u filler[4];
+    Bit8u  bl, bh;
+    Bit16u filler1;
+    Bit8u  dl, dh;
+    Bit16u filler2;
+    Bit8u  cl, ch;
+    Bit16u filler3;
+    Bit8u  al, ah;
+    Bit16u filler4;
+    } r8;
+  } u;
+} pushad_regs_t;
+
+typedef struct {
+  union {
+    struct {
+      Bit16u flags;
+      } r16;
+    struct {
+      Bit8u  flagsl;
+      Bit8u  flagsh;
+      } r8;
+    } u;
+  } flags_t;
+
+#define SetCF(x)   x.u.r8.flagsl |= 0x01
+#define SetZF(x)   x.u.r8.flagsl |= 0x40
+#define ClearCF(x) x.u.r8.flagsl &= 0xfe
+#define ClearZF(x) x.u.r8.flagsl &= 0xbf
+#define GetCF(x)   (x.u.r8.flagsl & 0x01)
+
+typedef struct {
+  Bit16u ip;
+  Bit16u cs;
+  flags_t flags;
+  } iret_addr_t;
+
+typedef struct {
+  Bit16u type;
+  Bit16u flags;
+  Bit32u vector;
+  Bit32u description;
+  Bit32u reserved;
+  } ipl_entry_t;
+
+
+
+static Bit8u          inb();
+static Bit8u          inb_cmos();
+static void           outb();
+static void           outb_cmos();
+static Bit16u         inw();
+static void           outw();
+static void           init_rtc();
+static bx_bool        rtc_updating();
+
+static Bit8u          read_byte();
+static Bit16u         read_word();
+static void           write_byte();
+static void           write_word();
+static void           bios_printf();
+
+static Bit8u          inhibit_mouse_int_and_events();
+static void           enable_mouse_int_and_events();
+static Bit8u          send_to_mouse_ctrl();
+static Bit8u          get_mouse_data();
+static void           set_kbd_command_byte();
+
+static void           int09_function();
+static void           int13_harddisk();
+static void           int13_cdrom();
+static void           int13_cdemu();
+static void           int13_eltorito();
+static void           int13_diskette_function();
+static void           int14_function();
+static void           int15_function();
+static void           int16_function();
+static void           int17_function();
+static void           int19_function();
+static void           int1a_function();
+static void           int70_function();
+static void           int74_function();
+static Bit16u         get_CS();
+static Bit16u         get_SS();
+static unsigned int   enqueue_key();
+static unsigned int   dequeue_key();
+static void           get_hd_geometry();
+static void           set_diskette_ret_status();
+static void           set_diskette_current_cyl();
+static void           determine_floppy_media();
+static bx_bool        floppy_drive_exists();
+static bx_bool        floppy_drive_recal();
+static bx_bool        floppy_media_known();
+static bx_bool        floppy_media_sense();
+static bx_bool        set_enable_a20();
+static void           debugger_on();
+static void           debugger_off();
+static void           keyboard_init();
+static void           keyboard_panic();
+static void           shutdown_status_panic();
+static void           nmi_handler_msg();
+static void           delay_ticks();
+static void           delay_ticks_and_check_for_keystroke();
+
+static void           interactive_bootkey();
+static void           print_bios_banner();
+static void           print_boot_device();
+static void           print_boot_failure();
+static void           print_cdromboot_failure();
+
+# if BX_USE_ATADRV
+
+// ATA / ATAPI driver
+void   ata_init();
+void   ata_detect();
+void   ata_reset();
+
+Bit16u ata_cmd_non_data();
+Bit16u ata_cmd_data_in();
+Bit16u ata_cmd_data_out();
+Bit16u ata_cmd_packet();
+
+Bit16u atapi_get_sense();
+Bit16u atapi_is_ready();
+Bit16u atapi_is_cdrom();
+
+#endif // BX_USE_ATADRV
+
+#if BX_ELTORITO_BOOT
+
+void   cdemu_init();
+Bit8u  cdemu_isactive();
+Bit8u  cdemu_emulated_drive();
+
+Bit16u cdrom_boot();
+
+#endif // BX_ELTORITO_BOOT
+
+static char bios_cvs_version_string[] = "$Revision: 1.182 $ $Date: 2007/08/01 17:09:51 $";
+
+#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
+
+#if DEBUG_ATA
+#  define BX_DEBUG_ATA(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_ATA(a...)
+#endif
+#if DEBUG_INT13_HD
+#  define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT13_HD(a...)
+#endif
+#if DEBUG_INT13_CD
+#  define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT13_CD(a...)
+#endif
+#if DEBUG_INT13_ET
+#  define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT13_ET(a...)
+#endif
+#if DEBUG_INT13_FL
+#  define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT13_FL(a...)
+#endif
+#if DEBUG_INT15
+#  define BX_DEBUG_INT15(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT15(a...)
+#endif
+#if DEBUG_INT16
+#  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT16(a...)
+#endif
+#if DEBUG_INT1A
+#  define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT1A(a...)
+#endif
+#if DEBUG_INT74
+#  define BX_DEBUG_INT74(a...) BX_DEBUG(a)
+#else
+#  define BX_DEBUG_INT74(a...)
+#endif
+
+#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 GET_ELDL() ( ELDX & 0x00ff )
+#define GET_ELDH() ( ELDX >> 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 UNSUPPORTED_FUNCTION 0x86
+
+#define none 0
+#define MAX_SCAN_CODE 0x58
+
+static struct {
+  Bit16u normal;
+  Bit16u shift;
+  Bit16u control;
+  Bit16u alt;
+  Bit8u lock_flags;
+  } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
+      {   none,   none,   none,   none, none },
+      { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
+      { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
+      { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
+      { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
+      { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
+      { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
+      { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
+      { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
+      { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
+      { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
+      { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
+      { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
+      { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
+      { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
+      { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
+      { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
+      { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
+      { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
+      { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
+      { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
+      { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
+      { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
+      { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
+      { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
+      { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
+      { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
+      { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
+      { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
+      {   none,   none,   none,   none, none }, /* L Ctrl */
+      { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
+      { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
+      { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
+      { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
+      { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
+      { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
+      { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
+      { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
+      { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
+      { 0x273b, 0x273a,   none,   none, none }, /* ;: */
+      { 0x2827, 0x2822,   none,   none, none }, /* '" */
+      { 0x2960, 0x297e,   none,   none, none }, /* `~ */
+      {   none,   none,   none,   none, none }, /* L shift */
+      { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
+      { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
+      { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
+      { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
+      { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
+      { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
+      { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
+      { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
+      { 0x332c, 0x333c,   none,   none, none }, /* ,< */
+      { 0x342e, 0x343e,   none,   none, none }, /* .> */
+      { 0x352f, 0x353f,   none,   none, none }, /* /? */
+      {   none,   none,   none,   none, none }, /* R Shift */
+      { 0x372a, 0x372a,   none,   none, none }, /* * */
+      {   none,   none,   none,   none, none }, /* L Alt */
+      { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
+      {   none,   none,   none,   none, none }, /* caps lock */
+      { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
+      { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
+      { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
+      { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
+      { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
+      { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
+      { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
+      { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
+      { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
+      { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
+      {   none,   none,   none,   none, none }, /* Num Lock */
+      {   none,   none,   none,   none, none }, /* Scroll Lock */
+      { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
+      { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
+      { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
+      { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
+      { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
+      { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
+      { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
+      { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
+      { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
+      { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
+      { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
+      { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
+      { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
+      {   none,   none,   none,   none, none },
+      {   none,   none,   none,   none, none },
+      { 0x565c, 0x567c,   none,   none, none }, /* \| */
+      { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
+      { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
+      };
+
+  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
+}
+
+#if BX_USE_ATADRV
+  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
+}
+#endif
+
+  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
+}
+
+#if BX_USE_ATADRV
+  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
+}
+#endif
+
+  void
+outb_cmos(cmos_reg, val)
+  Bit8u cmos_reg;
+  Bit8u val;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    mov  al, 4[bp] ;; cmos_reg
+    out  0x70, al
+    mov  al, 6[bp] ;; val
+    out  0x71, al
+
+  pop  bp
+ASM_END
+}
+
+  Bit8u
+inb_cmos(cmos_reg)
+  Bit8u cmos_reg;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    mov  al, 4[bp] ;; cmos_reg
+    out 0x70, al
+    in  al, 0x71
+
+  pop  bp
+ASM_END
+}
+
+  void
+init_rtc()
+{
+  outb_cmos(0x0a, 0x26);
+  outb_cmos(0x0b, 0x02);
+  inb_cmos(0x0c);
+  inb_cmos(0x0d);
+}
+
+  bx_bool
+rtc_updating()
+{
+  // This function checks to see if the update-in-progress bit
+  // is set in CMOS Status Register A.  If not, it returns 0.
+  // If it is set, it tries to wait until there is a transition
+  // to 0, and will return 0 if such a transition occurs.  A 1
+  // is returned only after timing out.  The maximum period
+  // that this bit should be set is constrained to 244useconds.
+  // The count I use below guarantees coverage or more than
+  // this time, with any reasonable IPS setting.
+
+  Bit16u count;
+
+  count = 25000;
+  while (--count != 0) {
+    if ( (inb_cmos(0x0a) & 0x80) == 0 )
+      return(0);
+    }
+  return(1); // update-in-progress never transitioned to 0
+}
+
+
+  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
+}
+
+  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
+}
+
+  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
+}
+
+  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
+}
+
+  Bit16u
+get_CS()
+{
+ASM_START
+  mov  ax, cs
+ASM_END
+}
+
+  Bit16u
+get_SS()
+{
+ASM_START
+  mov  ax, ss
+ASM_END
+}
+
+#if BX_DEBUG_SERIAL
+/* serial debug port*/
+#define BX_DEBUG_PORT 0x03f8
+
+/* data */
+#define UART_RBR 0x00
+#define UART_THR 0x00
+
+/* control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+int uart_can_tx_byte(base_port)
+    Bit16u base_port;
+{
+    return inb(base_port + UART_LSR) & 0x20;
+}
+
+void uart_wait_to_tx_byte(base_port)
+    Bit16u base_port;
+{
+    while (!uart_can_tx_byte(base_port));
+}
+
+void uart_wait_until_sent(base_port)
+    Bit16u base_port;
+{
+    while (!(inb(base_port + UART_LSR) & 0x40));
+}
+
+void uart_tx_byte(base_port, data)
+    Bit16u base_port;
+    Bit8u data;
+{
+    uart_wait_to_tx_byte(base_port);
+    outb(base_port + UART_THR, data);
+    uart_wait_until_sent(base_port);
+}
+#endif
+
+  void
+wrch(c)
+  Bit8u  c;
+{
+  ASM_START
+  push bp
+  mov  bp, sp
+
+  push bx
+  mov  ah, #0x0e
+  mov  al, 4[bp]
+  xor  bx,bx
+  int  #0x10
+  pop  bx
+
+  pop  bp
+  ASM_END
+}
+
+  void
+send(action, c)
+  Bit16u action;
+  Bit8u  c;
+{
+#if BX_DEBUG_SERIAL
+  if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
+  uart_tx_byte(BX_DEBUG_PORT, c);
+#endif
+#if BX_VIRTUAL_PORTS
+  if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
+  if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
+#endif
+  if (action & BIOS_PRINTF_SCREEN) {
+    if (c == '\n') wrch('\r');
+    wrch(c);
+  }
+}
+
+  void
+put_int(action, val, width, neg)
+  Bit16u action;
+  short val, width;
+  bx_bool neg;
+{
+  short nval = val / 10;
+  if (nval)
+    put_int(action, nval, width - 1, neg);
+  else {
+    while (--width > 0) send(action, ' ');
+    if (neg) send(action, '-');
+  }
+  send(action, val - (nval * 10) + '0');
+}
+
+  void
+put_uint(action, val, width, neg)
+  Bit16u action;
+  unsigned short val;
+  short width;
+  bx_bool neg;
+{
+  unsigned short nval = val / 10;
+  if (nval)
+    put_uint(action, nval, width - 1, neg);
+  else {
+    while (--width > 0) send(action, ' ');
+    if (neg) send(action, '-');
+  }
+  send(action, val - (nval * 10) + '0');
+}
+
+  void
+put_luint(action, val, width, neg)
+  Bit16u action;
+  unsigned long val;
+  short width;
+  bx_bool neg;
+{
+  unsigned long nval = val / 10;
+  if (nval)
+    put_luint(action, nval, width - 1, neg);
+  else {
+    while (--width > 0) send(action, ' ');
+    if (neg) send(action, '-');
+  }
+  send(action, val - (nval * 10) + '0');
+}
+
+void put_str(action, segment, offset)
+  Bit16u action;
+  Bit16u segment;
+  Bit16u offset;
+{
+  Bit8u c;
+
+  while (c = read_byte(segment, offset)) {
+    send(action, c);
+    offset++;
+  }
+}
+
+  void
+delay_ticks(ticks)
+  Bit16u ticks;
+{
+  long ticks_to_wait, delta;
+  Bit32u prev_ticks, t;
+
+   /*
+    * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
+    * We also have to be careful about interrupt storms.
+    */
+ASM_START
+  pushf
+  sti
+ASM_END
+  ticks_to_wait = ticks;
+  prev_ticks = read_dword(0x0, 0x46c);
+  do
+  {
+ASM_START
+    hlt
+ASM_END
+    t = read_dword(0x0, 0x46c);
+    if (t > prev_ticks)
+    {
+      delta = t - prev_ticks;     /* The temp var is required or bcc screws up. */
+      ticks_to_wait -= delta;
+    }
+    else if (t < prev_ticks)
+    {
+      ticks_to_wait -= t;         /* wrapped */
+    }
+
+    prev_ticks = t;
+  } while (ticks_to_wait > 0);
+ASM_START
+  cli
+  popf
+ASM_END
+}
+
+  Bit8u
+check_for_keystroke()
+{
+ASM_START
+  mov  ax, #0x100
+  int  #0x16
+  jz   no_key
+  mov  al, #1
+  jmp  done
+no_key:
+  xor  al, al
+done:
+ASM_END
+}
+
+  Bit8u
+get_keystroke()
+{
+ASM_START
+  mov  ax, #0x0
+  int  #0x16
+  xchg ah, al
+ASM_END
+}
+
+  void
+delay_ticks_and_check_for_keystroke(ticks, count)
+  Bit16u ticks, count;
+{
+  Bit16u i;
+  for (i = 1; i <= count; i++) {
+    delay_ticks(ticks);
+    if (check_for_keystroke())
+      break;
+  }
+}
+
+//--------------------------------------------------------------------------
+// bios_printf()
+//   A compact variable argument printf function.
+//
+//   Supports %[format_width][length]format
+//   where format can be x,X,u,d,s,S,c
+//   and the optional length modifier is l (ell)
+//--------------------------------------------------------------------------
+  void
+bios_printf(action, s)
+  Bit16u action;
+  Bit8u *s;
+{
+  Bit8u c, format_char;
+  bx_bool  in_format;
+  short i;
+  Bit16u  *arg_ptr;
+  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
+
+  arg_ptr = &s;
+  arg_seg = get_SS();
+
+  in_format = 0;
+  format_width = 0;
+
+  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
+#if BX_VIRTUAL_PORTS
+    outb(PANIC_PORT2, 0x00);
+#endif
+    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
+  }
+
+  while (c = read_byte(get_CS(), 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 {
+        arg_ptr++; // increment to next arg
+        arg = read_word(arg_seg, arg_ptr);
+        if (c == 'x' || c == 'X') {
+          if (format_width == 0)
+            format_width = 4;
+          if (c == 'x')
+            hexadd = 'a';
+          else
+            hexadd = 'A';
+          for (i=format_width-1; i>=0; i--) {
+            nibble = (arg >> (4 * i)) & 0x000f;
+            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
+            }
+          }
+        else if (c == 'u') {
+          put_uint(action, arg, format_width, 0);
+          }
+        else if (c == 'l') {
+          s++;
+          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
+          arg_ptr++; /* increment to next arg */
+          hibyte = read_word(arg_seg, arg_ptr);
+          if (c == 'd') {
+            if (hibyte & 0x8000)
+              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
+            else
+              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
+           }
+          else if (c == 'u') {
+            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
+           }
+          else if (c == 'x' || c == 'X')
+           {
+            if (format_width == 0)
+              format_width = 8;
+            if (c == 'x')
+              hexadd = 'a';
+            else
+              hexadd = 'A';
+            for (i=format_width-1; i>=0; i--) {
+              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
+              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
+              }
+           }
+          }
+        else if (c == 'd') {
+          if (arg & 0x8000)
+            put_int(action, -arg, format_width - 1, 1);
+          else
+            put_int(action, arg, format_width, 0);
+          }
+        else if (c == 's') {
+          put_str(action, get_CS(), arg);
+          }
+        else if (c == 'S') {
+          hibyte = arg;
+          arg_ptr++;
+          arg = read_word(arg_seg, arg_ptr);
+          put_str(action, hibyte, arg);
+          }
+        else if (c == 'c') {
+          send(action, arg);
+          }
+        else
+          BX_PANIC("bios_printf: unknown format\n");
+          in_format = 0;
+        }
+      }
+    else {
+      send(action, c);
+      }
+    s ++;
+    }
+
+  if (action & BIOS_PRINTF_HALT) {
+    // freeze in a busy loop.
+ASM_START
+    cli
+ halt2_loop:
+    hlt
+    jmp halt2_loop
+ASM_END
+    }
+}
+
+//--------------------------------------------------------------------------
+// keyboard_init
+//--------------------------------------------------------------------------
+// this file is based on LinuxBIOS implementation of keyboard.c
+// could convert to #asm to gain space
+  void
+keyboard_init()
+{
+    Bit16u max;
+
+    /* ------------------- Flush buffers ------------------------*/
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
+
+    /* flush incoming keys */
+    max=0x2000;
+    while (--max > 0) {
+        outb(0x80, 0x00);
+        if (inb(0x64) & 0x01) {
+            inb(0x60);
+            max = 0x2000;
+            }
+        }
+
+    // Due to timer issues, and if the IPS setting is > 15000000,
+    // the incoming keys might not be flushed here. That will
+    // cause a panic a few lines below.  See sourceforge bug report :
+    // [ 642031 ] FATAL: Keyboard RESET error:993
+
+    /* ------------------- controller side ----------------------*/
+    /* send cmd = 0xAA, self test 8042 */
+    outb(0x64, 0xaa);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
+    if (max==0x0) keyboard_panic(00);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
+    if (max==0x0) keyboard_panic(01);
+
+    /* read self-test result, 0x55 should be returned from 0x60 */
+    if ((inb(0x60) != 0x55)){
+        keyboard_panic(991);
+    }
+
+    /* send cmd = 0xAB, keyboard interface test */
+    outb(0x64,0xab);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
+    if (max==0x0) keyboard_panic(10);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
+    if (max==0x0) keyboard_panic(11);
+
+    /* read keyboard interface test result, */
+    /* 0x00 should be returned form 0x60 */
+    if ((inb(0x60) != 0x00)) {
+        keyboard_panic(992);
+    }
+
+    /* Enable Keyboard clock */
+    outb(0x64,0xae);
+    outb(0x64,0xa8);
+
+    /* ------------------- keyboard side ------------------------*/
+    /* reset kerboard and self test  (keyboard side) */
+    outb(0x60, 0xff);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
+    if (max==0x0) keyboard_panic(20);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
+    if (max==0x0) keyboard_panic(21);
+
+    /* keyboard should return ACK */
+    if ((inb(0x60) != 0xfa)) {
+        keyboard_panic(993);
+    }
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
+    if (max==0x0) keyboard_panic(31);
+
+    if ((inb(0x60) != 0xaa)) {
+        keyboard_panic(994);
+    }
+
+    /* Disable keyboard */
+    outb(0x60, 0xf5);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
+    if (max==0x0) keyboard_panic(40);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
+    if (max==0x0) keyboard_panic(41);
+
+    /* keyboard should return ACK */
+    if ((inb(0x60) != 0xfa)) {
+        keyboard_panic(995);
+    }
+
+    /* Write Keyboard Mode */
+    outb(0x64, 0x60);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
+    if (max==0x0) keyboard_panic(50);
+
+    /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
+    outb(0x60, 0x61);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
+    if (max==0x0) keyboard_panic(60);
+
+    /* Enable keyboard */
+    outb(0x60, 0xf4);
+
+    /* Wait until buffer is empty */
+    max=0xffff;
+    while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
+    if (max==0x0) keyboard_panic(70);
+
+    /* Wait for data */
+    max=0xffff;
+    while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
+    if (max==0x0) keyboard_panic(70);
+
+    /* keyboard should return ACK */
+    if ((inb(0x60) != 0xfa)) {
+        keyboard_panic(996);
+    }
+
+    outb(0x80, 0x77);
+}
+
+//--------------------------------------------------------------------------
+// keyboard_panic
+//--------------------------------------------------------------------------
+  void
+keyboard_panic(status)
+  Bit16u status;
+{
+  // If you're getting a 993 keyboard panic here,
+  // please see the comment in keyboard_init
+
+  BX_PANIC("Keyboard error:%u\n",status);
+}
+
+//--------------------------------------------------------------------------
+// shutdown_status_panic
+//   called when the shutdown statsu is not implemented, displays the status
+//--------------------------------------------------------------------------
+  void
+shutdown_status_panic(status)
+  Bit16u status;
+{
+  BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
+}
+
+void s3_resume_panic()
+{
+  BX_PANIC("Returned from s3_resume.\n");
+}
+
+//--------------------------------------------------------------------------
+// print_bios_banner
+//   displays a the bios version
+//--------------------------------------------------------------------------
+void
+print_bios_banner()
+{
+  printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
+    BIOS_BUILD_DATE, bios_cvs_version_string);
+  printf(
+#if BX_APM
+  "apmbios "
+#endif
+#if BX_PCIBIOS
+  "pcibios "
+#endif
+#if BX_ELTORITO_BOOT
+  "eltorito "
+#endif
+#if BX_ROMBIOS32
+  "rombios32 "
+#endif
+  "\n\n");
+}
+
+//--------------------------------------------------------------------------
+// BIOS Boot Specification 1.0.1 compatibility
+//
+// Very basic support for the BIOS Boot Specification, which allows expansion
+// ROMs to register themselves as boot devices, instead of just stealing the
+// INT 19h boot vector.
+//
+// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
+// one; we just lie to the option ROMs to make them behave correctly.
+// We also don't support letting option ROMs register as bootable disk
+// drives (BCVs), only as bootable devices (BEVs).
+//
+// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
+//--------------------------------------------------------------------------
+
+static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
+
+static void
+init_boot_vectors()
+{
+  ipl_entry_t e;
+  Bit16u count = 0;
+  Bit16u ss = get_SS();
+
+  /* Clear out the IPL table. */
+  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
+
+  /* User selected device not set */
+  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
+
+  /* Floppy drive */
+  e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
+  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
+  count++;
+
+  /* First HDD */
+  e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
+  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
+  count++;
+
+#if BX_ELTORITO_BOOT
+  /* CDROM */
+  e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
+  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
+  count++;
+#endif
+
+  /* Remember how many devices we have */
+  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
+  /* Not tried booting anything yet */
+  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
+}
+
+static Bit8u
+get_boot_vector(i, e)
+Bit16u i; ipl_entry_t *e;
+{
+  Bit16u count;
+  Bit16u ss = get_SS();
+  /* Get the count of boot devices, and refuse to overrun the array */
+  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
+  if (i >= count) return 0;
+  /* OK to read this device */
+  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
+  return 1;
+}
+
+#if BX_ELTORITO_BOOT
+#ifdef BX_QEMU
+int
+qemu_cfg_probe_bootkey()
+{
+  outw(QEMU_CFG_CTL_PORT, QEMU_CFG_SIGNATURE);
+  if (inb(QEMU_CFG_DATA_PORT) != 'Q' ||
+      inb(QEMU_CFG_DATA_PORT) != 'E' ||
+      inb(QEMU_CFG_DATA_PORT) != 'M' ||
+      inb(QEMU_CFG_DATA_PORT) != 'U') return 1;
+
+  outw(QEMU_CFG_CTL_PORT, QEMU_CFG_BOOT_MENU);
+  return inb(QEMU_CFG_DATA_PORT);
+}
+#endif // BX_QEMU
+
+  void
+interactive_bootkey()
+{
+  ipl_entry_t e;
+  Bit16u count;
+  char description[33];
+  Bit8u scan_code;
+  Bit8u i;
+  Bit16u ss = get_SS();
+  Bit16u valid_choice = 0;
+
+#ifdef BX_QEMU
+  if (!qemu_cfg_probe_bootkey()) return;
+#endif
+
+  while (check_for_keystroke())
+    get_keystroke();
+
+  printf("Press F12 for boot menu.\n\n");
+
+  delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
+  if (check_for_keystroke())
+  {
+    scan_code = get_keystroke();
+    if (scan_code == 0x86) /* F12 */
+    {
+      while (check_for_keystroke())
+        get_keystroke();
+
+      printf("Select boot device:\n\n");
+
+      count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
+      for (i = 0; i < count; i++)
+      {
+        memcpyb(ss, &e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
+        printf("%d. ", i+1);
+        switch(e.type)
+        {
+          case IPL_TYPE_FLOPPY:
+          case IPL_TYPE_HARDDISK:
+          case IPL_TYPE_CDROM:
+            printf("%s\n", drivetypes[e.type]);
+            break;
+          case IPL_TYPE_BEV:
+            printf("%s", drivetypes[4]);
+            if (e.description != 0)
+            {
+              memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
+              description[32] = 0;
+              printf(" [%S]", ss, description);
+           }
+           printf("\n");
+           break;
+        }
+      }
+
+      count++;
+      while (!valid_choice) {
+        scan_code = get_keystroke();
+        if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
+        {
+          valid_choice = 1;
+        }
+        else if (scan_code <= count)
+        {
+          valid_choice = 1;
+          scan_code -= 1;
+          /* Set user selected device */
+          write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, scan_code);
+        }
+      }
+    printf("\n");
+    }
+  }
+}
+#endif // BX_ELTORITO_BOOT
+
+//--------------------------------------------------------------------------
+// print_boot_device
+//   displays the boot device
+//--------------------------------------------------------------------------
+
+void
+print_boot_device(e)
+  ipl_entry_t *e;
+{
+  Bit16u type;
+  char description[33];
+  Bit16u ss = get_SS();
+  type = e->type;
+  /* NIC appears as type 0x80 */
+  if (type == IPL_TYPE_BEV) type = 0x4;
+  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
+  printf("Booting from %s", drivetypes[type]);
+  /* print product string if BEV */
+  if (type == 4 && e->description != 0) {
+    /* first 32 bytes are significant */
+    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
+    /* terminate string */
+    description[32] = 0;
+    printf(" [%S]", ss, description);
+  }
+  printf("...\n");
+}
+
+//--------------------------------------------------------------------------
+// print_boot_failure
+//   displays the reason why boot failed
+//--------------------------------------------------------------------------
+  void
+print_boot_failure(type, reason)
+  Bit16u type; Bit8u reason;
+{
+  if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
+
+  printf("Boot failed");
+  if (type < 4) {
+    /* Report the reason too */
+    if (reason==0)
+      printf(": not a bootable disk");
+    else
+      printf(": could not read the boot disk");
+  }
+  printf("\n\n");
+}
+
+//--------------------------------------------------------------------------
+// print_cdromboot_failure
+//   displays the reason why boot failed
+//--------------------------------------------------------------------------
+  void
+print_cdromboot_failure( code )
+  Bit16u code;
+{
+  bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
+
+  return;
+}
+
+void
+nmi_handler_msg()
+{
+  BX_PANIC("NMI Handler called\n");
+}
+
+void
+int18_panic_msg()
+{
+  BX_PANIC("INT18: BOOT FAILURE\n");
+}
+
+void
+log_bios_start()
+{
+#if BX_DEBUG_SERIAL
+  outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
+#endif
+  BX_INFO("%s\n", bios_cvs_version_string);
+}
+
+  bx_bool
+set_enable_a20(val)
+  bx_bool val;
+{
+  Bit8u  oldval;
+
+  // Use PS2 System Control port A to set A20 enable
+
+  // get current setting first
+  oldval = inb(0x92);
+
+  // change A20 status
+  if (val)
+    outb(0x92, oldval | 0x02);
+  else
+    outb(0x92, oldval & 0xfd);
+
+  return((oldval & 0x02) != 0);
+}
+
+  void
+debugger_on()
+{
+  outb(0xfedc, 0x01);
+}
+
+  void
+debugger_off()
+{
+  outb(0xfedc, 0x00);
+}
+
+int
+s3_resume()
+{
+    Bit32u s3_wakeup_vector;
+    Bit8u s3_resume_flag;
+
+    s3_resume_flag = read_byte(0x40, 0xb0);
+    s3_wakeup_vector = read_dword(0x40, 0xb2);
+
+    BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector);
+    if (s3_resume_flag != 0xFE || !s3_wakeup_vector)
+	    return 0;
+
+    write_byte(0x40, 0xb0, 0);
+
+    /* setup wakeup vector */
+    write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */
+    write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */
+
+    BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4),
+		    (s3_wakeup_vector & 0xF));
+ASM_START
+    mov sp, #0 ;; disable tpr patching on boot CPU
+    jmpf [0x04b6]
+ASM_END
+    return 1;
+}
+
+#if BX_USE_ATADRV
+
+// ---------------------------------------------------------------------------
+// Start of ATA/ATAPI Driver
+// ---------------------------------------------------------------------------
+
+// Global defines -- ATA register and register bits.
+// command block & control block regs
+#define ATA_CB_DATA  0   // data reg         in/out pio_base_addr1+0
+#define ATA_CB_ERR   1   // error            in     pio_base_addr1+1
+#define ATA_CB_FR    1   // feature reg         out pio_base_addr1+1
+#define ATA_CB_SC    2   // sector count     in/out pio_base_addr1+2
+#define ATA_CB_SN    3   // sector number    in/out pio_base_addr1+3
+#define ATA_CB_CL    4   // cylinder low     in/out pio_base_addr1+4
+#define ATA_CB_CH    5   // cylinder high    in/out pio_base_addr1+5
+#define ATA_CB_DH    6   // device head      in/out pio_base_addr1+6
+#define ATA_CB_STAT  7   // primary status   in     pio_base_addr1+7
+#define ATA_CB_CMD   7   // command             out pio_base_addr1+7
+#define ATA_CB_ASTAT 6   // alternate status in     pio_base_addr2+6
+#define ATA_CB_DC    6   // device control      out pio_base_addr2+6
+#define ATA_CB_DA    7   // device address   in     pio_base_addr2+7
+
+#define ATA_CB_ER_ICRC 0x80    // ATA Ultra DMA bad CRC
+#define ATA_CB_ER_BBK  0x80    // ATA bad block
+#define ATA_CB_ER_UNC  0x40    // ATA uncorrected error
+#define ATA_CB_ER_MC   0x20    // ATA media change
+#define ATA_CB_ER_IDNF 0x10    // ATA id not found
+#define ATA_CB_ER_MCR  0x08    // ATA media change request
+#define ATA_CB_ER_ABRT 0x04    // ATA command aborted
+#define ATA_CB_ER_NTK0 0x02    // ATA track 0 not found
+#define ATA_CB_ER_NDAM 0x01    // ATA address mark not found
+
+#define ATA_CB_ER_P_SNSKEY 0xf0   // ATAPI sense key (mask)
+#define ATA_CB_ER_P_MCR    0x08   // ATAPI Media Change Request
+#define ATA_CB_ER_P_ABRT   0x04   // ATAPI command abort
+#define ATA_CB_ER_P_EOM    0x02   // ATAPI End of Media
+#define ATA_CB_ER_P_ILI    0x01   // ATAPI Illegal Length Indication
+
+// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
+#define ATA_CB_SC_P_TAG    0xf8   // ATAPI tag (mask)
+#define ATA_CB_SC_P_REL    0x04   // ATAPI release
+#define ATA_CB_SC_P_IO     0x02   // ATAPI I/O
+#define ATA_CB_SC_P_CD     0x01   // ATAPI C/D
+
+// bits 7-4 of the device/head (CB_DH) reg
+#define ATA_CB_DH_DEV0 0xa0    // select device 0
+#define ATA_CB_DH_DEV1 0xb0    // select device 1
+#define ATA_CB_DH_LBA 0x40    // use LBA
+
+// status reg (CB_STAT and CB_ASTAT) bits
+#define ATA_CB_STAT_BSY  0x80  // busy
+#define ATA_CB_STAT_RDY  0x40  // ready
+#define ATA_CB_STAT_DF   0x20  // device fault
+#define ATA_CB_STAT_WFT  0x20  // write fault (old name)
+#define ATA_CB_STAT_SKC  0x10  // seek complete
+#define ATA_CB_STAT_SERV 0x10  // service
+#define ATA_CB_STAT_DRQ  0x08  // data request
+#define ATA_CB_STAT_CORR 0x04  // corrected
+#define ATA_CB_STAT_IDX  0x02  // index
+#define ATA_CB_STAT_ERR  0x01  // error (ATA)
+#define ATA_CB_STAT_CHK  0x01  // check (ATAPI)
+
+// device control reg (CB_DC) bits
+#define ATA_CB_DC_HD15   0x08  // bit should always be set to one
+#define ATA_CB_DC_SRST   0x04  // soft reset
+#define ATA_CB_DC_NIEN   0x02  // disable interrupts
+
+// Most mandtory and optional ATA commands (from ATA-3),
+#define ATA_CMD_CFA_ERASE_SECTORS            0xC0
+#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
+#define ATA_CMD_CFA_TRANSLATE_SECTOR         0x87
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
+#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
+#define ATA_CMD_CHECK_POWER_MODE1            0xE5
+#define ATA_CMD_CHECK_POWER_MODE2            0x98
+#define ATA_CMD_DEVICE_RESET                 0x08
+#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
+#define ATA_CMD_FLUSH_CACHE                  0xE7
+#define ATA_CMD_FORMAT_TRACK                 0x50
+#define ATA_CMD_IDENTIFY_DEVICE              0xEC
+#define ATA_CMD_IDENTIFY_DEVICE_PACKET       0xA1
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE       0xA1
+#define ATA_CMD_IDLE1                        0xE3
+#define ATA_CMD_IDLE2                        0x97
+#define ATA_CMD_IDLE_IMMEDIATE1              0xE1
+#define ATA_CMD_IDLE_IMMEDIATE2              0x95
+#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS  0x91
+#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_CMD_NOP                          0x00
+#define ATA_CMD_PACKET                       0xA0
+#define ATA_CMD_READ_BUFFER                  0xE4
+#define ATA_CMD_READ_DMA                     0xC8
+#define ATA_CMD_READ_DMA_QUEUED              0xC7
+#define ATA_CMD_READ_MULTIPLE                0xC4
+#define ATA_CMD_READ_SECTORS                 0x20
+#define ATA_CMD_READ_VERIFY_SECTORS          0x40
+#define ATA_CMD_RECALIBRATE                  0x10
+#define ATA_CMD_REQUEST_SENSE                0x03
+#define ATA_CMD_SEEK                         0x70
+#define ATA_CMD_SET_FEATURES                 0xEF
+#define ATA_CMD_SET_MULTIPLE_MODE            0xC6
+#define ATA_CMD_SLEEP1                       0xE6
+#define ATA_CMD_SLEEP2                       0x99
+#define ATA_CMD_STANDBY1                     0xE2
+#define ATA_CMD_STANDBY2                     0x96
+#define ATA_CMD_STANDBY_IMMEDIATE1           0xE0
+#define ATA_CMD_STANDBY_IMMEDIATE2           0x94
+#define ATA_CMD_WRITE_BUFFER                 0xE8
+#define ATA_CMD_WRITE_DMA                    0xCA
+#define ATA_CMD_WRITE_DMA_QUEUED             0xCC
+#define ATA_CMD_WRITE_MULTIPLE               0xC5
+#define ATA_CMD_WRITE_SECTORS                0x30
+#define ATA_CMD_WRITE_VERIFY                 0x3C
+
+#define ATA_IFACE_NONE    0x00
+#define ATA_IFACE_ISA     0x00
+#define ATA_IFACE_PCI     0x01
+
+#define ATA_TYPE_NONE     0x00
+#define ATA_TYPE_UNKNOWN  0x01
+#define ATA_TYPE_ATA      0x02
+#define ATA_TYPE_ATAPI    0x03
+
+#define ATA_DEVICE_NONE  0x00
+#define ATA_DEVICE_HD    0xFF
+#define ATA_DEVICE_CDROM 0x05
+
+#define ATA_MODE_NONE    0x00
+#define ATA_MODE_PIO16   0x00
+#define ATA_MODE_PIO32   0x01
+#define ATA_MODE_ISADMA  0x02
+#define ATA_MODE_PCIDMA  0x03
+#define ATA_MODE_USEIRQ  0x10
+
+#define ATA_TRANSLATION_NONE  0
+#define ATA_TRANSLATION_LBA   1
+#define ATA_TRANSLATION_LARGE 2
+#define ATA_TRANSLATION_RECHS 3
+
+#define ATA_DATA_NO      0x00
+#define ATA_DATA_IN      0x01
+#define ATA_DATA_OUT     0x02
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : initialization
+// ---------------------------------------------------------------------------
+void ata_init( )
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  channel, device;
+
+  // Channels info init.
+  for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
+    write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
+    write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
+    write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
+    write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
+    }
+
+  // Devices info init.
+  for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
+    write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
+    write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
+    write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
+    write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
+    write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
+    write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
+    write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
+
+    write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L);
+    write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L);
+    }
+
+  // hdidmap  and cdidmap init.
+  for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
+    write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
+    write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
+    }
+
+  write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
+  write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
+}
+
+#define TIMEOUT 0
+#define BSY 1
+#define NOT_BSY 2
+#define NOT_BSY_DRQ 3
+#define NOT_BSY_NOT_DRQ 4
+#define NOT_BSY_RDY 5
+
+#define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
+
+int await_ide();
+static int await_ide(when_done,base,timeout)
+  Bit8u when_done;
+  Bit16u base;
+  Bit16u timeout;
+{
+  Bit32u time=0,last=0;
+  Bit16u status;
+  Bit8u result;
+  status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away
+  for(;;) {
+    status = inb(base+ATA_CB_STAT);
+    time++;
+    if (when_done == BSY)
+      result = status & ATA_CB_STAT_BSY;
+    else if (when_done == NOT_BSY)
+      result = !(status & ATA_CB_STAT_BSY);
+    else if (when_done == NOT_BSY_DRQ)
+      result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ);
+    else if (when_done == NOT_BSY_NOT_DRQ)
+      result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ);
+    else if (when_done == NOT_BSY_RDY)
+      result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY);
+    else if (when_done == TIMEOUT)
+      result = 0;
+
+    if (result) return 0;
+    if (time>>16 != last) // mod 2048 each 16 ms
+    {
+      last = time >>16;
+      BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
+    }
+    if (status & ATA_CB_STAT_ERR)
+    {
+      BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
+      return -1;
+    }
+    if ((timeout == 0) || ((time>>11) > timeout)) break;
+  }
+  BX_INFO("IDE time out\n");
+  return -1;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : device detection
+// ---------------------------------------------------------------------------
+
+void ata_detect( )
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  hdcount, cdcount, device, type;
+  Bit8u  buffer[0x0200];
+
+#if BX_MAX_ATA_INTERFACES > 0
+  write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
+  write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
+  write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
+  write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
+#endif
+#if BX_MAX_ATA_INTERFACES > 1
+  write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
+  write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
+  write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
+  write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
+#endif
+#if BX_MAX_ATA_INTERFACES > 2
+  write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
+  write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
+  write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
+  write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
+#endif
+#if BX_MAX_ATA_INTERFACES > 3
+  write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
+  write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
+  write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
+  write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
+#endif
+#if BX_MAX_ATA_INTERFACES > 4
+#error Please fill the ATA interface informations
+#endif
+
+  // Device detection
+  hdcount=cdcount=0;
+
+  for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
+    Bit16u iobase1, iobase2;
+    Bit8u  channel, slave, shift;
+    Bit8u  sc, sn, cl, ch, st;
+
+    channel = device / 2;
+    slave = device % 2;
+
+    iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
+    iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
+
+    // Disable interrupts
+    outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+    // Look for device
+    outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+    outb(iobase1+ATA_CB_SC, 0x55);
+    outb(iobase1+ATA_CB_SN, 0xaa);
+    outb(iobase1+ATA_CB_SC, 0xaa);
+    outb(iobase1+ATA_CB_SN, 0x55);
+    outb(iobase1+ATA_CB_SC, 0x55);
+    outb(iobase1+ATA_CB_SN, 0xaa);
+
+    // If we found something
+    sc = inb(iobase1+ATA_CB_SC);
+    sn = inb(iobase1+ATA_CB_SN);
+
+    if ( (sc == 0x55) && (sn == 0xaa) ) {
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
+
+      // reset the channel
+      ata_reset(device);
+
+      // check for ATA or ATAPI
+      outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+      sc = inb(iobase1+ATA_CB_SC);
+      sn = inb(iobase1+ATA_CB_SN);
+      if ((sc==0x01) && (sn==0x01)) {
+        cl = inb(iobase1+ATA_CB_CL);
+        ch = inb(iobase1+ATA_CB_CH);
+        st = inb(iobase1+ATA_CB_STAT);
+
+        if ((cl==0x14) && (ch==0xeb)) {
+          write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
+        } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
+          write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
+        } else if ((cl==0xff) && (ch==0xff)) {
+          write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
+        }
+      }
+    }
+
+    type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
+
+    // Now we send a IDENTIFY command to ATA device
+    if(type == ATA_TYPE_ATA) {
+      Bit32u sectors_low, sectors_high;
+      Bit16u cylinders, heads, spt, blksize;
+      Bit8u  translation, removable, mode;
+
+      //Temporary values to do the transfer
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
+
+      if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 )
+        BX_PANIC("ata-detect: Failed to detect ATA device\n");
+
+      removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
+      mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+      blksize   = read_word(get_SS(),buffer+10);
+
+      cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
+      heads     = read_word(get_SS(),buffer+(3*2)); // word 3
+      spt       = read_word(get_SS(),buffer+(6*2)); // word 6
+
+      if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support
+        sectors_low  = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101
+        sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103
+      } else {
+        sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
+        sectors_high = 0;
+      }
+
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
+      write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low);
+      write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high);
+      BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
+
+      translation = inb_cmos(0x39 + channel/2);
+      for (shift=device%4; shift>0; shift--) translation >>= 2;
+      translation &= 0x03;
+
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
+
+      switch (translation) {
+        case ATA_TRANSLATION_NONE:
+          BX_INFO("none");
+          break;
+        case ATA_TRANSLATION_LBA:
+          BX_INFO("lba");
+          break;
+        case ATA_TRANSLATION_LARGE:
+          BX_INFO("large");
+          break;
+        case ATA_TRANSLATION_RECHS:
+          BX_INFO("r-echs");
+          break;
+        }
+      switch (translation) {
+        case ATA_TRANSLATION_NONE:
+          break;
+        case ATA_TRANSLATION_LBA:
+          spt = 63;
+          sectors_low /= 63;
+          heads = sectors_low / 1024;
+          if (heads>128) heads = 255;
+          else if (heads>64) heads = 128;
+          else if (heads>32) heads = 64;
+          else if (heads>16) heads = 32;
+          else heads=16;
+          cylinders = sectors_low / heads;
+          break;
+        case ATA_TRANSLATION_RECHS:
+          // Take care not to overflow
+          if (heads==16) {
+            if(cylinders>61439) cylinders=61439;
+            heads=15;
+            cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
+            }
+          // then go through the large bitshift process
+        case ATA_TRANSLATION_LARGE:
+          while(cylinders > 1024) {
+            cylinders >>= 1;
+            heads <<= 1;
+
+            // If we max out the head count
+            if (heads > 127) break;
+          }
+          break;
+        }
+      // clip to 1024 cylinders in lchs
+      if (cylinders > 1024) cylinders=1024;
+      BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
+
+      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
+
+      // fill hdidmap
+      write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
+      hdcount++;
+      }
+
+    // Now we send a IDENTIFY command to ATAPI device
+    if(type == ATA_TYPE_ATAPI) {
+
+      Bit8u  type, removable, mode;
+      Bit16u blksize;
+
+      //Temporary values to do the transfer
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
+
+      if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0)
+        BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
+
+      type      = read_byte(get_SS(),buffer+1) & 0x1f;
+      removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
+      mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+      blksize   = 2048;
+
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
+      write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
+      write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
+
+      // fill cdidmap
+      write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
+      cdcount++;
+      }
+
+      {
+      Bit32u sizeinmb;
+      Bit16u ataversion;
+      Bit8u  c, i, version, model[41];
+
+      switch (type) {
+        case ATA_TYPE_ATA:
+          sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21)
+            | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11);
+        case ATA_TYPE_ATAPI:
+          // Read ATA/ATAPI version
+          ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
+          for(version=15;version>0;version--) {
+            if((ataversion&(1<<version))!=0)
+            break;
+            }
+
+          // Read model name
+          for(i=0;i<20;i++){
+            write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
+            write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
+          }
+
+          // Reformat
+          write_byte(get_SS(),model+40,0x00);
+          for(i=39;i>0;i--){
+            if(read_byte(get_SS(),model+i)==0x20)
+              write_byte(get_SS(),model+i,0x00);
+            else break;
+          }
+          if (i>36) {
+            write_byte(get_SS(),model+36,0x00);
+            for(i=35;i>32;i--){
+              write_byte(get_SS(),model+i,0x2E);
+            }
+          }
+          break;
+        }
+
+      switch (type) {
+        case ATA_TYPE_ATA:
+          printf("ata%d %s: ",channel,slave?" slave":"master");
+          i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
+	  if (sizeinmb < (1UL<<16))
+            printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb);
+	  else
+            printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10));
+          break;
+        case ATA_TYPE_ATAPI:
+          printf("ata%d %s: ",channel,slave?" slave":"master");
+          i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
+          if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
+            printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
+          else
+            printf(" ATAPI-%d Device\n",version);
+          break;
+        case ATA_TYPE_UNKNOWN:
+          printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
+          break;
+        }
+      }
+    }
+
+  // Store the devices counts
+  write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
+  write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
+  write_byte(0x40,0x75, hdcount);
+
+  printf("\n");
+
+  // FIXME : should use bios=cmos|auto|disable bits
+  // FIXME : should know about translation bits
+  // FIXME : move hard_drive_post here
+
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : software reset
+// ---------------------------------------------------------------------------
+// ATA-3
+// 8.2.1 Software reset - Device 0
+
+void   ata_reset(device)
+Bit16u device;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit16u iobase1, iobase2;
+  Bit8u  channel, slave, sn, sc;
+  Bit8u  type;
+  Bit16u max;
+
+  channel = device / 2;
+  slave = device % 2;
+
+  iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+  iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+
+  // Reset
+
+// 8.2.1 (a) -- set SRST in DC
+  outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
+
+// 8.2.1 (b) -- wait for BSY
+  await_ide(BSY, iobase1, 20);
+
+// 8.2.1 (f) -- clear SRST
+  outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+  type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
+  if (type != ATA_TYPE_NONE) {
+
+// 8.2.1 (g) -- check for sc==sn==0x01
+    // select device
+    outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
+    sc = inb(iobase1+ATA_CB_SC);
+    sn = inb(iobase1+ATA_CB_SN);
+
+    if ( (sc==0x01) && (sn==0x01) ) {
+      if (type == ATA_TYPE_ATA) //ATA
+        await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT);
+      else //ATAPI
+        await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+    }
+
+// 8.2.1 (h) -- wait for not BSY
+    await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+  }
+
+  // Enable interrupts
+  outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a non data command
+// ---------------------------------------------------------------------------
+
+Bit16u ata_cmd_non_data()
+{return 0;}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a data-in command
+// ---------------------------------------------------------------------------
+      // returns
+      // 0 : no error
+      // 1 : BUSY bit set
+      // 2 : read error
+      // 3 : expected DRQ=1
+      // 4 : no sectors left to read/verify
+      // 5 : more sectors to read/verify
+      // 6 : no sectors left to write
+      // 7 : more sectors to write
+Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
+Bit16u device, command, count, cylinder, head, sector, segment, offset;
+Bit32u lba_low, lba_high;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit16u iobase1, iobase2, blksize;
+  Bit8u  channel, slave;
+  Bit8u  status, current, mode;
+
+  channel = device / 2;
+  slave   = device % 2;
+
+  iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+  iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+  mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+  blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+  if (mode == ATA_MODE_PIO32) blksize>>=2;
+  else blksize>>=1;
+
+  // Reset count of transferred data
+  write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
+  write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
+  current = 0;
+
+  status = inb(iobase1 + ATA_CB_STAT);
+  if (status & ATA_CB_STAT_BSY) return 1;
+
+  outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+  // sector will be 0 only on lba access. Convert to lba-chs
+  if (sector == 0) {
+    if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
+      outb(iobase1 + ATA_CB_FR, 0x00);
+      outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
+      outb(iobase1 + ATA_CB_SN, lba_low >> 24);
+      outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
+      outb(iobase1 + ATA_CB_CH, lba_high >> 8);
+      command |= 0x04;
+      count &= (1UL << 8) - 1;
+      lba_low &= (1UL << 24) - 1;
+      }
+    sector = (Bit16u) (lba_low & 0x000000ffL);
+    cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
+    head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
+  }
+
+  outb(iobase1 + ATA_CB_FR, 0x00);
+  outb(iobase1 + ATA_CB_SC, count);
+  outb(iobase1 + ATA_CB_SN, sector);
+  outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+  outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+  outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
+  outb(iobase1 + ATA_CB_CMD, command);
+
+  await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+  status = inb(iobase1 + ATA_CB_STAT);
+
+  if (status & ATA_CB_STAT_ERR) {
+    BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
+    return 2;
+    } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+    BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
+    return 3;
+  }
+
+  // FIXME : move seg/off translation here
+
+ASM_START
+        sti  ;; enable higher priority interrupts
+ASM_END
+
+  while (1) {
+
+ASM_START
+        push bp
+        mov  bp, sp
+        mov  di, _ata_cmd_data_in.offset + 2[bp]
+        mov  ax, _ata_cmd_data_in.segment + 2[bp]
+        mov  cx, _ata_cmd_data_in.blksize + 2[bp]
+
+        ;; adjust if there will be an overrun. 2K max sector size
+        cmp   di, #0xf800 ;;
+        jbe   ata_in_no_adjust
+
+ata_in_adjust:
+        sub   di, #0x0800 ;; sub 2 kbytes from offset
+        add   ax, #0x0080 ;; add 2 Kbytes to segment
+
+ata_in_no_adjust:
+        mov   es, ax      ;; segment in es
+
+        mov   dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
+
+        mov  ah, _ata_cmd_data_in.mode + 2[bp]
+        cmp  ah, #ATA_MODE_PIO32
+        je   ata_in_32
+
+ata_in_16:
+        rep
+          insw ;; CX words transfered from port(DX) to ES:[DI]
+        jmp ata_in_done
+
+ata_in_32:
+        rep
+          insd ;; CX dwords transfered from port(DX) to ES:[DI]
+
+ata_in_done:
+        mov  _ata_cmd_data_in.offset + 2[bp], di
+        mov  _ata_cmd_data_in.segment + 2[bp], es
+        pop  bp
+ASM_END
+
+    current++;
+    write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
+    count--;
+    await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+    status = inb(iobase1 + ATA_CB_STAT);
+    if (count == 0) {
+      if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+          != ATA_CB_STAT_RDY ) {
+        BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
+        return 4;
+        }
+      break;
+      }
+    else {
+      if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+          != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
+        BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
+        return 5;
+      }
+      continue;
+    }
+  }
+  // Enable interrupts
+  outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+  return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a data-out command
+// ---------------------------------------------------------------------------
+      // returns
+      // 0 : no error
+      // 1 : BUSY bit set
+      // 2 : read error
+      // 3 : expected DRQ=1
+      // 4 : no sectors left to read/verify
+      // 5 : more sectors to read/verify
+      // 6 : no sectors left to write
+      // 7 : more sectors to write
+Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
+Bit16u device, command, count, cylinder, head, sector, segment, offset;
+Bit32u lba_low, lba_high;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit16u iobase1, iobase2, blksize;
+  Bit8u  channel, slave;
+  Bit8u  status, current, mode;
+
+  channel = device / 2;
+  slave   = device % 2;
+
+  iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+  iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+  mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+  blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+  if (mode == ATA_MODE_PIO32) blksize>>=2;
+  else blksize>>=1;
+
+  // Reset count of transferred data
+  write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
+  write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
+  current = 0;
+
+  status = inb(iobase1 + ATA_CB_STAT);
+  if (status & ATA_CB_STAT_BSY) return 1;
+
+  outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+  // sector will be 0 only on lba access. Convert to lba-chs
+  if (sector == 0) {
+    if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
+      outb(iobase1 + ATA_CB_FR, 0x00);
+      outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
+      outb(iobase1 + ATA_CB_SN, lba_low >> 24);
+      outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
+      outb(iobase1 + ATA_CB_CH, lba_high >> 8);
+      command |= 0x04;
+      count &= (1UL << 8) - 1;
+      lba_low &= (1UL << 24) - 1;
+      }
+    sector = (Bit16u) (lba_low & 0x000000ffL);
+    cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
+    head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
+  }
+
+  outb(iobase1 + ATA_CB_FR, 0x00);
+  outb(iobase1 + ATA_CB_SC, count);
+  outb(iobase1 + ATA_CB_SN, sector);
+  outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+  outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+  outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
+  outb(iobase1 + ATA_CB_CMD, command);
+
+  await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+  status = inb(iobase1 + ATA_CB_STAT);
+
+  if (status & ATA_CB_STAT_ERR) {
+    BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
+    return 2;
+    } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+    BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
+    return 3;
+    }
+
+  // FIXME : move seg/off translation here
+
+ASM_START
+        sti  ;; enable higher priority interrupts
+ASM_END
+
+  while (1) {
+
+ASM_START
+        push bp
+        mov  bp, sp
+        mov  si, _ata_cmd_data_out.offset + 2[bp]
+        mov  ax, _ata_cmd_data_out.segment + 2[bp]
+        mov  cx, _ata_cmd_data_out.blksize + 2[bp]
+
+        ;; adjust if there will be an overrun. 2K max sector size
+        cmp   si, #0xf800 ;;
+        jbe   ata_out_no_adjust
+
+ata_out_adjust:
+        sub   si, #0x0800 ;; sub 2 kbytes from offset
+        add   ax, #0x0080 ;; add 2 Kbytes to segment
+
+ata_out_no_adjust:
+        mov   es, ax      ;; segment in es
+
+        mov   dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
+
+        mov  ah, _ata_cmd_data_out.mode + 2[bp]
+        cmp  ah, #ATA_MODE_PIO32
+        je   ata_out_32
+
+ata_out_16:
+        seg ES
+        rep
+          outsw ;; CX words transfered from port(DX) to ES:[SI]
+        jmp ata_out_done
+
+ata_out_32:
+        seg ES
+        rep
+          outsd ;; CX dwords transfered from port(DX) to ES:[SI]
+
+ata_out_done:
+        mov  _ata_cmd_data_out.offset + 2[bp], si
+        mov  _ata_cmd_data_out.segment + 2[bp], es
+        pop  bp
+ASM_END
+
+    current++;
+    write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
+    count--;
+    status = inb(iobase1 + ATA_CB_STAT);
+    if (count == 0) {
+      if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+          != ATA_CB_STAT_RDY ) {
+        BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
+        return 6;
+        }
+      break;
+      }
+    else {
+      if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+          != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
+        BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
+        return 7;
+      }
+      continue;
+    }
+  }
+  // Enable interrupts
+  outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+  return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a packet command
+// ---------------------------------------------------------------------------
+      // returns
+      // 0 : no error
+      // 1 : error in parameters
+      // 2 : BUSY bit set
+      // 3 : error
+      // 4 : not ready
+Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
+Bit8u  cmdlen,inout;
+Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
+Bit16u header;
+Bit32u length;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit16u iobase1, iobase2;
+  Bit16u lcount, lbefore, lafter, count;
+  Bit8u  channel, slave;
+  Bit8u  status, mode, lmode;
+  Bit32u total, transfer;
+
+  channel = device / 2;
+  slave = device % 2;
+
+  // Data out is not supported yet
+  if (inout == ATA_DATA_OUT) {
+    BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
+    return 1;
+    }
+
+  // The header length must be even
+  if (header & 1) {
+    BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
+    return 1;
+    }
+
+  iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+  iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+  mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+  transfer= 0L;
+
+  if (cmdlen < 12) cmdlen=12;
+  if (cmdlen > 12) cmdlen=16;
+  cmdlen>>=1;
+
+  // Reset count of transferred data
+  write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
+  write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
+
+  status = inb(iobase1 + ATA_CB_STAT);
+  if (status & ATA_CB_STAT_BSY) return 2;
+
+  outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+  outb(iobase1 + ATA_CB_FR, 0x00);
+  outb(iobase1 + ATA_CB_SC, 0x00);
+  outb(iobase1 + ATA_CB_SN, 0x00);
+  outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
+  outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
+  outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+  outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
+
+  // Device should ok to receive command
+  await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+  status = inb(iobase1 + ATA_CB_STAT);
+
+  if (status & ATA_CB_STAT_ERR) {
+    BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
+    return 3;
+    } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+    BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
+    return 4;
+    }
+
+  // Normalize address
+  cmdseg += (cmdoff / 16);
+  cmdoff %= 16;
+
+  // Send command to device
+ASM_START
+      sti  ;; enable higher priority interrupts
+
+      push bp
+      mov  bp, sp
+
+      mov  si, _ata_cmd_packet.cmdoff + 2[bp]
+      mov  ax, _ata_cmd_packet.cmdseg + 2[bp]
+      mov  cx, _ata_cmd_packet.cmdlen + 2[bp]
+      mov  es, ax      ;; segment in es
+
+      mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
+
+      seg ES
+      rep
+        outsw ;; CX words transfered from port(DX) to ES:[SI]
+
+      pop  bp
+ASM_END
+
+  if (inout == ATA_DATA_NO) {
+    await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+    status = inb(iobase1 + ATA_CB_STAT);
+    }
+  else {
+        Bit16u loops = 0;
+        Bit8u sc;
+  while (1) {
+
+      if (loops == 0) {//first time through
+        status = inb(iobase2 + ATA_CB_ASTAT);
+        await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+      }
+      else
+        await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+      loops++;
+
+      status = inb(iobase1 + ATA_CB_STAT);
+      sc = inb(iobase1 + ATA_CB_SC);
+
+      // Check if command completed
+      if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) &&
+         ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break;
+
+      if (status & ATA_CB_STAT_ERR) {
+        BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
+        return 3;
+      }
+
+      // Normalize address
+      bufseg += (bufoff / 16);
+      bufoff %= 16;
+
+      // Get the byte count
+      lcount =  ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
+
+      // adjust to read what we want
+      if(header>lcount) {
+         lbefore=lcount;
+         header-=lcount;
+         lcount=0;
+         }
+      else {
+        lbefore=header;
+        header=0;
+        lcount-=lbefore;
+        }
+
+      if(lcount>length) {
+        lafter=lcount-length;
+        lcount=length;
+        length=0;
+        }
+      else {
+        lafter=0;
+        length-=lcount;
+        }
+
+      // Save byte count
+      count = lcount;
+
+      BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
+      BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
+
+      // If counts not dividable by 4, use 16bits mode
+      lmode = mode;
+      if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
+      if (lcount  & 0x03) lmode=ATA_MODE_PIO16;
+      if (lafter  & 0x03) lmode=ATA_MODE_PIO16;
+
+      // adds an extra byte if count are odd. before is always even
+      if (lcount & 0x01) {
+        lcount+=1;
+        if ((lafter > 0) && (lafter & 0x01)) {
+          lafter-=1;
+          }
+        }
+
+      if (lmode == ATA_MODE_PIO32) {
+        lcount>>=2; lbefore>>=2; lafter>>=2;
+        }
+      else {
+        lcount>>=1; lbefore>>=1; lafter>>=1;
+        }
+
+       ;  // FIXME bcc bug
+
+ASM_START
+        push bp
+        mov  bp, sp
+
+        mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
+
+        mov  cx, _ata_cmd_packet.lbefore + 2[bp]
+        jcxz ata_packet_no_before
+
+        mov  ah, _ata_cmd_packet.lmode + 2[bp]
+        cmp  ah, #ATA_MODE_PIO32
+        je   ata_packet_in_before_32
+
+ata_packet_in_before_16:
+        in   ax, dx
+        loop ata_packet_in_before_16
+        jmp  ata_packet_no_before
+
+ata_packet_in_before_32:
+        push eax
+ata_packet_in_before_32_loop:
+        in   eax, dx
+        loop ata_packet_in_before_32_loop
+        pop  eax
+
+ata_packet_no_before:
+        mov  cx, _ata_cmd_packet.lcount + 2[bp]
+        jcxz ata_packet_after
+
+        mov  di, _ata_cmd_packet.bufoff + 2[bp]
+        mov  ax, _ata_cmd_packet.bufseg + 2[bp]
+        mov  es, ax
+
+        mov  ah, _ata_cmd_packet.lmode + 2[bp]
+        cmp  ah, #ATA_MODE_PIO32
+        je   ata_packet_in_32
+
+ata_packet_in_16:
+        rep
+          insw ;; CX words transfered tp port(DX) to ES:[DI]
+        jmp ata_packet_after
+
+ata_packet_in_32:
+        rep
+          insd ;; CX dwords transfered to port(DX) to ES:[DI]
+
+ata_packet_after:
+        mov  cx, _ata_cmd_packet.lafter + 2[bp]
+        jcxz ata_packet_done
+
+        mov  ah, _ata_cmd_packet.lmode + 2[bp]
+        cmp  ah, #ATA_MODE_PIO32
+        je   ata_packet_in_after_32
+
+ata_packet_in_after_16:
+        in   ax, dx
+        loop ata_packet_in_after_16
+        jmp  ata_packet_done
+
+ata_packet_in_after_32:
+        push eax
+ata_packet_in_after_32_loop:
+        in   eax, dx
+        loop ata_packet_in_after_32_loop
+        pop  eax
+
+ata_packet_done:
+        pop  bp
+ASM_END
+
+      // Compute new buffer address
+      bufoff += count;
+
+      // Save transferred bytes count
+      transfer += count;
+      write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
+      }
+    }
+
+  // Final check, device must be ready
+  if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+         != ATA_CB_STAT_RDY ) {
+    BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
+    return 4;
+    }
+
+  // Enable interrupts
+  outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+  return 0;
+}
+
+// ---------------------------------------------------------------------------
+// End of ATA/ATAPI Driver
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Start of ATA/ATAPI generic functions
+// ---------------------------------------------------------------------------
+
+  Bit16u
+atapi_get_sense(device, seg, asc, ascq)
+  Bit16u device;
+{
+  Bit8u  atacmd[12];
+  Bit8u  buffer[18];
+  Bit8u i;
+
+  memsetb(get_SS(),atacmd,0,12);
+
+  // Request SENSE
+  atacmd[0]=ATA_CMD_REQUEST_SENSE;
+  atacmd[4]=sizeof(buffer);
+  if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0)
+    return 0x0002;
+
+  write_byte(seg,asc,buffer[12]);
+  write_byte(seg,ascq,buffer[13]);
+
+  return 0;
+}
+
+  Bit16u
+atapi_is_ready(device)
+  Bit16u device;
+{
+  Bit8u packet[12];
+  Bit8u buf[8];
+  Bit32u block_len;
+  Bit32u sectors;
+  Bit32u timeout; //measured in ms
+  Bit32u time;
+  Bit8u asc, ascq;
+  Bit8u in_progress;
+  Bit16u ebda_seg = read_word(0x0040,0x000E);
+  if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) {
+    printf("not implemented for non-ATAPI device\n");
+    return -1;
+  }
+
+  BX_DEBUG_ATA("ata_detect_medium: begin\n");
+  memsetb(get_SS(),packet, 0, sizeof packet);
+  packet[0] = 0x25; /* READ CAPACITY */
+
+  /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
+   * is reported by the device. If the device reports "IN PROGRESS",
+   * 30 seconds is added. */
+  timeout = 5000;
+  time = 0;
+  in_progress = 0;
+  while (time < timeout) {
+    if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0)
+      goto ok;
+
+    if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) {
+      if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
+        BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
+        return -1;
+      }
+
+      if (asc == 0x04 && ascq == 0x01 && !in_progress) {
+        /* IN PROGRESS OF BECOMING READY */
+        printf("Waiting for device to detect medium... ");
+        /* Allow 30 seconds more */
+        timeout = 30000;
+        in_progress = 1;
+      }
+    }
+    time += 100;
+  }
+  BX_DEBUG_ATA("read capacity failed\n");
+  return -1;
+ok:
+
+  block_len = (Bit32u) buf[4] << 24
+    | (Bit32u) buf[5] << 16
+    | (Bit32u) buf[6] << 8
+    | (Bit32u) buf[7] << 0;
+  BX_DEBUG_ATA("block_len=%u\n", block_len);
+
+  if (block_len!= 2048 && block_len!= 512)
+  {
+    printf("Unsupported sector size %u\n", block_len);
+    return -1;
+  }
+  write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len);
+
+  sectors = (Bit32u) buf[0] << 24
+    | (Bit32u) buf[1] << 16
+    | (Bit32u) buf[2] << 8
+    | (Bit32u) buf[3] << 0;
+
+  BX_DEBUG_ATA("sectors=%u\n", sectors);
+  if (block_len == 2048)
+    sectors <<= 2; /* # of sectors in 512-byte "soft" sector */
+  if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low))
+    printf("%dMB medium detected\n", sectors>>(20-9));
+  write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors);
+  return 0;
+}
+
+  Bit16u
+atapi_is_cdrom(device)
+  Bit8u device;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+  if (device >= BX_MAX_ATA_DEVICES)
+    return 0;
+
+  if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
+    return 0;
+
+  if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
+    return 0;
+
+  return 1;
+}
+
+// ---------------------------------------------------------------------------
+// End of ATA/ATAPI generic functions
+// ---------------------------------------------------------------------------
+
+#endif // BX_USE_ATADRV
+
+#if BX_ELTORITO_BOOT
+
+// ---------------------------------------------------------------------------
+// Start of El-Torito boot functions
+// ---------------------------------------------------------------------------
+
+  void
+cdemu_init()
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+  // the only important data is this one for now
+  write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
+}
+
+  Bit8u
+cdemu_isactive()
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+  return(read_byte(ebda_seg,&EbdaData->cdemu.active));
+}
+
+  Bit8u
+cdemu_emulated_drive()
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+  return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
+}
+
+static char isotag[6]="CD001";
+static char eltorito[24]="EL TORITO SPECIFICATION";
+//
+// Returns ah: emulated drive, al: error code
+//
+  Bit16u
+cdrom_boot()
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  atacmd[12], buffer[2048];
+  Bit32u lba;
+  Bit16u boot_segment, nbsectors, i, error;
+  Bit8u  device;
+
+  // Find out the first cdrom
+  for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
+    if (atapi_is_cdrom(device)) break;
+    }
+
+  // if not found
+  if(device >= BX_MAX_ATA_DEVICES) return 2;
+
+  if(error = atapi_is_ready(device) != 0)
+    BX_INFO("ata_is_ready returned %d\n",error);
+
+  // Read the Boot Record Volume Descriptor
+  memsetb(get_SS(),atacmd,0,12);
+  atacmd[0]=0x28;                      // READ command
+  atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
+  atacmd[8]=(0x01 & 0x00ff);           // Sectors
+  atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
+  atacmd[3]=(0x11 & 0x00ff0000) >> 16;
+  atacmd[4]=(0x11 & 0x0000ff00) >> 8;
+  atacmd[5]=(0x11 & 0x000000ff);
+  if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
+    return 3;
+
+  // Validity checks
+  if(buffer[0]!=0)return 4;
+  for(i=0;i<5;i++){
+    if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
+   }
+  for(i=0;i<23;i++)
+    if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
+
+  // ok, now we calculate the Boot catalog address
+  lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
+
+  // And we read the Boot Catalog
+  memsetb(get_SS(),atacmd,0,12);
+  atacmd[0]=0x28;                      // READ command
+  atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
+  atacmd[8]=(0x01 & 0x00ff);           // Sectors
+  atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
+  atacmd[3]=(lba & 0x00ff0000) >> 16;
+  atacmd[4]=(lba & 0x0000ff00) >> 8;
+  atacmd[5]=(lba & 0x000000ff);
+  if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
+    return 7;
+
+  // Validation entry
+  if(buffer[0x00]!=0x01)return 8;   // Header
+  if(buffer[0x01]!=0x00)return 9;   // Platform
+  if(buffer[0x1E]!=0x55)return 10;  // key 1
+  if(buffer[0x1F]!=0xAA)return 10;  // key 2
+
+  // Initial/Default Entry
+  if(buffer[0x20]!=0x88)return 11; // Bootable
+
+  write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
+  if(buffer[0x21]==0){
+    // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
+    // Win2000 cd boot needs to know it booted from cd
+    write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
+    }
+  else if(buffer[0x21]<4)
+    write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
+  else
+    write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
+
+  write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
+  write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
+
+  boot_segment=buffer[0x23]*0x100+buffer[0x22];
+  if(boot_segment==0x0000)boot_segment=0x07C0;
+
+  write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
+  write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
+
+  nbsectors=buffer[0x27]*0x100+buffer[0x26];
+  write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
+
+  lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
+  write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
+
+  // And we read the image in memory
+  memsetb(get_SS(),atacmd,0,12);
+  atacmd[0]=0x28;                      // READ command
+  atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8;      // Sectors
+  atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff);           // Sectors
+  atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
+  atacmd[3]=(lba & 0x00ff0000) >> 16;
+  atacmd[4]=(lba & 0x0000ff00) >> 8;
+  atacmd[5]=(lba & 0x000000ff);
+  if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
+    return 12;
+
+  // Remember the media type
+  switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
+    case 0x01:  // 1.2M floppy
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
+      break;
+    case 0x02:  // 1.44M floppy
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
+      break;
+    case 0x03:  // 2.88M floppy
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
+      break;
+    case 0x04:  // Harddrive
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
+              (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
+      write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
+      break;
+   }
+
+  if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
+    // Increase bios installed hardware number of devices
+    if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
+      write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
+    else
+      write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
+   }
+
+
+  // everything is ok, so from now on, the emulation is active
+  if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
+    write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
+
+  // return the boot drive + no error
+  return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
+}
+
+// ---------------------------------------------------------------------------
+// End of El-Torito boot functions
+// ---------------------------------------------------------------------------
+#endif // BX_ELTORITO_BOOT
+
+  void
+int14_function(regs, ds, iret_addr)
+  pusha_regs_t regs; // regs pushed from PUSHA instruction
+  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
+{
+  Bit16u addr,timer,val16;
+  Bit8u timeout;
+
+  ASM_START
+  sti
+  ASM_END
+
+  addr = read_word(0x0040, (regs.u.r16.dx << 1));
+  timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
+  if ((regs.u.r16.dx < 4) && (addr > 0)) {
+    switch (regs.u.r8.ah) {
+      case 0:
+        outb(addr+3, inb(addr+3) | 0x80);
+        if (regs.u.r8.al & 0xE0 == 0) {
+          outb(addr, 0x17);
+          outb(addr+1, 0x04);
+        } else {
+          val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
+          outb(addr, val16 & 0xFF);
+          outb(addr+1, val16 >> 8);
+        }
+        outb(addr+3, regs.u.r8.al & 0x1F);
+        regs.u.r8.ah = inb(addr+5);
+        regs.u.r8.al = inb(addr+6);
+        ClearCF(iret_addr.flags);
+        break;
+      case 1:
+        timer = read_word(0x0040, 0x006C);
+        while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
+          val16 = read_word(0x0040, 0x006C);
+          if (val16 != timer) {
+            timer = val16;
+            timeout--;
+            }
+          }
+        if (timeout) outb(addr, regs.u.r8.al);
+        regs.u.r8.ah = inb(addr+5);
+        if (!timeout) regs.u.r8.ah |= 0x80;
+        ClearCF(iret_addr.flags);
+        break;
+      case 2:
+        timer = read_word(0x0040, 0x006C);
+        while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
+          val16 = read_word(0x0040, 0x006C);
+          if (val16 != timer) {
+            timer = val16;
+            timeout--;
+            }
+          }
+        if (timeout) {
+          regs.u.r8.ah = 0;
+          regs.u.r8.al = inb(addr);
+        } else {
+          regs.u.r8.ah = inb(addr+5);
+          }
+        ClearCF(iret_addr.flags);
+        break;
+      case 3:
+        regs.u.r8.ah = inb(addr+5);
+        regs.u.r8.al = inb(addr+6);
+        ClearCF(iret_addr.flags);
+        break;
+      default:
+        SetCF(iret_addr.flags); // Unsupported
+      }
+  } else {
+    SetCF(iret_addr.flags); // Unsupported
+    }
+}
+
+  void
+int15_function(regs, ES, DS, FLAGS)
+  pusha_regs_t regs; // REGS pushed via pusha
+  Bit16u ES, DS, FLAGS;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  bx_bool prev_a20_enable;
+  Bit16u  base15_00;
+  Bit8u   base23_16;
+  Bit16u  ss;
+  Bit16u  CX,DX;
+
+  Bit16u bRegister;
+  Bit8u irqDisable;
+
+BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
+
+  switch (regs.u.r8.ah) {
+    case 0x24: /* A20 Control */
+      switch (regs.u.r8.al) {
+        case 0x00:
+          set_enable_a20(0);
+          CLEAR_CF();
+          regs.u.r8.ah = 0;
+          break;
+        case 0x01:
+          set_enable_a20(1);
+          CLEAR_CF();
+          regs.u.r8.ah = 0;
+          break;
+        case 0x02:
+          regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
+          CLEAR_CF();
+          regs.u.r8.ah = 0;
+          break;
+        case 0x03:
+          CLEAR_CF();
+          regs.u.r8.ah = 0;
+          regs.u.r16.bx = 3;
+          break;
+        default:
+          BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
+          SET_CF();
+          regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      }
+      break;
+
+    case 0x41:
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+
+    case 0x4f:
+      /* keyboard intercept */
+#if BX_CPU < 2
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+#else
+      // nop
+#endif
+      SET_CF();
+      break;
+
+    case 0x52:    // removable media eject
+      CLEAR_CF();
+      regs.u.r8.ah = 0;  // "ok ejection may proceed"
+      break;
+
+    case 0x83: {
+      if( regs.u.r8.al == 0 ) {
+        // Set Interval requested.
+        if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
+          // Interval not already set.
+          write_byte( 0x40, 0xA0, 1 );  // Set status byte.
+          write_word( 0x40, 0x98, ES ); // Byte location, segment
+          write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
+          write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
+          write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
+          CLEAR_CF( );
+          irqDisable = inb( 0xA1 );
+          outb( 0xA1, irqDisable & 0xFE );
+          bRegister = inb_cmos( 0xB );  // Unmask IRQ8 so INT70 will get through.
+          outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
+        } else {
+          // Interval already set.
+          BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
+          SET_CF();
+          regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+        }
+      } else if( regs.u.r8.al == 1 ) {
+        // Clear Interval requested
+        write_byte( 0x40, 0xA0, 0 );  // Clear status byte
+        CLEAR_CF( );
+        bRegister = inb_cmos( 0xB );
+        outb_cmos( 0xB, bRegister & ~0x40 );  // Turn off the Periodic Interrupt timer
+      } else {
+        BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
+        SET_CF();
+        regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+        regs.u.r8.al--;
+      }
+
+      break;
+    }
+
+    case 0x87:
+#if BX_CPU < 3
+#  error "Int15 function 87h not supported on < 80386"
+#endif
+      // +++ should probably have descriptor checks
+      // +++ should have exception handlers
+
+ // turn off interrupts
+ASM_START
+  cli
+ASM_END
+
+      prev_a20_enable = set_enable_a20(1); // enable A20 line
+
+      // 128K max of transfer on 386+ ???
+      // source == destination ???
+
+      // ES:SI points to descriptor table
+      // offset   use     initially  comments
+      // ==============================================
+      // 00..07   Unused  zeros      Null descriptor
+      // 08..0f   GDT     zeros      filled in by BIOS
+      // 10..17   source  ssssssss   source of data
+      // 18..1f   dest    dddddddd   destination of data
+      // 20..27   CS      zeros      filled in by BIOS
+      // 28..2f   SS      zeros      filled in by BIOS
+
+      //es:si
+      //eeee0
+      //0ssss
+      //-----
+
+// check for access rights of source & dest here
+
+      // Initialize GDT descriptor
+      base15_00 = (ES << 4) + regs.u.r16.si;
+      base23_16 = ES >> 12;
+      if (base15_00 < (ES<<4))
+        base23_16++;
+      write_word(ES, regs.u.r16.si+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
+      write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
+      write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
+      write_byte(ES, regs.u.r16.si+0x08+5, 0x93);     // access
+      write_word(ES, regs.u.r16.si+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
+
+      // Initialize CS descriptor
+      write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
+      write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
+      write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
+      write_byte(ES, regs.u.r16.si+0x20+5, 0x9b);  // access
+      write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
+
+      // Initialize SS descriptor
+      ss = get_SS();
+      base15_00 = ss << 4;
+      base23_16 = ss >> 12;
+      write_word(ES, regs.u.r16.si+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
+      write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
+      write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
+      write_byte(ES, regs.u.r16.si+0x28+5, 0x93);     // access
+      write_word(ES, regs.u.r16.si+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
+
+      CX = regs.u.r16.cx;
+ASM_START
+      // Compile generates locals offset info relative to SP.
+      // Get CX (word count) from stack.
+      mov  bx, sp
+      SEG SS
+        mov  cx, _int15_function.CX [bx]
+
+      // since we need to set SS:SP, save them to the BDA
+      // for future restore
+      push eax
+      xor eax, eax
+      mov ds, ax
+      mov 0x0469, ss
+      mov 0x0467, sp
+
+      SEG ES
+        lgdt [si + 0x08]
+      SEG CS
+        lidt [pmode_IDT_info]
+      ;;  perhaps do something with IDT here
+
+      ;; set PE bit in CR0
+      mov  eax, cr0
+      or   al, #0x01
+      mov  cr0, eax
+      ;; far jump to flush CPU queue after transition to protected mode
+      JMP_AP(0x0020, protected_mode)
+
+protected_mode:
+      ;; GDT points to valid descriptor table, now load SS, DS, ES
+      mov  ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
+      mov  ss, ax
+      mov  ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
+      mov  ds, ax
+      mov  ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
+      mov  es, ax
+      xor  si, si
+      xor  di, di
+      cld
+      rep
+        movsw  ;; move CX words from DS:SI to ES:DI
+
+      ;; make sure DS and ES limits are 64KB
+      mov ax, #0x28
+      mov ds, ax
+      mov es, ax
+
+      ;; reset PG bit in CR0 ???
+      mov  eax, cr0
+      and  al, #0xFE
+      mov  cr0, eax
+
+      ;; far jump to flush CPU queue after transition to real mode
+      JMP_AP(0xf000, real_mode)
+
+real_mode:
+      ;; restore IDT to normal real-mode defaults
+      SEG CS
+        lidt [rmode_IDT_info]
+
+      // restore SS:SP from the BDA
+      xor ax, ax
+      mov ds, ax
+      mov ss, 0x0469
+      mov sp, 0x0467
+      pop eax
+ASM_END
+
+      set_enable_a20(prev_a20_enable);
+
+ // turn back on interrupts
+ASM_START
+  sti
+ASM_END
+
+      regs.u.r8.ah = 0;
+      CLEAR_CF();
+      break;
+
+
+    case 0x88:
+      // Get the amount of extended memory (above 1M)
+#if BX_CPU < 2
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      SET_CF();
+#else
+      regs.u.r8.al = inb_cmos(0x30);
+      regs.u.r8.ah = inb_cmos(0x31);
+
+      // According to Ralf Brown's interrupt the limit should be 15M,
+      // but real machines mostly return max. 63M.
+      if(regs.u.r16.ax > 0xffc0)
+        regs.u.r16.ax = 0xffc0;
+
+      CLEAR_CF();
+#endif
+      break;
+
+    case 0x90:
+      /* Device busy interrupt.  Called by Int 16h when no key available */
+      break;
+
+    case 0x91:
+      /* Interrupt complete.  Called by Int 16h when key becomes available */
+      break;
+
+    case 0xbf:
+      BX_INFO("*** int 15h function AH=bf not yet supported!\n");
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+
+    case 0xC0:
+#if 0
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+#endif
+      CLEAR_CF();
+      regs.u.r8.ah = 0;
+      regs.u.r16.bx =  BIOS_CONFIG_TABLE;
+      ES = 0xF000;
+      break;
+
+    case 0xc1:
+      ES = ebda_seg;
+      CLEAR_CF();
+      break;
+
+    case 0xd8:
+      bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+
+    default:
+      BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+        (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+    }
+}
+
+#if BX_USE_PS2_MOUSE
+  void
+int15_function_mouse(regs, ES, DS, FLAGS)
+  pusha_regs_t regs; // REGS pushed via pusha
+  Bit16u ES, DS, FLAGS;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  mouse_flags_1, mouse_flags_2;
+  Bit16u mouse_driver_seg;
+  Bit16u mouse_driver_offset;
+  Bit8u  comm_byte, prev_command_byte;
+  Bit8u  ret, mouse_data1, mouse_data2, mouse_data3;
+
+BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
+
+  switch (regs.u.r8.ah) {
+    case 0xC2:
+      // Return Codes status in AH
+      // =========================
+      // 00: success
+      // 01: invalid subfunction (AL > 7)
+      // 02: invalid input value (out of allowable range)
+      // 03: interface error
+      // 04: resend command received from mouse controller,
+      //     device driver should attempt command again
+      // 05: cannot enable mouse, since no far call has been installed
+      // 80/86: mouse service not implemented
+
+      switch (regs.u.r8.al) {
+        case 0: // Disable/Enable Mouse
+BX_DEBUG_INT15("case 0:\n");
+          switch (regs.u.r8.bh) {
+            case 0: // Disable Mouse
+BX_DEBUG_INT15("case 0: disable mouse\n");
+              inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+              ret = send_to_mouse_ctrl(0xF5); // disable mouse command
+              if (ret == 0) {
+                ret = get_mouse_data(&mouse_data1);
+                if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
+                  CLEAR_CF();
+                  regs.u.r8.ah = 0;
+                  return;
+                  }
+                }
+
+              // error
+              SET_CF();
+              regs.u.r8.ah = ret;
+              return;
+              break;
+
+            case 1: // Enable Mouse
+BX_DEBUG_INT15("case 1: enable mouse\n");
+              mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+              if ( (mouse_flags_2 & 0x80) == 0 ) {
+                BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
+                SET_CF();  // error
+                regs.u.r8.ah = 5; // no far call installed
+                return;
+                }
+              inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+              ret = send_to_mouse_ctrl(0xF4); // enable mouse command
+              if (ret == 0) {
+                ret = get_mouse_data(&mouse_data1);
+                if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
+                  enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
+                  CLEAR_CF();
+                  regs.u.r8.ah = 0;
+                  return;
+                  }
+                }
+              SET_CF();
+              regs.u.r8.ah = ret;
+              return;
+
+            default: // invalid subfunction
+              BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
+              SET_CF();  // error
+              regs.u.r8.ah = 1; // invalid subfunction
+              return;
+            }
+          break;
+
+        case 1: // Reset Mouse
+        case 5: // Initialize Mouse
+BX_DEBUG_INT15("case 1 or 5:\n");
+          if (regs.u.r8.al == 5) {
+            if (regs.u.r8.bh != 3) {
+              SET_CF();
+              regs.u.r8.ah = 0x02; // invalid input
+              return;
+            }
+            mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+            mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
+            mouse_flags_1 = 0x00;
+            write_byte(ebda_seg, 0x0026, mouse_flags_1);
+            write_byte(ebda_seg, 0x0027, mouse_flags_2);
+          }
+
+          inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+          ret = send_to_mouse_ctrl(0xFF); // reset mouse command
+          if (ret == 0) {
+            ret = get_mouse_data(&mouse_data3);
+            // if no mouse attached, it will return RESEND
+            if (mouse_data3 == 0xfe) {
+              SET_CF();
+              return;
+            }
+            if (mouse_data3 != 0xfa)
+              BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
+            if ( ret == 0 ) {
+              ret = get_mouse_data(&mouse_data1);
+              if ( ret == 0 ) {
+                ret = get_mouse_data(&mouse_data2);
+                if ( ret == 0 ) {
+                  // turn IRQ12 and packet generation on
+                  enable_mouse_int_and_events();
+                  CLEAR_CF();
+                  regs.u.r8.ah = 0;
+                  regs.u.r8.bl = mouse_data1;
+                  regs.u.r8.bh = mouse_data2;
+                  return;
+                  }
+                }
+              }
+            }
+
+          // error
+          SET_CF();
+          regs.u.r8.ah = ret;
+          return;
+
+        case 2: // Set Sample Rate
+BX_DEBUG_INT15("case 2:\n");
+          switch (regs.u.r8.bh) {
+            case 0: mouse_data1 = 10; break; //  10 reports/sec
+            case 1: mouse_data1 = 20; break; //  20 reports/sec
+            case 2: mouse_data1 = 40; break; //  40 reports/sec
+            case 3: mouse_data1 = 60; break; //  60 reports/sec
+            case 4: mouse_data1 = 80; break; //  80 reports/sec
+            case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
+            case 6: mouse_data1 = 200; break; // 200 reports/sec
+            default: mouse_data1 = 0;
+          }
+          if (mouse_data1 > 0) {
+            ret = send_to_mouse_ctrl(0xF3); // set sample rate command
+            if (ret == 0) {
+              ret = get_mouse_data(&mouse_data2);
+              ret = send_to_mouse_ctrl(mouse_data1);
+              ret = get_mouse_data(&mouse_data2);
+              CLEAR_CF();
+              regs.u.r8.ah = 0;
+            } else {
+              // error
+              SET_CF();
+              regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+            }
+          } else {
+            // error
+            SET_CF();
+            regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+          }
+          break;
+
+        case 3: // Set Resolution
+BX_DEBUG_INT15("case 3:\n");
+          // BH:
+          //      0 =  25 dpi, 1 count  per millimeter
+          //      1 =  50 dpi, 2 counts per millimeter
+          //      2 = 100 dpi, 4 counts per millimeter
+          //      3 = 200 dpi, 8 counts per millimeter
+          comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+          if (regs.u.r8.bh < 4) {
+            ret = send_to_mouse_ctrl(0xE8); // set resolution command
+            if (ret == 0) {
+              ret = get_mouse_data(&mouse_data1);
+              if (mouse_data1 != 0xfa)
+                BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
+              ret = send_to_mouse_ctrl(regs.u.r8.bh);
+              ret = get_mouse_data(&mouse_data1);
+              if (mouse_data1 != 0xfa)
+                BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
+              CLEAR_CF();
+              regs.u.r8.ah = 0;
+            } else {
+              // error
+              SET_CF();
+              regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+            }
+          } else {
+            // error
+            SET_CF();
+            regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+          }
+          set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+          break;
+
+        case 4: // Get Device ID
+BX_DEBUG_INT15("case 4:\n");
+          inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+          ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
+          if (ret == 0) {
+            ret = get_mouse_data(&mouse_data1);
+            ret = get_mouse_data(&mouse_data2);
+            CLEAR_CF();
+            regs.u.r8.ah = 0;
+            regs.u.r8.bh = mouse_data2;
+          } else {
+            // error
+            SET_CF();
+            regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+          }
+          break;
+
+        case 6: // Return Status & Set Scaling Factor...
+BX_DEBUG_INT15("case 6:\n");
+          switch (regs.u.r8.bh) {
+            case 0: // Return Status
+              comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+              ret = send_to_mouse_ctrl(0xE9); // get mouse info command
+              if (ret == 0) {
+                ret = get_mouse_data(&mouse_data1);
+                if (mouse_data1 != 0xfa)
+                  BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
+                if (ret == 0) {
+                  ret = get_mouse_data(&mouse_data1);
+                  if ( ret == 0 ) {
+                    ret = get_mouse_data(&mouse_data2);
+                    if ( ret == 0 ) {
+                      ret = get_mouse_data(&mouse_data3);
+                      if ( ret == 0 ) {
+                        CLEAR_CF();
+                        regs.u.r8.ah = 0;
+                        regs.u.r8.bl = mouse_data1;
+                        regs.u.r8.cl = mouse_data2;
+                        regs.u.r8.dl = mouse_data3;
+                        set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+                        return;
+                        }
+                      }
+                    }
+                  }
+                }
+
+              // error
+              SET_CF();
+              regs.u.r8.ah = ret;
+              set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+              return;
+
+            case 1: // Set Scaling Factor to 1:1
+            case 2: // Set Scaling Factor to 2:1
+              comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+              if (regs.u.r8.bh == 1) {
+                ret = send_to_mouse_ctrl(0xE6);
+              } else {
+                ret = send_to_mouse_ctrl(0xE7);
+              }
+              if (ret == 0) {
+                get_mouse_data(&mouse_data1);
+                ret = (mouse_data1 != 0xFA);
+              }
+              if (ret == 0) {
+                CLEAR_CF();
+                regs.u.r8.ah = 0;
+              } else {
+                // error
+                SET_CF();
+                regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+              }
+              set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+              break;
+
+            default:
+              BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
+            }
+          break;
+
+        case 7: // Set Mouse Handler Address
+BX_DEBUG_INT15("case 7:\n");
+          mouse_driver_seg = ES;
+          mouse_driver_offset = regs.u.r16.bx;
+          write_word(ebda_seg, 0x0022, mouse_driver_offset);
+          write_word(ebda_seg, 0x0024, mouse_driver_seg);
+          mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+          if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
+            /* remove handler */
+            if ( (mouse_flags_2 & 0x80) != 0 ) {
+              mouse_flags_2 &= ~0x80;
+              inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+              }
+            }
+          else {
+            /* install handler */
+            mouse_flags_2 |= 0x80;
+            }
+          write_byte(ebda_seg, 0x0027, mouse_flags_2);
+          CLEAR_CF();
+          regs.u.r8.ah = 0;
+          break;
+
+        default:
+BX_DEBUG_INT15("case default:\n");
+          regs.u.r8.ah = 1; // invalid function
+          SET_CF();
+        }
+      break;
+
+    default:
+      BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+        (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+    }
+}
+#endif // BX_USE_PS2_MOUSE
+
+
+void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
+     Bit16u ES;
+     Bit16u DI;
+     Bit32u start;
+     Bit32u end;
+     Bit8u extra_start;
+     Bit8u extra_end;
+     Bit16u type;
+{
+    write_word(ES, DI, start);
+    write_word(ES, DI+2, start >> 16);
+    write_word(ES, DI+4, extra_start);
+    write_word(ES, DI+6, 0x00);
+
+    end -= start;
+    extra_end -= extra_start;
+    write_word(ES, DI+8, end);
+    write_word(ES, DI+10, end >> 16);
+    write_word(ES, DI+12, extra_end);
+    write_word(ES, DI+14, 0x0000);
+
+    write_word(ES, DI+16, type);
+    write_word(ES, DI+18, 0x0);
+}
+
+  void
+int15_function32(regs, ES, DS, FLAGS)
+  pushad_regs_t regs; // REGS pushed via pushad
+  Bit16u ES, DS, FLAGS;
+{
+  Bit32u  extended_memory_size=0; // 64bits long
+  Bit32u  extra_lowbits_memory_size=0;
+  Bit16u  CX,DX;
+  Bit8u   extra_highbits_memory_size=0;
+
+BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
+
+  switch (regs.u.r8.ah) {
+    case 0x86:
+      // Wait for CX:DX microseconds. currently using the
+      // refresh request port 0x61 bit4, toggling every 15usec
+
+      CX = regs.u.r16.cx;
+      DX = regs.u.r16.dx;
+
+ASM_START
+      sti
+
+      ;; Get the count in eax
+      mov  bx, sp
+      SEG SS
+        mov  ax, _int15_function32.CX [bx]
+      shl  eax, #16
+      SEG SS
+        mov  ax, _int15_function32.DX [bx]
+
+      ;; convert to numbers of 15usec ticks
+      mov ebx, #15
+      xor edx, edx
+      div eax, ebx
+      mov ecx, eax
+
+      ;; wait for ecx number of refresh requests
+      in al, #0x61
+      and al,#0x10
+      mov ah, al
+
+      or ecx, ecx
+      je int1586_tick_end
+int1586_tick:
+      in al, #0x61
+      and al,#0x10
+      cmp al, ah
+      je  int1586_tick
+      mov ah, al
+      dec ecx
+      jnz int1586_tick
+int1586_tick_end:
+ASM_END
+
+      break;
+
+    case 0xe8:
+        switch(regs.u.r8.al)
+        {
+         case 0x20: // coded by osmaker aka K.J.
+            if(regs.u.r32.edx == 0x534D4150)
+            {
+                extended_memory_size = inb_cmos(0x35);
+                extended_memory_size <<= 8;
+                extended_memory_size |= inb_cmos(0x34);
+                extended_memory_size *= 64;
+                // greater than EFF00000???
+                if(extended_memory_size > 0x3bc000) {
+                    extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
+                }
+                extended_memory_size *= 1024;
+                extended_memory_size += (16L * 1024 * 1024);
+
+                if(extended_memory_size <= (16L * 1024 * 1024)) {
+                    extended_memory_size = inb_cmos(0x31);
+                    extended_memory_size <<= 8;
+                    extended_memory_size |= inb_cmos(0x30);
+                    extended_memory_size *= 1024;
+                    extended_memory_size += (1L * 1024 * 1024);
+                }
+
+                extra_lowbits_memory_size = inb_cmos(0x5c);
+                extra_lowbits_memory_size <<= 8;
+                extra_lowbits_memory_size |= inb_cmos(0x5b);
+                extra_lowbits_memory_size *= 64;
+                extra_lowbits_memory_size *= 1024;
+                extra_highbits_memory_size = inb_cmos(0x5d);
+
+                switch(regs.u.r16.bx)
+                {
+                    case 0:
+                        set_e820_range(ES, regs.u.r16.di,
+                                       0x0000000L, 0x0009f000L, 0, 0, 1);
+                        regs.u.r32.ebx = 1;
+                        break;
+                    case 1:
+                        set_e820_range(ES, regs.u.r16.di,
+                                       0x0009f000L, 0x000a0000L, 0, 0, 2);
+                        regs.u.r32.ebx = 2;
+                        break;
+                    case 2:
+                        set_e820_range(ES, regs.u.r16.di,
+                                       0x000e8000L, 0x00100000L, 0, 0, 2);
+                        regs.u.r32.ebx = 3;
+                        break;
+                    case 3:
+#if BX_ROMBIOS32
+                        set_e820_range(ES, regs.u.r16.di,
+                                       0x00100000L,
+                                       extended_memory_size - ACPI_DATA_SIZE ,0, 0, 1);
+                        regs.u.r32.ebx = 4;
+#else
+                        set_e820_range(ES, regs.u.r16.di,
+                                       0x00100000L,
+                                       extended_memory_size, 1);
+                        regs.u.r32.ebx = 5;
+#endif
+                        break;
+                    case 4:
+                        set_e820_range(ES, regs.u.r16.di,
+                                       extended_memory_size - ACPI_DATA_SIZE,
+                                       extended_memory_size ,0, 0, 3); // ACPI RAM
+                        regs.u.r32.ebx = 5;
+                        break;
+                    case 5:
+                        /* 4 pages before the bios, 3 pages for vmx tss pages,
+			 * the other page for EPT real mode pagetable */
+                        set_e820_range(ES, regs.u.r16.di, 0xfffbc000L,
+                                       0xfffc0000L, 0, 0, 2);
+                        regs.u.r32.ebx = 6;
+                        break;
+                    case 6:
+                        /* 256KB BIOS area at the end of 4 GB */
+                        set_e820_range(ES, regs.u.r16.di,
+                                       0xfffc0000L, 0x00000000L ,0, 0, 2);
+                        if (extra_highbits_memory_size || extra_lowbits_memory_size)
+                            regs.u.r32.ebx = 7;
+                        else
+                            regs.u.r32.ebx = 0;
+                        break;
+                    case 7:
+                        /* Maping of memory above 4 GB */
+                        set_e820_range(ES, regs.u.r16.di, 0x00000000L,
+                        extra_lowbits_memory_size, 1, extra_highbits_memory_size
+                                       + 1, 1);
+                        regs.u.r32.ebx = 0;
+                        break;
+                    default:  /* AX=E820, DX=534D4150, BX unrecognized */
+                        goto int15_unimplemented;
+                        break;
+                }
+                regs.u.r32.eax = 0x534D4150;
+                regs.u.r32.ecx = 0x14;
+                CLEAR_CF();
+            } else {
+              // if DX != 0x534D4150)
+              goto int15_unimplemented;
+            }
+            break;
+
+        case 0x01:
+          // do we have any reason to fail here ?
+          CLEAR_CF();
+
+          // my real system sets ax and bx to 0
+          // this is confirmed by Ralph Brown list
+          // but syslinux v1.48 is known to behave
+          // strangely if ax is set to 0
+          // regs.u.r16.ax = 0;
+          // regs.u.r16.bx = 0;
+
+          // Get the amount of extended memory (above 1M)
+          regs.u.r8.cl = inb_cmos(0x30);
+          regs.u.r8.ch = inb_cmos(0x31);
+
+          // limit to 15M
+          if(regs.u.r16.cx > 0x3c00)
+          {
+            regs.u.r16.cx = 0x3c00;
+          }
+
+          // Get the amount of extended memory above 16M in 64k blocs
+          regs.u.r8.dl = inb_cmos(0x34);
+          regs.u.r8.dh = inb_cmos(0x35);
+
+          // Set configured memory equal to extended memory
+          regs.u.r16.ax = regs.u.r16.cx;
+          regs.u.r16.bx = regs.u.r16.dx;
+          break;
+        default:  /* AH=0xE8?? but not implemented */
+          goto int15_unimplemented;
+       }
+       break;
+    int15_unimplemented:
+       // fall into the default
+    default:
+      BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+        (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
+      SET_CF();
+      regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+      break;
+    }
+}
+
+  void
+int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
+{
+  Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
+  Bit16u kbd_code, max;
+
+  BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
+
+  shift_flags = read_byte(0x0040, 0x17);
+  led_flags = read_byte(0x0040, 0x97);
+  if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
+ASM_START
+    cli
+ASM_END
+    outb(0x60, 0xed);
+    while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
+    if ((inb(0x60) == 0xfa)) {
+      led_flags &= 0xf8;
+      led_flags |= ((shift_flags >> 4) & 0x07);
+      outb(0x60, led_flags & 0x07);
+      while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
+      inb(0x60);
+      write_byte(0x0040, 0x97, led_flags);
+    }
+ASM_START
+    sti
+ASM_END
+  }
+
+  switch (GET_AH()) {
+    case 0x00: /* read keyboard input */
+
+      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
+        BX_PANIC("KBD: int16h: out of keyboard input\n");
+        }
+      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+      else if (ascii_code == 0xE0) ascii_code = 0;
+      AX = (scan_code << 8) | ascii_code;
+      break;
+
+    case 0x01: /* check keyboard status */
+      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
+        SET_ZF();
+        return;
+        }
+      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+      else if (ascii_code == 0xE0) ascii_code = 0;
+      AX = (scan_code << 8) | ascii_code;
+      CLEAR_ZF();
+      break;
+
+    case 0x02: /* get shift flag status */
+      shift_flags = read_byte(0x0040, 0x17);
+      SET_AL(shift_flags);
+      break;
+
+    case 0x05: /* store key-stroke into buffer */
+      if ( !enqueue_key(GET_CH(), GET_CL()) ) {
+        SET_AL(1);
+        }
+      else {
+        SET_AL(0);
+        }
+      break;
+
+    case 0x09: /* GET KEYBOARD FUNCTIONALITY */
+      // bit Bochs Description
+      //  7    0   reserved
+      //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
+      //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
+      //  4    1   INT 16/AH=0Ah supported
+      //  3    0   INT 16/AX=0306h supported
+      //  2    0   INT 16/AX=0305h supported
+      //  1    0   INT 16/AX=0304h supported
+      //  0    0   INT 16/AX=0300h supported
+      //
+      SET_AL(0x30);
+      break;
+
+    case 0x0A: /* GET KEYBOARD ID */
+      count = 2;
+      kbd_code = 0x0;
+      outb(0x60, 0xf2);
+      /* Wait for data */
+      max=0xffff;
+      while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
+      if (max>0x0) {
+        if ((inb(0x60) == 0xfa)) {
+          do {
+            max=0xffff;
+            while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
+            if (max>0x0) {
+              kbd_code >>= 8;
+              kbd_code |= (inb(0x60) << 8);
+            }
+          } while (--count>0);
+        }
+      }
+      BX=kbd_code;
+      break;
+
+    case 0x10: /* read MF-II keyboard input */
+
+      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
+        BX_PANIC("KBD: int16h: out of keyboard input\n");
+        }
+      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+      AX = (scan_code << 8) | ascii_code;
+      break;
+
+    case 0x11: /* check MF-II keyboard status */
+      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
+        SET_ZF();
+        return;
+        }
+      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+      AX = (scan_code << 8) | ascii_code;
+      CLEAR_ZF();
+      break;
+
+    case 0x12: /* get extended keyboard status */
+      shift_flags = read_byte(0x0040, 0x17);
+      SET_AL(shift_flags);
+      shift_flags = read_byte(0x0040, 0x18) & 0x73;
+      shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
+      SET_AH(shift_flags);
+      BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
+      break;
+
+    case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
+      SET_AH(0x80); // function int16 ah=0x10-0x12 supported
+      break;
+
+    case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
+      // don't change AH : function int16 ah=0x20-0x22 NOT supported
+      break;
+
+    case 0x6F:
+      if (GET_AL() == 0x08)
+        SET_AH(0x02); // unsupported, aka normal keyboard
+
+    default:
+      BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
+    }
+}
+
+  unsigned int
+dequeue_key(scan_code, ascii_code, incr)
+  Bit8u *scan_code;
+  Bit8u *ascii_code;
+  unsigned int incr;
+{
+  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
+  Bit16u ss;
+  Bit8u  acode, scode;
+
+#if BX_CPU < 2
+  buffer_start = 0x001E;
+  buffer_end   = 0x003E;
+#else
+  buffer_start = read_word(0x0040, 0x0080);
+  buffer_end   = read_word(0x0040, 0x0082);
+#endif
+
+  buffer_head = read_word(0x0040, 0x001a);
+  buffer_tail = read_word(0x0040, 0x001c);
+
+  if (buffer_head != buffer_tail) {
+    ss = get_SS();
+    acode = read_byte(0x0040, buffer_head);
+    scode = read_byte(0x0040, buffer_head+1);
+    write_byte(ss, ascii_code, acode);
+    write_byte(ss, scan_code, scode);
+
+    if (incr) {
+      buffer_head += 2;
+      if (buffer_head >= buffer_end)
+        buffer_head = buffer_start;
+      write_word(0x0040, 0x001a, buffer_head);
+      }
+    return(1);
+    }
+  else {
+    return(0);
+    }
+}
+
+static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
+
+  Bit8u
+inhibit_mouse_int_and_events()
+{
+  Bit8u command_byte, prev_command_byte;
+
+  // Turn off IRQ generation and aux data line
+  if ( inb(0x64) & 0x02 )
+    BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
+  outb(0x64, 0x20); // get command byte
+  while ( (inb(0x64) & 0x01) != 0x01 );
+  prev_command_byte = inb(0x60);
+  command_byte = prev_command_byte;
+  //while ( (inb(0x64) & 0x02) );
+  if ( inb(0x64) & 0x02 )
+    BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
+  command_byte &= 0xfd; // turn off IRQ 12 generation
+  command_byte |= 0x20; // disable mouse serial clock line
+  outb(0x64, 0x60); // write command byte
+  outb(0x60, command_byte);
+  return(prev_command_byte);
+}
+
+  void
+enable_mouse_int_and_events()
+{
+  Bit8u command_byte;
+
+  // Turn on IRQ generation and aux data line
+  if ( inb(0x64) & 0x02 )
+    BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
+  outb(0x64, 0x20); // get command byte
+  while ( (inb(0x64) & 0x01) != 0x01 );
+  command_byte = inb(0x60);
+  //while ( (inb(0x64) & 0x02) );
+  if ( inb(0x64) & 0x02 )
+    BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
+  command_byte |= 0x02; // turn on IRQ 12 generation
+  command_byte &= 0xdf; // enable mouse serial clock line
+  outb(0x64, 0x60); // write command byte
+  outb(0x60, command_byte);
+}
+
+  Bit8u
+send_to_mouse_ctrl(sendbyte)
+  Bit8u sendbyte;
+{
+  Bit8u response;
+
+  // wait for chance to write to ctrl
+  if ( inb(0x64) & 0x02 )
+    BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
+  outb(0x64, 0xD4);
+  outb(0x60, sendbyte);
+  return(0);
+}
+
+
+  Bit8u
+get_mouse_data(data)
+  Bit8u *data;
+{
+  Bit8u response;
+  Bit16u ss;
+
+  while ( (inb(0x64) & 0x21) != 0x21 ) {
+    }
+
+  response = inb(0x60);
+
+  ss = get_SS();
+  write_byte(ss, data, response);
+  return(0);
+}
+
+  void
+set_kbd_command_byte(command_byte)
+  Bit8u command_byte;
+{
+  if ( inb(0x64) & 0x02 )
+    BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
+  outb(0x64, 0xD4);
+
+  outb(0x64, 0x60); // write command byte
+  outb(0x60, command_byte);
+}
+
+  void
+int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
+{
+  Bit8u scancode, asciicode, shift_flags;
+  Bit8u mf2_flags, mf2_state;
+
+  //
+  // DS has been set to F000 before call
+  //
+
+
+  scancode = GET_AL();
+
+  if (scancode == 0) {
+    BX_INFO("KBD: int09 handler: AL=0\n");
+    return;
+    }
+
+
+  shift_flags = read_byte(0x0040, 0x17);
+  mf2_flags = read_byte(0x0040, 0x18);
+  mf2_state = read_byte(0x0040, 0x96);
+  asciicode = 0;
+
+  switch (scancode) {
+    case 0x3a: /* Caps Lock press */
+      shift_flags ^= 0x40;
+      write_byte(0x0040, 0x17, shift_flags);
+      mf2_flags |= 0x40;
+      write_byte(0x0040, 0x18, mf2_flags);
+      break;
+    case 0xba: /* Caps Lock release */
+      mf2_flags &= ~0x40;
+      write_byte(0x0040, 0x18, mf2_flags);
+      break;
+
+    case 0x2a: /* L Shift press */
+      shift_flags |= 0x02;
+      write_byte(0x0040, 0x17, shift_flags);
+      break;
+    case 0xaa: /* L Shift release */
+      shift_flags &= ~0x02;
+      write_byte(0x0040, 0x17, shift_flags);
+      break;
+
+    case 0x36: /* R Shift press */
+      shift_flags |= 0x01;
+      write_byte(0x0040, 0x17, shift_flags);
+      break;
+    case 0xb6: /* R Shift release */
+      shift_flags &= ~0x01;
+      write_byte(0x0040, 0x17, shift_flags);
+      break;
+
+    case 0x1d: /* Ctrl press */
+      if ((mf2_state & 0x01) == 0) {
+        shift_flags |= 0x04;
+        write_byte(0x0040, 0x17, shift_flags);
+        if (mf2_state & 0x02) {
+          mf2_state |= 0x04;
+          write_byte(0x0040, 0x96, mf2_state);
+        } else {
+          mf2_flags |= 0x01;
+          write_byte(0x0040, 0x18, mf2_flags);
+        }
+      }
+      break;
+    case 0x9d: /* Ctrl release */
+      if ((mf2_state & 0x01) == 0) {
+        shift_flags &= ~0x04;
+        write_byte(0x0040, 0x17, shift_flags);
+        if (mf2_state & 0x02) {
+          mf2_state &= ~0x04;
+          write_byte(0x0040, 0x96, mf2_state);
+        } else {
+          mf2_flags &= ~0x01;
+          write_byte(0x0040, 0x18, mf2_flags);
+        }
+      }
+      break;
+
+    case 0x38: /* Alt press */
+      shift_flags |= 0x08;
+      write_byte(0x0040, 0x17, shift_flags);
+      if (mf2_state & 0x02) {
+        mf2_state |= 0x08;
+        write_byte(0x0040, 0x96, mf2_state);
+      } else {
+        mf2_flags |= 0x02;
+        write_byte(0x0040, 0x18, mf2_flags);
+      }
+      break;
+    case 0xb8: /* Alt release */
+      shift_flags &= ~0x08;
+      write_byte(0x0040, 0x17, shift_flags);
+      if (mf2_state & 0x02) {
+        mf2_state &= ~0x08;
+        write_byte(0x0040, 0x96, mf2_state);
+      } else {
+        mf2_flags &= ~0x02;
+        write_byte(0x0040, 0x18, mf2_flags);
+      }
+      break;
+
+    case 0x45: /* Num Lock press */
+      if ((mf2_state & 0x03) == 0) {
+        mf2_flags |= 0x20;
+        write_byte(0x0040, 0x18, mf2_flags);
+        shift_flags ^= 0x20;
+        write_byte(0x0040, 0x17, shift_flags);
+      }
+      break;
+    case 0xc5: /* Num Lock release */
+      if ((mf2_state & 0x03) == 0) {
+        mf2_flags &= ~0x20;
+        write_byte(0x0040, 0x18, mf2_flags);
+      }
+      break;
+
+    case 0x46: /* Scroll Lock press */
+      mf2_flags |= 0x10;
+      write_byte(0x0040, 0x18, mf2_flags);
+      shift_flags ^= 0x10;
+      write_byte(0x0040, 0x17, shift_flags);
+      break;
+
+    case 0xc6: /* Scroll Lock release */
+      mf2_flags &= ~0x10;
+      write_byte(0x0040, 0x18, mf2_flags);
+      break;
+
+    default:
+      if (scancode & 0x80) {
+        break; /* toss key releases ... */
+      }
+      if (scancode > MAX_SCAN_CODE) {
+        BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
+        return;
+      }
+      if (shift_flags & 0x08) { /* ALT */
+        asciicode = scan_to_scanascii[scancode].alt;
+        scancode = scan_to_scanascii[scancode].alt >> 8;
+      } else if (shift_flags & 0x04) { /* CONTROL */
+        asciicode = scan_to_scanascii[scancode].control;
+        scancode = scan_to_scanascii[scancode].control >> 8;
+      } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
+        /* extended keys handling */
+        asciicode = 0xe0;
+        scancode = scan_to_scanascii[scancode].normal >> 8;
+      } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
+        /* check if lock state should be ignored
+         * because a SHIFT key are pressed */
+
+        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
+          asciicode = scan_to_scanascii[scancode].normal;
+          scancode = scan_to_scanascii[scancode].normal >> 8;
+        } else {
+          asciicode = scan_to_scanascii[scancode].shift;
+          scancode = scan_to_scanascii[scancode].shift >> 8;
+        }
+      } else {
+        /* check if lock is on */
+        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
+          asciicode = scan_to_scanascii[scancode].shift;
+          scancode = scan_to_scanascii[scancode].shift >> 8;
+        } else {
+          asciicode = scan_to_scanascii[scancode].normal;
+          scancode = scan_to_scanascii[scancode].normal >> 8;
+        }
+      }
+      if (scancode==0 && asciicode==0) {
+        BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
+      }
+      enqueue_key(scancode, asciicode);
+      break;
+  }
+  if ((scancode & 0x7f) != 0x1d) {
+    mf2_state &= ~0x01;
+  }
+  mf2_state &= ~0x02;
+  write_byte(0x0040, 0x96, mf2_state);
+}
+
+  unsigned int
+enqueue_key(scan_code, ascii_code)
+  Bit8u scan_code, ascii_code;
+{
+  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
+
+#if BX_CPU < 2
+  buffer_start = 0x001E;
+  buffer_end   = 0x003E;
+#else
+  buffer_start = read_word(0x0040, 0x0080);
+  buffer_end   = read_word(0x0040, 0x0082);
+#endif
+
+  buffer_head = read_word(0x0040, 0x001A);
+  buffer_tail = read_word(0x0040, 0x001C);
+
+  temp_tail = buffer_tail;
+  buffer_tail += 2;
+  if (buffer_tail >= buffer_end)
+    buffer_tail = buffer_start;
+
+  if (buffer_tail == buffer_head) {
+    return(0);
+    }
+
+   write_byte(0x0040, temp_tail, ascii_code);
+   write_byte(0x0040, temp_tail+1, scan_code);
+   write_word(0x0040, 0x001C, buffer_tail);
+   return(1);
+}
+
+
+  void
+int74_function(make_farcall, Z, Y, X, status)
+  Bit16u make_farcall, Z, Y, X, status;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  in_byte, index, package_count;
+  Bit8u  mouse_flags_1, mouse_flags_2;
+
+BX_DEBUG_INT74("entering int74_function\n");
+  make_farcall = 0;
+
+  in_byte = inb(0x64);
+  if ( (in_byte & 0x21) != 0x21 ) {
+    return;
+    }
+  in_byte = inb(0x60);
+BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
+
+  mouse_flags_1 = read_byte(ebda_seg, 0x0026);
+  mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+
+  if ( (mouse_flags_2 & 0x80) != 0x80 ) {
+      return;
+  }
+
+  package_count = mouse_flags_2 & 0x07;
+  index = mouse_flags_1 & 0x07;
+  write_byte(ebda_seg, 0x28 + index, in_byte);
+
+  if ( (index+1) >= package_count ) {
+BX_DEBUG_INT74("int74_function: make_farcall=1\n");
+    status = read_byte(ebda_seg, 0x0028 + 0);
+    X      = read_byte(ebda_seg, 0x0028 + 1);
+    Y      = read_byte(ebda_seg, 0x0028 + 2);
+    Z      = 0;
+    mouse_flags_1 = 0;
+    // check if far call handler installed
+    if (mouse_flags_2 & 0x80)
+      make_farcall = 1;
+    }
+  else {
+    mouse_flags_1++;
+    }
+  write_byte(ebda_seg, 0x0026, mouse_flags_1);
+}
+
+#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
+
+#if BX_USE_ATADRV
+
+  void
+int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit32u lba_low, lba_high;
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit16u cylinder, head, sector;
+  Bit16u segment, offset;
+  Bit16u npc, nph, npspt, nlc, nlh, nlspt;
+  Bit16u size, count;
+  Bit8u  device, status;
+
+  BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+  write_byte(0x0040, 0x008e, 0);  // clear completion flag
+
+  // basic check : device has to be defined
+  if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
+    BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
+    goto int13_fail;
+    }
+
+  // Get the ata channel
+  device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
+
+  // basic check : device has to be valid
+  if (device >= BX_MAX_ATA_DEVICES) {
+    BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
+    goto int13_fail;
+    }
+
+  switch (GET_AH()) {
+
+    case 0x00: /* disk controller reset */
+      ata_reset (device);
+      goto int13_success;
+      break;
+
+    case 0x01: /* read disk status */
+      status = read_byte(0x0040, 0x0074);
+      SET_AH(status);
+      SET_DISK_RET_STATUS(0);
+      /* set CF if error status read */
+      if (status) goto int13_fail_nostatus;
+      else        goto int13_success_noah;
+      break;
+
+    case 0x02: // read disk sectors
+    case 0x03: // write disk sectors
+    case 0x04: // verify disk sectors
+
+      count       = GET_AL();
+      cylinder    = GET_CH();
+      cylinder   |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
+      sector      = (GET_CL() & 0x3f);
+      head        = GET_DH();
+
+      segment = ES;
+      offset  = BX;
+
+      if ((count > 128) || (count == 0) || (sector == 0)) {
+        BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
+        goto int13_fail;
+      }
+
+      nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
+      nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
+      nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
+
+      // sanity check on cyl heads, sec
+      if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
+        BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
+        goto int13_fail;
+        }
+
+      // FIXME verify
+      if ( GET_AH() == 0x04 ) goto int13_success;
+
+      nph   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
+      npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
+
+      // if needed, translate lchs to lba, and execute command
+      if ( (nph != nlh) || (npspt != nlspt)) {
+        lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
+        lba_high = 0;
+        sector = 0; // this forces the command to be lba
+        }
+
+      if ( GET_AH() == 0x02 )
+        status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
+      else
+        status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
+
+      // Set nb of sector transferred
+      SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
+
+      if (status != 0) {
+        BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
+        SET_AH(0x0c);
+        goto int13_fail_noah;
+        }
+
+      goto int13_success;
+      break;
+
+    case 0x05: /* format disk track */
+      BX_INFO("format disk track called\n");
+      goto int13_success;
+      return;
+      break;
+
+    case 0x08: /* read disk drive parameters */
+
+      // Get logical geometry from table
+      nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
+      nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
+      nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
+      count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
+
+      nlc = nlc - 2; /* 0 based , last sector not used */
+      SET_AL(0);
+      SET_CH(nlc & 0xff);
+      SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
+      SET_DH(nlh - 1);
+      SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
+
+      // FIXME should set ES & DI
+
+      goto int13_success;
+      break;
+
+    case 0x10: /* check drive ready */
+      // should look at 40:8E also???
+
+      // Read the status from controller
+      status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
+      if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
+        goto int13_success;
+        }
+      else {
+        SET_AH(0xAA);
+        goto int13_fail_noah;
+        }
+      break;
+
+    case 0x15: /* read disk drive size */
+
+      // Get logical geometry from table
+      nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
+      nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
+      nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
+
+      // Compute sector count seen by int13
+      lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt;
+      CX = lba_low >> 16;
+      DX = lba_low & 0xffff;
+
+      SET_AH(3);  // hard disk accessible
+      goto int13_success_noah;
+      break;
+
+    case 0x41: // IBM/MS installation check
+      BX=0xaa55;     // install check
+      SET_AH(0x30);  // EDD 3.0
+      CX=0x0007;     // ext disk access and edd, removable supported
+      goto int13_success_noah;
+      break;
+
+    case 0x42: // IBM/MS extended read
+    case 0x43: // IBM/MS extended write
+    case 0x44: // IBM/MS verify
+    case 0x47: // IBM/MS extended seek
+
+      count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
+      segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
+      offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
+
+      // Get 32 msb lba and check
+      lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
+      if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) {
+        BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
+        goto int13_fail;
+        }
+
+      // Get 32 lsb lba and check
+      lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
+      if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high)
+          && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) {
+        BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
+        goto int13_fail;
+        }
+
+      // If verify or seek
+      if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
+        goto int13_success;
+
+      // Execute the command
+      if ( GET_AH() == 0x42 )
+        status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
+      else
+        status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
+
+      count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
+      write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
+
+      if (status != 0) {
+        BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
+        SET_AH(0x0c);
+        goto int13_fail_noah;
+        }
+
+      goto int13_success;
+      break;
+
+    case 0x45: // IBM/MS lock/unlock drive
+    case 0x49: // IBM/MS extended media change
+      goto int13_success;    // Always success for HD
+      break;
+
+    case 0x46: // IBM/MS eject media
+      SET_AH(0xb2);          // Volume Not Removable
+      goto int13_fail_noah;  // Always fail for HD
+      break;
+
+    case 0x48: // IBM/MS get drive parameters
+      size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
+
+      // Buffer is too small
+      if(size < 0x1a)
+        goto int13_fail;
+
+      // EDD 1.x
+      if(size >= 0x1a) {
+        Bit16u   blksize;
+
+        npc     = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
+        nph     = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
+        npspt   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
+        lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low);
+        lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high);
+        blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
+        if (lba_high || (lba_low/npspt)/nph > 0x3fff)
+        {
+          write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid
+          write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff);
+        }
+        else
+        {
+          write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
+          write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
+        }
+        write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high);
+        write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
+        }
+
+      // EDD 2.x
+      if(size >= 0x1e) {
+        Bit8u  channel, dev, irq, mode, checksum, i, translation;
+        Bit16u iobase1, iobase2, options;
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
+        write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
+
+        // Fill in dpte
+        channel = device / 2;
+        iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+        iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+        irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
+        mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+        translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
+
+        options  = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
+        options |= (1<<4); // lba translation
+        options |= (mode==ATA_MODE_PIO32?1:0)<<7;
+        options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
+        options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
+
+        write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
+        write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
+        write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
+        write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
+        write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
+        if (size >=0x42)
+          write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
+        else
+          write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10);
+
+        checksum=0;
+        for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
+        checksum = ~checksum;
+        write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
+        }
+
+      // EDD 3.x
+      if(size >= 0x42) {
+        Bit8u channel, iface, checksum, i;
+        Bit16u iobase1;
+
+        channel = device / 2;
+        iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
+        iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
+        write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
+        write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
+        write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
+        write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
+
+        if (iface==ATA_IFACE_ISA) {
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
+          }
+        else {
+          // FIXME PCI
+          }
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
+
+        if (iface==ATA_IFACE_ISA) {
+          write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
+          write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
+          write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
+          }
+        else {
+          // FIXME PCI
+          }
+        write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
+        write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
+        write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
+
+        checksum=0;
+        for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
+        checksum = ~checksum;
+        write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
+        }
+
+      goto int13_success;
+      break;
+
+    case 0x4e: // // IBM/MS set hardware configuration
+      // DMA, prefetch, PIO maximum not supported
+      switch (GET_AL()) {
+        case 0x01:
+        case 0x03:
+        case 0x04:
+        case 0x06:
+          goto int13_success;
+          break;
+        default :
+          goto int13_fail;
+        }
+      break;
+
+    case 0x09: /* initialize drive parameters */
+    case 0x0c: /* seek to specified cylinder */
+    case 0x0d: /* alternate disk reset */
+    case 0x11: /* recalibrate */
+    case 0x14: /* controller internal diagnostic */
+      BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
+      goto int13_success;
+      break;
+
+    case 0x0a: /* read disk sectors with ECC */
+    case 0x0b: /* write disk sectors with ECC */
+    case 0x18: // set media type for format
+    case 0x50: // IBM/MS send packet command
+    default:
+      BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
+      goto int13_fail;
+      break;
+    }
+
+int13_fail:
+    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13_fail_noah:
+    SET_DISK_RET_STATUS(GET_AH());
+int13_fail_nostatus:
+    SET_CF();     // error occurred
+    return;
+
+int13_success:
+    SET_AH(0x00); // no error
+int13_success_noah:
+    SET_DISK_RET_STATUS(0x00);
+    CLEAR_CF();   // no error
+    return;
+}
+
+// ---------------------------------------------------------------------------
+// Start of int13 for cdrom
+// ---------------------------------------------------------------------------
+
+  void
+int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  device, status, locks;
+  Bit8u  atacmd[12];
+  Bit32u lba;
+  Bit16u count, segment, offset, i, size;
+
+  BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+  SET_DISK_RET_STATUS(0x00);
+
+  /* basic check : device should be 0xE0+ */
+  if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
+    BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
+    goto int13_fail;
+    }
+
+  // Get the ata channel
+  device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
+
+  /* basic check : device has to be valid  */
+  if (device >= BX_MAX_ATA_DEVICES) {
+    BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
+    goto int13_fail;
+    }
+
+  switch (GET_AH()) {
+
+    // all those functions return SUCCESS
+    case 0x00: /* disk controller reset */
+    case 0x09: /* initialize drive parameters */
+    case 0x0c: /* seek to specified cylinder */
+    case 0x0d: /* alternate disk reset */
+    case 0x10: /* check drive ready */
+    case 0x11: /* recalibrate */
+    case 0x14: /* controller internal diagnostic */
+    case 0x16: /* detect disk change */
+      goto int13_success;
+      break;
+
+    // all those functions return disk write-protected
+    case 0x03: /* write disk sectors */
+    case 0x05: /* format disk track */
+    case 0x43: // IBM/MS extended write
+      SET_AH(0x03);
+      goto int13_fail_noah;
+      break;
+
+    case 0x01: /* read disk status */
+      status = read_byte(0x0040, 0x0074);
+      SET_AH(status);
+      SET_DISK_RET_STATUS(0);
+
+      /* set CF if error status read */
+      if (status) goto int13_fail_nostatus;
+      else        goto int13_success_noah;
+      break;
+
+    case 0x15: /* read disk drive size */
+      SET_AH(0x02);
+      goto int13_fail_noah;
+      break;
+
+    case 0x41: // IBM/MS installation check
+      BX=0xaa55;     // install check
+      SET_AH(0x30);  // EDD 2.1
+      CX=0x0007;     // ext disk access, removable and edd
+      goto int13_success_noah;
+      break;
+
+    case 0x42: // IBM/MS extended read
+    case 0x44: // IBM/MS verify sectors
+    case 0x47: // IBM/MS extended seek
+
+      count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
+      segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
+      offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
+
+      // Can't use 64 bits lba
+      lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
+      if (lba != 0L) {
+        BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
+        goto int13_fail;
+        }
+
+      // Get 32 bits lba
+      lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
+
+      // If verify or seek
+      if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
+        goto int13_success;
+
+      memsetb(get_SS(),atacmd,0,12);
+      atacmd[0]=0x28;                      // READ command
+      atacmd[7]=(count & 0xff00) >> 8;     // Sectors
+      atacmd[8]=(count & 0x00ff);          // Sectors
+      atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
+      atacmd[3]=(lba & 0x00ff0000) >> 16;
+      atacmd[4]=(lba & 0x0000ff00) >> 8;
+      atacmd[5]=(lba & 0x000000ff);
+      status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
+
+      count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
+      write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
+
+      if (status != 0) {
+        BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
+        SET_AH(0x0c);
+        goto int13_fail_noah;
+        }
+
+      goto int13_success;
+      break;
+
+    case 0x45: // IBM/MS lock/unlock drive
+      if (GET_AL() > 2) goto int13_fail;
+
+      locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
+
+      switch (GET_AL()) {
+        case 0 :  // lock
+          if (locks == 0xff) {
+            SET_AH(0xb4);
+            SET_AL(1);
+            goto int13_fail_noah;
+            }
+          write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
+          SET_AL(1);
+          break;
+        case 1 :  // unlock
+          if (locks == 0x00) {
+            SET_AH(0xb0);
+            SET_AL(0);
+            goto int13_fail_noah;
+            }
+          write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
+          SET_AL(locks==0?0:1);
+          break;
+        case 2 :  // status
+          SET_AL(locks==0?0:1);
+          break;
+        }
+      goto int13_success;
+      break;
+
+    case 0x46: // IBM/MS eject media
+      locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
+
+      if (locks != 0) {
+        SET_AH(0xb1); // media locked
+        goto int13_fail_noah;
+        }
+      // FIXME should handle 0x31 no media in device
+      // FIXME should handle 0xb5 valid request failed
+
+      // Call removable media eject
+      ASM_START
+        push bp
+        mov  bp, sp
+
+        mov ah, #0x52
+        int #0x15
+        mov _int13_cdrom.status + 2[bp], ah
+        jnc int13_cdrom_rme_end
+        mov _int13_cdrom.status, #1
+int13_cdrom_rme_end:
+        pop bp
+      ASM_END
+
+      if (status != 0) {
+        SET_AH(0xb1); // media locked
+        goto int13_fail_noah;
+      }
+
+      goto int13_success;
+      break;
+
+    case 0x48: // IBM/MS get drive parameters
+      size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
+
+      // Buffer is too small
+      if(size < 0x1a)
+        goto int13_fail;
+
+      // EDD 1.x
+      if(size >= 0x1a) {
+        Bit16u   cylinders, heads, spt, blksize;
+
+        blksize   = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
+        write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
+        write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff);  // FIXME should be Bit64
+        write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
+        write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
+        }
+
+      // EDD 2.x
+      if(size >= 0x1e) {
+        Bit8u  channel, dev, irq, mode, checksum, i;
+        Bit16u iobase1, iobase2, options;
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
+        write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
+
+        // Fill in dpte
+        channel = device / 2;
+        iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+        iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+        irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
+        mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+
+        // FIXME atapi device
+        options  = (1<<4); // lba translation
+        options |= (1<<5); // removable device
+        options |= (1<<6); // atapi device
+        options |= (mode==ATA_MODE_PIO32?1:0<<7);
+
+        write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
+        write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
+        write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
+        write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
+        write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
+        write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
+        write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
+
+        checksum=0;
+        for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
+        checksum = ~checksum;
+        write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
+        }
+
+      // EDD 3.x
+      if(size >= 0x42) {
+        Bit8u channel, iface, checksum, i;
+        Bit16u iobase1;
+
+        channel = device / 2;
+        iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
+        iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+
+        write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
+        write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
+        write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
+        write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
+        write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
+
+        if (iface==ATA_IFACE_ISA) {
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
+          write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
+          }
+        else {
+          // FIXME PCI
+          }
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
+        write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
+
+        if (iface==ATA_IFACE_ISA) {
+          write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
+          write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
+          write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
+          }
+        else {
+          // FIXME PCI
+          }
+        write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
+        write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
+        write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
+        write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
+
+        checksum=0;
+        for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
+        checksum = ~checksum;
+        write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
+        }
+
+      goto int13_success;
+      break;
+
+    case 0x49: // IBM/MS extended media change
+      // always send changed ??
+      SET_AH(06);
+      goto int13_fail_nostatus;
+      break;
+
+    case 0x4e: // // IBM/MS set hardware configuration
+      // DMA, prefetch, PIO maximum not supported
+      switch (GET_AL()) {
+        case 0x01:
+        case 0x03:
+        case 0x04:
+        case 0x06:
+          goto int13_success;
+          break;
+        default :
+          goto int13_fail;
+        }
+      break;
+
+    // all those functions return unimplemented
+    case 0x02: /* read sectors */
+    case 0x04: /* verify sectors */
+    case 0x08: /* read disk drive parameters */
+    case 0x0a: /* read disk sectors with ECC */
+    case 0x0b: /* write disk sectors with ECC */
+    case 0x18: /* set media type for format */
+    case 0x50: // ? - send packet command
+    default:
+      BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
+      goto int13_fail;
+      break;
+    }
+
+int13_fail:
+    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13_fail_noah:
+    SET_DISK_RET_STATUS(GET_AH());
+int13_fail_nostatus:
+    SET_CF();     // error occurred
+    return;
+
+int13_success:
+    SET_AH(0x00); // no error
+int13_success_noah:
+    SET_DISK_RET_STATUS(0x00);
+    CLEAR_CF();   // no error
+    return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 for cdrom
+// ---------------------------------------------------------------------------
+
+#if BX_ELTORITO_BOOT
+// ---------------------------------------------------------------------------
+// Start of int13 for eltorito functions
+// ---------------------------------------------------------------------------
+
+  void
+int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+  BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+  // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
+
+  switch (GET_AH()) {
+
+    // FIXME ElTorito Various. Should be implemented
+    case 0x4a: // ElTorito - Initiate disk emu
+    case 0x4c: // ElTorito - Initiate disk emu and boot
+    case 0x4d: // ElTorito - Return Boot catalog
+      BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
+      goto int13_fail;
+      break;
+
+    case 0x4b: // ElTorito - Terminate disk emu
+      // FIXME ElTorito Hardcoded
+      write_byte(DS,SI+0x00,0x13);
+      write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
+      write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
+      write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
+      write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
+      write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
+      write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
+      write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
+      write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
+      write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
+      write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
+      write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
+
+      // If we have to terminate emulation
+      if(GET_AL() == 0x00) {
+        // FIXME ElTorito Various. Should be handled accordingly to spec
+        write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
+        }
+
+      goto int13_success;
+      break;
+
+    default:
+      BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
+      goto int13_fail;
+      break;
+    }
+
+int13_fail:
+    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+    SET_DISK_RET_STATUS(GET_AH());
+    SET_CF();     // error occurred
+    return;
+
+int13_success:
+    SET_AH(0x00); // no error
+    SET_DISK_RET_STATUS(0x00);
+    CLEAR_CF();   // no error
+    return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 for eltorito functions
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Start of int13 when emulating a device from the cd
+// ---------------------------------------------------------------------------
+
+  void
+int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit8u  device, status;
+  Bit16u vheads, vspt, vcylinders;
+  Bit16u head, sector, cylinder, nbsectors;
+  Bit32u vlba, ilba, slba, elba;
+  Bit16u before, segment, offset;
+  Bit8u  atacmd[12];
+
+  BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+  /* at this point, we are emulating a floppy/harddisk */
+
+  // Recompute the device number
+  device  = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
+  device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
+
+  SET_DISK_RET_STATUS(0x00);
+
+  /* basic checks : emulation should be active, dl should equal the emulated drive */
+  if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
+   || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
+    BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
+    goto int13_fail;
+    }
+
+  switch (GET_AH()) {
+
+    // all those functions return SUCCESS
+    case 0x00: /* disk controller reset */
+    case 0x09: /* initialize drive parameters */
+    case 0x0c: /* seek to specified cylinder */
+    case 0x0d: /* alternate disk reset */  // FIXME ElTorito Various. should really reset ?
+    case 0x10: /* check drive ready */     // FIXME ElTorito Various. should check if ready ?
+    case 0x11: /* recalibrate */
+    case 0x14: /* controller internal diagnostic */
+    case 0x16: /* detect disk change */
+      goto int13_success;
+      break;
+
+    // all those functions return disk write-protected
+    case 0x03: /* write disk sectors */
+    case 0x05: /* format disk track */
+      SET_AH(0x03);
+      goto int13_fail_noah;
+      break;
+
+    case 0x01: /* read disk status */
+      status=read_byte(0x0040, 0x0074);
+      SET_AH(status);
+      SET_DISK_RET_STATUS(0);
+
+      /* set CF if error status read */
+      if (status) goto int13_fail_nostatus;
+      else        goto int13_success_noah;
+      break;
+
+    case 0x02: // read disk sectors
+    case 0x04: // verify disk sectors
+      vspt       = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
+      vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
+      vheads     = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
+
+      ilba       = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
+
+      sector    = GET_CL() & 0x003f;
+      cylinder  = (GET_CL() & 0x00c0) << 2 | GET_CH();
+      head      = GET_DH();
+      nbsectors = GET_AL();
+      segment   = ES;
+      offset    = BX;
+
+      // no sector to read ?
+      if(nbsectors==0) goto int13_success;
+
+      // sanity checks sco openserver needs this!
+      if ((sector   >  vspt)
+       || (cylinder >= vcylinders)
+       || (head     >= vheads)) {
+        goto int13_fail;
+        }
+
+      // After controls, verify do nothing
+      if (GET_AH() == 0x04) goto int13_success;
+
+      segment = ES+(BX / 16);
+      offset  = BX % 16;
+
+      // calculate the virtual lba inside the image
+      vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
+
+      // In advance so we don't loose the count
+      SET_AL(nbsectors);
+
+      // start lba on cd
+      slba  = (Bit32u)vlba/4;
+      before= (Bit16u)vlba%4;
+
+      // end lba on cd
+      elba = (Bit32u)(vlba+nbsectors-1)/4;
+
+      memsetb(get_SS(),atacmd,0,12);
+      atacmd[0]=0x28;                      // READ command
+      atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
+      atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff);      // Sectors
+      atacmd[2]=(ilba+slba & 0xff000000) >> 24;  // LBA
+      atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
+      atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
+      atacmd[5]=(ilba+slba & 0x000000ff);
+      if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
+        BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
+        SET_AH(0x02);
+        SET_AL(0);
+        goto int13_fail_noah;
+        }
+
+      goto int13_success;
+      break;
+
+    case 0x08: /* read disk drive parameters */
+      vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
+      vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
+      vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
+
+      SET_AL( 0x00 );
+      SET_BL( 0x00 );
+      SET_CH( vcylinders & 0xff );
+      SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt  & 0x3f ));
+      SET_DH( vheads );
+      SET_DL( 0x02 );   // FIXME ElTorito Various. should send the real count of drives 1 or 2
+                        // FIXME ElTorito Harddisk. should send the HD count
+
+      switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
+        case 0x01: SET_BL( 0x02 ); break;
+        case 0x02: SET_BL( 0x04 ); break;
+        case 0x03: SET_BL( 0x06 ); break;
+        }
+
+ASM_START
+      push bp
+      mov  bp, sp
+      mov ax, #diskette_param_table2
+      mov _int13_cdemu.DI+2[bp], ax
+      mov _int13_cdemu.ES+2[bp], cs
+      pop  bp
+ASM_END
+      goto int13_success;
+      break;
+
+    case 0x15: /* read disk drive size */
+      // FIXME ElTorito Harddisk. What geometry to send ?
+      SET_AH(0x03);
+      goto int13_success_noah;
+      break;
+
+    // all those functions return unimplemented
+    case 0x0a: /* read disk sectors with ECC */
+    case 0x0b: /* write disk sectors with ECC */
+    case 0x18: /* set media type for format */
+    case 0x41: // IBM/MS installation check
+      // FIXME ElTorito Harddisk. Darwin would like to use EDD
+    case 0x42: // IBM/MS extended read
+    case 0x43: // IBM/MS extended write
+    case 0x44: // IBM/MS verify sectors
+    case 0x45: // IBM/MS lock/unlock drive
+    case 0x46: // IBM/MS eject media
+    case 0x47: // IBM/MS extended seek
+    case 0x48: // IBM/MS get drive parameters
+    case 0x49: // IBM/MS extended media change
+    case 0x4e: // ? - set hardware configuration
+    case 0x50: // ? - send packet command
+    default:
+      BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
+      goto int13_fail;
+      break;
+    }
+
+int13_fail:
+    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13_fail_noah:
+    SET_DISK_RET_STATUS(GET_AH());
+int13_fail_nostatus:
+    SET_CF();     // error occurred
+    return;
+
+int13_success:
+    SET_AH(0x00); // no error
+int13_success_noah:
+    SET_DISK_RET_STATUS(0x00);
+    CLEAR_CF();   // no error
+    return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 when emulating a device from the cd
+// ---------------------------------------------------------------------------
+
+#endif // BX_ELTORITO_BOOT
+
+#else //BX_USE_ATADRV
+
+  void
+outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
+  Bit16u cylinder;
+  Bit16u hd_heads;
+  Bit16u head;
+  Bit16u hd_sectors;
+  Bit16u sector;
+  Bit16u dl;
+{
+ASM_START
+        push   bp
+        mov    bp, sp
+        push   eax
+        push   ebx
+        push   edx
+        xor    eax,eax
+        mov    ax,4[bp]  // cylinder
+        xor    ebx,ebx
+        mov    bl,6[bp]  // hd_heads
+        imul   ebx
+
+        mov    bl,8[bp]  // head
+        add    eax,ebx
+        mov    bl,10[bp] // hd_sectors
+        imul   ebx
+        mov    bl,12[bp] // sector
+        add    eax,ebx
+
+        dec    eax
+        mov    dx,#0x1f3
+        out    dx,al
+        mov    dx,#0x1f4
+        mov    al,ah
+        out    dx,al
+        shr    eax,#16
+        mov    dx,#0x1f5
+        out    dx,al
+        and    ah,#0xf
+        mov    bl,14[bp] // dl
+        and    bl,#1
+        shl    bl,#4
+        or     ah,bl
+        or     ah,#0xe0
+        mov    al,ah
+        mov    dx,#0x01f6
+        out    dx,al
+        pop    edx
+        pop    ebx
+        pop    eax
+        pop    bp
+ASM_END
+}
+
+  void
+int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit8u    drive, num_sectors, sector, head, status, mod;
+  Bit8u    drive_map;
+  Bit8u    n_drives;
+  Bit16u   cyl_mod, ax;
+  Bit16u   max_cylinder, cylinder, total_sectors;
+  Bit16u   hd_cylinders;
+  Bit8u    hd_heads, hd_sectors;
+  Bit16u   val16;
+  Bit8u    sector_count;
+  unsigned int i;
+  Bit16u   tempbx;
+  Bit16u   dpsize;
+
+  Bit16u   count, segment, offset;
+  Bit32u   lba;
+  Bit16u   error;
+
+  BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+  write_byte(0x0040, 0x008e, 0);  // clear completion flag
+
+  /* at this point, DL is >= 0x80 to be passed from the floppy int13h
+     handler code */
+  /* check how many disks first (cmos reg 0x12), return an error if
+     drive not present */
+  drive_map = inb_cmos(0x12);
+  drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
+              (((drive_map & 0x0f)==0) ? 0 : 2);
+  n_drives = (drive_map==0) ? 0 :
+    ((drive_map==3) ? 2 : 1);
+
+  if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
+    SET_AH(0x01);
+    SET_DISK_RET_STATUS(0x01);
+    SET_CF(); /* error occurred */
+    return;
+    }
+
+  switch (GET_AH()) {
+
+    case 0x00: /* disk controller reset */
+BX_DEBUG_INT13_HD("int13_f00\n");
+
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      set_diskette_ret_status(0);
+      set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
+      set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x01: /* read disk status */
+BX_DEBUG_INT13_HD("int13_f01\n");
+      status = read_byte(0x0040, 0x0074);
+      SET_AH(status);
+      SET_DISK_RET_STATUS(0);
+      /* set CF if error status read */
+      if (status) SET_CF();
+      else        CLEAR_CF();
+      return;
+      break;
+
+    case 0x04: // verify disk sectors
+    case 0x02: // read disk sectors
+      drive = GET_ELDL();
+      get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+
+      num_sectors = GET_AL();
+      cylinder    = (GET_CL() & 0x00c0) << 2 | GET_CH();
+      sector      = (GET_CL() & 0x3f);
+      head        = GET_DH();
+
+
+      if (hd_cylinders > 1024) {
+        if (hd_cylinders <= 2048) {
+          cylinder <<= 1;
+          }
+        else if (hd_cylinders <= 4096) {
+          cylinder <<= 2;
+          }
+        else if (hd_cylinders <= 8192) {
+          cylinder <<= 3;
+          }
+        else { // hd_cylinders <= 16384
+          cylinder <<= 4;
+          }
+
+        ax = head / hd_heads;
+        cyl_mod = ax & 0xff;
+        head    = ax >> 8;
+        cylinder |= cyl_mod;
+        }
+
+      if ( (cylinder >= hd_cylinders) ||
+           (sector > hd_sectors) ||
+           (head >= hd_heads) ) {
+        SET_AH(1);
+        SET_DISK_RET_STATUS(1);
+        SET_CF(); /* error occurred */
+        return;
+        }
+
+      if ( (num_sectors > 128) || (num_sectors == 0) )
+        BX_PANIC("int13_harddisk: num_sectors out of range!\n");
+
+      if (head > 15)
+        BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
+
+      if ( GET_AH() == 0x04 ) {
+        SET_AH(0);
+        SET_DISK_RET_STATUS(0);
+        CLEAR_CF();
+        return;
+        }
+
+      status = inb(0x1f7);
+      if (status & 0x80) {
+        BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
+        }
+      outb(0x01f2, num_sectors);
+      /* activate LBA? (tomv) */
+      if (hd_heads > 16) {
+BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
+        outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
+        }
+      else {
+        outb(0x01f3, sector);
+        outb(0x01f4, cylinder & 0x00ff);
+        outb(0x01f5, cylinder >> 8);
+        outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
+        }
+      outb(0x01f7, 0x20);
+
+      while (1) {
+        status = inb(0x1f7);
+        if ( !(status & 0x80) ) break;
+        }
+
+      if (status & 0x01) {
+        BX_PANIC("hard drive BIOS:(read/verify) read error\n");
+      } else if ( !(status & 0x08) ) {
+        BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
+        BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
+      }
+
+      sector_count = 0;
+      tempbx = BX;
+
+ASM_START
+  sti  ;; enable higher priority interrupts
+ASM_END
+
+      while (1) {
+ASM_START
+        ;; store temp bx in real DI register
+        push bp
+        mov  bp, sp
+        mov  di, _int13_harddisk.tempbx + 2 [bp]
+        pop  bp
+
+        ;; adjust if there will be an overrun
+        cmp   di, #0xfe00
+        jbe   i13_f02_no_adjust
+i13_f02_adjust:
+        sub   di, #0x0200 ; sub 512 bytes from offset
+        mov   ax, es
+        add   ax, #0x0020 ; add 512 to segment
+        mov   es, ax
+
+i13_f02_no_adjust:
+        mov  cx, #0x0100   ;; counter (256 words = 512b)
+        mov  dx, #0x01f0  ;; AT data read port
+
+        rep
+          insw ;; CX words transfered from port(DX) to ES:[DI]
+
+i13_f02_done:
+        ;; store real DI register back to temp bx
+        push bp
+        mov  bp, sp
+        mov  _int13_harddisk.tempbx + 2 [bp], di
+        pop  bp
+ASM_END
+
+        sector_count++;
+        num_sectors--;
+        if (num_sectors == 0) {
+          status = inb(0x1f7);
+          if ( (status & 0xc9) != 0x40 )
+            BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
+          break;
+          }
+        else {
+          status = inb(0x1f7);
+          if ( (status & 0xc9) != 0x48 )
+            BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
+          continue;
+          }
+        }
+
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      SET_AL(sector_count);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+
+    case 0x03: /* write disk sectors */
+BX_DEBUG_INT13_HD("int13_f03\n");
+      drive = GET_ELDL ();
+      get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+
+      num_sectors = GET_AL();
+      cylinder    = GET_CH();
+      cylinder    |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
+      sector      = (GET_CL() & 0x3f);
+      head        = GET_DH();
+
+      if (hd_cylinders > 1024) {
+        if (hd_cylinders <= 2048) {
+          cylinder <<= 1;
+          }
+        else if (hd_cylinders <= 4096) {
+          cylinder <<= 2;
+          }
+        else if (hd_cylinders <= 8192) {
+          cylinder <<= 3;
+          }
+        else { // hd_cylinders <= 16384
+          cylinder <<= 4;
+          }
+
+        ax = head / hd_heads;
+        cyl_mod = ax & 0xff;
+        head    = ax >> 8;
+        cylinder |= cyl_mod;
+        }
+
+      if ( (cylinder >= hd_cylinders) ||
+           (sector > hd_sectors) ||
+           (head >= hd_heads) ) {
+        SET_AH( 1);
+        SET_DISK_RET_STATUS(1);
+        SET_CF(); /* error occurred */
+        return;
+        }
+
+      if ( (num_sectors > 128) || (num_sectors == 0) )
+        BX_PANIC("int13_harddisk: num_sectors out of range!\n");
+
+      if (head > 15)
+        BX_PANIC("hard drive BIOS:(read) head > 15\n");
+
+      status = inb(0x1f7);
+      if (status & 0x80) {
+        BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
+        }
+// should check for Drive Ready Bit also in status reg
+      outb(0x01f2, num_sectors);
+
+      /* activate LBA? (tomv) */
+      if (hd_heads > 16) {
+BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
+        outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
+        }
+      else {
+        outb(0x01f3, sector);
+        outb(0x01f4, cylinder & 0x00ff);
+        outb(0x01f5, cylinder >> 8);
+        outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
+        }
+      outb(0x01f7, 0x30);
+
+      // wait for busy bit to turn off after seeking
+      while (1) {
+        status = inb(0x1f7);
+        if ( !(status & 0x80) ) break;
+        }
+
+      if ( !(status & 0x08) ) {
+        BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
+        BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
+        }
+
+      sector_count = 0;
+      tempbx = BX;
+
+ASM_START
+  sti  ;; enable higher priority interrupts
+ASM_END
+
+      while (1) {
+ASM_START
+        ;; store temp bx in real SI register
+        push bp
+        mov  bp, sp
+        mov  si, _int13_harddisk.tempbx + 2 [bp]
+        pop  bp
+
+        ;; adjust if there will be an overrun
+        cmp   si, #0xfe00
+        jbe   i13_f03_no_adjust
+i13_f03_adjust:
+        sub   si, #0x0200 ; sub 512 bytes from offset
+        mov   ax, es
+        add   ax, #0x0020 ; add 512 to segment
+        mov   es, ax
+
+i13_f03_no_adjust:
+        mov  cx, #0x0100   ;; counter (256 words = 512b)
+        mov  dx, #0x01f0  ;; AT data read port
+
+        seg ES
+        rep
+          outsw ;; CX words tranfered from ES:[SI] to port(DX)
+
+        ;; store real SI register back to temp bx
+        push bp
+        mov  bp, sp
+        mov  _int13_harddisk.tempbx + 2 [bp], si
+        pop  bp
+ASM_END
+
+        sector_count++;
+        num_sectors--;
+        if (num_sectors == 0) {
+          status = inb(0x1f7);
+          if ( (status & 0xe9) != 0x40 )
+            BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
+          break;
+          }
+        else {
+          status = inb(0x1f7);
+          if ( (status & 0xc9) != 0x48 )
+            BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
+          continue;
+          }
+        }
+
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      SET_AL(sector_count);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x05: /* format disk track */
+BX_DEBUG_INT13_HD("int13_f05\n");
+      BX_PANIC("format disk track called\n");
+      /* nop */
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x08: /* read disk drive parameters */
+BX_DEBUG_INT13_HD("int13_f08\n");
+
+      drive = GET_ELDL ();
+      get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+
+      // translate CHS
+      //
+      if (hd_cylinders <= 1024) {
+        // hd_cylinders >>= 0;
+        // hd_heads <<= 0;
+        }
+      else if (hd_cylinders <= 2048) {
+        hd_cylinders >>= 1;
+        hd_heads <<= 1;
+        }
+      else if (hd_cylinders <= 4096) {
+        hd_cylinders >>= 2;
+        hd_heads <<= 2;
+        }
+      else if (hd_cylinders <= 8192) {
+        hd_cylinders >>= 3;
+        hd_heads <<= 3;
+        }
+      else { // hd_cylinders <= 16384
+        hd_cylinders >>= 4;
+        hd_heads <<= 4;
+        }
+
+      max_cylinder = hd_cylinders - 2; /* 0 based */
+      SET_AL(0);
+      SET_CH(max_cylinder & 0xff);
+      SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
+      SET_DH(hd_heads - 1);
+      SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+
+      return;
+      break;
+
+    case 0x09: /* initialize drive parameters */
+BX_DEBUG_INT13_HD("int13_f09\n");
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x0a: /* read disk sectors with ECC */
+BX_DEBUG_INT13_HD("int13_f0a\n");
+    case 0x0b: /* write disk sectors with ECC */
+BX_DEBUG_INT13_HD("int13_f0b\n");
+      BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
+      return;
+      break;
+
+    case 0x0c: /* seek to specified cylinder */
+BX_DEBUG_INT13_HD("int13_f0c\n");
+      BX_INFO("int13h function 0ch (seek) not implemented!\n");
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x0d: /* alternate disk reset */
+BX_DEBUG_INT13_HD("int13_f0d\n");
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x10: /* check drive ready */
+BX_DEBUG_INT13_HD("int13_f10\n");
+      //SET_AH(0);
+      //SET_DISK_RET_STATUS(0);
+      //CLEAR_CF(); /* successful */
+      //return;
+      //break;
+
+      // should look at 40:8E also???
+      status = inb(0x01f7);
+      if ( (status & 0xc0) == 0x40 ) {
+        SET_AH(0);
+        SET_DISK_RET_STATUS(0);
+        CLEAR_CF(); // drive ready
+        return;
+        }
+      else {
+        SET_AH(0xAA);
+        SET_DISK_RET_STATUS(0xAA);
+        SET_CF(); // not ready
+        return;
+        }
+      break;
+
+    case 0x11: /* recalibrate */
+BX_DEBUG_INT13_HD("int13_f11\n");
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+      return;
+      break;
+
+    case 0x14: /* controller internal diagnostic */
+BX_DEBUG_INT13_HD("int13_f14\n");
+      SET_AH(0);
+      SET_DISK_RET_STATUS(0);
+      CLEAR_CF(); /* successful */
+      SET_AL(0);
+      return;
+      break;
+
+    case 0x15: /* read disk drive size */
+      drive = GET_ELDL();
+      get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+ASM_START
+      push bp
+      mov  bp, sp
+      mov  al, _int13_harddisk.hd_heads + 2 [bp]
+      mov  ah, _int13_harddisk.hd_sectors + 2 [bp]
+      mul  al, ah ;; ax = heads * sectors
+      mov  bx, _int13_harddisk.hd_cylinders + 2 [bp]
+      dec  bx     ;; use (cylinders - 1) ???
+      mul  ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
+      ;; now we need to move the 32bit result dx:ax to what the
+      ;; BIOS wants which is cx:dx.
+      ;; and then into CX:DX on the stack
+      mov  _int13_harddisk.CX + 2 [bp], dx
+      mov  _int13_harddisk.DX + 2 [bp], ax
+      pop  bp
+ASM_END
+      SET_AH(3);  // hard disk accessible
+      SET_DISK_RET_STATUS(0); // ??? should this be 0
+      CLEAR_CF(); // successful
+      return;
+      break;
+
+    case 0x18: // set media type for format
+    case 0x41: // IBM/MS
+    case 0x42: // IBM/MS
+    case 0x43: // IBM/MS
+    case 0x44: // IBM/MS
+    case 0x45: // IBM/MS lock/unlock drive
+    case 0x46: // IBM/MS eject media
+    case 0x47: // IBM/MS extended seek
+    case 0x49: // IBM/MS extended media change
+    case 0x50: // IBM/MS send packet command
+    default:
+      BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
+
+      SET_AH(1);  // code=invalid function in AH or invalid parameter
+      SET_DISK_RET_STATUS(1);
+      SET_CF(); /* unsuccessful */
+      return;
+      break;
+    }
+}
+
+static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
+static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
+
+  void
+get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
+  Bit8u drive;
+  Bit16u *hd_cylinders;
+  Bit8u  *hd_heads;
+  Bit8u  *hd_sectors;
+{
+  Bit8u hd_type;
+  Bit16u ss;
+  Bit16u cylinders;
+  Bit8u iobase;
+
+  ss = get_SS();
+  if (drive == 0x80) {
+    hd_type = inb_cmos(0x12) & 0xf0;
+    if (hd_type != 0xf0)
+      BX_INFO(panic_msg_reg12h,0);
+    hd_type = inb_cmos(0x19); // HD0: extended type
+    if (hd_type != 47)
+      BX_INFO(panic_msg_reg19h,0,0x19);
+    iobase = 0x1b;
+  } else {
+    hd_type = inb_cmos(0x12) & 0x0f;
+    if (hd_type != 0x0f)
+      BX_INFO(panic_msg_reg12h,1);
+    hd_type = inb_cmos(0x1a); // HD1: extended type
+    if (hd_type != 47)
+      BX_INFO(panic_msg_reg19h,0,0x1a);
+    iobase = 0x24;
+  }
+
+  // cylinders
+  cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
+  write_word(ss, hd_cylinders, cylinders);
+
+  // heads
+  write_byte(ss, hd_heads, inb_cmos(iobase+2));
+
+  // sectors per track
+  write_byte(ss, hd_sectors, inb_cmos(iobase+8));
+}
+
+#endif //else BX_USE_ATADRV
+
+#if BX_SUPPORT_FLOPPY
+
+//////////////////////
+// FLOPPY functions //
+//////////////////////
+
+void floppy_reset_controller()
+{
+  Bit8u val8;
+
+  // Reset controller
+  val8 = inb(0x03f2);
+  outb(0x03f2, val8 & ~0x04);
+  outb(0x03f2, val8 | 0x04);
+
+  // Wait for controller to come out of reset
+  do {
+    val8 = inb(0x3f4);
+  } while ( (val8 & 0xc0) != 0x80 );
+}
+
+void floppy_prepare_controller(drive)
+  Bit16u drive;
+{
+  Bit8u  val8, dor, prev_reset;
+
+  // set 40:3e bit 7 to 0
+  val8 = read_byte(0x0040, 0x003e);
+  val8 &= 0x7f;
+  write_byte(0x0040, 0x003e, val8);
+
+  // turn on motor of selected drive, DMA & int enabled, normal operation
+  prev_reset = inb(0x03f2) & 0x04;
+  if (drive)
+    dor = 0x20;
+  else
+    dor = 0x10;
+  dor |= 0x0c;
+  dor |= drive;
+  outb(0x03f2, dor);
+
+  // reset the disk motor timeout value of INT 08
+  write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
+
+  // wait for drive readiness
+  do {
+    val8 = inb(0x3f4);
+  } while ( (val8 & 0xc0) != 0x80 );
+
+  if (prev_reset == 0) {
+    // turn on interrupts
+ASM_START
+    sti
+ASM_END
+    // wait on 40:3e bit 7 to become 1
+    do {
+      val8 = read_byte(0x0040, 0x003e);
+    } while ( (val8 & 0x80) == 0 );
+    val8 &= 0x7f;
+ASM_START
+    cli
+ASM_END
+    write_byte(0x0040, 0x003e, val8);
+  }
+}
+
+  bx_bool
+floppy_media_known(drive)
+  Bit16u drive;
+{
+  Bit8u  val8;
+  Bit16u media_state_offset;
+
+  val8 = read_byte(0x0040, 0x003e); // diskette recal status
+  if (drive)
+    val8 >>= 1;
+  val8 &= 0x01;
+  if (val8 == 0)
+    return(0);
+
+  media_state_offset = 0x0090;
+  if (drive)
+    media_state_offset += 1;
+
+  val8 = read_byte(0x0040, media_state_offset);
+  val8 = (val8 >> 4) & 0x01;
+  if (val8 == 0)
+    return(0);
+
+  // check pass, return KNOWN
+  return(1);
+}
+
+  bx_bool
+floppy_media_sense(drive)
+  Bit16u drive;
+{
+  bx_bool retval;
+  Bit16u  media_state_offset;
+  Bit8u   drive_type, config_data, media_state;
+
+  if (floppy_drive_recal(drive) == 0) {
+    return(0);
+    }
+
+  // for now cheat and get drive type from CMOS,
+  // assume media is same as drive type
+
+  // ** config_data **
+  // Bitfields for diskette media control:
+  // Bit(s)  Description (Table M0028)
+  //  7-6  last data rate set by controller
+  //        00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+  //  5-4  last diskette drive step rate selected
+  //        00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+  //  3-2  {data rate at start of operation}
+  //  1-0  reserved
+
+  // ** media_state **
+  // Bitfields for diskette drive media state:
+  // Bit(s)  Description (Table M0030)
+  //  7-6  data rate
+  //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+  //  5  double stepping required (e.g. 360kB in 1.2MB)
+  //  4  media type established
+  //  3  drive capable of supporting 4MB media
+  //  2-0  on exit from BIOS, contains
+  //    000 trying 360kB in 360kB
+  //    001 trying 360kB in 1.2MB
+  //    010 trying 1.2MB in 1.2MB
+  //    011 360kB in 360kB established
+  //    100 360kB in 1.2MB established
+  //    101 1.2MB in 1.2MB established
+  //    110 reserved
+  //    111 all other formats/drives
+
+  drive_type = inb_cmos(0x10);
+  if (drive == 0)
+    drive_type >>= 4;
+  else
+    drive_type &= 0x0f;
+  if ( drive_type == 1 ) {
+    // 360K 5.25" drive
+    config_data = 0x00; // 0000 0000
+    media_state = 0x25; // 0010 0101
+    retval = 1;
+    }
+  else if ( drive_type == 2 ) {
+    // 1.2 MB 5.25" drive
+    config_data = 0x00; // 0000 0000
+    media_state = 0x25; // 0010 0101   // need double stepping??? (bit 5)
+    retval = 1;
+    }
+  else if ( drive_type == 3 ) {
+    // 720K 3.5" drive
+    config_data = 0x00; // 0000 0000 ???
+    media_state = 0x17; // 0001 0111
+    retval = 1;
+    }
+  else if ( drive_type == 4 ) {
+    // 1.44 MB 3.5" drive
+    config_data = 0x00; // 0000 0000
+    media_state = 0x17; // 0001 0111
+    retval = 1;
+    }
+  else if ( drive_type == 5 ) {
+    // 2.88 MB 3.5" drive
+    config_data = 0xCC; // 1100 1100
+    media_state = 0xD7; // 1101 0111
+    retval = 1;
+    }
+  //
+  // Extended floppy size uses special cmos setting
+  else if ( drive_type == 6 ) {
+    // 160k 5.25" drive
+    config_data = 0x00; // 0000 0000
+    media_state = 0x27; // 0010 0111
+    retval = 1;
+    }
+  else if ( drive_type == 7 ) {
+    // 180k 5.25" drive
+    config_data = 0x00; // 0000 0000
+    media_state = 0x27; // 0010 0111
+    retval = 1;
+    }
+  else if ( drive_type == 8 ) {
+    // 320k 5.25" drive
+    config_data = 0x00; // 0000 0000
+    media_state = 0x27; // 0010 0111
+    retval = 1;
+    }
+
+  else {
+    // not recognized
+    config_data = 0x00; // 0000 0000
+    media_state = 0x00; // 0000 0000
+    retval = 0;
+    }
+
+  if (drive == 0)
+    media_state_offset = 0x90;
+  else
+    media_state_offset = 0x91;
+  write_byte(0x0040, 0x008B, config_data);
+  write_byte(0x0040, media_state_offset, media_state);
+
+  return(retval);
+}
+
+  bx_bool
+floppy_drive_recal(drive)
+  Bit16u drive;
+{
+  Bit8u  val8;
+  Bit16u curr_cyl_offset;
+
+  floppy_prepare_controller(drive);
+
+  // send Recalibrate command (2 bytes) to controller
+  outb(0x03f5, 0x07);  // 07: Recalibrate
+  outb(0x03f5, drive); // 0=drive0, 1=drive1
+
+  // turn on interrupts
+ASM_START
+  sti
+ASM_END
+
+  // wait on 40:3e bit 7 to become 1
+  do {
+    val8 = (read_byte(0x0040, 0x003e) & 0x80);
+  } while ( val8 == 0 );
+
+  val8 = 0; // separate asm from while() loop
+  // turn off interrupts
+ASM_START
+  cli
+ASM_END
+
+  // set 40:3e bit 7 to 0, and calibrated bit
+  val8 = read_byte(0x0040, 0x003e);
+  val8 &= 0x7f;
+  if (drive) {
+    val8 |= 0x02; // Drive 1 calibrated
+    curr_cyl_offset = 0x0095;
+  } else {
+    val8 |= 0x01; // Drive 0 calibrated
+    curr_cyl_offset = 0x0094;
+  }
+  write_byte(0x0040, 0x003e, val8);
+  write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
+
+  return(1);
+}
+
+
+
+  bx_bool
+floppy_drive_exists(drive)
+  Bit16u drive;
+{
+  Bit8u  drive_type;
+
+  // check CMOS to see if drive exists
+  drive_type = inb_cmos(0x10);
+  if (drive == 0)
+    drive_type >>= 4;
+  else
+    drive_type &= 0x0f;
+  if ( drive_type == 0 )
+    return(0);
+  else
+    return(1);
+}
+
+  void
+int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit8u  drive, num_sectors, track, sector, head, status;
+  Bit16u base_address, base_count, base_es;
+  Bit8u  page, mode_register, val8, dor;
+  Bit8u  return_status[7];
+  Bit8u  drive_type, num_floppies, ah;
+  Bit16u es, last_addr;
+
+  BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+  ah = GET_AH();
+
+  switch ( ah ) {
+    case 0x00: // diskette controller reset
+BX_DEBUG_INT13_FL("floppy f00\n");
+      drive = GET_ELDL();
+      if (drive > 1) {
+        SET_AH(1); // invalid param
+        set_diskette_ret_status(1);
+        SET_CF();
+        return;
+      }
+      drive_type = inb_cmos(0x10);
+
+      if (drive == 0)
+        drive_type >>= 4;
+      else
+        drive_type &= 0x0f;
+      if (drive_type == 0) {
+        SET_AH(0x80); // drive not responding
+        set_diskette_ret_status(0x80);
+        SET_CF();
+        return;
+      }
+      SET_AH(0);
+      set_diskette_ret_status(0);
+      CLEAR_CF(); // successful
+      set_diskette_current_cyl(drive, 0); // current cylinder
+      return;
+
+    case 0x01: // Read Diskette Status
+      CLEAR_CF();
+      val8 = read_byte(0x0000, 0x0441);
+      SET_AH(val8);
+      if (val8) {
+        SET_CF();
+      }
+      return;
+
+    case 0x02: // Read Diskette Sectors
+    case 0x03: // Write Diskette Sectors
+    case 0x04: // Verify Diskette Sectors
+      num_sectors = GET_AL();
+      track       = GET_CH();
+      sector      = GET_CL();
+      head        = GET_DH();
+      drive       = GET_ELDL();
+
+      if ((drive > 1) || (head > 1) || (sector == 0) ||
+          (num_sectors == 0) || (num_sectors > 72)) {
+        BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
+        SET_AH(1);
+        set_diskette_ret_status(1);
+        SET_AL(0); // no sectors read
+        SET_CF(); // error occurred
+        return;
+      }
+
+      // see if drive exists
+      if (floppy_drive_exists(drive) == 0) {
+        SET_AH(0x80); // not responding
+        set_diskette_ret_status(0x80);
+        SET_AL(0); // no sectors read
+        SET_CF(); // error occurred
+        return;
+      }
+
+      // see if media in drive, and type is known
+      if (floppy_media_known(drive) == 0) {
+        if (floppy_media_sense(drive) == 0) {
+          SET_AH(0x0C); // Media type not found
+          set_diskette_ret_status(0x0C);
+          SET_AL(0); // no sectors read
+          SET_CF(); // error occurred
+          return;
+        }
+      }
+
+      if (ah == 0x02) {
+        // Read Diskette Sectors
+
+        //-----------------------------------
+        // set up DMA controller for transfer
+        //-----------------------------------
+
+        // es:bx = pointer to where to place information from diskette
+        // port 04: DMA-1 base and current address, channel 2
+        // port 05: DMA-1 base and current count, channel 2
+        page = (ES >> 12);   // upper 4 bits
+        base_es = (ES << 4); // lower 16bits contributed by ES
+        base_address = base_es + BX; // lower 16 bits of address
+                                     // contributed by ES:BX
+        if ( base_address < base_es ) {
+          // in case of carry, adjust page by 1
+          page++;
+        }
+        base_count = (num_sectors * 512) - 1;
+
+        // check for 64K boundary overrun
+        last_addr = base_address + base_count;
+        if (last_addr < base_address) {
+          SET_AH(0x09);
+          set_diskette_ret_status(0x09);
+          SET_AL(0); // no sectors read
+          SET_CF(); // error occurred
+          return;
+        }
+
+        BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
+        outb(0x000a, 0x06);
+
+  BX_DEBUG_INT13_FL("clear flip-flop\n");
+        outb(0x000c, 0x00); // clear flip-flop
+        outb(0x0004, base_address);
+        outb(0x0004, base_address>>8);
+  BX_DEBUG_INT13_FL("clear flip-flop\n");
+        outb(0x000c, 0x00); // clear flip-flop
+        outb(0x0005, base_count);
+        outb(0x0005, base_count>>8);
+
+        // port 0b: DMA-1 Mode Register
+        mode_register = 0x46; // single mode, increment, autoinit disable,
+                              // transfer type=write, channel 2
+  BX_DEBUG_INT13_FL("setting mode register\n");
+        outb(0x000b, mode_register);
+
+  BX_DEBUG_INT13_FL("setting page register\n");
+        // port 81: DMA-1 Page Register, channel 2
+        outb(0x0081, page);
+
+  BX_DEBUG_INT13_FL("unmask chan 2\n");
+        outb(0x000a, 0x02); // unmask channel 2
+
+        BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
+        outb(0x000a, 0x02);
+
+        //--------------------------------------
+        // set up floppy controller for transfer
+        //--------------------------------------
+        floppy_prepare_controller(drive);
+
+        // send read-normal-data command (9 bytes) to controller
+        outb(0x03f5, 0xe6); // e6: read normal data
+        outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+        outb(0x03f5, track);
+        outb(0x03f5, head);
+        outb(0x03f5, sector);
+        outb(0x03f5, 2); // 512 byte sector size
+        outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
+        outb(0x03f5, 0); // Gap length
+        outb(0x03f5, 0xff); // Gap length
+
+        // turn on interrupts
+  ASM_START
+        sti
+  ASM_END
+
+        // wait on 40:3e bit 7 to become 1
+        do {
+          val8 = read_byte(0x0040, 0x0040);
+          if (val8 == 0) {
+            floppy_reset_controller();
+            SET_AH(0x80); // drive not ready (timeout)
+            set_diskette_ret_status(0x80);
+            SET_AL(0); // no sectors read
+            SET_CF(); // error occurred
+            return;
+          }
+          val8 = (read_byte(0x0040, 0x003e) & 0x80);
+        } while ( val8 == 0 );
+
+        val8 = 0; // separate asm from while() loop
+        // turn off interrupts
+  ASM_START
+        cli
+  ASM_END
+
+        // set 40:3e bit 7 to 0
+        val8 = read_byte(0x0040, 0x003e);
+        val8 &= 0x7f;
+        write_byte(0x0040, 0x003e, val8);
+
+        // check port 3f4 for accessibility to status bytes
+        val8 = inb(0x3f4);
+        if ( (val8 & 0xc0) != 0xc0 )
+          BX_PANIC("int13_diskette: ctrl not ready\n");
+
+        // read 7 return status bytes from controller
+        // using loop index broken, have to unroll...
+        return_status[0] = inb(0x3f5);
+        return_status[1] = inb(0x3f5);
+        return_status[2] = inb(0x3f5);
+        return_status[3] = inb(0x3f5);
+        return_status[4] = inb(0x3f5);
+        return_status[5] = inb(0x3f5);
+        return_status[6] = inb(0x3f5);
+        // record in BIOS Data Area
+        write_byte(0x0040, 0x0042, return_status[0]);
+        write_byte(0x0040, 0x0043, return_status[1]);
+        write_byte(0x0040, 0x0044, return_status[2]);
+        write_byte(0x0040, 0x0045, return_status[3]);
+        write_byte(0x0040, 0x0046, return_status[4]);
+        write_byte(0x0040, 0x0047, return_status[5]);
+        write_byte(0x0040, 0x0048, return_status[6]);
+
+        if ( (return_status[0] & 0xc0) != 0 ) {
+          SET_AH(0x20);
+          set_diskette_ret_status(0x20);
+          SET_AL(0); // no sectors read
+          SET_CF(); // error occurred
+          return;
+        }
+
+        // ??? should track be new val from return_status[3] ?
+        set_diskette_current_cyl(drive, track);
+        // AL = number of sectors read (same value as passed)
+        SET_AH(0x00); // success
+        CLEAR_CF();   // success
+        return;
+      } else if (ah == 0x03) {
+        // Write Diskette Sectors
+
+        //-----------------------------------
+        // set up DMA controller for transfer
+        //-----------------------------------
+
+        // es:bx = pointer to where to place information from diskette
+        // port 04: DMA-1 base and current address, channel 2
+        // port 05: DMA-1 base and current count, channel 2
+        page = (ES >> 12);   // upper 4 bits
+        base_es = (ES << 4); // lower 16bits contributed by ES
+        base_address = base_es + BX; // lower 16 bits of address
+                                     // contributed by ES:BX
+        if ( base_address < base_es ) {
+          // in case of carry, adjust page by 1
+          page++;
+        }
+        base_count = (num_sectors * 512) - 1;
+
+        // check for 64K boundary overrun
+        last_addr = base_address + base_count;
+        if (last_addr < base_address) {
+          SET_AH(0x09);
+          set_diskette_ret_status(0x09);
+          SET_AL(0); // no sectors read
+          SET_CF(); // error occurred
+          return;
+        }
+
+        BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
+        outb(0x000a, 0x06);
+
+        outb(0x000c, 0x00); // clear flip-flop
+        outb(0x0004, base_address);
+        outb(0x0004, base_address>>8);
+        outb(0x000c, 0x00); // clear flip-flop
+        outb(0x0005, base_count);
+        outb(0x0005, base_count>>8);
+
+        // port 0b: DMA-1 Mode Register
+        mode_register = 0x4a; // single mode, increment, autoinit disable,
+                              // transfer type=read, channel 2
+        outb(0x000b, mode_register);
+
+        // port 81: DMA-1 Page Register, channel 2
+        outb(0x0081, page);
+
+        BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
+        outb(0x000a, 0x02);
+
+        //--------------------------------------
+        // set up floppy controller for transfer
+        //--------------------------------------
+        floppy_prepare_controller(drive);
+
+        // send write-normal-data command (9 bytes) to controller
+        outb(0x03f5, 0xc5); // c5: write normal data
+        outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+        outb(0x03f5, track);
+        outb(0x03f5, head);
+        outb(0x03f5, sector);
+        outb(0x03f5, 2); // 512 byte sector size
+        outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
+        outb(0x03f5, 0); // Gap length
+        outb(0x03f5, 0xff); // Gap length
+
+        // turn on interrupts
+  ASM_START
+        sti
+  ASM_END
+
+        // wait on 40:3e bit 7 to become 1
+        do {
+          val8 = read_byte(0x0040, 0x0040);
+          if (val8 == 0) {
+            floppy_reset_controller();
+            SET_AH(0x80); // drive not ready (timeout)
+            set_diskette_ret_status(0x80);
+            SET_AL(0); // no sectors written
+            SET_CF(); // error occurred
+            return;
+          }
+          val8 = (read_byte(0x0040, 0x003e) & 0x80);
+        } while ( val8 == 0 );
+
+        val8 = 0; // separate asm from while() loop
+        // turn off interrupts
+  ASM_START
+        cli
+  ASM_END
+
+        // set 40:3e bit 7 to 0
+        val8 = read_byte(0x0040, 0x003e);
+        val8 &= 0x7f;
+        write_byte(0x0040, 0x003e, val8);
+
+        // check port 3f4 for accessibility to status bytes
+        val8 = inb(0x3f4);
+        if ( (val8 & 0xc0) != 0xc0 )
+          BX_PANIC("int13_diskette: ctrl not ready\n");
+
+        // read 7 return status bytes from controller
+        // using loop index broken, have to unroll...
+        return_status[0] = inb(0x3f5);
+        return_status[1] = inb(0x3f5);
+        return_status[2] = inb(0x3f5);
+        return_status[3] = inb(0x3f5);
+        return_status[4] = inb(0x3f5);
+        return_status[5] = inb(0x3f5);
+        return_status[6] = inb(0x3f5);
+        // record in BIOS Data Area
+        write_byte(0x0040, 0x0042, return_status[0]);
+        write_byte(0x0040, 0x0043, return_status[1]);
+        write_byte(0x0040, 0x0044, return_status[2]);
+        write_byte(0x0040, 0x0045, return_status[3]);
+        write_byte(0x0040, 0x0046, return_status[4]);
+        write_byte(0x0040, 0x0047, return_status[5]);
+        write_byte(0x0040, 0x0048, return_status[6]);
+
+        if ( (return_status[0] & 0xc0) != 0 ) {
+          if ( (return_status[1] & 0x02) != 0 ) {
+            // diskette not writable.
+            // AH=status code=0x03 (tried to write on write-protected disk)
+            // AL=number of sectors written=0
+            AX = 0x0300;
+            SET_CF();
+            return;
+          } else {
+            BX_PANIC("int13_diskette_function: read error\n");
+          }
+        }
+
+        // ??? should track be new val from return_status[3] ?
+        set_diskette_current_cyl(drive, track);
+        // AL = number of sectors read (same value as passed)
+        SET_AH(0x00); // success
+        CLEAR_CF();   // success
+        return;
+      } else {  // if (ah == 0x04)
+        // Verify Diskette Sectors
+
+        // ??? should track be new val from return_status[3] ?
+        set_diskette_current_cyl(drive, track);
+        // AL = number of sectors verified (same value as passed)
+        CLEAR_CF();   // success
+        SET_AH(0x00); // success
+        return;
+      }
+      break;
+
+    case 0x05: // format diskette track
+BX_DEBUG_INT13_FL("floppy f05\n");
+
+      num_sectors = GET_AL();
+      track       = GET_CH();
+      head        = GET_DH();
+      drive       = GET_ELDL();
+
+      if ((drive > 1) || (head > 1) || (track > 79) ||
+          (num_sectors == 0) || (num_sectors > 18)) {
+        SET_AH(1);
+        set_diskette_ret_status(1);
+        SET_CF(); // error occurred
+      }
+
+      // see if drive exists
+      if (floppy_drive_exists(drive) == 0) {
+        SET_AH(0x80); // drive not responding
+        set_diskette_ret_status(0x80);
+        SET_CF(); // error occurred
+        return;
+      }
+
+      // see if media in drive, and type is known
+      if (floppy_media_known(drive) == 0) {
+        if (floppy_media_sense(drive) == 0) {
+          SET_AH(0x0C); // Media type not found
+          set_diskette_ret_status(0x0C);
+          SET_AL(0); // no sectors read
+          SET_CF(); // error occurred
+          return;
+        }
+      }
+
+      // set up DMA controller for transfer
+      page = (ES >> 12);   // upper 4 bits
+      base_es = (ES << 4); // lower 16bits contributed by ES
+      base_address = base_es + BX; // lower 16 bits of address
+                                   // contributed by ES:BX
+      if ( base_address < base_es ) {
+        // in case of carry, adjust page by 1
+        page++;
+      }
+      base_count = (num_sectors * 4) - 1;
+
+      // check for 64K boundary overrun
+      last_addr = base_address + base_count;
+      if (last_addr < base_address) {
+        SET_AH(0x09);
+        set_diskette_ret_status(0x09);
+        SET_AL(0); // no sectors read
+        SET_CF(); // error occurred
+        return;
+      }
+
+      outb(0x000a, 0x06);
+      outb(0x000c, 0x00); // clear flip-flop
+      outb(0x0004, base_address);
+      outb(0x0004, base_address>>8);
+      outb(0x000c, 0x00); // clear flip-flop
+      outb(0x0005, base_count);
+      outb(0x0005, base_count>>8);
+      mode_register = 0x4a; // single mode, increment, autoinit disable,
+                            // transfer type=read, channel 2
+      outb(0x000b, mode_register);
+      // port 81: DMA-1 Page Register, channel 2
+      outb(0x0081, page);
+      outb(0x000a, 0x02);
+
+      // set up floppy controller for transfer
+      floppy_prepare_controller(drive);
+
+      // send format-track command (6 bytes) to controller
+      outb(0x03f5, 0x4d); // 4d: format track
+      outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+      outb(0x03f5, 2); // 512 byte sector size
+      outb(0x03f5, num_sectors); // number of sectors per track
+      outb(0x03f5, 0); // Gap length
+      outb(0x03f5, 0xf6); // Fill byte
+      // turn on interrupts
+  ASM_START
+      sti
+  ASM_END
+
+      // wait on 40:3e bit 7 to become 1
+      do {
+        val8 = read_byte(0x0040, 0x0040);
+        if (val8 == 0) {
+          floppy_reset_controller();
+          SET_AH(0x80); // drive not ready (timeout)
+          set_diskette_ret_status(0x80);
+          SET_CF(); // error occurred
+          return;
+        }
+        val8 = (read_byte(0x0040, 0x003e) & 0x80);
+      } while ( val8 == 0 );
+
+      val8 = 0; // separate asm from while() loop
+      // turn off interrupts
+  ASM_START
+      cli
+  ASM_END
+      // set 40:3e bit 7 to 0
+      val8 = read_byte(0x0040, 0x003e);
+      val8 &= 0x7f;
+      write_byte(0x0040, 0x003e, val8);
+      // check port 3f4 for accessibility to status bytes
+      val8 = inb(0x3f4);
+      if ( (val8 & 0xc0) != 0xc0 )
+        BX_PANIC("int13_diskette: ctrl not ready\n");
+
+      // read 7 return status bytes from controller
+      // using loop index broken, have to unroll...
+      return_status[0] = inb(0x3f5);
+      return_status[1] = inb(0x3f5);
+      return_status[2] = inb(0x3f5);
+      return_status[3] = inb(0x3f5);
+      return_status[4] = inb(0x3f5);
+      return_status[5] = inb(0x3f5);
+      return_status[6] = inb(0x3f5);
+      // record in BIOS Data Area
+      write_byte(0x0040, 0x0042, return_status[0]);
+      write_byte(0x0040, 0x0043, return_status[1]);
+      write_byte(0x0040, 0x0044, return_status[2]);
+      write_byte(0x0040, 0x0045, return_status[3]);
+      write_byte(0x0040, 0x0046, return_status[4]);
+      write_byte(0x0040, 0x0047, return_status[5]);
+      write_byte(0x0040, 0x0048, return_status[6]);
+
+      if ( (return_status[0] & 0xc0) != 0 ) {
+        if ( (return_status[1] & 0x02) != 0 ) {
+          // diskette not writable.
+          // AH=status code=0x03 (tried to write on write-protected disk)
+          // AL=number of sectors written=0
+          AX = 0x0300;
+          SET_CF();
+          return;
+        } else {
+          BX_PANIC("int13_diskette_function: write error\n");
+        }
+      }
+
+      SET_AH(0);
+      set_diskette_ret_status(0);
+      set_diskette_current_cyl(drive, 0);
+      CLEAR_CF(); // successful
+      return;
+
+
+    case 0x08: // read diskette drive parameters
+BX_DEBUG_INT13_FL("floppy f08\n");
+      drive = GET_ELDL();
+
+      if (drive > 1) {
+        AX = 0;
+        BX = 0;
+        CX = 0;
+        DX = 0;
+        ES = 0;
+        DI = 0;
+        SET_DL(num_floppies);
+        SET_CF();
+        return;
+        }
+
+      drive_type = inb_cmos(0x10);
+      num_floppies = 0;
+      if (drive_type & 0xf0)
+        num_floppies++;
+      if (drive_type & 0x0f)
+        num_floppies++;
+
+      if (drive == 0)
+        drive_type >>= 4;
+      else
+        drive_type &= 0x0f;
+
+      SET_BH(0);
+      SET_BL(drive_type);
+      SET_AH(0);
+      SET_AL(0);
+      SET_DL(num_floppies);
+
+      switch (drive_type) {
+        case 0: // none
+          CX = 0;
+          SET_DH(0); // max head #
+          break;
+
+        case 1: // 360KB, 5.25"
+          CX = 0x2709; // 40 tracks, 9 sectors
+          SET_DH(1); // max head #
+          break;
+
+        case 2: // 1.2MB, 5.25"
+          CX = 0x4f0f; // 80 tracks, 15 sectors
+          SET_DH(1); // max head #
+          break;
+
+        case 3: // 720KB, 3.5"
+          CX = 0x4f09; // 80 tracks, 9 sectors
+          SET_DH(1); // max head #
+          break;
+
+        case 4: // 1.44MB, 3.5"
+          CX = 0x4f12; // 80 tracks, 18 sectors
+          SET_DH(1); // max head #
+          break;
+
+        case 5: // 2.88MB, 3.5"
+          CX = 0x4f24; // 80 tracks, 36 sectors
+          SET_DH(1); // max head #
+          break;
+
+        case 6: // 160k, 5.25"
+          CX = 0x2708; // 40 tracks, 8 sectors
+          SET_DH(0); // max head #
+          break;
+
+        case 7: // 180k, 5.25"
+          CX = 0x2709; // 40 tracks, 9 sectors
+          SET_DH(0); // max head #
+          break;
+
+        case 8: // 320k, 5.25"
+          CX = 0x2708; // 40 tracks, 8 sectors
+          SET_DH(1); // max head #
+          break;
+
+        default: // ?
+          BX_PANIC("floppy: int13: bad floppy type\n");
+        }
+
+      /* set es & di to point to 11 byte diskette param table in ROM */
+ASM_START
+      push bp
+      mov  bp, sp
+      mov ax, #diskette_param_table2
+      mov _int13_diskette_function.DI+2[bp], ax
+      mov _int13_diskette_function.ES+2[bp], cs
+      pop  bp
+ASM_END
+      CLEAR_CF(); // success
+      /* disk status not changed upon success */
+      return;
+
+
+    case 0x15: // read diskette drive type
+BX_DEBUG_INT13_FL("floppy f15\n");
+      drive = GET_ELDL();
+      if (drive > 1) {
+        SET_AH(0); // only 2 drives supported
+        // set_diskette_ret_status here ???
+        SET_CF();
+        return;
+        }
+      drive_type = inb_cmos(0x10);
+
+      if (drive == 0)
+        drive_type >>= 4;
+      else
+        drive_type &= 0x0f;
+      CLEAR_CF(); // successful, not present
+      if (drive_type==0) {
+        SET_AH(0); // drive not present
+        }
+      else {
+        SET_AH(1); // drive present, does not support change line
+        }
+
+      return;
+
+    case 0x16: // get diskette change line status
+BX_DEBUG_INT13_FL("floppy f16\n");
+      drive = GET_ELDL();
+      if (drive > 1) {
+        SET_AH(0x01); // invalid drive
+        set_diskette_ret_status(0x01);
+        SET_CF();
+        return;
+        }
+
+      SET_AH(0x06); // change line not supported
+      set_diskette_ret_status(0x06);
+      SET_CF();
+      return;
+
+    case 0x17: // set diskette type for format(old)
+BX_DEBUG_INT13_FL("floppy f17\n");
+      /* not used for 1.44M floppies */
+      SET_AH(0x01); // not supported
+      set_diskette_ret_status(1); /* not supported */
+      SET_CF();
+      return;
+
+    case 0x18: // set diskette type for format(new)
+BX_DEBUG_INT13_FL("floppy f18\n");
+      SET_AH(0x01); // do later
+      set_diskette_ret_status(1);
+      SET_CF();
+      return;
+
+    default:
+        BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
+
+      // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
+        SET_AH(0x01); // ???
+        set_diskette_ret_status(1);
+        SET_CF();
+        return;
+      //   }
+    }
+}
+#else  // #if BX_SUPPORT_FLOPPY
+  void
+int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+  Bit8u  val8;
+
+  switch ( GET_AH() ) {
+
+    case 0x01: // Read Diskette Status
+      CLEAR_CF();
+      val8 = read_byte(0x0000, 0x0441);
+      SET_AH(val8);
+      if (val8) {
+        SET_CF();
+        }
+      return;
+
+    default:
+      SET_CF();
+      write_byte(0x0000, 0x0441, 0x01);
+      SET_AH(0x01);
+    }
+}
+#endif  // #if BX_SUPPORT_FLOPPY
+
+ void
+set_diskette_ret_status(value)
+  Bit8u value;
+{
+  write_byte(0x0040, 0x0041, value);
+}
+
+  void
+set_diskette_current_cyl(drive, cyl)
+  Bit8u drive;
+  Bit8u cyl;
+{
+  if (drive > 1)
+    BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
+  write_byte(0x0040, 0x0094+drive, cyl);
+}
+
+  void
+determine_floppy_media(drive)
+  Bit16u drive;
+{
+#if 0
+  Bit8u  val8, DOR, ctrl_info;
+
+  ctrl_info = read_byte(0x0040, 0x008F);
+  if (drive==1)
+    ctrl_info >>= 4;
+  else
+    ctrl_info &= 0x0f;
+
+#if 0
+  if (drive == 0) {
+    DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
+    }
+  else {
+    DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
+    }
+#endif
+
+  if ( (ctrl_info & 0x04) != 0x04 ) {
+    // Drive not determined means no drive exists, done.
+    return;
+    }
+
+#if 0
+  // check Main Status Register for readiness
+  val8 = inb(0x03f4) & 0x80; // Main Status Register
+  if (val8 != 0x80)
+    BX_PANIC("d_f_m: MRQ bit not set\n");
+
+  // change line
+
+  // existing BDA values
+
+  // turn on drive motor
+  outb(0x03f2, DOR); // Digital Output Register
+  //
+#endif
+  BX_PANIC("d_f_m: OK so far\n");
+#endif
+}
+
+  void
+int17_function(regs, ds, iret_addr)
+  pusha_regs_t regs; // regs pushed from PUSHA instruction
+  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
+{
+  Bit16u addr,timeout;
+  Bit8u val8;
+
+  ASM_START
+  sti
+  ASM_END
+
+  addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
+  if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
+    timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
+    if (regs.u.r8.ah == 0) {
+      outb(addr, regs.u.r8.al);
+      val8 = inb(addr+2);
+      outb(addr+2, val8 | 0x01); // send strobe
+      ASM_START
+      nop
+      ASM_END
+      outb(addr+2, val8 & ~0x01);
+      while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
+        timeout--;
+      }
+    }
+    if (regs.u.r8.ah == 1) {
+      val8 = inb(addr+2);
+      outb(addr+2, val8 & ~0x04); // send init
+      ASM_START
+      nop
+      ASM_END
+      outb(addr+2, val8 | 0x04);
+    }
+    val8 = inb(addr+1);
+    regs.u.r8.ah = (val8 ^ 0x48);
+    if (!timeout) regs.u.r8.ah |= 0x01;
+    ClearCF(iret_addr.flags);
+  } else {
+    SetCF(iret_addr.flags); // Unsupported
+  }
+}
+
+void
+int19_function(seq_nr)
+Bit16u seq_nr;
+{
+  Bit16u ebda_seg=read_word(0x0040,0x000E);
+  Bit16u bootdev;
+  Bit8u  bootdrv;
+  Bit8u  bootchk;
+  Bit16u bootseg;
+  Bit16u bootip;
+  Bit16u status;
+  Bit16u bootfirst;
+
+  ipl_entry_t e;
+
+  // if BX_ELTORITO_BOOT is not defined, old behavior
+  //   check bit 5 in CMOS reg 0x2d.  load either 0x00 or 0x80 into DL
+  //   in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
+  //     0: system boot sequence, first drive C: then A:
+  //     1: system boot sequence, first drive A: then C:
+  // else BX_ELTORITO_BOOT is defined
+  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
+  //     CMOS reg 0x3D & 0x0f : 1st boot device
+  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
+  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
+  //   boot device codes:
+  //     0x00 : not defined
+  //     0x01 : first floppy
+  //     0x02 : first harddrive
+  //     0x03 : first cdrom
+  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
+  //     else : boot failure
+
+  // Get the boot sequence
+#if BX_ELTORITO_BOOT
+  bootdev = inb_cmos(0x3d);
+  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
+  bootdev >>= 4 * seq_nr;
+  bootdev &= 0xf;
+
+  /* Read user selected device */
+  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
+  if (bootfirst != 0xFFFF) {
+    bootdev = bootfirst;
+    /* User selected device not set */
+    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
+    /* Reset boot sequence */
+    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
+  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
+
+  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
+  bootdev -= 1;
+#else
+  if (seq_nr ==2) BX_PANIC("No more boot devices.");
+  if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
+      /* Boot from floppy if the bit is set or it's the second boot */
+    bootdev = 0x00;
+  else
+    bootdev = 0x01;
+#endif
+
+  /* Read the boot device from the IPL table */
+  if (get_boot_vector(bootdev, &e) == 0) {
+    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
+    return;
+  }
+
+  /* Do the loading, and set up vector as a far pointer to the boot
+   * address, and bootdrv as the boot drive */
+  print_boot_device(&e);
+
+  switch(e.type) {
+  case IPL_TYPE_FLOPPY: /* FDD */
+  case IPL_TYPE_HARDDISK: /* HDD */
+
+    bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
+    bootseg = 0x07c0;
+    status = 0;
+
+ASM_START
+    push bp
+    mov  bp, sp
+    push ax
+    push bx
+    push cx
+    push dx
+
+    mov  dl, _int19_function.bootdrv + 2[bp]
+    mov  ax, _int19_function.bootseg + 2[bp]
+    mov  es, ax         ;; segment
+    xor  bx, bx         ;; offset
+    mov  ah, #0x02      ;; function 2, read diskette sector
+    mov  al, #0x01      ;; read 1 sector
+    mov  ch, #0x00      ;; track 0
+    mov  cl, #0x01      ;; sector 1
+    mov  dh, #0x00      ;; head 0
+    int  #0x13          ;; read sector
+    jnc  int19_load_done
+    mov  ax, #0x0001
+    mov  _int19_function.status + 2[bp], ax
+
+int19_load_done:
+    pop  dx
+    pop  cx
+    pop  bx
+    pop  ax
+    pop  bp
+ASM_END
+
+    if (status != 0) {
+      print_boot_failure(e.type, 1);
+      return;
+    }
+
+    /* Always check the signature on a HDD boot sector; on FDD, only do
+     * the check if the CMOS doesn't tell us to skip it */
+    if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) {
+      if (read_word(bootseg,0x1fe) != 0xaa55) {
+        print_boot_failure(e.type, 0);
+        return;
+      }
+    }
+
+    /* Canonicalize bootseg:bootip */
+    bootip = (bootseg & 0x0fff) << 4;
+    bootseg &= 0xf000;
+  break;
+
+#if BX_ELTORITO_BOOT
+  case IPL_TYPE_CDROM: /* CD-ROM */
+    status = cdrom_boot();
+
+    // If failure
+    if ( (status & 0x00ff) !=0 ) {
+      print_cdromboot_failure(status);
+      print_boot_failure(e.type, 1);
+      return;
+    }
+
+    bootdrv = (Bit8u)(status>>8);
+    bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
+    bootip = 0;
+    break;
+#endif
+
+  case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
+    bootseg = e.vector >> 16;
+    bootip = e.vector & 0xffff;
+    break;
+
+  default: return;
+  }
+
+  /* Debugging info */
+  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
+
+  /* Jump to the boot vector */
+ASM_START
+    mov  bp, sp
+    push cs
+    push #int18_handler
+    ;; Build an iret stack frame that will take us to the boot vector.
+    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
+    pushf
+    mov  ax, _int19_function.bootseg + 0[bp]
+    push ax
+    mov  ax, _int19_function.bootip + 0[bp]
+    push ax
+    ;; Set the magic number in ax and the boot drive in dl.
+    mov  ax, #0xaa55
+    mov  dl, _int19_function.bootdrv + 0[bp]
+    ;; Zero some of the other registers.
+    xor  bx, bx
+    mov  ds, bx
+    mov  es, bx
+    mov  bp, bx
+    ;; Go!
+    iret
+ASM_END
+}
+
+  void
+int1a_function(regs, ds, iret_addr)
+  pusha_regs_t regs; // regs pushed from PUSHA instruction
+  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
+{
+  Bit8u val8;
+
+  BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
+
+  ASM_START
+  sti
+  ASM_END
+
+  switch (regs.u.r8.ah) {
+    case 0: // get current clock count
+      ASM_START
+      cli
+      ASM_END
+      regs.u.r16.cx = BiosData->ticks_high;
+      regs.u.r16.dx = BiosData->ticks_low;
+      regs.u.r8.al  = BiosData->midnight_flag;
+      BiosData->midnight_flag = 0; // reset flag
+      ASM_START
+      sti
+      ASM_END
+      // AH already 0
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+    case 1: // Set Current Clock Count
+      ASM_START
+      cli
+      ASM_END
+      BiosData->ticks_high = regs.u.r16.cx;
+      BiosData->ticks_low  = regs.u.r16.dx;
+      BiosData->midnight_flag = 0; // reset flag
+      ASM_START
+      sti
+      ASM_END
+      regs.u.r8.ah = 0;
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+
+    case 2: // Read CMOS Time
+      if (rtc_updating()) {
+        SetCF(iret_addr.flags);
+        break;
+        }
+
+      regs.u.r8.dh = inb_cmos(0x00); // Seconds
+      regs.u.r8.cl = inb_cmos(0x02); // Minutes
+      regs.u.r8.ch = inb_cmos(0x04); // Hours
+      regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
+      regs.u.r8.ah = 0;
+      regs.u.r8.al = regs.u.r8.ch;
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+    case 3: // Set CMOS Time
+      // Using a debugger, I notice the following masking/setting
+      // of bits in Status Register B, by setting Reg B to
+      // a few values and getting its value after INT 1A was called.
+      //
+      //        try#1       try#2       try#3
+      // before 1111 1101   0111 1101   0000 0000
+      // after  0110 0010   0110 0010   0000 0010
+      //
+      // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+      // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
+      if (rtc_updating()) {
+        init_rtc();
+        // fall through as if an update were not in progress
+        }
+      outb_cmos(0x00, regs.u.r8.dh); // Seconds
+      outb_cmos(0x02, regs.u.r8.cl); // Minutes
+      outb_cmos(0x04, regs.u.r8.ch); // Hours
+      // Set Daylight Savings time enabled bit to requested value
+      val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
+      // (reg B already selected)
+      outb_cmos(0x0b, val8);
+      regs.u.r8.ah = 0;
+      regs.u.r8.al = val8; // val last written to Reg B
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+    case 4: // Read CMOS Date
+      regs.u.r8.ah = 0;
+      if (rtc_updating()) {
+        SetCF(iret_addr.flags);
+        break;
+        }
+      regs.u.r8.cl = inb_cmos(0x09); // Year
+      regs.u.r8.dh = inb_cmos(0x08); // Month
+      regs.u.r8.dl = inb_cmos(0x07); // Day of Month
+      regs.u.r8.ch = inb_cmos(0x32); // Century
+      regs.u.r8.al = regs.u.r8.ch;
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+    case 5: // Set CMOS Date
+      // Using a debugger, I notice the following masking/setting
+      // of bits in Status Register B, by setting Reg B to
+      // a few values and getting its value after INT 1A was called.
+      //
+      //        try#1       try#2       try#3       try#4
+      // before 1111 1101   0111 1101   0000 0010   0000 0000
+      // after  0110 1101   0111 1101   0000 0010   0000 0000
+      //
+      // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+      // My assumption: RegB = (RegB & 01111111b)
+      if (rtc_updating()) {
+        init_rtc();
+        SetCF(iret_addr.flags);
+        break;
+        }
+      outb_cmos(0x09, regs.u.r8.cl); // Year
+      outb_cmos(0x08, regs.u.r8.dh); // Month
+      outb_cmos(0x07, regs.u.r8.dl); // Day of Month
+      outb_cmos(0x32, regs.u.r8.ch); // Century
+      val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
+      outb_cmos(0x0b, val8);
+      regs.u.r8.ah = 0;
+      regs.u.r8.al = val8; // AL = val last written to Reg B
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+    case 6: // Set Alarm Time in CMOS
+      // Using a debugger, I notice the following masking/setting
+      // of bits in Status Register B, by setting Reg B to
+      // a few values and getting its value after INT 1A was called.
+      //
+      //        try#1       try#2       try#3
+      // before 1101 1111   0101 1111   0000 0000
+      // after  0110 1111   0111 1111   0010 0000
+      //
+      // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+      // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
+      val8 = inb_cmos(0x0b); // Get Status Reg B
+      regs.u.r16.ax = 0;
+      if (val8 & 0x20) {
+        // Alarm interrupt enabled already
+        SetCF(iret_addr.flags); // Error: alarm in use
+        break;
+        }
+      if (rtc_updating()) {
+        init_rtc();
+        // fall through as if an update were not in progress
+        }
+      outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
+      outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
+      outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
+      outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
+      // enable Status Reg B alarm bit, clear halt clock bit
+      outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
+      ClearCF(iret_addr.flags); // OK
+      break;
+
+    case 7: // Turn off Alarm
+      // Using a debugger, I notice the following masking/setting
+      // of bits in Status Register B, by setting Reg B to
+      // a few values and getting its value after INT 1A was called.
+      //
+      //        try#1       try#2       try#3       try#4
+      // before 1111 1101   0111 1101   0010 0000   0010 0010
+      // after  0100 0101   0101 0101   0000 0000   0000 0010
+      //
+      // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+      // My assumption: RegB = (RegB & 01010111b)
+      val8 = inb_cmos(0x0b); // Get Status Reg B
+      // clear clock-halt bit, disable alarm bit
+      outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
+      regs.u.r8.ah = 0;
+      regs.u.r8.al = val8; // val last written to Reg B
+      ClearCF(iret_addr.flags); // OK
+      break;
+#if BX_PCIBIOS
+    case 0xb1:
+      // real mode PCI BIOS functions now handled in assembler code
+      // this C code handles the error code for information only
+      if (regs.u.r8.bl == 0xff) {
+        BX_INFO("PCI BIOS: PCI not present\n");
+      } else if (regs.u.r8.bl == 0x81) {
+        BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
+      } else if (regs.u.r8.bl == 0x83) {
+        BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
+      } else if (regs.u.r8.bl == 0x86) {
+        if (regs.u.r8.al == 0x02) {
+          BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
+        } else {
+          BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs.u.r8.cl, regs.u.r16.dx, regs.u.r16.si);
+        }
+      }
+      regs.u.r8.ah = regs.u.r8.bl;
+      SetCF(iret_addr.flags);
+      break;
+#endif
+
+    default:
+      SetCF(iret_addr.flags); // Unsupported
+    }
+}
+
+  void
+int70_function(regs, ds, iret_addr)
+  pusha_regs_t regs; // regs pushed from PUSHA instruction
+  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
+{
+  // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
+  Bit8u registerB = 0, registerC = 0;
+
+  // Check which modes are enabled and have occurred.
+  registerB = inb_cmos( 0xB );
+  registerC = inb_cmos( 0xC );
+
+  if( ( registerB & 0x60 ) != 0 ) {
+    if( ( registerC & 0x20 ) != 0 ) {
+      // Handle Alarm Interrupt.
+ASM_START
+      sti
+      int #0x4a
+      cli
+ASM_END
+    }
+    if( ( registerC & 0x40 ) != 0 ) {
+      // Handle Periodic Interrupt.
+
+      if( read_byte( 0x40, 0xA0 ) != 0 ) {
+        // Wait Interval (Int 15, AH=83) active.
+        Bit32u time, toggle;
+
+        time = read_dword( 0x40, 0x9C );  // Time left in microseconds.
+        if( time < 0x3D1 ) {
+          // Done waiting.
+          Bit16u segment, offset;
+
+          segment = read_word( 0x40, 0x98 );
+          offset = read_word( 0x40, 0x9A );
+          write_byte( 0x40, 0xA0, 0 );  // Turn of status byte.
+          outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
+          write_byte(segment, offset, read_byte(segment, offset) | 0x80 );  // Write to specified flag byte.
+        } else {
+          // Continue waiting.
+          time -= 0x3D1;
+          write_dword( 0x40, 0x9C, time );
+        }
+      }
+    }
+  }
+
+ASM_START
+  call eoi_both_pics
+ASM_END
+}
+
+
+ASM_START
+;------------------------------------------
+;- INT74h : PS/2 mouse hardware interrupt -
+;------------------------------------------
+int74_handler:
+  sti
+  pusha
+  push ds         ;; save DS
+  push #0x00 ;; placeholder for status
+  push #0x00 ;; placeholder for X
+  push #0x00 ;; placeholder for Y
+  push #0x00 ;; placeholder for Z
+  push #0x00 ;; placeholder for make_far_call boolean
+  call _int74_function
+  pop  cx      ;; remove make_far_call from stack
+  jcxz int74_done
+
+  ;; make far call to EBDA:0022
+  push #0x00
+  pop ds
+  push 0x040E     ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
+  pop ds
+  //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
+  call far ptr[0x22]
+int74_done:
+  cli
+  call eoi_both_pics
+  add sp, #8     ;; pop status, x, y, z
+
+  pop ds          ;; restore DS
+  popa
+  iret
+
+
+;; This will perform an IRET, but will retain value of current CF
+;; by altering flags on stack.  Better than RETF #02.
+iret_modify_cf:
+  jc   carry_set
+  push bp
+  mov  bp, sp
+  and  BYTE [bp + 0x06], #0xfe
+  pop  bp
+  iret
+carry_set:
+  push bp
+  mov  bp, sp
+  or   BYTE [bp + 0x06], #0x01
+  pop  bp
+  iret
+
+
+;----------------------
+;- INT13h (relocated) -
+;----------------------
+;
+; int13_relocated is a little bit messed up since I played with it
+; I have to rewrite it:
+;   - call a function that detect which function to call
+;   - make all called C function get the same parameters list
+;
+int13_relocated:
+
+#if BX_ELTORITO_BOOT
+  ;; check for an eltorito function
+  cmp   ah,#0x4a
+  jb    int13_not_eltorito
+  cmp   ah,#0x4d
+  ja    int13_not_eltorito
+
+  pusha
+  push  es
+  push  ds
+  push  ss
+  pop   ds
+
+  push  #int13_out
+  jmp   _int13_eltorito      ;; ELDX not used
+
+int13_not_eltorito:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+
+  ;; check if emulation active
+  call  _cdemu_isactive
+  cmp   al,#0x00
+  je    int13_cdemu_inactive
+
+  ;; check if access to the emulated drive
+  call  _cdemu_emulated_drive
+  pop   dx
+  push  dx
+  cmp   al,dl                ;; int13 on emulated drive
+  jne   int13_nocdemu
+
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+
+  pusha
+  push  es
+  push  ds
+  push  ss
+  pop   ds
+
+  push  #int13_out
+  jmp   _int13_cdemu         ;; ELDX not used
+
+int13_nocdemu:
+  and   dl,#0xE0             ;; mask to get device class, including cdroms
+  cmp   al,dl                ;; al is 0x00 or 0x80
+  jne   int13_cdemu_inactive ;; inactive for device class
+
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+
+  push  ax
+  push  cx
+  push  dx
+  push  bx
+
+  dec   dl                   ;; real drive is dl - 1
+  jmp   int13_legacy
+
+int13_cdemu_inactive:
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+
+#endif // BX_ELTORITO_BOOT
+
+int13_noeltorito:
+
+  push  ax
+  push  cx
+  push  dx
+  push  bx
+
+int13_legacy:
+
+  push  dx                   ;; push eltorito value of dx instead of sp
+
+  push  bp
+  push  si
+  push  di
+
+  push  es
+  push  ds
+  push  ss
+  pop   ds
+
+  ;; now the 16-bit registers can be restored with:
+  ;; pop ds; pop es; popa; iret
+  ;; arguments passed to functions should be
+  ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
+
+  test  dl, #0x80
+  jnz   int13_notfloppy
+
+  push #int13_out
+  jmp _int13_diskette_function
+
+int13_notfloppy:
+
+#if BX_USE_ATADRV
+
+  cmp   dl, #0xE0
+  jb    int13_notcdrom
+
+  // ebx is modified: BSD 5.2.1 boot loader problem
+  // someone should figure out which 32 bit register that actually are used
+
+  shr   ebx, #16
+  push  bx
+
+  call  _int13_cdrom
+
+  pop   bx
+  shl   ebx, #16
+
+  jmp int13_out
+
+int13_notcdrom:
+
+#endif
+
+int13_disk:
+  ;; int13_harddisk modifies high word of EAX
+  shr   eax, #16
+  push  ax
+  call  _int13_harddisk
+  pop   ax
+  shl   eax, #16
+
+int13_out:
+  pop ds
+  pop es
+  popa
+  iret
+
+;----------
+;- INT18h -
+;----------
+int18_handler: ;; Boot Failure recovery: try the next device.
+
+  ;; Reset SP and SS
+  mov  ax, #0xfffe
+  mov  sp, ax
+  xor  ax, ax
+  mov  ss, ax
+
+  ;; Get the boot sequence number out of the IPL memory
+  mov  bx, #IPL_SEG
+  mov  ds, bx                     ;; Set segment
+  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
+  inc  bx                         ;; ++
+  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
+  mov  ds, ax                     ;; and reset the segment to zero.
+
+  ;; Carry on in the INT 19h handler, using the new sequence number
+  push bx
+
+  jmp  int19_next_boot
+
+;----------
+;- INT19h -
+;----------
+int19_relocated: ;; Boot function, relocated
+
+  ;; int19 was beginning to be really complex, so now it
+  ;; just calls a C function that does the work
+
+  push bp
+  mov  bp, sp
+
+  ;; Reset SS and SP
+  mov  ax, #0xfffe
+  mov  sp, ax
+  xor  ax, ax
+  mov  ss, ax
+
+  ;; Start from the first boot device (0, in AX)
+  mov  bx, #IPL_SEG
+  mov  ds, bx                     ;; Set segment to write to the IPL memory
+  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
+  mov  ds, ax                     ;; and reset the segment.
+
+  push ax
+
+int19_next_boot:
+
+  ;; Call the C code for the next boot device
+  call _int19_function
+
+  ;; Boot failed: invoke the boot recovery function
+  int  #0x18
+
+;----------
+;- INT1Ch -
+;----------
+int1c_handler: ;; User Timer Tick
+  iret
+
+
+;----------------------
+;- POST: Floppy Drive -
+;----------------------
+floppy_drive_post:
+  xor  ax, ax
+  mov  ds, ax
+
+  mov  al, #0x00
+  mov  0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
+
+  mov  0x043f, al  ;; diskette motor status: read op, drive0, motors off
+
+  mov  0x0440, al  ;; diskette motor timeout counter: not active
+  mov  0x0441, al  ;; diskette controller status return code
+
+  mov  0x0442, al  ;; disk & diskette controller status register 0
+  mov  0x0443, al  ;; diskette controller status register 1
+  mov  0x0444, al  ;; diskette controller status register 2
+  mov  0x0445, al  ;; diskette controller cylinder number
+  mov  0x0446, al  ;; diskette controller head number
+  mov  0x0447, al  ;; diskette controller sector number
+  mov  0x0448, al  ;; diskette controller bytes written
+
+  mov  0x048b, al  ;; diskette configuration data
+
+  ;; -----------------------------------------------------------------
+  ;; (048F) diskette controller information
+  ;;
+  mov  al, #0x10   ;; get CMOS diskette drive type
+  out  0x70, AL
+  in   AL, 0x71
+  mov  ah, al      ;; save byte to AH
+
+look_drive0:
+  shr  al, #4      ;; look at top 4 bits for drive 0
+  jz   f0_missing  ;; jump if no drive0
+  mov  bl, #0x07   ;; drive0 determined, multi-rate, has changed line
+  jmp  look_drive1
+f0_missing:
+  mov  bl, #0x00   ;; no drive0
+
+look_drive1:
+  mov  al, ah      ;; restore from AH
+  and  al, #0x0f   ;; look at bottom 4 bits for drive 1
+  jz   f1_missing  ;; jump if no drive1
+  or   bl, #0x70   ;; drive1 determined, multi-rate, has changed line
+f1_missing:
+                   ;; leave high bits in BL zerod
+  mov  0x048f, bl  ;; put new val in BDA (diskette controller information)
+  ;; -----------------------------------------------------------------
+
+  mov  al, #0x00
+  mov  0x0490, al  ;; diskette 0 media state
+  mov  0x0491, al  ;; diskette 1 media state
+
+                   ;; diskette 0,1 operational starting state
+                   ;; drive type has not been determined,
+                   ;; has no changed detection line
+  mov  0x0492, al
+  mov  0x0493, al
+
+  mov  0x0494, al  ;; diskette 0 current cylinder
+  mov  0x0495, al  ;; diskette 1 current cylinder
+
+  mov  al, #0x02
+  out  #0x0a, al   ;; clear DMA-1 channel 2 mask bit
+
+  SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
+  SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
+  SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
+
+  ret
+
+
+;--------------------
+;- POST: HARD DRIVE -
+;--------------------
+; relocated here because the primary POST area isnt big enough.
+hard_drive_post:
+  // IRQ 14 = INT 76h
+  // INT 76h calls INT 15h function ax=9100
+
+  mov  al, #0x0a   ; 0000 1010 = reserved, disable IRQ 14
+  mov  dx, #0x03f6
+  out  dx, al
+
+  xor  ax, ax
+  mov  ds, ax
+  mov  0x0474, al /* hard disk status of last operation */
+  mov  0x0477, al /* hard disk port offset (XT only ???) */
+  mov  0x048c, al /* hard disk status register */
+  mov  0x048d, al /* hard disk error register */
+  mov  0x048e, al /* hard disk task complete flag */
+  mov  al, #0x01
+  mov  0x0475, al /* hard disk number attached */
+  mov  al, #0xc0
+  mov  0x0476, al /* hard disk control byte */
+  SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
+  SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
+  ;; INT 41h: hard disk 0 configuration pointer
+  ;; INT 46h: hard disk 1 configuration pointer
+  SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
+  SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
+
+  ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
+  mov  al, #0x12
+  out  #0x70, al
+  in   al, #0x71
+  and  al, #0xf0
+  cmp  al, #0xf0
+  je   post_d0_extended
+  jmp check_for_hd1
+post_d0_extended:
+  mov  al, #0x19
+  out  #0x70, al
+  in   al, #0x71
+  cmp  al, #47  ;; decimal 47 - user definable
+  je   post_d0_type47
+  HALT(__LINE__)
+post_d0_type47:
+  ;; CMOS  purpose                  param table offset
+  ;; 1b    cylinders low            0
+  ;; 1c    cylinders high           1
+  ;; 1d    heads                    2
+  ;; 1e    write pre-comp low       5
+  ;; 1f    write pre-comp high      6
+  ;; 20    retries/bad map/heads>8  8
+  ;; 21    landing zone low         C
+  ;; 22    landing zone high        D
+  ;; 23    sectors/track            E
+
+  mov  ax, #EBDA_SEG
+  mov  ds, ax
+
+  ;;; Filling EBDA table for hard disk 0.
+  mov  al, #0x1f
+  out  #0x70, al
+  in   al, #0x71
+  mov  ah, al
+  mov  al, #0x1e
+  out  #0x70, al
+  in   al, #0x71
+  mov   (0x003d + 0x05), ax ;; write precomp word
+
+  mov  al, #0x20
+  out  #0x70, al
+  in   al, #0x71
+  mov   (0x003d + 0x08), al ;; drive control byte
+
+  mov  al, #0x22
+  out  #0x70, al
+  in   al, #0x71
+  mov  ah, al
+  mov  al, #0x21
+  out  #0x70, al
+  in   al, #0x71
+  mov   (0x003d + 0x0C), ax ;; landing zone word
+
+  mov  al, #0x1c   ;; get cylinders word in AX
+  out  #0x70, al
+  in   al, #0x71   ;; high byte
+  mov  ah, al
+  mov  al, #0x1b
+  out  #0x70, al
+  in   al, #0x71   ;; low byte
+  mov  bx, ax      ;; BX = cylinders
+
+  mov  al, #0x1d
+  out  #0x70, al
+  in   al, #0x71
+  mov  cl, al      ;; CL = heads
+
+  mov  al, #0x23
+  out  #0x70, al
+  in   al, #0x71
+  mov  dl, al      ;; DL = sectors
+
+  cmp  bx, #1024
+  jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
+
+hd0_post_physical_chs:
+  ;; no logical CHS mapping used, just physical CHS
+  ;; use Standard Fixed Disk Parameter Table (FDPT)
+  mov   (0x003d + 0x00), bx ;; number of physical cylinders
+  mov   (0x003d + 0x02), cl ;; number of physical heads
+  mov   (0x003d + 0x0E), dl ;; number of physical sectors
+  jmp check_for_hd1
+
+hd0_post_logical_chs:
+  ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
+  mov   (0x003d + 0x09), bx ;; number of physical cylinders
+  mov   (0x003d + 0x0b), cl ;; number of physical heads
+  mov   (0x003d + 0x04), dl ;; number of physical sectors
+  mov   (0x003d + 0x0e), dl ;; number of logical sectors (same)
+  mov al, #0xa0
+  mov   (0x003d + 0x03), al ;; A0h signature, indicates translated table
+
+  cmp bx, #2048
+  jnbe hd0_post_above_2048
+  ;; 1024 < c <= 2048 cylinders
+  shr bx, #0x01
+  shl cl, #0x01
+  jmp hd0_post_store_logical
+
+hd0_post_above_2048:
+  cmp bx, #4096
+  jnbe hd0_post_above_4096
+  ;; 2048 < c <= 4096 cylinders
+  shr bx, #0x02
+  shl cl, #0x02
+  jmp hd0_post_store_logical
+
+hd0_post_above_4096:
+  cmp bx, #8192
+  jnbe hd0_post_above_8192
+  ;; 4096 < c <= 8192 cylinders
+  shr bx, #0x03
+  shl cl, #0x03
+  jmp hd0_post_store_logical
+
+hd0_post_above_8192:
+  ;; 8192 < c <= 16384 cylinders
+  shr bx, #0x04
+  shl cl, #0x04
+
+hd0_post_store_logical:
+  mov   (0x003d + 0x00), bx ;; number of physical cylinders
+  mov   (0x003d + 0x02), cl ;; number of physical heads
+  ;; checksum
+  mov   cl, #0x0f     ;; repeat count
+  mov   si, #0x003d   ;; offset to disk0 FDPT
+  mov   al, #0x00     ;; sum
+hd0_post_checksum_loop:
+  add   al, [si]
+  inc   si
+  dec   cl
+  jnz hd0_post_checksum_loop
+  not   al  ;; now take 2s complement
+  inc   al
+  mov   [si], al
+;;; Done filling EBDA table for hard disk 0.
+
+
+check_for_hd1:
+  ;; is there really a second hard disk?  if not, return now
+  mov  al, #0x12
+  out  #0x70, al
+  in   al, #0x71
+  and  al, #0x0f
+  jnz   post_d1_exists
+  ret
+post_d1_exists:
+  ;; check that the hd type is really 0x0f.
+  cmp al, #0x0f
+  jz post_d1_extended
+  HALT(__LINE__)
+post_d1_extended:
+  ;; check that the extended type is 47 - user definable
+  mov  al, #0x1a
+  out  #0x70, al
+  in   al, #0x71
+  cmp  al, #47  ;; decimal 47 - user definable
+  je   post_d1_type47
+  HALT(__LINE__)
+post_d1_type47:
+  ;; Table for disk1.
+  ;; CMOS  purpose                  param table offset
+  ;; 0x24    cylinders low            0
+  ;; 0x25    cylinders high           1
+  ;; 0x26    heads                    2
+  ;; 0x27    write pre-comp low       5
+  ;; 0x28    write pre-comp high      6
+  ;; 0x29    heads>8                  8
+  ;; 0x2a    landing zone low         C
+  ;; 0x2b    landing zone high        D
+  ;; 0x2c    sectors/track            E
+;;; Fill EBDA table for hard disk 1.
+  mov  ax, #EBDA_SEG
+  mov  ds, ax
+  mov  al, #0x28
+  out  #0x70, al
+  in   al, #0x71
+  mov  ah, al
+  mov  al, #0x27
+  out  #0x70, al
+  in   al, #0x71
+  mov   (0x004d + 0x05), ax ;; write precomp word
+
+  mov  al, #0x29
+  out  #0x70, al
+  in   al, #0x71
+  mov   (0x004d + 0x08), al ;; drive control byte
+
+  mov  al, #0x2b
+  out  #0x70, al
+  in   al, #0x71
+  mov  ah, al
+  mov  al, #0x2a
+  out  #0x70, al
+  in   al, #0x71
+  mov   (0x004d + 0x0C), ax ;; landing zone word
+
+  mov  al, #0x25   ;; get cylinders word in AX
+  out  #0x70, al
+  in   al, #0x71   ;; high byte
+  mov  ah, al
+  mov  al, #0x24
+  out  #0x70, al
+  in   al, #0x71   ;; low byte
+  mov  bx, ax      ;; BX = cylinders
+
+  mov  al, #0x26
+  out  #0x70, al
+  in   al, #0x71
+  mov  cl, al      ;; CL = heads
+
+  mov  al, #0x2c
+  out  #0x70, al
+  in   al, #0x71
+  mov  dl, al      ;; DL = sectors
+
+  cmp  bx, #1024
+  jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
+
+hd1_post_physical_chs:
+  ;; no logical CHS mapping used, just physical CHS
+  ;; use Standard Fixed Disk Parameter Table (FDPT)
+  mov   (0x004d + 0x00), bx ;; number of physical cylinders
+  mov   (0x004d + 0x02), cl ;; number of physical heads
+  mov   (0x004d + 0x0E), dl ;; number of physical sectors
+  ret
+
+hd1_post_logical_chs:
+  ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
+  mov   (0x004d + 0x09), bx ;; number of physical cylinders
+  mov   (0x004d + 0x0b), cl ;; number of physical heads
+  mov   (0x004d + 0x04), dl ;; number of physical sectors
+  mov   (0x004d + 0x0e), dl ;; number of logical sectors (same)
+  mov al, #0xa0
+  mov   (0x004d + 0x03), al ;; A0h signature, indicates translated table
+
+  cmp bx, #2048
+  jnbe hd1_post_above_2048
+  ;; 1024 < c <= 2048 cylinders
+  shr bx, #0x01
+  shl cl, #0x01
+  jmp hd1_post_store_logical
+
+hd1_post_above_2048:
+  cmp bx, #4096
+  jnbe hd1_post_above_4096
+  ;; 2048 < c <= 4096 cylinders
+  shr bx, #0x02
+  shl cl, #0x02
+  jmp hd1_post_store_logical
+
+hd1_post_above_4096:
+  cmp bx, #8192
+  jnbe hd1_post_above_8192
+  ;; 4096 < c <= 8192 cylinders
+  shr bx, #0x03
+  shl cl, #0x03
+  jmp hd1_post_store_logical
+
+hd1_post_above_8192:
+  ;; 8192 < c <= 16384 cylinders
+  shr bx, #0x04
+  shl cl, #0x04
+
+hd1_post_store_logical:
+  mov   (0x004d + 0x00), bx ;; number of physical cylinders
+  mov   (0x004d + 0x02), cl ;; number of physical heads
+  ;; checksum
+  mov   cl, #0x0f     ;; repeat count
+  mov   si, #0x004d   ;; offset to disk0 FDPT
+  mov   al, #0x00     ;; sum
+hd1_post_checksum_loop:
+  add   al, [si]
+  inc   si
+  dec   cl
+  jnz hd1_post_checksum_loop
+  not   al  ;; now take 2s complement
+  inc   al
+  mov   [si], al
+;;; Done filling EBDA table for hard disk 1.
+
+  ret
+
+;--------------------
+;- POST: EBDA segment
+;--------------------
+; relocated here because the primary POST area isnt big enough.
+ebda_post:
+#if BX_USE_EBDA
+  mov ax, #EBDA_SEG
+  mov ds, ax
+  mov byte ptr [0x0], #EBDA_SIZE
+#endif
+  xor ax, ax            ; mov EBDA seg into 40E
+  mov ds, ax
+  mov word ptr [0x40E], #EBDA_SEG
+  ret;;
+
+;--------------------
+;- POST: EOI + jmp via [0x40:67)
+;--------------------
+; relocated here because the primary POST area isnt big enough.
+eoi_jmp_post:
+  mov   al, #0x20
+  out   #0xA0, al ;; slave  PIC EOI
+  mov   al, #0x20
+  out   #0x20, al ;; master PIC EOI
+
+jmp_post_0x467:
+  xor ax, ax
+  mov ds, ax
+
+  jmp far ptr [0x467]
+
+iret_post_0x467:
+  xor ax, ax
+  mov ds, ax
+
+  mov sp, [0x467]
+  mov ss, [0x469]
+  iret
+
+retf_post_0x467:
+  xor ax, ax
+  mov ds, ax
+
+  mov sp, [0x467]
+  mov ss, [0x469]
+  retf
+
+s3_post:
+  mov sp, #0xffe
+#if BX_ROMBIOS32
+  call rombios32_init
+#endif
+  call _s3_resume
+  mov bl, #0x00
+  and ax, ax
+  jz normal_post
+  call _s3_resume_panic
+
+;--------------------
+eoi_both_pics:
+  mov   al, #0x20
+  out   #0xA0, al ;; slave  PIC EOI
+eoi_master_pic:
+  mov   al, #0x20
+  out   #0x20, al ;; master PIC EOI
+  ret
+
+;--------------------
+BcdToBin:
+  ;; in:  AL in BCD format
+  ;; out: AL in binary format, AH will always be 0
+  ;; trashes BX
+  mov  bl, al
+  and  bl, #0x0f ;; bl has low digit
+  shr  al, #4    ;; al has high digit
+  mov  bh, #10
+  mul  al, bh    ;; multiply high digit by 10 (result in AX)
+  add  al, bl    ;;   then add low digit
+  ret
+
+;--------------------
+timer_tick_post:
+  ;; Setup the Timer Ticks Count (0x46C:dword) and
+  ;;   Timer Ticks Roller Flag (0x470:byte)
+  ;; The Timer Ticks Count needs to be set according to
+  ;; the current CMOS time, as if ticks have been occurring
+  ;; at 18.2hz since midnight up to this point.  Calculating
+  ;; this is a little complicated.  Here are the factors I gather
+  ;; regarding this.  14,318,180 hz was the original clock speed,
+  ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
+  ;; at the time, or 4 to drive the CGA video adapter.  The div3
+  ;; source was divided again by 4 to feed a 1.193Mhz signal to
+  ;; the timer.  With a maximum 16bit timer count, this is again
+  ;; divided down by 65536 to 18.2hz.
+  ;;
+  ;; 14,318,180 Hz clock
+  ;;   /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
+  ;;   /4 = 1,193,181 Hz fed to timer
+  ;;   /65536 (maximum timer count) = 18.20650736 ticks/second
+  ;; 1 second = 18.20650736 ticks
+  ;; 1 minute = 1092.390442 ticks
+  ;; 1 hour   = 65543.42651 ticks
+  ;;
+  ;; Given the values in the CMOS clock, one could calculate
+  ;; the number of ticks by the following:
+  ;;   ticks = (BcdToBin(seconds) * 18.206507) +
+  ;;           (BcdToBin(minutes) * 1092.3904)
+  ;;           (BcdToBin(hours)   * 65543.427)
+  ;; To get a little more accuracy, since Im using integer
+  ;; arithmatic, I use:
+  ;;   ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
+  ;;           (BcdToBin(minutes) * 10923904) / 10000 +
+  ;;           (BcdToBin(hours)   * 65543427) / 1000
+
+  ;; assuming DS=0000
+
+  ;; get CMOS seconds
+  xor  eax, eax ;; clear EAX
+  mov  al, #0x00
+  out  #0x70, al
+  in   al, #0x71 ;; AL has CMOS seconds in BCD
+  call BcdToBin  ;; EAX now has seconds in binary
+  mov  edx, #18206507
+  mul  eax, edx
+  mov  ebx, #1000000
+  xor  edx, edx
+  div  eax, ebx
+  mov  ecx, eax  ;; ECX will accumulate total ticks
+
+  ;; get CMOS minutes
+  xor  eax, eax ;; clear EAX
+  mov  al, #0x02
+  out  #0x70, al
+  in   al, #0x71 ;; AL has CMOS minutes in BCD
+  call BcdToBin  ;; EAX now has minutes in binary
+  mov  edx, #10923904
+  mul  eax, edx
+  mov  ebx, #10000
+  xor  edx, edx
+  div  eax, ebx
+  add  ecx, eax  ;; add to total ticks
+
+  ;; get CMOS hours
+  xor  eax, eax ;; clear EAX
+  mov  al, #0x04
+  out  #0x70, al
+  in   al, #0x71 ;; AL has CMOS hours in BCD
+  call BcdToBin  ;; EAX now has hours in binary
+  mov  edx, #65543427
+  mul  eax, edx
+  mov  ebx, #1000
+  xor  edx, edx
+  div  eax, ebx
+  add  ecx, eax  ;; add to total ticks
+
+  mov  0x46C, ecx ;; Timer Ticks Count
+  xor  al, al
+  mov  0x470, al  ;; Timer Ticks Rollover Flag
+  ret
+
+;--------------------
+int76_handler:
+  ;; record completion in BIOS task complete flag
+  push  ax
+  push  ds
+  mov   ax, #0x0040
+  mov   ds, ax
+  mov   0x008E, #0xff
+  call  eoi_both_pics
+  pop   ds
+  pop   ax
+  iret
+
+
+;--------------------
+#if BX_APM
+
+use32 386
+#define APM_PROT32
+#include "apmbios.S"
+
+use16 386
+#define APM_PROT16
+#include "apmbios.S"
+
+#define APM_REAL
+#include "apmbios.S"
+
+#endif
+
+;--------------------
+#if BX_PCIBIOS
+use32 386
+.align 16
+bios32_structure:
+  db 0x5f, 0x33, 0x32, 0x5f  ;; "_32_" signature
+  dw bios32_entry_point, 0xf ;; 32 bit physical address
+  db 0             ;; revision level
+  ;; length in paragraphs and checksum stored in a word to prevent errors
+  dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
+        & 0xff) << 8) + 0x01
+  db 0,0,0,0,0     ;; reserved
+
+.align 16
+bios32_entry_point:
+  pushfd
+  cmp eax, #0x49435024 ;; "$PCI"
+  jne unknown_service
+  mov eax, #0x80000000
+  mov dx, #0x0cf8
+  out dx, eax
+  mov dx, #0x0cfc
+  in  eax, dx
+#ifdef PCI_FIXED_HOST_BRIDGE
+  cmp eax, #PCI_FIXED_HOST_BRIDGE
+  jne unknown_service
+#else
+  ;; say ok if a device is present
+  cmp eax, #0xffffffff
+  je unknown_service
+#endif
+  mov ebx, #0x000f0000
+  mov ecx, #0
+  mov edx, #pcibios_protected
+  xor al, al
+  jmp bios32_end
+unknown_service:
+  mov al, #0x80
+bios32_end:
+#ifdef BX_QEMU
+  and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
+#endif
+  popfd
+  retf
+
+.align 16
+pcibios_protected:
+  pushfd
+  cli
+  push esi
+  push edi
+  cmp al, #0x01 ;; installation check
+  jne pci_pro_f02
+  mov bx, #0x0210
+  mov cx, #0
+  mov edx, #0x20494350 ;; "PCI "
+  mov al, #0x01
+  jmp pci_pro_ok
+pci_pro_f02: ;; find pci device
+  cmp al, #0x02
+  jne pci_pro_f03
+  shl ecx, #16
+  mov cx, dx
+  xor bx, bx
+  mov di, #0x00
+pci_pro_devloop:
+  call pci_pro_select_reg
+  mov dx, #0x0cfc
+  in  eax, dx
+  cmp eax, ecx
+  jne pci_pro_nextdev
+  cmp si, #0
+  je  pci_pro_ok
+  dec si
+pci_pro_nextdev:
+  inc bx
+  cmp bx, #0x0100
+  jne pci_pro_devloop
+  mov ah, #0x86
+  jmp pci_pro_fail
+pci_pro_f03: ;; find class code
+  cmp al, #0x03
+  jne pci_pro_f08
+  xor bx, bx
+  mov di, #0x08
+pci_pro_devloop2:
+  call pci_pro_select_reg
+  mov dx, #0x0cfc
+  in  eax, dx
+  shr eax, #8
+  cmp eax, ecx
+  jne pci_pro_nextdev2
+  cmp si, #0
+  je  pci_pro_ok
+  dec si
+pci_pro_nextdev2:
+  inc bx
+  cmp bx, #0x0100
+  jne pci_pro_devloop2
+  mov ah, #0x86
+  jmp pci_pro_fail
+pci_pro_f08: ;; read configuration byte
+  cmp al, #0x08
+  jne pci_pro_f09
+  call pci_pro_select_reg
+  push edx
+  mov dx, di
+  and dx, #0x03
+  add dx, #0x0cfc
+  in  al, dx
+  pop edx
+  mov cl, al
+  jmp pci_pro_ok
+pci_pro_f09: ;; read configuration word
+  cmp al, #0x09
+  jne pci_pro_f0a
+  call pci_pro_select_reg
+  push edx
+  mov dx, di
+  and dx, #0x02
+  add dx, #0x0cfc
+  in  ax, dx
+  pop edx
+  mov cx, ax
+  jmp pci_pro_ok
+pci_pro_f0a: ;; read configuration dword
+  cmp al, #0x0a
+  jne pci_pro_f0b
+  call pci_pro_select_reg
+  push edx
+  mov dx, #0x0cfc
+  in  eax, dx
+  pop edx
+  mov ecx, eax
+  jmp pci_pro_ok
+pci_pro_f0b: ;; write configuration byte
+  cmp al, #0x0b
+  jne pci_pro_f0c
+  call pci_pro_select_reg
+  push edx
+  mov dx, di
+  and dx, #0x03
+  add dx, #0x0cfc
+  mov al, cl
+  out dx, al
+  pop edx
+  jmp pci_pro_ok
+pci_pro_f0c: ;; write configuration word
+  cmp al, #0x0c
+  jne pci_pro_f0d
+  call pci_pro_select_reg
+  push edx
+  mov dx, di
+  and dx, #0x02
+  add dx, #0x0cfc
+  mov ax, cx
+  out dx, ax
+  pop edx
+  jmp pci_pro_ok
+pci_pro_f0d: ;; write configuration dword
+  cmp al, #0x0d
+  jne pci_pro_unknown
+  call pci_pro_select_reg
+  push edx
+  mov dx, #0x0cfc
+  mov eax, ecx
+  out dx, eax
+  pop edx
+  jmp pci_pro_ok
+pci_pro_unknown:
+  mov ah, #0x81
+pci_pro_fail:
+  pop edi
+  pop esi
+#ifdef BX_QEMU
+  and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
+#endif
+  popfd
+  stc
+  retf
+pci_pro_ok:
+  xor ah, ah
+  pop edi
+  pop esi
+#ifdef BX_QEMU
+  and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
+#endif
+  popfd
+  clc
+  retf
+
+pci_pro_select_reg:
+  push edx
+  mov eax, #0x800000
+  mov ax,  bx
+  shl eax, #8
+  and di,  #0xff
+  or  ax,  di
+  and al,  #0xfc
+  mov dx, #0x0cf8
+  out dx,  eax
+  pop edx
+  ret
+
+use16 386
+
+pcibios_real:
+  push eax
+  push dx
+  mov eax, #0x80000000
+  mov dx, #0x0cf8
+  out dx, eax
+  mov dx, #0x0cfc
+  in  eax, dx
+#ifdef PCI_FIXED_HOST_BRIDGE
+  cmp eax, #PCI_FIXED_HOST_BRIDGE
+  je  pci_present
+#else
+  ;; say ok if a device is present
+  cmp eax, #0xffffffff
+  jne  pci_present
+#endif
+  pop dx
+  pop eax
+  mov ah, #0xff
+  stc
+  ret
+pci_present:
+  pop dx
+  pop eax
+  cmp al, #0x01 ;; installation check
+  jne pci_real_f02
+  mov ax, #0x0001
+  mov bx, #0x0210
+  mov cx, #0
+  mov edx, #0x20494350 ;; "PCI "
+  mov edi, #0xf0000
+  mov di, #pcibios_protected
+  clc
+  ret
+pci_real_f02: ;; find pci device
+  push esi
+  push edi
+  cmp al, #0x02
+  jne pci_real_f03
+  shl ecx, #16
+  mov cx, dx
+  xor bx, bx
+  mov di, #0x00
+pci_real_devloop:
+  call pci_real_select_reg
+  mov dx, #0x0cfc
+  in  eax, dx
+  cmp eax, ecx
+  jne pci_real_nextdev
+  cmp si, #0
+  je  pci_real_ok
+  dec si
+pci_real_nextdev:
+  inc bx
+  cmp bx, #0x0100
+  jne pci_real_devloop
+  mov dx, cx
+  shr ecx, #16
+  mov ax, #0x8602
+  jmp pci_real_fail
+pci_real_f03: ;; find class code
+  cmp al, #0x03
+  jne pci_real_f08
+  xor bx, bx
+  mov di, #0x08
+pci_real_devloop2:
+  call pci_real_select_reg
+  mov dx, #0x0cfc
+  in  eax, dx
+  shr eax, #8
+  cmp eax, ecx
+  jne pci_real_nextdev2
+  cmp si, #0
+  je  pci_real_ok
+  dec si
+pci_real_nextdev2:
+  inc bx
+  cmp bx, #0x0100
+  jne pci_real_devloop2
+  mov dx, cx
+  shr ecx, #16
+  mov ax, #0x8603
+  jmp pci_real_fail
+pci_real_f08: ;; read configuration byte
+  cmp al, #0x08
+  jne pci_real_f09
+  call pci_real_select_reg
+  push dx
+  mov dx, di
+  and dx, #0x03
+  add dx, #0x0cfc
+  in  al, dx
+  pop dx
+  mov cl, al
+  jmp pci_real_ok
+pci_real_f09: ;; read configuration word
+  cmp al, #0x09
+  jne pci_real_f0a
+  call pci_real_select_reg
+  push dx
+  mov dx, di
+  and dx, #0x02
+  add dx, #0x0cfc
+  in  ax, dx
+  pop dx
+  mov cx, ax
+  jmp pci_real_ok
+pci_real_f0a: ;; read configuration dword
+  cmp al, #0x0a
+  jne pci_real_f0b
+  call pci_real_select_reg
+  push dx
+  mov dx, #0x0cfc
+  in  eax, dx
+  pop dx
+  mov ecx, eax
+  jmp pci_real_ok
+pci_real_f0b: ;; write configuration byte
+  cmp al, #0x0b
+  jne pci_real_f0c
+  call pci_real_select_reg
+  push dx
+  mov dx, di
+  and dx, #0x03
+  add dx, #0x0cfc
+  mov al, cl
+  out dx, al
+  pop dx
+  jmp pci_real_ok
+pci_real_f0c: ;; write configuration word
+  cmp al, #0x0c
+  jne pci_real_f0d
+  call pci_real_select_reg
+  push dx
+  mov dx, di
+  and dx, #0x02
+  add dx, #0x0cfc
+  mov ax, cx
+  out dx, ax
+  pop dx
+  jmp pci_real_ok
+pci_real_f0d: ;; write configuration dword
+  cmp al, #0x0d
+  jne pci_real_f0e
+  call pci_real_select_reg
+  push dx
+  mov dx, #0x0cfc
+  mov eax, ecx
+  out dx, eax
+  pop dx
+  jmp pci_real_ok
+pci_real_f0e: ;; get irq routing options
+  cmp al, #0x0e
+  jne pci_real_unknown
+  SEG ES
+  cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
+  jb pci_real_too_small
+  SEG ES
+  mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
+  pushf
+  push ds
+  push es
+  push cx
+  push si
+  push di
+  cld
+  mov si, #pci_routing_table_structure_start
+  push cs
+  pop ds
+  SEG ES
+  mov cx, [di+2]
+  SEG ES
+  mov es, [di+4]
+  mov di, cx
+  mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
+  rep
+      movsb
+  pop di
+  pop si
+  pop cx
+  pop es
+  pop ds
+  popf
+  mov bx, #(1 << 9) | (1 << 11)   ;; irq 9 and 11 are used
+  jmp pci_real_ok
+pci_real_too_small:
+  SEG ES
+  mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
+  mov ah, #0x89
+  jmp pci_real_fail
+
+pci_real_unknown:
+  mov ah, #0x81
+pci_real_fail:
+  pop edi
+  pop esi
+  stc
+  ret
+pci_real_ok:
+  xor ah, ah
+  pop edi
+  pop esi
+  clc
+  ret
+
+pci_real_select_reg:
+  push dx
+  mov eax, #0x800000
+  mov ax,  bx
+  shl eax, #8
+  and di,  #0xff
+  or  ax,  di
+  and al,  #0xfc
+  mov dx,  #0x0cf8
+  out dx,  eax
+  pop dx
+  ret
+
+.align 16
+pci_routing_table_structure:
+  db 0x24, 0x50, 0x49, 0x52  ;; "$PIR" signature
+  db 0, 1 ;; version
+  dw 32 + (6 * 16) ;; table size
+  db 0 ;; PCI interrupt router bus
+  db 0x08 ;; PCI interrupt router DevFunc
+  dw 0x0000 ;; PCI exclusive IRQs
+  dw 0x8086 ;; compatible PCI interrupt router vendor ID
+  dw 0x122e ;; compatible PCI interrupt router device ID
+  dw 0,0 ;; Miniport data
+  db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
+  db 0x37 ;; checksum
+pci_routing_table_structure_start:
+  ;; first slot entry PCI-to-ISA (embedded)
+  db 0 ;; pci bus number
+  db 0x08 ;; pci device number (bit 7-3)
+  db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
+  dw 0xdef8 ;; IRQ bitmap INTA#
+  db 0x61 ;; link value INTB#
+  dw 0xdef8 ;; IRQ bitmap INTB#
+  db 0x62 ;; link value INTC#
+  dw 0xdef8 ;; IRQ bitmap INTC#
+  db 0x63 ;; link value INTD#
+  dw 0xdef8 ;; IRQ bitmap INTD#
+  db 0 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; second slot entry: 1st PCI slot
+  db 0 ;; pci bus number
+  db 0x10 ;; pci device number (bit 7-3)
+  db 0x61 ;; link value INTA#
+  dw 0xdef8 ;; IRQ bitmap INTA#
+  db 0x62 ;; link value INTB#
+  dw 0xdef8 ;; IRQ bitmap INTB#
+  db 0x63 ;; link value INTC#
+  dw 0xdef8 ;; IRQ bitmap INTC#
+  db 0x60 ;; link value INTD#
+  dw 0xdef8 ;; IRQ bitmap INTD#
+  db 1 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; third slot entry: 2nd PCI slot
+  db 0 ;; pci bus number
+  db 0x18 ;; pci device number (bit 7-3)
+  db 0x62 ;; link value INTA#
+  dw 0xdef8 ;; IRQ bitmap INTA#
+  db 0x63 ;; link value INTB#
+  dw 0xdef8 ;; IRQ bitmap INTB#
+  db 0x60 ;; link value INTC#
+  dw 0xdef8 ;; IRQ bitmap INTC#
+  db 0x61 ;; link value INTD#
+  dw 0xdef8 ;; IRQ bitmap INTD#
+  db 2 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 4th slot entry: 3rd PCI slot
+  db 0 ;; pci bus number
+  db 0x20 ;; pci device number (bit 7-3)
+  db 0x63 ;; link value INTA#
+  dw 0xdef8 ;; IRQ bitmap INTA#
+  db 0x60 ;; link value INTB#
+  dw 0xdef8 ;; IRQ bitmap INTB#
+  db 0x61 ;; link value INTC#
+  dw 0xdef8 ;; IRQ bitmap INTC#
+  db 0x62 ;; link value INTD#
+  dw 0xdef8 ;; IRQ bitmap INTD#
+  db 3 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 5th slot entry: 4rd PCI slot
+  db 0 ;; pci bus number
+  db 0x28 ;; pci device number (bit 7-3)
+  db 0x60 ;; link value INTA#
+  dw 0xdef8 ;; IRQ bitmap INTA#
+  db 0x61 ;; link value INTB#
+  dw 0xdef8 ;; IRQ bitmap INTB#
+  db 0x62 ;; link value INTC#
+  dw 0xdef8 ;; IRQ bitmap INTC#
+  db 0x63 ;; link value INTD#
+  dw 0xdef8 ;; IRQ bitmap INTD#
+  db 4 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+  ;; 6th slot entry: 5rd PCI slot
+  db 0 ;; pci bus number
+  db 0x30 ;; pci device number (bit 7-3)
+  db 0x61 ;; link value INTA#
+  dw 0xdef8 ;; IRQ bitmap INTA#
+  db 0x62 ;; link value INTB#
+  dw 0xdef8 ;; IRQ bitmap INTB#
+  db 0x63 ;; link value INTC#
+  dw 0xdef8 ;; IRQ bitmap INTC#
+  db 0x60 ;; link value INTD#
+  dw 0xdef8 ;; IRQ bitmap INTD#
+  db 5 ;; physical slot (0 = embedded)
+  db 0 ;; reserved
+pci_routing_table_structure_end:
+
+#if !BX_ROMBIOS32
+pci_irq_list:
+  db 11, 10, 9, 5;
+
+pcibios_init_sel_reg:
+  push eax
+  mov eax, #0x800000
+  mov ax,  bx
+  shl eax, #8
+  and dl,  #0xfc
+  or  al,  dl
+  mov dx,  #0x0cf8
+  out dx,  eax
+  pop eax
+  ret
+
+pcibios_init_iomem_bases:
+  push bp
+  mov  bp, sp
+  mov  eax, #0xe0000000 ;; base for memory init
+  push eax
+  mov  ax, #0xc000 ;; base for i/o init
+  push ax
+  mov  ax, #0x0010 ;; start at base address #0
+  push ax
+  mov  bx, #0x0008
+pci_init_io_loop1:
+  mov  dl, #0x00
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  in   ax, dx
+  cmp  ax, #0xffff
+  jz   next_pci_dev
+  mov  dl, #0x04 ;; disable i/o and memory space access
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  in   al, dx
+  and  al, #0xfc
+  out  dx, al
+pci_init_io_loop2:
+  mov  dl, [bp-8]
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  in   eax, dx
+  test al, #0x01
+  jnz  init_io_base
+  mov  ecx, eax
+  mov  eax, #0xffffffff
+  out  dx, eax
+  in   eax, dx
+  cmp  eax, ecx
+  je   next_pci_base
+  xor  eax, #0xffffffff
+  mov  ecx, eax
+  mov  eax, [bp-4]
+  out  dx, eax
+  add  eax, ecx ;; calculate next free mem base
+  add  eax, #0x01000000
+  and  eax, #0xff000000
+  mov  [bp-4], eax
+  jmp  next_pci_base
+init_io_base:
+  mov  cx, ax
+  mov  ax, #0xffff
+  out  dx, ax
+  in   ax, dx
+  cmp  ax, cx
+  je   next_pci_base
+  xor  ax, #0xfffe
+  mov  cx, ax
+  mov  ax, [bp-6]
+  out  dx, ax
+  add  ax, cx ;; calculate next free i/o base
+  add  ax, #0x0100
+  and  ax, #0xff00
+  mov  [bp-6], ax
+next_pci_base:
+  mov  al, [bp-8]
+  add  al, #0x04
+  cmp  al, #0x28
+  je   enable_iomem_space
+  mov  byte ptr[bp-8], al
+  jmp  pci_init_io_loop2
+enable_iomem_space:
+  mov  dl, #0x04 ;; enable i/o and memory space access if available
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  in   al, dx
+  or   al, #0x07
+  out  dx, al
+next_pci_dev:
+  mov  byte ptr[bp-8], #0x10
+  inc  bx
+  cmp  bx, #0x0100
+  jne  pci_init_io_loop1
+  mov  sp, bp
+  pop  bp
+  ret
+
+pcibios_init_set_elcr:
+  push ax
+  push cx
+  mov  dx, #0x04d0
+  test al, #0x08
+  jz   is_master_pic
+  inc  dx
+  and  al, #0x07
+is_master_pic:
+  mov  cl, al
+  mov  bl, #0x01
+  shl  bl, cl
+  in   al, dx
+  or   al, bl
+  out  dx, al
+  pop  cx
+  pop  ax
+  ret
+
+pcibios_init_irqs:
+  push ds
+  push bp
+  mov  ax, #0xf000
+  mov  ds, ax
+  mov  dx, #0x04d0 ;; reset ELCR1 + ELCR2
+  mov  al, #0x00
+  out  dx, al
+  inc  dx
+  out  dx, al
+  mov  si, #pci_routing_table_structure
+  mov  bh, [si+8]
+  mov  bl, [si+9]
+  mov  dl, #0x00
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  in   ax, dx
+  cmp  ax, [si+12] ;; check irq router
+  jne  pci_init_end
+  mov  dl, [si+34]
+  call pcibios_init_sel_reg
+  push bx ;; save irq router bus + devfunc
+  mov  dx, #0x0cfc
+  mov  ax, #0x8080
+  out  dx, ax ;; reset PIRQ route control
+  add  dx, #2
+  out  dx, ax
+  mov  ax, [si+6]
+  sub  ax, #0x20
+  shr  ax, #4
+  mov  cx, ax
+  add  si, #0x20 ;; set pointer to 1st entry
+  mov  bp, sp
+  mov  ax, #pci_irq_list
+  push ax
+  xor  ax, ax
+  push ax
+pci_init_irq_loop1:
+  mov  bh, [si]
+  mov  bl, [si+1]
+pci_init_irq_loop2:
+  mov  dl, #0x00
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  in   ax, dx
+  cmp  ax, #0xffff
+  jnz  pci_test_int_pin
+  test bl, #0x07
+  jz   next_pir_entry
+  jmp  next_pci_func
+pci_test_int_pin:
+  mov  dl, #0x3c
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfd
+  in   al, dx
+  and  al, #0x07
+  jz   next_pci_func
+  dec  al ;; determine pirq reg
+  mov  dl, #0x03
+  mul  al, dl
+  add  al, #0x02
+  xor  ah, ah
+  mov  bx, ax
+  mov  al, [si+bx]
+  mov  dl, al
+  mov  bx, [bp]
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  and  al, #0x03
+  add  dl, al
+  in   al, dx
+  cmp  al, #0x80
+  jb   pirq_found
+  mov  bx, [bp-2] ;; pci irq list pointer
+  mov  al, [bx]
+  out  dx, al
+  inc  bx
+  mov  [bp-2], bx
+  call pcibios_init_set_elcr
+pirq_found:
+  mov  bh, [si]
+  mov  bl, [si+1]
+  add  bl, [bp-3] ;; pci function number
+  mov  dl, #0x3c
+  call pcibios_init_sel_reg
+  mov  dx, #0x0cfc
+  out  dx, al
+next_pci_func:
+  inc  byte ptr[bp-3]
+  inc  bl
+  test bl, #0x07
+  jnz  pci_init_irq_loop2
+next_pir_entry:
+  add  si, #0x10
+  mov  byte ptr[bp-3], #0x00
+  loop pci_init_irq_loop1
+  mov  sp, bp
+  pop  bx
+pci_init_end:
+  pop  bp
+  pop  ds
+  ret
+#endif // !BX_ROMBIOS32
+#endif // BX_PCIBIOS
+
+#if BX_ROMBIOS32
+rombios32_init:
+  ;; save a20 and enable it
+  in al, 0x92
+  push ax
+  or al, #0x02
+  out 0x92, al
+
+  ;; save SS:SP to the BDA
+  xor ax, ax
+  mov ds, ax
+  mov 0x0469, ss
+  mov 0x0467, sp
+
+  SEG CS
+    lidt [pmode_IDT_info]
+  SEG CS
+    lgdt [rombios32_gdt_48]
+  ;; set PE bit in CR0
+  mov  eax, cr0
+  or   al, #0x01
+  mov  cr0, eax
+  ;; start protected mode code: ljmpl 0x10:rombios32_init1
+  db 0x66, 0xea
+  dw rombios32_05
+  dw 0x000f       ;; high 16 bit address
+  dw 0x0010
+
+use32 386
+rombios32_05:
+  ;; init data segments
+  mov eax, #0x18
+  mov ds, ax
+  mov es, ax
+  mov ss, ax
+  xor eax, eax
+  mov fs, ax
+  mov gs, ax
+  cld
+
+  ;; init the stack pointer to point below EBDA
+  mov ax, [0x040e]
+  shl eax, #4
+  mov esp, #-0x10
+  add esp, eax
+
+  ;; pass pointer to s3_resume_flag and s3_resume_vector to rombios32
+  push #0x04b0
+  push #0x04b2
+
+  ;; call rombios32 code
+  mov eax, #0x000e0000
+  call eax
+
+  ;; return to 16 bit protected mode first
+  db 0xea
+  dd rombios32_10
+  dw 0x20
+
+use16 386
+rombios32_10:
+  ;; restore data segment limits to 0xffff
+  mov ax, #0x28
+  mov ds, ax
+  mov es, ax
+  mov ss, ax
+  mov fs, ax
+  mov gs, ax
+
+  ;; reset PE bit in CR0
+  mov  eax, cr0
+  and  al, #0xFE
+  mov  cr0, eax
+
+  ;; far jump to flush CPU queue after transition to real mode
+  JMP_AP(0xf000, rombios32_real_mode)
+
+rombios32_real_mode:
+  ;; restore IDT to normal real-mode defaults
+  SEG CS
+    lidt [rmode_IDT_info]
+
+  xor ax, ax
+  mov ds, ax
+  mov es, ax
+  mov fs, ax
+  mov gs, ax
+
+  ;; restore SS:SP from the BDA
+  mov ss, 0x0469
+  xor esp, esp
+  mov sp, 0x0467
+  ;; restore a20
+  pop ax
+  out 0x92, al
+  ret
+
+rombios32_gdt_48:
+  dw 0x30
+  dw rombios32_gdt
+  dw 0x000f
+
+rombios32_gdt:
+  dw 0, 0, 0, 0
+  dw 0, 0, 0, 0
+  dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
+  dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
+  dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
+  dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
+#endif // BX_ROMBIOS32
+
+
+; parallel port detection: base address in DX, index in BX, timeout in CL
+detect_parport:
+  push dx
+  add  dx, #2
+  in   al, dx
+  and  al, #0xdf ; clear input mode
+  out  dx, al
+  pop  dx
+  mov  al, #0xaa
+  out  dx, al
+  in   al, dx
+  cmp  al, #0xaa
+  jne  no_parport
+  push bx
+  shl  bx, #1
+  mov  [bx+0x408], dx ; Parallel I/O address
+  pop  bx
+  mov  [bx+0x478], cl ; Parallel printer timeout
+  inc  bx
+no_parport:
+  ret
+
+; serial port detection: base address in DX, index in BX, timeout in CL
+detect_serial:
+  push dx
+  inc  dx
+  mov  al, #0x02
+  out  dx, al
+  in   al, dx
+  cmp  al, #0x02
+  jne  no_serial
+  inc  dx
+  in   al, dx
+  cmp  al, #0x02
+  jne  no_serial
+  dec  dx
+  xor  al, al
+  out  dx, al
+  pop  dx
+  push bx
+  shl  bx, #1
+  mov  [bx+0x400], dx ; Serial I/O address
+  pop  bx
+  mov  [bx+0x47c], cl ; Serial timeout
+  inc  bx
+  ret
+no_serial:
+  pop  dx
+  ret
+
+rom_checksum:
+  push ax
+  push bx
+  push cx
+  xor  ax, ax
+  xor  bx, bx
+  xor  cx, cx
+  mov  ch, [2]
+  shl  cx, #1
+checksum_loop:
+  add  al, [bx]
+  inc  bx
+  loop checksum_loop
+  and  al, #0xff
+  pop  cx
+  pop  bx
+  pop  ax
+  ret
+
+
+;; We need a copy of this string, but we are not actually a PnP BIOS,
+;; so make sure it is *not* aligned, so OSes will not see it if they scan.
+.align 16
+  db 0
+pnp_string:
+  .ascii "$PnP"
+
+
+rom_scan:
+  ;; Scan for existence of valid expansion ROMS.
+  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
+  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
+  ;;   System  ROM: only 0xE0000
+  ;;
+  ;; Header:
+  ;;   Offset    Value
+  ;;   0         0x55
+  ;;   1         0xAA
+  ;;   2         ROM length in 512-byte blocks
+  ;;   3         ROM initialization entry point (FAR CALL)
+
+rom_scan_loop:
+  push ax       ;; Save AX
+  mov  ds, cx
+  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
+  cmp [0], #0xAA55 ;; look for signature
+  jne  rom_scan_increment
+  call rom_checksum
+  jnz  rom_scan_increment
+  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
+
+  ;; We want our increment in 512-byte quantities, rounded to
+  ;; the nearest 2k quantity, since we only scan at 2k intervals.
+  test al, #0x03
+  jz   block_count_rounded
+  and  al, #0xfc ;; needs rounding up
+  add  al, #0x04
+block_count_rounded:
+
+  push ax       ;; Save AX
+  push di       ;; Save DI
+  ;; Push addr of ROM entry point
+  push cx       ;; Push seg
+  push #0x0003  ;; Push offset
+
+  ;; Get the BDF into ax before invoking the option ROM
+  mov  bl, [2]
+  mov  al, bl
+  shr  al, #7
+  cmp  al, #1
+  jne  fetch_bdf
+  mov  ax, ds ;; Increment the DS since rom size larger than an segment
+  add  ax, #0x1000
+  mov  ds, ax
+fetch_bdf:
+  shl  bx, #9
+  xor  ax, ax
+  mov  al, [bx]
+
+  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
+  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
+  mov  bx, #0xf000
+  mov  es, bx
+  lea  di, pnp_string
+
+  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
+  db   0xff     ;; call_far ss:[bp+0]
+  db   0x5e
+  db   0
+  cli           ;; In case expansion ROM BIOS turns IF on
+  add  sp, #2   ;; Pop offset value
+  pop  cx       ;; Pop seg value (restore CX)
+
+  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
+  ;; to init all the ROMs and then go back and build an IPL table of
+  ;; all the bootable devices, but we can get away with one pass.
+  mov  ds, cx       ;; ROM base
+  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
+  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
+  cmp  ax, #0x5024  ;; we look for signature "$PnP"
+  jne  no_bev
+  mov  ax, 2[bx]
+  cmp  ax, #0x506e
+  jne  no_bev
+
+  mov  ax, 0x16[bx] ;; 0x16 is the offset of Boot Connection Vector
+  cmp  ax, #0x0000
+  je   no_bcv
+
+  ;; Option ROM has BCV. Run it now.
+  push cx       ;; Push seg
+  push ax       ;; Push offset
+
+  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
+  mov  bx, #0xf000
+  mov  es, bx
+  lea  di, pnp_string
+  /* jump to BCV function entry pointer */
+  mov  bp, sp   ;; Call ROM BCV routine using seg:off on stack
+  db   0xff     ;; call_far ss:[bp+0]
+  db   0x5e
+  db   0
+  cli           ;; In case expansion ROM BIOS turns IF on
+  add  sp, #2   ;; Pop offset value
+  pop  cx       ;; Pop seg value (restore CX)
+  jmp   no_bev
+
+no_bcv:
+  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
+  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
+  je   no_bev
+
+  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
+  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
+  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
+  mov  ds, bx
+  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
+  cmp  bx, #IPL_TABLE_ENTRIES
+  je   no_bev                  ;; Get out if the table is full
+  shl  bx, #0x4                ;; Turn count into offset (entries are 16 bytes)
+  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
+  mov  6[bx], cx               ;; Build a far pointer from the segment...
+  mov  4[bx], ax               ;; and the offset
+  cmp  di, #0x0000
+  je   no_prod_str
+  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
+  mov  8[bx], di               ;; and the offset
+no_prod_str:
+  shr  bx, #0x4                ;; Turn the offset back into a count
+  inc  bx                      ;; We have one more entry now
+  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
+
+no_bev:
+  pop  di       ;; Restore DI
+  pop  ax       ;; Restore AX
+rom_scan_increment:
+  shl  ax, #5   ;; convert 512-bytes blocks to 16-byte increments
+                ;; because the segment selector is shifted left 4 bits.
+  add  cx, ax
+  pop  ax       ;; Restore AX
+  cmp  cx, ax
+  jbe  rom_scan_loop
+
+  xor  ax, ax   ;; Restore DS back to 0000:
+  mov  ds, ax
+  ret
+
+post_enable_cache:
+  ;; enable cache
+  mov eax, cr0
+  and eax, #0x9fffffff
+  mov cr0, eax
+  jmp post_enable_cache_done
+
+post_init_pic:
+  mov al, #0x11 ; send initialisation commands
+  out 0x20, al
+  out 0xa0, al
+  mov al, #0x08
+  out 0x21, al
+  mov al, #0x70
+  out 0xa1, al
+  mov al, #0x04
+  out 0x21, al
+  mov al, #0x02
+  out 0xa1, al
+  mov al, #0x01
+  out 0x21, al
+  out 0xa1, al
+  mov  al, #0xb8
+  out  0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
+#if BX_USE_PS2_MOUSE
+  mov  al, #0x8f
+#else
+  mov  al, #0x9f
+#endif
+  out  0xa1, AL ;slave  pic: unmask IRQ 12, 13, 14
+  ret
+
+;; the following area can be used to write dynamically generated tables
+  .align 16
+bios_table_area_start:
+  dd 0xaafb4442
+  dd bios_table_area_end - bios_table_area_start - 8;
+
+
+;--------
+;- POST -
+;--------
+.org 0xe05b ; POST Entry Point
+post:
+  jmp post_enable_cache ; hack: we have limited space before next .org,
+	                ;       so take this bit out-of-line
+post_enable_cache_done:
+  xor ax, ax
+
+  ;; first reset the DMA controllers
+  out 0x0d,al
+  out 0xda,al
+
+  ;; then initialize the DMA controllers
+  mov al, #0xC0
+  out 0xD6, al ; cascade mode of channel 4 enabled
+  mov al, #0x00
+  out 0xD4, al ; unmask channel 4
+
+  ;; Examine CMOS shutdown status.
+  mov AL, #0x0f
+  out 0x70, AL
+  in  AL, 0x71
+
+  ;; backup status
+  mov bl, al
+
+  ;; Reset CMOS shutdown status.
+  mov AL, #0x0f
+  out 0x70, AL          ; select CMOS register Fh
+  mov AL, #0x00
+  out 0x71, AL          ; set shutdown action to normal
+
+  ;; Examine CMOS shutdown status.
+  mov al, bl
+
+  ;; 0x00, 0x09, 0x0D+ = normal startup
+  cmp AL, #0x00
+  jz normal_post
+  cmp AL, #0x0d
+  jae normal_post
+  cmp AL, #0x09
+  je normal_post
+
+  ;; 0x05 = eoi + jmp via [0x40:0x67] jump
+  cmp al, #0x05
+  je  eoi_jmp_post
+
+  ;; 0x0A = jmp via [0x40:0x67] jump
+  cmp al, #0x0a
+  je  jmp_post_0x467
+
+  ;; 0x0B = iret via [0x40:0x67]
+  cmp al, #0x0b
+  je  iret_post_0x467
+
+  ;; 0x0C = retf via [0x40:0x67]
+  cmp al, #0x0c
+  je  retf_post_0x467
+
+  ;; Examine CMOS shutdown status.
+  ;;  0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status.
+  push bx
+  call _shutdown_status_panic
+
+#if 0
+  HALT(__LINE__)
+  ;
+  ;#if 0
+  ;  0xb0, 0x20,       /* mov al, #0x20 */
+  ;  0xe6, 0x20,       /* out 0x20, al    ;send EOI to PIC */
+  ;#endif
+  ;
+  pop es
+  pop ds
+  popa
+  iret
+#endif
+
+normal_post:
+  ; case 0: normal startup
+
+  cli
+  mov  ax, #0xfffe
+  mov  sp, ax
+  xor  ax, ax
+  mov  ds, ax
+  mov  ss, ax
+
+  ;; Save shutdown status
+  mov 0x04b0, bl
+
+  cmp bl, #0xfe
+  jz s3_post
+
+  ;; zero out BIOS data area (40:00..40:ff)
+  mov  es, ax
+  mov  cx, #0x0080 ;; 128 words
+  mov  di, #0x0400
+  cld
+  rep
+    stosw
+
+  call _log_bios_start
+
+  ;; set all interrupts to default handler
+  xor  bx, bx         ;; offset index
+  mov  cx, #0x0100    ;; counter (256 interrupts)
+  mov  ax, #dummy_iret_handler
+  mov  dx, #0xF000
+
+post_default_ints:
+  mov  [bx], ax
+  add  bx, #2
+  mov  [bx], dx
+  add  bx, #2
+  loop post_default_ints
+
+  ;; set vector 0x79 to zero
+  ;; this is used by 'gardian angel' protection system
+  SET_INT_VECTOR(0x79, #0, #0)
+
+  ;; base memory in K 40:13 (word)
+  mov  ax, #BASE_MEM_IN_K
+  mov  0x0413, ax
+
+
+  ;; Manufacturing Test 40:12
+  ;;   zerod out above
+
+  ;; Warm Boot Flag 0040:0072
+  ;;   value of 1234h = skip memory checks
+  ;;   zerod out above
+
+
+  ;; Printer Services vector
+  SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
+
+  ;; Bootstrap failure vector
+  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
+
+  ;; Bootstrap Loader vector
+  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
+
+  ;; User Timer Tick vector
+  SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
+
+  ;; Memory Size Check vector
+  SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
+
+  ;; Equipment Configuration Check vector
+  SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
+
+  ;; System Services
+  SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
+
+  ;; EBDA setup
+  call ebda_post
+
+  ;; PIT setup
+  SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
+  ;; int 1C already points at dummy_iret_handler (above)
+  mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
+  out 0x43, al
+  mov al, #0x00 ; maximum count of 0000H = 18.2Hz
+  out 0x40, al
+  out 0x40, al
+
+  ;; Keyboard
+  SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
+  SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
+
+  xor  ax, ax
+  mov  ds, ax
+  mov  0x0417, al /* keyboard shift flags, set 1 */
+  mov  0x0418, al /* keyboard shift flags, set 2 */
+  mov  0x0419, al /* keyboard alt-numpad work area */
+  mov  0x0471, al /* keyboard ctrl-break flag */
+  mov  0x0497, al /* keyboard status flags 4 */
+  mov  al, #0x10
+  mov  0x0496, al /* keyboard status flags 3 */
+
+
+  /* keyboard head of buffer pointer */
+  mov  bx, #0x001E
+  mov  0x041A, bx
+
+  /* keyboard end of buffer pointer */
+  mov  0x041C, bx
+
+  /* keyboard pointer to start of buffer */
+  mov  bx, #0x001E
+  mov  0x0480, bx
+
+  /* keyboard pointer to end of buffer */
+  mov  bx, #0x003E
+  mov  0x0482, bx
+
+  /* init the keyboard */
+  call _keyboard_init
+
+  ;; mov CMOS Equipment Byte to BDA Equipment Word
+  mov  ax, 0x0410
+  mov  al, #0x14
+  out  0x70, al
+  in   al, 0x71
+  mov  0x0410, ax
+
+
+  ;; Parallel setup
+  SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
+  xor ax, ax
+  mov ds, ax
+  xor bx, bx
+  mov cl, #0x14 ; timeout value
+  mov dx, #0x378 ; Parallel I/O address, port 1
+  call detect_parport
+  mov dx, #0x278 ; Parallel I/O address, port 2
+  call detect_parport
+  shl bx, #0x0e
+  mov ax, 0x410   ; Equipment word bits 14..15 determing # parallel ports
+  and ax, #0x3fff
+  or  ax, bx ; set number of parallel ports
+  mov 0x410, ax
+
+  ;; Serial setup
+  SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
+  SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
+  xor bx, bx
+  mov cl, #0x0a ; timeout value
+  mov dx, #0x03f8 ; Serial I/O address, port 1
+  call detect_serial
+  mov dx, #0x02f8 ; Serial I/O address, port 2
+  call detect_serial
+  mov dx, #0x03e8 ; Serial I/O address, port 3
+  call detect_serial
+  mov dx, #0x02e8 ; Serial I/O address, port 4
+  call detect_serial
+  shl bx, #0x09
+  mov ax, 0x410   ; Equipment word bits 9..11 determing # serial ports
+  and ax, #0xf1ff
+  or  ax, bx ; set number of serial port
+  mov 0x410, ax
+
+  ;; CMOS RTC
+  SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
+  SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
+  SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
+  ;; BIOS DATA AREA 0x4CE ???
+  call timer_tick_post
+
+  ;; PS/2 mouse setup
+  SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
+
+  ;; IRQ13 (FPU exception) setup
+  SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
+
+  ;; Video setup
+  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
+
+  ;; PIC
+  call post_init_pic
+
+  mov  cx, #0xc000  ;; init vga bios
+  mov  ax, #0xc780
+  call rom_scan
+
+  call _print_bios_banner
+
+#if BX_ROMBIOS32
+  call rombios32_init
+#else
+#if BX_PCIBIOS
+  call pcibios_init_iomem_bases
+  call pcibios_init_irqs
+#endif //BX_PCIBIOS
+#endif
+
+  ;;
+  ;; Floppy setup
+  ;;
+  call floppy_drive_post
+
+  ;;
+  ;; Hard Drive setup
+  ;;
+  call hard_drive_post
+
+#if BX_USE_ATADRV
+
+  ;;
+  ;; ATA/ATAPI driver setup
+  ;;
+  call _ata_init
+  call _ata_detect
+  ;;
+
+#endif // BX_USE_ATADRV
+
+#if BX_ELTORITO_BOOT
+  ;;
+  ;; eltorito floppy/harddisk emulation from cd
+  ;;
+  call _cdemu_init
+  ;;
+#endif // BX_ELTORITO_BOOT
+
+  call _init_boot_vectors
+
+  mov  cx, #0xc800  ;; init option roms
+  mov  ax, #0xe000
+  call rom_scan
+
+#if BX_ELTORITO_BOOT
+  call _interactive_bootkey
+#endif // BX_ELTORITO_BOOT
+
+  sti        ;; enable interrupts
+  int  #0x19
+
+.org 0xe2c3 ; NMI Handler Entry Point
+nmi:
+  ;; FIXME the NMI handler should not panic
+  ;; but iret when called from int75 (fpu exception)
+  call _nmi_handler_msg
+  iret
+
+int75_handler:
+  out  0xf0, al         // clear irq13
+  call eoi_both_pics    // clear interrupt
+  int  2                // legacy nmi call
+  iret
+
+;-------------------------------------------
+;- INT 13h Fixed Disk Services Entry Point -
+;-------------------------------------------
+.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
+int13_handler:
+  //JMPL(int13_relocated)
+  jmp int13_relocated
+
+.org 0xe401 ; Fixed Disk Parameter Table
+
+;----------
+;- INT19h -
+;----------
+.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
+int19_handler:
+
+  jmp int19_relocated
+;-------------------------------------------
+;- System BIOS Configuration Data Table
+;-------------------------------------------
+.org BIOS_CONFIG_TABLE
+db 0x08                  ; Table size (bytes) -Lo
+db 0x00                  ; Table size (bytes) -Hi
+db SYS_MODEL_ID
+db SYS_SUBMODEL_ID
+db BIOS_REVISION
+; Feature byte 1
+; b7: 1=DMA channel 3 used by hard disk
+; b6: 1=2 interrupt controllers present
+; b5: 1=RTC present
+; b4: 1=BIOS calls int 15h/4Fh every key
+; b3: 1=wait for extern event supported (Int 15h/41h)
+; b2: 1=extended BIOS data area used
+; b1: 0=AT or ESDI bus, 1=MicroChannel
+; b0: 1=Dual bus (MicroChannel + ISA)
+db (0 << 7) | \
+   (1 << 6) | \
+   (1 << 5) | \
+   (BX_CALL_INT15_4F << 4) | \
+   (0 << 3) | \
+   (BX_USE_EBDA << 2) | \
+   (0 << 1) | \
+   (0 << 0)
+; Feature byte 2
+; b7: 1=32-bit DMA supported
+; b6: 1=int16h, function 9 supported
+; b5: 1=int15h/C6h (get POS data) supported
+; b4: 1=int15h/C7h (get mem map info) supported
+; b3: 1=int15h/C8h (en/dis CPU) supported
+; b2: 1=non-8042 kb controller
+; b1: 1=data streaming supported
+; b0: reserved
+db (0 << 7) | \
+   (1 << 6) | \
+   (0 << 5) | \
+   (0 << 4) | \
+   (0 << 3) | \
+   (0 << 2) | \
+   (0 << 1) | \
+   (0 << 0)
+; Feature byte 3
+; b7: not used
+; b6: reserved
+; b5: reserved
+; b4: POST supports ROM-to-RAM enable/disable
+; b3: SCSI on system board
+; b2: info panel installed
+; b1: Initial Machine Load (IML) system - BIOS on disk
+; b0: SCSI supported in IML
+db 0x00
+; Feature byte 4
+; b7: IBM private
+; b6: EEPROM present
+; b5-3: ABIOS presence (011 = not supported)
+; b2: private
+; b1: memory split above 16Mb supported
+; b0: POSTEXT directly supported by POST
+db 0x00
+; Feature byte 5 (IBM)
+; b1: enhanced mouse
+; b0: flash EPROM
+db 0x00
+
+
+
+.org 0xe729 ; Baud Rate Generator Table
+
+;----------
+;- INT14h -
+;----------
+.org 0xe739 ; INT 14h Serial Communications Service Entry Point
+int14_handler:
+  push ds
+  pusha
+  xor  ax, ax
+  mov  ds, ax
+  call _int14_function
+  popa
+  pop  ds
+  iret
+
+
+;----------------------------------------
+;- INT 16h Keyboard Service Entry Point -
+;----------------------------------------
+.org 0xe82e
+int16_handler:
+
+  sti
+  push  ds
+  pushf
+  pusha
+
+  cmp   ah, #0x00
+  je    int16_F00
+  cmp   ah, #0x10
+  je    int16_F00
+
+  mov  bx, #0xf000
+  mov  ds, bx
+  call _int16_function
+  popa
+  popf
+  pop  ds
+  jz   int16_zero_set
+
+int16_zero_clear:
+  push bp
+  mov  bp, sp
+  //SEG SS
+  and  BYTE [bp + 0x06], #0xbf
+  pop  bp
+  iret
+
+int16_zero_set:
+  push bp
+  mov  bp, sp
+  //SEG SS
+  or   BYTE [bp + 0x06], #0x40
+  pop  bp
+  iret
+
+int16_F00:
+  mov  bx, #0x0040
+  mov  ds, bx
+
+int16_wait_for_key:
+  cli
+  mov  bx, 0x001a
+  cmp  bx, 0x001c
+  jne  int16_key_found
+  sti
+  nop
+#if 0
+                           /* no key yet, call int 15h, function AX=9002 */
+  0x50,                    /* push AX */
+  0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
+  0xcd, 0x15,              /* int 15h */
+  0x58,                    /* pop  AX */
+  0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
+#endif
+  jmp  int16_wait_for_key
+
+int16_key_found:
+  mov  bx, #0xf000
+  mov  ds, bx
+  call _int16_function
+  popa
+  popf
+  pop  ds
+#if 0
+                           /* notify int16 complete w/ int 15h, function AX=9102 */
+  0x50,                    /* push AX */
+  0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
+  0xcd, 0x15,              /* int 15h */
+  0x58,                    /* pop  AX */
+#endif
+  iret
+
+
+
+;-------------------------------------------------
+;- INT09h : Keyboard Hardware Service Entry Point -
+;-------------------------------------------------
+.org 0xe987
+int09_handler:
+  cli
+  push ax
+
+  mov al, #0xAD      ;;disable keyboard
+  out #0x64, al
+
+  mov al, #0x0B
+  out #0x20, al
+  in  al, #0x20
+  and al, #0x02
+  jz  int09_finish
+
+  in  al, #0x60             ;;read key from keyboard controller
+  sti
+  push  ds
+  pusha
+#ifdef BX_CALL_INT15_4F
+  mov  ah, #0x4f     ;; allow for keyboard intercept
+  stc
+  int  #0x15
+  jnc  int09_done
+#endif
+
+  ;; check for extended key
+  cmp  al, #0xe0
+  jne int09_check_pause
+  xor  ax, ax
+  mov  ds, ax
+  mov  al, BYTE [0x496]     ;; mf2_state |= 0x02
+  or   al, #0x02
+  mov  BYTE [0x496], al
+  jmp int09_done
+
+int09_check_pause: ;; check for pause key
+  cmp  al, #0xe1
+  jne int09_process_key
+  xor  ax, ax
+  mov  ds, ax
+  mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
+  or   al, #0x01
+  mov  BYTE [0x496], al
+  jmp int09_done
+
+int09_process_key:
+  mov   bx, #0xf000
+  mov   ds, bx
+  call  _int09_function
+
+int09_done:
+  popa
+  pop   ds
+  cli
+  call eoi_master_pic
+
+int09_finish:
+  mov al, #0xAE      ;;enable keyboard
+  out #0x64, al
+  pop ax
+  iret
+
+
+;----------------------------------------
+;- INT 13h Diskette Service Entry Point -
+;----------------------------------------
+.org 0xec59
+int13_diskette:
+  jmp int13_noeltorito
+
+;---------------------------------------------
+;- INT 0Eh Diskette Hardware ISR Entry Point -
+;---------------------------------------------
+.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
+int0e_handler:
+  push ax
+  push dx
+  mov  dx, #0x03f4
+  in   al, dx
+  and  al, #0xc0
+  cmp  al, #0xc0
+  je   int0e_normal
+  mov  dx, #0x03f5
+  mov  al, #0x08 ; sense interrupt status
+  out  dx, al
+int0e_loop1:
+  mov  dx, #0x03f4
+  in   al, dx
+  and  al, #0xc0
+  cmp  al, #0xc0
+  jne  int0e_loop1
+int0e_loop2:
+  mov  dx, #0x03f5
+  in   al, dx
+  mov  dx, #0x03f4
+  in   al, dx
+  and  al, #0xc0
+  cmp  al, #0xc0
+  je int0e_loop2
+int0e_normal:
+  push ds
+  xor  ax, ax ;; segment 0000
+  mov  ds, ax
+  call eoi_master_pic
+  mov  al, 0x043e
+  or   al, #0x80 ;; diskette interrupt has occurred
+  mov  0x043e, al
+  pop  ds
+  pop  dx
+  pop  ax
+  iret
+
+
+.org 0xefc7 ; Diskette Controller Parameter Table
+diskette_param_table:
+;;  Since no provisions are made for multiple drive types, most
+;;  values in this table are ignored.  I set parameters for 1.44M
+;;  floppy here
+db  0xAF
+db  0x02 ;; head load time 0000001, DMA used
+db  0x25
+db  0x02
+db    18
+db  0x1B
+db  0xFF
+db  0x6C
+db  0xF6
+db  0x0F
+db  0x08
+
+
+;----------------------------------------
+;- INT17h : Printer Service Entry Point -
+;----------------------------------------
+.org 0xefd2
+int17_handler:
+  push ds
+  pusha
+  xor  ax, ax
+  mov  ds, ax
+  call _int17_function
+  popa
+  pop  ds
+  iret
+
+diskette_param_table2:
+;;  New diskette parameter table adding 3 parameters from IBM
+;;  Since no provisions are made for multiple drive types, most
+;;  values in this table are ignored.  I set parameters for 1.44M
+;;  floppy here
+db  0xAF
+db  0x02 ;; head load time 0000001, DMA used
+db  0x25
+db  0x02
+db    18
+db  0x1B
+db  0xFF
+db  0x6C
+db  0xF6
+db  0x0F
+db  0x08
+db    79 ;; maximum track
+db     0 ;; data transfer rate
+db     4 ;; drive type in cmos
+
+.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
+  HALT(__LINE__)
+  iret
+
+;----------
+;- INT10h -
+;----------
+.org 0xf065 ; INT 10h Video Support Service Entry Point
+int10_handler:
+  ;; dont do anything, since the VGA BIOS handles int10h requests
+  iret
+
+.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
+
+;----------
+;- INT12h -
+;----------
+.org 0xf841 ; INT 12h Memory Size Service Entry Point
+; ??? different for Pentium (machine check)?
+int12_handler:
+  push ds
+  mov  ax, #0x0040
+  mov  ds, ax
+  mov  ax, 0x0013
+  pop  ds
+  iret
+
+;----------
+;- INT11h -
+;----------
+.org 0xf84d ; INT 11h Equipment List Service Entry Point
+int11_handler:
+  push ds
+  mov  ax, #0x0040
+  mov  ds, ax
+  mov  ax, 0x0010
+  pop  ds
+  iret
+
+;----------
+;- INT15h -
+;----------
+.org 0xf859 ; INT 15h System Services Entry Point
+int15_handler:
+  pushf
+#if BX_APM
+  cmp ah, #0x53
+  je apm_call
+#endif
+  push  ds
+  push  es
+  cmp  ah, #0x86
+  je int15_handler32
+  cmp  ah, #0xE8
+  je int15_handler32
+  pusha
+#if BX_USE_PS2_MOUSE
+  cmp  ah, #0xC2
+  je int15_handler_mouse
+#endif
+  call _int15_function
+int15_handler_mouse_ret:
+  popa
+int15_handler32_ret:
+  pop   es
+  pop   ds
+  popf
+  jmp iret_modify_cf
+#if BX_APM
+apm_call:
+  jmp _apmreal_entry
+#endif
+
+#if BX_USE_PS2_MOUSE
+int15_handler_mouse:
+  call _int15_function_mouse
+  jmp int15_handler_mouse_ret
+#endif
+
+int15_handler32:
+  pushad
+  call _int15_function32
+  popad
+  jmp int15_handler32_ret
+
+;; Protected mode IDT descriptor
+;;
+;; I just make the limit 0, so the machine will shutdown
+;; if an exception occurs during protected mode memory
+;; transfers.
+;;
+;; Set base to f0000 to correspond to beginning of BIOS,
+;; in case I actually define an IDT later
+;; Set limit to 0
+
+pmode_IDT_info:
+dw 0x0000  ;; limit 15:00
+dw 0x0000  ;; base  15:00
+db 0x0f    ;; base  23:16
+
+;; Real mode IDT descriptor
+;;
+;; Set to typical real-mode values.
+;; base  = 000000
+;; limit =   03ff
+
+rmode_IDT_info:
+dw 0x03ff  ;; limit 15:00
+dw 0x0000  ;; base  15:00
+db 0x00    ;; base  23:16
+
+
+;----------
+;- INT1Ah -
+;----------
+.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
+int1a_handler:
+#if BX_PCIBIOS
+  cmp  ah, #0xb1
+  jne  int1a_normal
+  call pcibios_real
+  jc   pcibios_error
+  retf 2
+pcibios_error:
+  mov  bl, ah
+  mov  ah, #0xb1
+  push ds
+  pusha
+  mov ax, ss  ; set readable descriptor to ds, for calling pcibios
+  mov ds, ax  ;  on 16bit protected mode.
+  jmp int1a_callfunction
+int1a_normal:
+#endif
+  push ds
+  pusha
+  xor  ax, ax
+  mov  ds, ax
+int1a_callfunction:
+  call _int1a_function
+  popa
+  pop  ds
+  iret
+
+;;
+;; int70h: IRQ8 - CMOS RTC
+;;
+int70_handler:
+  push ds
+  pushad
+  xor  ax, ax
+  mov  ds, ax
+  call _int70_function
+  popad
+  pop  ds
+  iret
+
+;---------
+;- INT08 -
+;---------
+.org 0xfea5 ; INT 08h System Timer ISR Entry Point
+int08_handler:
+  sti
+  push eax
+  push ds
+  xor ax, ax
+  mov ds, ax
+
+  ;; time to turn off drive(s)?
+  mov  al,0x0440
+  or   al,al
+  jz   int08_floppy_off
+  dec  al
+  mov  0x0440,al
+  jnz  int08_floppy_off
+  ;; turn motor(s) off
+  push dx
+  mov  dx,#0x03f2
+  in   al,dx
+  and  al,#0xcf
+  out  dx,al
+  pop  dx
+int08_floppy_off:
+
+  mov eax, 0x046c ;; get ticks dword
+  inc eax
+
+  ;; compare eax to one days worth of timer ticks at 18.2 hz
+  cmp eax, #0x001800B0
+  jb  int08_store_ticks
+  ;; there has been a midnight rollover at this point
+  xor eax, eax    ;; zero out counter
+  inc BYTE 0x0470 ;; increment rollover flag
+
+int08_store_ticks:
+  mov 0x046c, eax ;; store new ticks dword
+  ;; chain to user timer tick INT #0x1c
+  //pushf
+  //;; call_ep [ds:loc]
+  //CALL_EP( 0x1c << 2 )
+  int #0x1c
+  cli
+  call eoi_master_pic
+  pop ds
+  pop eax
+  iret
+
+.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
+
+
+.org 0xff00
+.ascii BIOS_COPYRIGHT_STRING
+
+;------------------------------------------------
+;- IRET Instruction for Dummy Interrupt Handler -
+;------------------------------------------------
+.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
+dummy_iret_handler:
+  iret
+
+.org 0xff54 ; INT 05h Print Screen Service Entry Point
+  HALT(__LINE__)
+  iret
+
+.org 0xfff0 ; Power-up Entry Point
+  jmp 0xf000:post
+
+.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
+.ascii BIOS_BUILD_DATE
+
+.org 0xfffe ; System Model ID
+db SYS_MODEL_ID
+db 0x00   ; filler
+
+.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+ASM_END
+/*
+ * This font comes from the fntcol16.zip package (c) by  Joseph Gil
+ * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * This font is public domain
+ */
+static Bit8u vgafont8[128*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,
+};
+
+ASM_START
+.org 0xcc00
+bios_table_area_end:
+// bcc-generated data will be placed here
+ASM_END
diff --git a/kvm/bios/rombios.h b/kvm/bios/rombios.h
new file mode 100644
index 0000000..c8f64f3
--- /dev/null
+++ b/kvm/bios/rombios.h
@@ -0,0 +1,83 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rombios.h,v 1.4 2007/02/20 09:36:55 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2006 Volker Ruppert
+//
+//  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
+
+/* define it to include QEMU specific code */
+#define BX_QEMU
+
+#ifndef LEGACY
+#  define BX_ROMBIOS32     1
+#else
+#  define BX_ROMBIOS32     0
+#endif
+#define DEBUG_ROMBIOS    0
+
+#define PANIC_PORT  0x400
+#define PANIC_PORT2 0x401
+#define INFO_PORT   0x402
+#define DEBUG_PORT  0x403
+
+#define BIOS_PRINTF_HALT     1
+#define BIOS_PRINTF_SCREEN   2
+#define BIOS_PRINTF_INFO     4
+#define BIOS_PRINTF_DEBUG    8
+#define BIOS_PRINTF_ALL      (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
+#define BIOS_PRINTF_DEBHALT  (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
+
+#define printf(format, p...)  bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
+
+// Defines the output macros.
+// BX_DEBUG goes to INFO port until we can easily choose debug info on a
+// per-device basis. Debug info are sent only in debug mode
+#if DEBUG_ROMBIOS
+#  define BX_DEBUG(format, p...)  bios_printf(BIOS_PRINTF_INFO, format, ##p)
+#else
+#  define BX_DEBUG(format, p...)
+#endif
+#define BX_INFO(format, p...)   bios_printf(BIOS_PRINTF_INFO, format, ##p)
+#define BX_PANIC(format, p...)  bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
+
+#define ACPI_DATA_SIZE    0x00010000L
+#define PM_IO_BASE        0xb000
+#define SMB_IO_BASE       0xb100
+#define SMP_MSR_ADDR      0x0510
+#define APIC_MADT_PTR     0x0514
+
+#define MAX_CPUS 16
+
+#define QEMU_CFG_CTL_PORT         0x510
+#define QEMU_CFG_DATA_PORT        0x511
+#define QEMU_CFG_SIGNATURE        0x00
+#define QEMU_CFG_ID               0x01
+#define QEMU_CFG_UUID             0x02
+#define QEMU_CFG_NUMA             0x0d
+#define QEMU_CFG_BOOT_MENU        0x0e
+#define QEMU_CFG_ARCH_LOCAL       0x8000
+#define QEMU_CFG_ACPI_TABLES      (QEMU_CFG_ARCH_LOCAL + 0)
+#define QEMU_CFG_SMBIOS_ENTRIES   (QEMU_CFG_ARCH_LOCAL + 1)
+#define QEMU_CFG_IRQ0_OVERRIDE    (QEMU_CFG_ARCH_LOCAL + 2)
+
+  // Define the application NAME
+#if defined(BX_QEMU)
+#  define BX_APPNAME "QEMU"
+#elif defined(PLEX86)
+#  define BX_APPNAME "Plex86"
+#else
+#  define BX_APPNAME "Bochs"
+#endif
diff --git a/kvm/bios/rombios32.c b/kvm/bios/rombios32.c
new file mode 100755
index 0000000..0b3556c
--- /dev/null
+++ b/kvm/bios/rombios32.c
@@ -0,0 +1,2749 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rombios32.c,v 1.11 2007/08/03 13:56:13 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  32 bit Bochs BIOS init code
+//  Copyright (C) 2006 Fabrice Bellard
+//
+//  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 <stdarg.h>
+#include <stddef.h>
+
+#include "rombios.h"
+
+typedef signed char  int8_t;
+typedef short int16_t;
+typedef int   int32_t;
+typedef long long int64_t;
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int   uint32_t;
+typedef unsigned long long uint64_t;
+
+/* if true, put the MP float table and ACPI RSDT in EBDA and the MP
+   table in RAM. Unfortunately, Linux has bugs with that, so we prefer
+   to modify the BIOS in shadow RAM */
+//#define BX_USE_EBDA_TABLES
+
+/* define it if the (emulated) hardware supports SMM mode */
+//#define BX_USE_SMM
+
+#define cpuid(index, eax, ebx, ecx, edx) \
+  asm volatile ("cpuid" \
+                : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
+                : "0" (index))
+
+#define wbinvd() asm volatile("wbinvd")
+
+#define CPUID_MSR (1 << 5)
+#define CPUID_APIC (1 << 9)
+#define CPUID_MTRR (1 << 12)
+
+#define APIC_BASE    ((uint8_t *)0xfee00000)
+#define APIC_ICR_LOW 0x300
+#define APIC_SVR     0x0F0
+#define APIC_ID      0x020
+#define APIC_LVT3    0x370
+
+/* IRQs 5,9,10,11 */
+#define PCI_ISA_IRQ_MASK    0x0e20U
+
+#define APIC_ENABLED 0x0100
+
+#define AP_BOOT_ADDR 0x9f000
+
+#define MPTABLE_MAX_SIZE  0x00002000
+#define SMI_CMD_IO_ADDR   0xb2
+
+#define BIOS_TMP_STORAGE  0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */
+
+#define MSR_MTRRcap                     0x000000fe
+#define MSR_MTRRfix64K_00000            0x00000250
+#define MSR_MTRRfix16K_80000            0x00000258
+#define MSR_MTRRfix16K_A0000            0x00000259
+#define MSR_MTRRfix4K_C0000             0x00000268
+#define MSR_MTRRfix4K_C8000             0x00000269
+#define MSR_MTRRfix4K_D0000             0x0000026a
+#define MSR_MTRRfix4K_D8000             0x0000026b
+#define MSR_MTRRfix4K_E0000             0x0000026c
+#define MSR_MTRRfix4K_E8000             0x0000026d
+#define MSR_MTRRfix4K_F0000             0x0000026e
+#define MSR_MTRRfix4K_F8000             0x0000026f
+#define MSR_MTRRdefType                 0x000002ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define MAX_INT_OVERRIDES 16
+
+static inline void outl(int addr, int val)
+{
+    asm volatile ("outl %1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline void outw(int addr, int val)
+{
+    asm volatile ("outw %w1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline void outb(int addr, int val)
+{
+    asm volatile ("outb %b1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline uint32_t inl(int addr)
+{
+    uint32_t val;
+    asm volatile ("inl %w1, %0" : "=a" (val) : "d" (addr));
+    return val;
+}
+
+static inline uint16_t inw(int addr)
+{
+    uint16_t val;
+    asm volatile ("inw %w1, %w0" : "=a" (val) : "d" (addr));
+    return val;
+}
+
+static inline uint8_t inb(int addr)
+{
+    uint8_t val;
+    asm volatile ("inb %w1, %b0" : "=a" (val) : "d" (addr));
+    return val;
+}
+
+static inline void writel(void *addr, uint32_t val)
+{
+    *(volatile uint32_t *)addr = val;
+}
+
+static inline void writew(void *addr, uint16_t val)
+{
+    *(volatile uint16_t *)addr = val;
+}
+
+static inline void writeb(void *addr, uint8_t val)
+{
+    *(volatile uint8_t *)addr = val;
+}
+
+static inline uint32_t readl(const void *addr)
+{
+    return *(volatile const uint32_t *)addr;
+}
+
+static inline uint16_t readw(const void *addr)
+{
+    return *(volatile const uint16_t *)addr;
+}
+
+static inline uint8_t readb(const void *addr)
+{
+    return *(volatile const uint8_t *)addr;
+}
+
+static inline void putc(int c)
+{
+    outb(INFO_PORT, c);
+}
+
+static uint64_t rdmsr(unsigned index)
+{
+    unsigned long long ret;
+
+    asm ("rdmsr" : "=A"(ret) : "c"(index));
+    return ret;
+}
+
+static void wrmsr(unsigned index, uint64_t val)
+{
+    asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
+static inline int isdigit(int c)
+{
+    return c >= '0' && c <= '9';
+}
+
+void *memset(void *d1, int val, size_t len)
+{
+    uint8_t *d = d1;
+
+    while (len--) {
+        *d++ = val;
+    }
+    return d1;
+}
+
+void *memcpy(void *d1, const void *s1, size_t len)
+{
+    uint8_t *d = d1;
+    const uint8_t *s = s1;
+
+    while (len--) {
+        *d++ = *s++;
+    }
+    return d1;
+}
+
+void *memmove(void *d1, const void *s1, size_t len)
+{
+    uint8_t *d = d1;
+    const uint8_t *s = s1;
+
+    if (d <= s) {
+        while (len--) {
+            *d++ = *s++;
+        }
+    } else {
+        d += len;
+        s += len;
+        while (len--) {
+            *--d = *--s;
+        }
+    }
+    return d1;
+}
+
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+    const int8_t *p1 = s1;
+    const int8_t *p2 = s2;
+
+    while (len--) {
+        int r = *p1++ - *p2++;
+        if(r)
+            return r;
+    }
+
+    return 0;
+}
+
+size_t strlen(const char *s)
+{
+    const char *s1;
+    for(s1 = s; *s1 != '\0'; s1++);
+    return s1 - s;
+}
+
+/* from BSD ppp sources */
+int vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
+{
+    int c, i, n;
+    int width, prec, fillch;
+    int base, len, neg;
+    unsigned long val = 0;
+    const char *f;
+    char *str, *buf0;
+    char num[32];
+    static const char hexchars[] = "0123456789abcdef";
+
+    buf0 = buf;
+    --buflen;
+    while (buflen > 0) {
+	for (f = fmt; *f != '%' && *f != 0; ++f)
+	    ;
+	if (f > fmt) {
+	    len = f - fmt;
+	    if (len > buflen)
+		len = buflen;
+	    memcpy(buf, fmt, len);
+	    buf += len;
+	    buflen -= len;
+	    fmt = f;
+	}
+	if (*fmt == 0)
+	    break;
+	c = *++fmt;
+	width = prec = 0;
+	fillch = ' ';
+	if (c == '0') {
+	    fillch = '0';
+	    c = *++fmt;
+	}
+	if (c == '*') {
+	    width = va_arg(args, int);
+	    c = *++fmt;
+	} else {
+	    while (isdigit(c)) {
+		width = width * 10 + c - '0';
+		c = *++fmt;
+	    }
+	}
+	if (c == '.') {
+	    c = *++fmt;
+	    if (c == '*') {
+		prec = va_arg(args, int);
+		c = *++fmt;
+	    } else {
+		while (isdigit(c)) {
+		    prec = prec * 10 + c - '0';
+		    c = *++fmt;
+		}
+	    }
+	}
+        /* modifiers */
+        switch(c) {
+        case 'l':
+            c = *++fmt;
+            break;
+        default:
+            break;
+        }
+        str = 0;
+	base = 0;
+	neg = 0;
+	++fmt;
+	switch (c) {
+	case 'd':
+	    i = va_arg(args, int);
+	    if (i < 0) {
+		neg = 1;
+		val = -i;
+	    } else
+		val = i;
+	    base = 10;
+	    break;
+	case 'o':
+	    val = va_arg(args, unsigned int);
+	    base = 8;
+	    break;
+	case 'x':
+	case 'X':
+	    val = va_arg(args, unsigned int);
+	    base = 16;
+	    break;
+	case 'p':
+	    val = (unsigned long) va_arg(args, void *);
+	    base = 16;
+	    neg = 2;
+	    break;
+	case 's':
+	    str = va_arg(args, char *);
+	    break;
+	case 'c':
+	    num[0] = va_arg(args, int);
+	    num[1] = 0;
+	    str = num;
+	    break;
+	default:
+	    *buf++ = '%';
+	    if (c != '%')
+		--fmt;		/* so %z outputs %z etc. */
+	    --buflen;
+	    continue;
+	}
+	if (base != 0) {
+	    str = num + sizeof(num);
+	    *--str = 0;
+	    while (str > num + neg) {
+		*--str = hexchars[val % base];
+		val = val / base;
+		if (--prec <= 0 && val == 0)
+		    break;
+	    }
+	    switch (neg) {
+	    case 1:
+		*--str = '-';
+		break;
+	    case 2:
+		*--str = 'x';
+		*--str = '0';
+		break;
+	    }
+	    len = num + sizeof(num) - 1 - str;
+	} else {
+	    len = strlen(str);
+	    if (prec > 0 && len > prec)
+		len = prec;
+	}
+	if (width > 0) {
+	    if (width > buflen)
+		width = buflen;
+	    if ((n = width - len) > 0) {
+		buflen -= n;
+		for (; n > 0; --n)
+		    *buf++ = fillch;
+	    }
+	}
+	if (len > buflen)
+	    len = buflen;
+	memcpy(buf, str, len);
+	buf += len;
+	buflen -= len;
+    }
+    *buf = 0;
+    return buf - buf0;
+}
+
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsnprintf(buf,size,fmt,args);
+	va_end(args);
+	return i;
+}
+
+void bios_printf(int flags, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[1024];
+    const char *s;
+
+    if ((flags & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
+        outb(PANIC_PORT2, 0x00);
+
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    s = buf;
+    while (*s)
+        putc(*s++);
+    va_end(ap);
+}
+
+void delay_ms(int n)
+{
+    int i, j;
+    for(i = 0; i < n; i++) {
+#ifdef BX_QEMU
+        /* approximative ! */
+        for(j = 0; j < 1000000; j++);
+#else
+        {
+          int r1, r2;
+          j = 66;
+          r1 = inb(0x61) & 0x10;
+          do {
+            r2 = inb(0x61) & 0x10;
+            if (r1 != r2) {
+              j--;
+              r1 = r2;
+            }
+          } while (j > 0);
+        }
+#endif
+    }
+}
+
+uint16_t smp_cpus;
+uint32_t cpuid_signature;
+uint32_t cpuid_features;
+uint32_t cpuid_ext_features;
+unsigned long ram_size;
+uint64_t ram_end;
+#ifdef BX_QEMU
+uint8_t irq0_override;
+#endif
+#ifdef BX_USE_EBDA_TABLES
+unsigned long ebda_cur_addr;
+#endif
+int acpi_enabled;
+uint32_t pm_io_base, smb_io_base;
+int pm_sci_int;
+unsigned long bios_table_cur_addr;
+unsigned long bios_table_end_addr;
+
+void init_smp_msrs(void)
+{
+    *(uint32_t *)SMP_MSR_ADDR = 0;
+}
+
+static inline uint64_t le64_to_cpu(uint64_t x)
+{
+    return x;
+}
+
+void wrmsr_smp(uint32_t index, uint64_t val)
+{
+    static struct { uint32_t ecx, eax, edx; } *p = (void *)SMP_MSR_ADDR;
+
+    wrmsr(index, val);
+    p->ecx = index;
+    p->eax = val;
+    p->edx = val >> 32;
+    ++p;
+    p->ecx = 0;
+}
+
+#ifdef BX_QEMU
+
+int qemu_cfg_port;
+
+void qemu_cfg_select(int f)
+{
+    outw(QEMU_CFG_CTL_PORT, f);
+}
+
+int qemu_cfg_port_probe()
+{
+    char *sig = "QEMU";
+    int i;
+
+    qemu_cfg_select(QEMU_CFG_SIGNATURE);
+
+    for (i = 0; i < 4; i++)
+        if (inb(QEMU_CFG_DATA_PORT) != sig[i])
+            return 0;
+
+    return 1;
+}
+
+void qemu_cfg_read(uint8_t *buf, int len)
+{
+    while (len--)
+        *(buf++) = inb(QEMU_CFG_DATA_PORT);
+}
+
+static uint16_t acpi_additional_tables(void)
+{
+    uint16_t cnt;
+
+    qemu_cfg_select(QEMU_CFG_ACPI_TABLES);
+    qemu_cfg_read((uint8_t*)&cnt, sizeof(cnt));
+
+    return cnt;
+}
+
+static int acpi_load_table(int i, uint32_t addr, uint16_t *len)
+{
+    qemu_cfg_read((uint8_t*)len, sizeof(*len));
+
+    if (!*len)
+        return -1;
+
+    qemu_cfg_read((uint8_t*)addr, *len);
+    return 0;
+}
+
+static uint16_t smbios_entries(void)
+{
+    uint16_t cnt;
+
+    qemu_cfg_select(QEMU_CFG_SMBIOS_ENTRIES);
+    qemu_cfg_read((uint8_t*)&cnt, sizeof(cnt));
+
+    return cnt;
+}
+
+uint64_t qemu_cfg_get64 (void)
+{
+    uint64_t ret;
+
+    qemu_cfg_read((uint8_t*)&ret, 8);
+    return le64_to_cpu(ret);
+}
+#endif
+
+#ifdef BX_QEMU
+void irq0_override_probe(void)
+{
+    if(qemu_cfg_port) {
+        qemu_cfg_select(QEMU_CFG_IRQ0_OVERRIDE);
+        qemu_cfg_read(&irq0_override, 1);
+    }
+}
+#endif
+
+void cpu_probe(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+    cpuid(1, eax, ebx, ecx, edx);
+    cpuid_signature = eax;
+    cpuid_features = edx;
+    cpuid_ext_features = ecx;
+}
+
+static int cmos_readb(int addr)
+{
+    outb(0x70, addr);
+    return inb(0x71);
+}
+
+void setup_mtrr(void)
+{
+    int i, vcnt, fix, wc;
+    uint32_t mtrr_cap;
+    union {
+        uint8_t valb[8];
+        uint64_t val;
+    } u;
+
+    if (!(cpuid_features & CPUID_MTRR))
+        return;
+
+    if (!(cpuid_features & CPUID_MSR))
+        return;
+
+    mtrr_cap = rdmsr(MSR_MTRRcap);
+    vcnt = mtrr_cap & 0xff;
+    fix = mtrr_cap & 0x100;
+    wc = mtrr_cap & 0x400;
+    if (!vcnt || !fix)
+        return;
+
+    u.val = 0;
+    for (i = 0; i < 8; ++i)
+        if (ram_size >= 65536 * (i + 1))
+            u.valb[i] = 6;
+    wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+    u.val = 0;
+    for (i = 0; i < 8; ++i)
+        if (ram_size >= 65536 * 8 + 16384 * (i + 1))
+            u.valb[i] = 6;
+    wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+    wrmsr_smp(MSR_MTRRfix16K_A0000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_C0000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_C8000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_D0000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_D8000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_E0000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_E8000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_F0000, 0);
+    wrmsr_smp(MSR_MTRRfix4K_F8000, 0);
+    /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+    wrmsr_smp(MTRRphysBase_MSR(0), 0xe0000000ull | 0);
+    wrmsr_smp(MTRRphysMask_MSR(0), ~(0x20000000ull - 1) | 0x800);
+    wrmsr_smp(MSR_MTRRdefType, 0xc06);
+}
+
+void ram_probe(void)
+{
+  if (cmos_readb(0x34) | cmos_readb(0x35))
+    ram_size = (cmos_readb(0x34) | (cmos_readb(0x35) << 8)) * 65536 +
+        16 * 1024 * 1024;
+  else
+    ram_size = (cmos_readb(0x17) | (cmos_readb(0x18) << 8)) * 1024;
+
+  if (cmos_readb(0x5b) | cmos_readb(0x5c) | cmos_readb(0x5d))
+    ram_end = (((uint64_t)cmos_readb(0x5b) << 16) |
+               ((uint64_t)cmos_readb(0x5c) << 24) |
+               ((uint64_t)cmos_readb(0x5d) << 32)) + (1ull << 32);
+  else
+    ram_end = ram_size;
+
+  BX_INFO("end of ram=%ldMB\n", ram_end >> 20);
+
+  BX_INFO("ram_size=0x%08lx\n", ram_size);
+#ifdef BX_USE_EBDA_TABLES
+  ebda_cur_addr = ((*(uint16_t *)(0x40e)) << 4) + 0x380;
+  BX_INFO("ebda_cur_addr: 0x%08lx\n", ebda_cur_addr);
+#endif
+}
+
+/****************************************************/
+/* SMP probe */
+
+extern uint8_t smp_ap_boot_code_start;
+extern uint8_t smp_ap_boot_code_end;
+
+/* find the number of CPUs by launching a SIPI to them */
+void smp_probe(void)
+{
+    uint32_t val, sipi_vector;
+
+    writew(&smp_cpus, 1);
+    if (cpuid_features & CPUID_APIC) {
+
+        /* enable local APIC */
+        val = readl(APIC_BASE + APIC_SVR);
+        val |= APIC_ENABLED;
+        writel(APIC_BASE + APIC_SVR, val);
+
+        /* copy AP boot code */
+        memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start,
+               &smp_ap_boot_code_end - &smp_ap_boot_code_start);
+
+        /* broadcast SIPI */
+        writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500);
+        sipi_vector = AP_BOOT_ADDR >> 12;
+        writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+#ifndef BX_QEMU
+        delay_ms(10);
+#else
+        while (cmos_readb(0x5f) + 1 != readw(&smp_cpus))
+            ;
+#endif
+    }
+    BX_INFO("Found %d cpu(s)\n", readw(&smp_cpus));
+}
+
+/****************************************************/
+/* PCI init */
+
+#define PCI_ADDRESS_SPACE_MEM		0x00
+#define PCI_ADDRESS_SPACE_IO		0x01
+#define PCI_ADDRESS_SPACE_MEM_PREFETCH	0x08
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+#define PCI_DEVICES_MAX 64
+
+#define PCI_VENDOR_ID		0x00	/* 16 bits */
+#define PCI_DEVICE_ID		0x02	/* 16 bits */
+#define PCI_COMMAND		0x04	/* 16 bits */
+#define  PCI_COMMAND_IO		0x1	/* Enable response in I/O space */
+#define  PCI_COMMAND_MEMORY	0x2	/* Enable response in Memory space */
+#define PCI_CLASS_DEVICE        0x0a    /* Device class */
+#define PCI_INTERRUPT_LINE	0x3c	/* 8 bits */
+#define PCI_INTERRUPT_PIN	0x3d	/* 8 bits */
+#define PCI_MIN_GNT		0x3e	/* 8 bits */
+#define PCI_MAX_LAT		0x3f	/* 8 bits */
+
+#define PCI_VENDOR_ID_INTEL             0x8086
+#define PCI_DEVICE_ID_INTEL_82441       0x1237
+#define PCI_DEVICE_ID_INTEL_82371SB_0   0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1   0x7010
+#define PCI_DEVICE_ID_INTEL_82371AB_0   0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB     0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_3   0x7113
+
+#define PCI_VENDOR_ID_IBM               0x1014
+#define PCI_VENDOR_ID_APPLE             0x106b
+
+typedef struct PCIDevice {
+    int bus;
+    int devfn;
+} PCIDevice;
+
+static uint32_t pci_bios_io_addr;
+static uint32_t pci_bios_mem_addr;
+static uint32_t pci_bios_bigmem_addr;
+/* host irqs corresponding to PCI irqs A-D */
+static uint8_t pci_irqs[4] = { 10, 10, 11, 11 };
+static PCIDevice i440_pcidev;
+
+static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+    outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+    outl(0xcfc, val);
+}
+
+static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+    outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+    outw(0xcfc + (addr & 2), val);
+}
+
+static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+    outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+    outb(0xcfc + (addr & 3), val);
+}
+
+static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
+{
+    outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+    return inl(0xcfc);
+}
+
+static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
+{
+    outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+    return inw(0xcfc + (addr & 2));
+}
+
+static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
+{
+    outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+    return inb(0xcfc + (addr & 3));
+}
+
+static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
+{
+    uint16_t cmd;
+    uint32_t ofs, old_addr;
+
+    if ( region_num == PCI_ROM_SLOT ) {
+        ofs = 0x30;
+    }else{
+        ofs = 0x10 + region_num * 4;
+    }
+
+    old_addr = pci_config_readl(d, ofs);
+
+    pci_config_writel(d, ofs, addr);
+    BX_INFO("region %d: 0x%08x\n", region_num, addr);
+
+    /* enable memory mappings */
+    cmd = pci_config_readw(d, PCI_COMMAND);
+    if ( region_num == PCI_ROM_SLOT )
+        cmd |= 2;
+    else if (old_addr & PCI_ADDRESS_SPACE_IO)
+        cmd |= 1;
+    else
+        cmd |= 2;
+    pci_config_writew(d, PCI_COMMAND, cmd);
+}
+
+/* return the global irq number corresponding to a given device irq
+   pin. We could also use the bus number to have a more precise
+   mapping. */
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot_addend;
+    slot_addend = (pci_dev->devfn >> 3) - 1;
+    return (irq_num + slot_addend) & 3;
+}
+
+static void find_bios_table_area(void)
+{
+    unsigned long addr;
+    for(addr = 0xf0000; addr < 0x100000; addr += 16) {
+        if (*(uint32_t *)addr == 0xaafb4442) {
+            bios_table_cur_addr = addr + 8;
+            bios_table_end_addr = bios_table_cur_addr + *(uint32_t *)(addr + 4);
+            BX_INFO("bios_table_addr: 0x%08lx end=0x%08lx\n",
+                    bios_table_cur_addr, bios_table_end_addr);
+            return;
+        }
+    }
+    return;
+}
+
+static void bios_shadow_init(PCIDevice *d)
+{
+    int v;
+
+    if (bios_table_cur_addr == 0)
+        return;
+
+    /* remap the BIOS to shadow RAM an keep it read/write while we
+       are writing tables */
+    v = pci_config_readb(d, 0x59);
+    v &= 0xcf;
+    pci_config_writeb(d, 0x59, v);
+    memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000);
+    v |= 0x30;
+    pci_config_writeb(d, 0x59, v);
+    memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000);
+
+    i440_pcidev = *d;
+}
+
+static void bios_lock_shadow_ram(void)
+{
+    PCIDevice *d = &i440_pcidev;
+    int v;
+
+    wbinvd();
+    v = pci_config_readb(d, 0x59);
+    v = (v & 0x0f) | (0x10);
+    pci_config_writeb(d, 0x59, v);
+}
+
+static void pci_bios_init_bridges(PCIDevice *d)
+{
+    uint16_t vendor_id, device_id;
+
+    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+    device_id = pci_config_readw(d, PCI_DEVICE_ID);
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL &&
+       (device_id == PCI_DEVICE_ID_INTEL_82371SB_0 ||
+        device_id == PCI_DEVICE_ID_INTEL_82371AB_0)) {
+        int i, irq;
+        uint8_t elcr[2];
+
+        /* PIIX3/PIIX4 PCI to ISA bridge */
+
+        elcr[0] = 0x00;
+        elcr[1] = 0x00;
+        for(i = 0; i < 4; i++) {
+            irq = pci_irqs[i];
+            /* set to trigger level */
+            elcr[irq >> 3] |= (1 << (irq & 7));
+            /* activate irq remapping in PIIX */
+            pci_config_writeb(d, 0x60 + i, irq);
+        }
+        outb(0x4d0, elcr[0]);
+        outb(0x4d1, elcr[1]);
+        BX_INFO("PIIX3/PIIX4 init: elcr=%02x %02x\n",
+                elcr[0], elcr[1]);
+    } else if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == PCI_DEVICE_ID_INTEL_82441) {
+        /* i440 PCI bridge */
+        bios_shadow_init(d);
+    }
+}
+
+extern uint8_t smm_relocation_start, smm_relocation_end;
+extern uint8_t smm_code_start, smm_code_end;
+
+#ifdef BX_USE_SMM
+static void smm_init(PCIDevice *d)
+{
+    uint32_t value;
+
+    /* check if SMM init is already done */
+    value = pci_config_readl(d, 0x58);
+    if ((value & (1 << 25)) == 0) {
+
+        /* enable the SMM memory window */
+        pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x48);
+
+        /* save original memory content */
+        memcpy((void *)0xa8000, (void *)0x38000, 0x8000);
+
+        /* copy the SMM relocation code */
+        memcpy((void *)0x38000, &smm_relocation_start,
+               &smm_relocation_end - &smm_relocation_start);
+
+        /* enable SMI generation when writing to the APMC register */
+        pci_config_writel(d, 0x58, value | (1 << 25));
+
+        /* init APM status port */
+        outb(0xb3, 0x01);
+
+        /* raise an SMI interrupt */
+        outb(0xb2, 0x00);
+
+        /* wait until SMM code executed */
+        while (inb(0xb3) != 0x00);
+
+        /* restore original memory content */
+        memcpy((void *)0x38000, (void *)0xa8000, 0x8000);
+
+        /* copy the SMM code */
+        memcpy((void *)0xa8000, &smm_code_start,
+               &smm_code_end - &smm_code_start);
+        wbinvd();
+
+        /* close the SMM memory window and enable normal SMM */
+        pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08);
+    }
+}
+#endif
+
+static void piix4_pm_enable(PCIDevice *d)
+{
+        /* PIIX4 Power Management device (for ACPI) */
+        pci_config_writel(d, 0x40, PM_IO_BASE | 1);
+        pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */
+        pci_config_writel(d, 0x90, SMB_IO_BASE | 1);
+        pci_config_writeb(d, 0xd2, 0x09); /* enable SMBus io space */
+#ifdef BX_USE_SMM
+        smm_init(d);
+#endif
+}
+
+static void pci_bios_init_device(PCIDevice *d)
+{
+    int class;
+    uint32_t *paddr;
+    int i, pin, pic_irq, vendor_id, device_id;
+
+    class = pci_config_readw(d, PCI_CLASS_DEVICE);
+    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+    device_id = pci_config_readw(d, PCI_DEVICE_ID);
+    BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x class=0x%04x\n",
+            d->bus, d->devfn, vendor_id, device_id, class);
+    switch(class) {
+    case 0x0101: /* Mass storage controller - IDE interface */
+        if (vendor_id == PCI_VENDOR_ID_INTEL &&
+           (device_id == PCI_DEVICE_ID_INTEL_82371SB_1 ||
+            device_id == PCI_DEVICE_ID_INTEL_82371AB)) {
+            /* PIIX3/PIIX4 IDE */
+            pci_config_writew(d, 0x40, 0x8000); // enable IDE0
+            pci_config_writew(d, 0x42, 0x8000); // enable IDE1
+            goto default_map;
+        } else {
+            /* IDE: we map it as in ISA mode */
+            pci_set_io_region_addr(d, 0, 0x1f0);
+            pci_set_io_region_addr(d, 1, 0x3f4);
+            pci_set_io_region_addr(d, 2, 0x170);
+            pci_set_io_region_addr(d, 3, 0x374);
+        }
+        break;
+    case 0x0300: /* Display controller - VGA compatible controller */
+        if (vendor_id != 0x1234)
+            goto default_map;
+        /* VGA: map frame buffer to default Bochs VBE address */
+        pci_set_io_region_addr(d, 0, 0xE0000000);
+        break;
+    case 0x0800: /* Generic system peripheral - PIC */
+        if (vendor_id == PCI_VENDOR_ID_IBM) {
+            /* IBM */
+            if (device_id == 0x0046 || device_id == 0xFFFF) {
+                /* MPIC & MPIC2 */
+                pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
+            }
+        }
+        break;
+    case 0xff00:
+        if (vendor_id == PCI_VENDOR_ID_APPLE &&
+            (device_id == 0x0017 || device_id == 0x0022)) {
+            /* macio bridge */
+            pci_set_io_region_addr(d, 0, 0x80800000);
+        }
+        break;
+    default:
+    default_map:
+        /* default memory mappings */
+        for(i = 0; i < PCI_NUM_REGIONS; i++) {
+            int ofs;
+            uint32_t val, size ;
+
+            if (i == PCI_ROM_SLOT)
+                ofs = 0x30;
+            else
+                ofs = 0x10 + i * 4;
+            pci_config_writel(d, ofs, 0xffffffff);
+            val = pci_config_readl(d, ofs);
+            if (val != 0) {
+                size = (~(val & ~0xf)) + 1;
+                if (val & PCI_ADDRESS_SPACE_IO)
+                    paddr = &pci_bios_io_addr;
+                else if (size >= 0x04000000)
+                    paddr = &pci_bios_bigmem_addr;
+                else
+                    paddr = &pci_bios_mem_addr;
+                *paddr = (*paddr + size - 1) & ~(size - 1);
+                pci_set_io_region_addr(d, i, *paddr);
+                *paddr += size;
+                /* make memory address page aligned */
+                if (!(val & PCI_ADDRESS_SPACE_IO))
+                    *paddr = (*paddr + 0xfff) & 0xfffff000;
+            }
+        }
+        break;
+    }
+
+    /* map the interrupt */
+    pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
+    if (pin != 0) {
+        pin = pci_slot_get_pirq(d, pin - 1);
+        pic_irq = pci_irqs[pin];
+        pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
+    }
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == PCI_DEVICE_ID_INTEL_82371AB_3) {
+        /* PIIX4 Power Management device (for ACPI) */
+
+        // acpi sci is hardwired to 9
+        pci_config_writeb(d, PCI_INTERRUPT_LINE, 9);
+
+        pm_io_base = PM_IO_BASE;
+        smb_io_base = SMB_IO_BASE;
+        pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
+        piix4_pm_enable(d);
+        acpi_enabled = 1;
+    }
+}
+
+void pci_for_each_device(void (*init_func)(PCIDevice *d))
+{
+    PCIDevice d1, *d = &d1;
+    int bus, devfn;
+    uint16_t vendor_id, device_id;
+
+    for(bus = 0; bus < 1; bus++) {
+        for(devfn = 0; devfn < 256; devfn++) {
+            d->bus = bus;
+            d->devfn = devfn;
+            vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+            device_id = pci_config_readw(d, PCI_DEVICE_ID);
+            if (vendor_id != 0xffff || device_id != 0xffff) {
+                init_func(d);
+            }
+        }
+    }
+}
+
+void pci_bios_init(void)
+{
+    pci_bios_io_addr = 0xc000;
+    pci_bios_mem_addr = 0xf0000000;
+    pci_bios_bigmem_addr = ram_size;
+    if (pci_bios_bigmem_addr < 0x90000000)
+        pci_bios_bigmem_addr = 0x90000000;
+
+    pci_for_each_device(pci_bios_init_bridges);
+
+    pci_for_each_device(pci_bios_init_device);
+}
+
+/****************************************************/
+/* Multi Processor table init */
+
+static void putb(uint8_t **pp, int val)
+{
+    uint8_t *q;
+    q = *pp;
+    *q++ = val;
+    *pp = q;
+}
+
+static void putstr(uint8_t **pp, const char *str)
+{
+    uint8_t *q;
+    q = *pp;
+    while (*str)
+        *q++ = *str++;
+    *pp = q;
+}
+
+static void putle16(uint8_t **pp, int val)
+{
+    uint8_t *q;
+    q = *pp;
+    *q++ = val;
+    *q++ = val >> 8;
+    *pp = q;
+}
+
+static void putle32(uint8_t **pp, int val)
+{
+    uint8_t *q;
+    q = *pp;
+    *q++ = val;
+    *q++ = val >> 8;
+    *q++ = val >> 16;
+    *q++ = val >> 24;
+    *pp = q;
+}
+
+static int mpf_checksum(const uint8_t *data, int len)
+{
+    int sum, i;
+    sum = 0;
+    for(i = 0; i < len; i++)
+        sum += data[i];
+    return sum & 0xff;
+}
+
+static unsigned long align(unsigned long addr, unsigned long v)
+{
+    return (addr + v - 1) & ~(v - 1);
+}
+
+static void mptable_init(void)
+{
+    uint8_t *mp_config_table, *q, *float_pointer_struct;
+    int ioapic_id, i, len;
+    int mp_config_table_size;
+
+#ifdef BX_USE_EBDA_TABLES
+    mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE);
+#else
+    bios_table_cur_addr = align(bios_table_cur_addr, 16);
+    mp_config_table = (uint8_t *)bios_table_cur_addr;
+#endif
+    q = mp_config_table;
+    putstr(&q, "PCMP"); /* "PCMP signature */
+    putle16(&q, 0); /* table length (patched later) */
+    putb(&q, 4); /* spec rev */
+    putb(&q, 0); /* checksum (patched later) */
+#ifdef BX_QEMU
+    putstr(&q, "QEMUCPU "); /* OEM id */
+#else
+    putstr(&q, "BOCHSCPU");
+#endif
+    putstr(&q, "0.1         "); /* vendor id */
+    putle32(&q, 0); /* OEM table ptr */
+    putle16(&q, 0); /* OEM table size */
+#ifdef BX_QEMU
+    if (irq0_override)
+        putle16(&q, MAX_CPUS + 17); /* entry count */
+    else
+        putle16(&q, MAX_CPUS + 18); /* entry count */
+#else
+    putle16(&q, MAX_CPUS + 18); /* entry count */
+#endif
+    putle32(&q, 0xfee00000); /* local APIC addr */
+    putle16(&q, 0); /* ext table length */
+    putb(&q, 0); /* ext table checksum */
+    putb(&q, 0); /* reserved */
+
+    for(i = 0; i < MAX_CPUS ; i++) {
+        putb(&q, 0); /* entry type = processor */
+        putb(&q, i); /* APIC id */
+        putb(&q, 0x11); /* local APIC version number */
+        if (i == 0)
+            putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
+        else if ( i < smp_cpus)
+            putb(&q, 1); /* cpu flags: enabled */
+        else
+            putb(&q, 0); /* cpu flags: disabled */
+        putb(&q, 0); /* cpu signature */
+        putb(&q, 6);
+        putb(&q, 0);
+        putb(&q, 0);
+        putle16(&q, 0x201); /* feature flags */
+        putle16(&q, 0);
+
+        putle16(&q, 0); /* reserved */
+        putle16(&q, 0);
+        putle16(&q, 0);
+        putle16(&q, 0);
+    }
+
+    /* isa bus */
+    putb(&q, 1); /* entry type = bus */
+    putb(&q, 0); /* bus ID */
+    putstr(&q, "ISA   ");
+
+    /* ioapic */
+    ioapic_id = smp_cpus;
+    putb(&q, 2); /* entry type = I/O APIC */
+    putb(&q, ioapic_id); /* apic ID */
+    putb(&q, 0x11); /* I/O APIC version number */
+    putb(&q, 1); /* enable */
+    putle32(&q, 0xfec00000); /* I/O APIC addr */
+
+    /* irqs */
+    for(i = 0; i < 16; i++) {
+#ifdef BX_QEMU
+        /* One entry per ioapic interrupt destination. Destination 2 is covered
+         * by irq0->inti2 override (i == 0). Source IRQ 2 is unused
+         */
+        if (irq0_override && i == 2)
+            continue;
+#endif
+        putb(&q, 3); /* entry type = I/O interrupt */
+        putb(&q, 0); /* interrupt type = vectored interrupt */
+        putb(&q, 0); /* flags: po=0, el=0 */
+        putb(&q, 0);
+        putb(&q, 0); /* source bus ID = ISA */
+        putb(&q, i); /* source bus IRQ */
+        putb(&q, ioapic_id); /* dest I/O APIC ID */
+#ifdef BX_QEMU
+        if (irq0_override && i == 0)
+            putb(&q, 2); /* dest I/O APIC interrupt in */
+        else
+#endif
+            putb(&q, i); /* dest I/O APIC interrupt in */
+    }
+    /* patch length */
+    len = q - mp_config_table;
+    mp_config_table[4] = len;
+    mp_config_table[5] = len >> 8;
+
+    mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
+
+    mp_config_table_size = q - mp_config_table;
+
+#ifndef BX_USE_EBDA_TABLES
+    bios_table_cur_addr += mp_config_table_size;
+#endif
+
+    /* floating pointer structure */
+#ifdef BX_USE_EBDA_TABLES
+    ebda_cur_addr = align(ebda_cur_addr, 16);
+    float_pointer_struct = (uint8_t *)ebda_cur_addr;
+#else
+    bios_table_cur_addr = align(bios_table_cur_addr, 16);
+    float_pointer_struct = (uint8_t *)bios_table_cur_addr;
+#endif
+    q = float_pointer_struct;
+    putstr(&q, "_MP_");
+    /* pointer to MP config table */
+    putle32(&q, (unsigned long)mp_config_table);
+
+    putb(&q, 1); /* length in 16 byte units */
+    putb(&q, 4); /* MP spec revision */
+    putb(&q, 0); /* checksum (patched later) */
+    putb(&q, 0); /* MP feature byte 1 */
+
+    putb(&q, 0);
+    putb(&q, 0);
+    putb(&q, 0);
+    putb(&q, 0);
+    float_pointer_struct[10] =
+        -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
+#ifdef BX_USE_EBDA_TABLES
+    ebda_cur_addr += (q - float_pointer_struct);
+#else
+    bios_table_cur_addr += (q - float_pointer_struct);
+#endif
+    BX_INFO("MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n",
+            (unsigned long)float_pointer_struct,
+            (unsigned long)mp_config_table,
+            mp_config_table_size);
+}
+
+/****************************************************/
+/* ACPI tables init */
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+   BSD license) */
+
+/*
+ * All tables must be byte-packed to match the ACPI specification, since
+ * the tables are provided by the system BIOS.
+ */
+
+#define ACPI_TABLE_HEADER_DEF   /* ACPI common table header */ \
+	uint8_t                            signature [4];          /* ACPI signature (4 ASCII characters) */\
+	uint32_t                             length;                 /* Length of table, in bytes, including header */\
+	uint8_t                              revision;               /* ACPI Specification minor version # */\
+	uint8_t                              checksum;               /* To make sum of entire table == 0 */\
+	uint8_t                            oem_id [6];             /* OEM identification */\
+	uint8_t                            oem_table_id [8];       /* OEM table identification */\
+	uint32_t                             oem_revision;           /* OEM revision number */\
+	uint8_t                            asl_compiler_id [4];    /* ASL compiler vendor ID */\
+	uint32_t                             asl_compiler_revision;  /* ASL compiler revision number */
+
+
+struct acpi_table_header         /* ACPI common table header */
+{
+	ACPI_TABLE_HEADER_DEF
+} __attribute__((__packed__));
+
+struct rsdp_descriptor         /* Root System Descriptor Pointer */
+{
+	uint8_t                            signature [8];          /* ACPI signature, contains "RSD PTR " */
+	uint8_t                              checksum;               /* To make sum of struct == 0 */
+	uint8_t                            oem_id [6];             /* OEM identification */
+	uint8_t                              revision;               /* Must be 0 for 1.0, 2 for 2.0 */
+	uint32_t                             rsdt_physical_address;  /* 32-bit physical address of RSDT */
+	uint32_t                             length;                 /* XSDT Length in bytes including hdr */
+	uint64_t                             xsdt_physical_address;  /* 64-bit physical address of XSDT */
+	uint8_t                              extended_checksum;      /* Checksum of entire table */
+	uint8_t                            reserved [3];           /* Reserved field must be 0 */
+} __attribute__((__packed__));
+
+#define MAX_RSDT_ENTRIES 100
+
+/*
+ * ACPI 1.0 Root System Description Table (RSDT)
+ */
+struct rsdt_descriptor_rev1
+{
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
+	uint32_t                             table_offset_entry [MAX_RSDT_ENTRIES]; /* Array of pointers to other */
+			 /* ACPI tables */
+} __attribute__((__packed__));
+
+/*
+ * ACPI 1.0 Firmware ACPI Control Structure (FACS)
+ */
+struct facs_descriptor_rev1
+{
+	uint8_t                            signature[4];           /* ACPI Signature */
+	uint32_t                             length;                 /* Length of structure, in bytes */
+	uint32_t                             hardware_signature;     /* Hardware configuration signature */
+	uint32_t                             firmware_waking_vector; /* ACPI OS waking vector */
+	uint32_t                             global_lock;            /* Global Lock */
+	uint32_t                             S4bios_f        : 1;    /* Indicates if S4BIOS support is present */
+	uint32_t                             reserved1       : 31;   /* Must be 0 */
+	uint8_t                              resverved3 [40];        /* Reserved - must be zero */
+} __attribute__((__packed__));
+
+
+/*
+ * ACPI 1.0 Fixed ACPI Description Table (FADT)
+ */
+struct fadt_descriptor_rev1
+{
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
+	uint32_t                             firmware_ctrl;          /* Physical address of FACS */
+	uint32_t                             dsdt;                   /* Physical address of DSDT */
+	uint8_t                              model;                  /* System Interrupt Model */
+	uint8_t                              reserved1;              /* Reserved */
+	uint16_t                             sci_int;                /* System vector of SCI interrupt */
+	uint32_t                             smi_cmd;                /* Port address of SMI command port */
+	uint8_t                              acpi_enable;            /* Value to write to smi_cmd to enable ACPI */
+	uint8_t                              acpi_disable;           /* Value to write to smi_cmd to disable ACPI */
+	uint8_t                              S4bios_req;             /* Value to write to SMI CMD to enter S4BIOS state */
+	uint8_t                              reserved2;              /* Reserved - must be zero */
+	uint32_t                             pm1a_evt_blk;           /* Port address of Power Mgt 1a acpi_event Reg Blk */
+	uint32_t                             pm1b_evt_blk;           /* Port address of Power Mgt 1b acpi_event Reg Blk */
+	uint32_t                             pm1a_cnt_blk;           /* Port address of Power Mgt 1a Control Reg Blk */
+	uint32_t                             pm1b_cnt_blk;           /* Port address of Power Mgt 1b Control Reg Blk */
+	uint32_t                             pm2_cnt_blk;            /* Port address of Power Mgt 2 Control Reg Blk */
+	uint32_t                             pm_tmr_blk;             /* Port address of Power Mgt Timer Ctrl Reg Blk */
+	uint32_t                             gpe0_blk;               /* Port addr of General Purpose acpi_event 0 Reg Blk */
+	uint32_t                             gpe1_blk;               /* Port addr of General Purpose acpi_event 1 Reg Blk */
+	uint8_t                              pm1_evt_len;            /* Byte length of ports at pm1_x_evt_blk */
+	uint8_t                              pm1_cnt_len;            /* Byte length of ports at pm1_x_cnt_blk */
+	uint8_t                              pm2_cnt_len;            /* Byte Length of ports at pm2_cnt_blk */
+	uint8_t                              pm_tmr_len;              /* Byte Length of ports at pm_tm_blk */
+	uint8_t                              gpe0_blk_len;           /* Byte Length of ports at gpe0_blk */
+	uint8_t                              gpe1_blk_len;           /* Byte Length of ports at gpe1_blk */
+	uint8_t                              gpe1_base;              /* Offset in gpe model where gpe1 events start */
+	uint8_t                              reserved3;              /* Reserved */
+	uint16_t                             plvl2_lat;              /* Worst case HW latency to enter/exit C2 state */
+	uint16_t                             plvl3_lat;              /* Worst case HW latency to enter/exit C3 state */
+	uint16_t                             flush_size;             /* Size of area read to flush caches */
+	uint16_t                             flush_stride;           /* Stride used in flushing caches */
+	uint8_t                              duty_offset;            /* Bit location of duty cycle field in p_cnt reg */
+	uint8_t                              duty_width;             /* Bit width of duty cycle field in p_cnt reg */
+	uint8_t                              day_alrm;               /* Index to day-of-month alarm in RTC CMOS RAM */
+	uint8_t                              mon_alrm;               /* Index to month-of-year alarm in RTC CMOS RAM */
+	uint8_t                              century;                /* Index to century in RTC CMOS RAM */
+	uint8_t                              reserved4;              /* Reserved */
+	uint8_t                              reserved4a;             /* Reserved */
+	uint8_t                              reserved4b;             /* Reserved */
+#if 0
+	uint32_t                             wb_invd         : 1;    /* The wbinvd instruction works properly */
+	uint32_t                             wb_invd_flush   : 1;    /* The wbinvd flushes but does not invalidate */
+	uint32_t                             proc_c1         : 1;    /* All processors support C1 state */
+	uint32_t                             plvl2_up        : 1;    /* C2 state works on MP system */
+	uint32_t                             pwr_button      : 1;    /* Power button is handled as a generic feature */
+	uint32_t                             sleep_button    : 1;    /* Sleep button is handled as a generic feature, or not present */
+	uint32_t                             fixed_rTC       : 1;    /* RTC wakeup stat not in fixed register space */
+	uint32_t                             rtcs4           : 1;    /* RTC wakeup stat not possible from S4 */
+	uint32_t                             tmr_val_ext     : 1;    /* The tmr_val width is 32 bits (0 = 24 bits) */
+	uint32_t                             reserved5       : 23;   /* Reserved - must be zero */
+#else
+        uint32_t flags;
+#endif
+} __attribute__((__packed__));
+
+/*
+ * MADT values and structures
+ */
+
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC                0
+#define MULTIPLE_APIC           1
+
+
+/* Master MADT */
+
+struct multiple_apic_table
+{
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
+	uint32_t                             local_apic_address;     /* Physical address of local APIC */
+#if 0
+	uint32_t                             PCATcompat      : 1;    /* A one indicates system also has dual 8259s */
+	uint32_t                             reserved1       : 31;
+#else
+        uint32_t                             flags;
+#endif
+} __attribute__((__packed__));
+
+
+/* Values for Type in APIC sub-headers */
+
+#define APIC_PROCESSOR          0
+#define APIC_IO                 1
+#define APIC_XRUPT_OVERRIDE     2
+#define APIC_NMI                3
+#define APIC_LOCAL_NMI          4
+#define APIC_ADDRESS_OVERRIDE   5
+#define APIC_IO_SAPIC           6
+#define APIC_LOCAL_SAPIC        7
+#define APIC_XRUPT_SOURCE       8
+#define APIC_RESERVED           9           /* 9 and greater are reserved */
+
+#define ACPI_SUB_HEADER_DEF                 /* Common ACPI sub-structure header */\
+	uint8_t                              type; \
+	uint8_t                              length;
+
+/*
+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ */
+/* Sub-structures for MADT */
+
+struct madt_processor_apic
+{
+	ACPI_SUB_HEADER_DEF
+	uint8_t                              processor_id;           /* ACPI processor id */
+	uint8_t                              local_apic_id;          /* Processor's local APIC id */
+#if 0
+	uint32_t                             processor_enabled: 1;   /* Processor is usable if set */
+	uint32_t                             reserved2       : 31;   /* Reserved, must be zero */
+#else
+        uint32_t flags;
+#endif
+} __attribute__((__packed__));
+
+/*
+ * SRAT (NUMA topology description) table
+ */
+
+#define SRAT_PROCESSOR          0
+#define SRAT_MEMORY             1
+
+struct system_resource_affinity_table
+{
+    ACPI_TABLE_HEADER_DEF
+    uint32_t    reserved1;
+    uint32_t    reserved2[2];
+};
+
+struct srat_processor_affinity
+{
+    ACPI_SUB_HEADER_DEF
+    uint8_t     proximity_lo;
+    uint8_t     local_apic_id;
+    uint32_t    flags;
+    uint8_t     local_sapic_eid;
+    uint8_t     proximity_hi[3];
+    uint32_t    reserved;
+};
+
+struct srat_memory_affinity
+{
+    ACPI_SUB_HEADER_DEF
+    uint8_t     proximity[4];
+    uint16_t    reserved1;
+    uint32_t    base_addr_low,base_addr_high;
+    uint32_t    length_low,length_high;
+    uint32_t    reserved2;
+    uint32_t    flags;
+    uint32_t    reserved3[2];
+};
+
+#ifdef BX_QEMU
+/*
+ *  * ACPI 2.0 Generic Address Space definition.
+ *   */
+struct acpi_20_generic_address {
+    uint8_t  address_space_id;
+    uint8_t  register_bit_width;
+    uint8_t  register_bit_offset;
+    uint8_t  reserved;
+    uint64_t address;
+} __attribute__((__packed__));
+
+/*
+ *  HPET Description Table
+ */
+struct acpi_20_hpet {
+    ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
+    uint32_t           timer_block_id;
+    struct acpi_20_generic_address addr;
+    uint8_t            hpet_number;
+    uint16_t           min_tick;
+    uint8_t            page_protect;
+} __attribute__((__packed__));
+#define ACPI_HPET_ADDRESS 0xFED00000UL
+#endif
+
+struct madt_io_apic
+{
+	ACPI_SUB_HEADER_DEF
+	uint8_t                              io_apic_id;             /* I/O APIC ID */
+	uint8_t                              reserved;               /* Reserved - must be zero */
+	uint32_t                             address;                /* APIC physical address */
+	uint32_t                             interrupt;              /* Global system interrupt where INTI
+			  * lines start */
+} __attribute__((__packed__));
+
+#ifdef BX_QEMU
+struct madt_int_override
+{
+	ACPI_SUB_HEADER_DEF
+	uint8_t                bus;     /* Identifies ISA Bus */
+	uint8_t                source;  /* Bus-relative interrupt source */
+	uint32_t               gsi;     /* GSI that source will signal */
+	uint16_t               flags;   /* MPS INTI flags */
+} __attribute__((__packed__));
+#endif
+
+#include "acpi-dsdt.hex"
+#include "acpi-ssdt.hex"
+
+static inline uint16_t cpu_to_le16(uint16_t x)
+{
+    return x;
+}
+
+static inline uint32_t cpu_to_le32(uint32_t x)
+{
+    return x;
+}
+
+static int acpi_checksum(const uint8_t *data, int len)
+{
+    int sum, i;
+    sum = 0;
+    for(i = 0; i < len; i++)
+        sum += data[i];
+    return (-sum) & 0xff;
+}
+
+static void acpi_build_table_header(struct acpi_table_header *h,
+                                    char *sig, int len, uint8_t rev)
+{
+    memcpy(h->signature, sig, 4);
+    h->length = cpu_to_le32(len);
+    h->revision = rev;
+#ifdef BX_QEMU
+    memcpy(h->oem_id, "QEMU  ", 6);
+    memcpy(h->oem_table_id, "QEMU", 4);
+#else
+    memcpy(h->oem_id, "BOCHS ", 6);
+    memcpy(h->oem_table_id, "BXPC", 4);
+#endif
+    memcpy(h->oem_table_id + 4, sig, 4);
+    h->oem_revision = cpu_to_le32(1);
+#ifdef BX_QEMU
+    memcpy(h->asl_compiler_id, "QEMU", 4);
+#else
+    memcpy(h->asl_compiler_id, "BXPC", 4);
+#endif
+    h->asl_compiler_revision = cpu_to_le32(1);
+    h->checksum = acpi_checksum((void *)h, len);
+}
+
+static void acpi_build_srat_memory(struct srat_memory_affinity *numamem,
+    uint64_t base, uint64_t len, int node, int enabled)
+{
+     numamem->type = SRAT_MEMORY;
+     numamem->length = sizeof(*numamem);
+     memset (numamem->proximity, 0 ,4);
+     numamem->proximity[0] = node;
+     numamem->flags = cpu_to_le32(!!enabled);
+     numamem->base_addr_low = base & 0xFFFFFFFF;
+     numamem->base_addr_high = base >> 32;
+     numamem->length_low = len & 0xFFFFFFFF;
+     numamem->length_high = len >> 32;
+     return;
+}
+
+/* base_addr must be a multiple of 4KB */
+void acpi_bios_init(void)
+{
+    struct rsdp_descriptor *rsdp;
+    struct rsdt_descriptor_rev1 *rsdt;
+    struct fadt_descriptor_rev1 *fadt;
+    struct facs_descriptor_rev1 *facs;
+    struct multiple_apic_table *madt;
+    uint8_t *dsdt, *ssdt;
+#ifdef BX_QEMU
+    struct system_resource_affinity_table *srat;
+    struct acpi_20_hpet *hpet;
+    uint32_t hpet_addr;
+#endif
+    uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
+    uint32_t acpi_tables_size, madt_addr, madt_size, rsdt_size, madt_end, rsdt_end;
+    uint32_t srat_addr,srat_size;
+    uint16_t i, external_tables;
+    int nb_numa_nodes;
+    int nb_rsdt_entries = 0;
+
+    /* reserve memory space for tables */
+#ifdef BX_USE_EBDA_TABLES
+    ebda_cur_addr = align(ebda_cur_addr, 16);
+    rsdp = (void *)(ebda_cur_addr);
+    ebda_cur_addr += sizeof(*rsdp);
+#else
+    bios_table_cur_addr = align(bios_table_cur_addr, 16);
+    rsdp = (void *)(bios_table_cur_addr);
+    bios_table_cur_addr += sizeof(*rsdp);
+#endif
+
+#ifdef BX_QEMU
+    external_tables = acpi_additional_tables();
+#else
+    external_tables = 0;
+#endif
+
+    addr = base_addr = ram_size - ACPI_DATA_SIZE;
+    rsdt_addr = addr;
+    rsdt = (void *)(addr);
+    rsdt_size = sizeof(*rsdt);
+    addr += rsdt_size;
+
+    fadt_addr = addr;
+    fadt = (void *)(addr);
+    addr += sizeof(*fadt);
+
+    /* XXX: FACS should be in RAM */
+    addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
+    facs_addr = addr;
+    facs = (void *)(addr);
+    addr += sizeof(*facs);
+
+    dsdt_addr = addr;
+    dsdt = (void *)(addr);
+    addr += sizeof(DSDTCode);
+
+    ssdt_addr = addr;
+    ssdt = (void *)(addr);
+    addr += sizeof(SSDTCode);
+
+#ifdef BX_QEMU
+    qemu_cfg_select(QEMU_CFG_NUMA);
+    nb_numa_nodes = qemu_cfg_get64();
+#else
+    nb_numa_nodes = 0;
+#endif
+    if (nb_numa_nodes > 0) {
+        addr = (addr + 7) & ~7;
+        srat_addr = addr;
+        srat_size = sizeof(*srat) +
+            sizeof(struct srat_processor_affinity) * smp_cpus +
+            sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+        srat = (void *)(addr);
+        addr += srat_size;
+    } else {
+        srat_addr = addr;
+        srat = (void*)(addr);
+        srat_size = 0;
+    }
+
+    addr = (addr + 7) & ~7;
+    madt_addr = addr;
+    madt_size = sizeof(*madt) +
+        sizeof(struct madt_processor_apic) * MAX_CPUS +
+#ifdef BX_QEMU
+        sizeof(struct madt_io_apic)  + sizeof(struct madt_int_override) * MAX_INT_OVERRIDES;
+#else
+        sizeof(struct madt_io_apic);
+#endif
+    madt = (void *)(addr);
+    addr += madt_size;
+
+#ifdef BX_QEMU
+    addr = (addr + 7) & ~7;
+    hpet_addr = addr;
+    hpet = (void *)(addr);
+    addr += sizeof(*hpet);
+#endif
+
+    /* RSDP */
+    memset(rsdp, 0, sizeof(*rsdp));
+    memcpy(rsdp->signature, "RSD PTR ", 8);
+#ifdef BX_QEMU
+    memcpy(rsdp->oem_id, "QEMU  ", 6);
+#else
+    memcpy(rsdp->oem_id, "BOCHS ", 6);
+#endif
+    rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
+    rsdp->checksum = acpi_checksum((void *)rsdp, 20);
+
+    /* FADT */
+    memset(fadt, 0, sizeof(*fadt));
+    fadt->firmware_ctrl = cpu_to_le32(facs_addr);
+    fadt->dsdt = cpu_to_le32(dsdt_addr);
+    fadt->model = 1;
+    fadt->reserved1 = 0;
+    fadt->sci_int = cpu_to_le16(pm_sci_int);
+    fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
+    fadt->acpi_enable = 0xf1;
+    fadt->acpi_disable = 0xf0;
+    fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
+    fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
+    fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
+    fadt->pm1_evt_len = 4;
+    fadt->pm1_cnt_len = 2;
+    fadt->pm_tmr_len = 4;
+    fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+    fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+    fadt->gpe0_blk = cpu_to_le32(0xafe0);
+    fadt->gpe0_blk_len = 4;
+    /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC */
+    fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6));
+    acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
+                            sizeof(*fadt), 1);
+
+    /* FACS */
+    memset(facs, 0, sizeof(*facs));
+    memcpy(facs->signature, "FACS", 4);
+    facs->length = cpu_to_le32(sizeof(*facs));
+    BX_INFO("Firmware waking vector %p\n", &facs->firmware_waking_vector);
+
+    /* DSDT */
+    memcpy(dsdt, DSDTCode, sizeof(DSDTCode));
+
+    /* SSDT */
+    memcpy(ssdt, SSDTCode, sizeof(SSDTCode));
+
+    /* MADT */
+    {
+        struct madt_processor_apic *apic;
+        struct madt_io_apic *io_apic;
+#ifdef BX_QEMU
+        struct madt_int_override *int_override;
+#endif
+
+        memset(madt, 0, madt_size);
+        madt->local_apic_address = cpu_to_le32(0xfee00000);
+        madt->flags = cpu_to_le32(1);
+        *(uint32_t*)APIC_MADT_PTR = apic = (void *)(madt + 1);
+        for(i=0;i<MAX_CPUS;i++) {
+            apic->type = APIC_PROCESSOR;
+            apic->length = sizeof(*apic);
+            apic->processor_id = i;
+            apic->local_apic_id = i;
+            if (i < smp_cpus)
+                apic->flags = cpu_to_le32(1);
+            else
+                apic->flags = 0;
+            apic++;
+        }
+        io_apic = (void *)apic;
+        io_apic->type = APIC_IO;
+        io_apic->length = sizeof(*io_apic);
+        io_apic->io_apic_id = smp_cpus;
+        io_apic->address = cpu_to_le32(0xfec00000);
+        io_apic->interrupt = cpu_to_le32(0);
+        io_apic++;
+        int_override = (struct madt_int_override*)(io_apic);
+#ifdef BX_QEMU
+        if (irq0_override) {
+            memset(int_override, 0, sizeof(*int_override));
+            int_override->type = APIC_XRUPT_OVERRIDE;
+            int_override->length = sizeof(*int_override);
+            int_override->source = 0;
+            int_override->gsi = 2;
+            int_override->flags = 0; /* conforms to bus specifications */
+            int_override++;
+        }
+#endif
+        for (i = 0; i < 16; i++) {
+            if (PCI_ISA_IRQ_MASK & (1U << i)) {
+                memset(int_override, 0, sizeof(*int_override));
+                int_override->type   = APIC_XRUPT_OVERRIDE;
+                int_override->length = sizeof(*int_override);
+                int_override->source = i;
+                int_override->gsi    = i;
+                int_override->flags  = 0xd; /* active high, level triggered */
+            } else {
+                /* No need for a INT source override structure. */
+                continue;
+            }
+            int_override++;
+        }
+        madt_end = (uint32_t)int_override;
+        madt_size = madt_end - madt_addr;
+        acpi_build_table_header((struct acpi_table_header *)madt,
+                                "APIC", madt_size, 1);
+    }
+
+    memset(rsdt, 0, rsdt_size);
+#ifdef BX_QEMU
+    /* SRAT */
+    if (nb_numa_nodes > 0) {
+        struct srat_processor_affinity *core;
+        struct srat_memory_affinity *numamem;
+        int slots;
+        uint64_t mem_len, mem_base, next_base = 0, curnode;
+
+        qemu_cfg_select(QEMU_CFG_NUMA);
+        qemu_cfg_get64();
+        memset (srat, 0 , srat_size);
+        srat->reserved1=1;
+ 
+        core = (void*)(srat + 1);
+        for (i = 0; i < smp_cpus; ++i) {
+             core->type = SRAT_PROCESSOR;
+             core->length = sizeof(*core);
+             core->local_apic_id = i;
+             curnode = qemu_cfg_get64();
+             core->proximity_lo = curnode;
+             memset (core->proximity_hi, 0, 3);
+             core->local_sapic_eid = 0;
+             if (i < smp_cpus)
+                 core->flags = cpu_to_le32(1);
+             else
+                 core->flags = 0;
+             core++;
+        }
+
+        /* the memory map is a bit tricky, it contains at least one hole
+         * from 640k-1M and possibly another one from 3.5G-4G.
+         */
+        numamem = (void*)core; slots = 0;
+        acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
+        next_base = 1024 * 1024; numamem++;slots++;
+        for (i = 1; i < nb_numa_nodes + 1; ++i) {
+            mem_base = next_base;
+            mem_len = qemu_cfg_get64();
+            if (i == 1) mem_len -= 1024 * 1024;
+            next_base = mem_base + mem_len;
+ 
+            /* Cut out the PCI hole */
+            if (mem_base <= ram_size && next_base > ram_size) {
+                mem_len -= next_base - ram_size;
+                if (mem_len > 0) {
+                    acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+                    numamem++; slots++;
+                }
+                mem_base = 1ULL << 32;
+                mem_len = next_base - ram_size;
+                next_base += (1ULL << 32) - ram_size;
+            }
+            acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+            numamem++; slots++;
+        }
+        for (; slots < nb_numa_nodes + 2; slots++) {
+            acpi_build_srat_memory(numamem, 0, 0, 0, 0);
+            numamem++;
+        }
+
+         acpi_build_table_header((struct acpi_table_header *)srat,
+                                "SRAT", srat_size, 1);
+    }
+
+    /* HPET */
+    memset(hpet, 0, sizeof(*hpet));
+    /* Note timer_block_id value must be kept in sync with value advertised by
+     * emulated hpet
+     */
+    hpet->timer_block_id = cpu_to_le32(0x8086a201);
+    hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS);
+    acpi_build_table_header((struct  acpi_table_header *)hpet,
+                             "HPET", sizeof(*hpet), 1);
+
+#endif
+
+    /* RSDT */
+    rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(fadt_addr);
+    /* On real hardware the SSDT seems to come before the MADT (APIC) */
+    rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(ssdt_addr);
+    rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(madt_addr);
+#ifdef BX_QEMU
+    rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(hpet_addr);
+    if (nb_numa_nodes > 0)
+        rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(srat_addr);
+    acpi_additional_tables(); /* resets cfg to required entry */
+    for(i = 0; i < external_tables; i++) {
+        uint16_t len;
+        if(acpi_load_table(i, addr, &len) < 0)
+            BX_PANIC("Failed to load ACPI table from QEMU\n");
+        rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(addr);
+        addr += len;
+        if ((addr >= ram_size) || (nb_rsdt_entries > MAX_RSDT_ENTRIES))
+            BX_PANIC("ACPI table overflow\n");
+    }
+#endif
+    rsdt_end = (uint32_t)(&rsdt->table_offset_entry[nb_rsdt_entries]);
+    rsdt_size = rsdt_end - rsdt_addr;
+    acpi_build_table_header((struct acpi_table_header *)rsdt, "RSDT",
+                            rsdt_size, 1);
+
+    acpi_tables_size = addr - base_addr;
+
+    BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
+            (unsigned long)rsdp,
+            (unsigned long)rsdt, acpi_tables_size);
+
+}
+
+/* SMBIOS entry point -- must be written to a 16-bit aligned address
+   between 0xf0000 and 0xfffff.
+ */
+struct smbios_entry_point {
+	char anchor_string[4];
+	uint8_t checksum;
+	uint8_t length;
+	uint8_t smbios_major_version;
+	uint8_t smbios_minor_version;
+	uint16_t max_structure_size;
+	uint8_t entry_point_revision;
+	uint8_t formatted_area[5];
+	char intermediate_anchor_string[5];
+	uint8_t intermediate_checksum;
+	uint16_t structure_table_length;
+	uint32_t structure_table_address;
+	uint16_t number_of_structures;
+	uint8_t smbios_bcd_revision;
+} __attribute__((__packed__));
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+	uint8_t type;
+	uint8_t length;
+	uint16_t handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+	struct smbios_structure_header header;
+	uint8_t vendor_str;
+	uint8_t bios_version_str;
+	uint16_t bios_starting_address_segment;
+	uint8_t bios_release_date_str;
+	uint8_t bios_rom_size;
+	uint8_t bios_characteristics[8];
+	uint8_t bios_characteristics_extension_bytes[2];
+	uint8_t system_bios_major_release;
+	uint8_t system_bios_minor_release;
+	uint8_t embedded_controller_major_release;
+	uint8_t embedded_controller_minor_release;
+} __attribute__((__packed__));
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+	struct smbios_structure_header header;
+	uint8_t manufacturer_str;
+	uint8_t product_name_str;
+	uint8_t version_str;
+	uint8_t serial_number_str;
+	uint8_t uuid[16];
+	uint8_t wake_up_type;
+	uint8_t sku_number_str;
+	uint8_t family_str;
+} __attribute__((__packed__));
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+	struct smbios_structure_header header;
+	uint8_t manufacturer_str;
+	uint8_t type;
+	uint8_t version_str;
+	uint8_t serial_number_str;
+	uint8_t asset_tag_number_str;
+	uint8_t boot_up_state;
+	uint8_t power_supply_state;
+	uint8_t thermal_state;
+	uint8_t security_status;
+    uint32_t oem_defined;
+    uint8_t height;
+    uint8_t number_of_power_cords;
+    uint8_t contained_element_count;
+    // contained elements follow
+} __attribute__((__packed__));
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+	struct smbios_structure_header header;
+	uint8_t socket_designation_str;
+	uint8_t processor_type;
+	uint8_t processor_family;
+	uint8_t processor_manufacturer_str;
+	uint32_t processor_id[2];
+	uint8_t processor_version_str;
+	uint8_t voltage;
+	uint16_t external_clock;
+	uint16_t max_speed;
+	uint16_t current_speed;
+	uint8_t status;
+	uint8_t processor_upgrade;
+        uint16_t l1_cache_handle;
+        uint16_t l2_cache_handle;
+        uint16_t l3_cache_handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 16 - Physical Memory Array
+ *   Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+	struct smbios_structure_header header;
+	uint8_t location;
+	uint8_t use;
+	uint8_t error_correction;
+	uint32_t maximum_capacity;
+	uint16_t memory_error_information_handle;
+	uint16_t number_of_memory_devices;
+} __attribute__((__packed__));
+
+/* SMBIOS type 17 - Memory Device
+ *   Associated with one type 19
+ */
+struct smbios_type_17 {
+	struct smbios_structure_header header;
+	uint16_t physical_memory_array_handle;
+	uint16_t memory_error_information_handle;
+	uint16_t total_width;
+	uint16_t data_width;
+	uint16_t size;
+	uint8_t form_factor;
+	uint8_t device_set;
+	uint8_t device_locator_str;
+	uint8_t bank_locator_str;
+	uint8_t memory_type;
+	uint16_t type_detail;
+} __attribute__((__packed__));
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+	struct smbios_structure_header header;
+	uint32_t starting_address;
+	uint32_t ending_address;
+	uint16_t memory_array_handle;
+	uint8_t partition_width;
+} __attribute__((__packed__));
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+	struct smbios_structure_header header;
+	uint32_t starting_address;
+	uint32_t ending_address;
+	uint16_t memory_device_handle;
+	uint16_t memory_array_mapped_address_handle;
+	uint8_t partition_row_position;
+	uint8_t interleave_position;
+	uint8_t interleaved_data_depth;
+} __attribute__((__packed__));
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+	struct smbios_structure_header header;
+	uint8_t reserved[6];
+	uint8_t boot_status;
+} __attribute__((__packed__));
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+	struct smbios_structure_header header;
+} __attribute__((__packed__));
+
+static void
+smbios_entry_point_init(void *start,
+                        uint16_t max_structure_size,
+                        uint16_t structure_table_length,
+                        uint32_t structure_table_address,
+                        uint16_t number_of_structures)
+{
+    uint8_t sum;
+    int i;
+    struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
+
+    memcpy(ep->anchor_string, "_SM_", 4);
+    ep->length = 0x1f;
+    ep->smbios_major_version = 2;
+    ep->smbios_minor_version = 4;
+    ep->max_structure_size = max_structure_size;
+    ep->entry_point_revision = 0;
+    memset(ep->formatted_area, 0, 5);
+    memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
+
+    ep->structure_table_length = structure_table_length;
+    ep->structure_table_address = structure_table_address;
+    ep->number_of_structures = number_of_structures;
+    ep->smbios_bcd_revision = 0x24;
+
+    ep->checksum = 0;
+    ep->intermediate_checksum = 0;
+
+    sum = 0;
+    for (i = 0; i < 0x10; i++)
+        sum += ((int8_t *)start)[i];
+    ep->checksum = -sum;
+
+    sum = 0;
+    for (i = 0x10; i < ep->length; i++)
+        sum += ((int8_t *)start)[i];
+    ep->intermediate_checksum = -sum;
+    }
+
+struct smbios_header {
+    uint16_t length;
+    uint8_t type;
+} __attribute__((__packed__));
+
+struct smbios_field {
+    struct smbios_header header;
+    uint8_t type;
+    uint16_t offset;
+    uint8_t data[];
+} __attribute__((__packed__));
+
+struct smbios_table {
+    struct smbios_header header;
+    uint8_t data[];
+} __attribute__((__packed__));
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+static size_t
+smbios_load_field(int type, size_t offset, void *addr)
+{
+#ifdef BX_QEMU
+    int i;
+
+    for (i = smbios_entries(); i > 0; i--) {
+        struct smbios_field field;
+
+        qemu_cfg_read((uint8_t *)&field, sizeof(struct smbios_header));
+        field.header.length -= sizeof(struct smbios_header);
+
+        if (field.header.type != SMBIOS_FIELD_ENTRY) {
+            while (field.header.length--)
+                inb(QEMU_CFG_DATA_PORT);
+            continue;
+        }
+
+        qemu_cfg_read((uint8_t *)&field.type,
+                      sizeof(field) - sizeof(struct smbios_header));
+        field.header.length -= sizeof(field) - sizeof(struct smbios_header);
+
+        if (field.type != type || field.offset != offset) {
+            while (field.header.length--)
+                inb(QEMU_CFG_DATA_PORT);
+            continue;
+        }
+
+        qemu_cfg_read(addr, field.header.length);
+        return (size_t)field.header.length;
+    }
+#endif
+    return 0;
+}
+ 
+#define load_str_field_with_default(type, field, def) do {             \
+    size = smbios_load_field(type, offsetof(struct smbios_type_##type, \
+                                            field), end);              \
+    if (size > 0) {                                                    \
+        end += size;                                                   \
+    } else {                                                           \
+        memcpy(end, def, sizeof(def));                                 \
+        end += sizeof(def);                                            \
+    }                                                                  \
+    p->field = ++str_index;                                            \
+} while (0)
+
+#define load_str_field_or_skip(type, field) do {                       \
+    size = smbios_load_field(type, offsetof(struct smbios_type_##type, \
+                                            field), end);              \
+    if (size > 0) {                                                    \
+        end += size;                                                   \
+        p->field = ++str_index;                                        \
+    } else {                                                           \
+        p->field = 0;                                                  \
+    }                                                                  \
+} while (0)
+
+/* Type 0 -- BIOS Information */
+#define RELEASE_DATE_STR "01/01/2007"
+static void *
+smbios_init_type_0(void *start)
+{
+    struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_0);
+    size_t size;
+    int str_index = 0;
+
+    p->header.type = 0;
+    p->header.length = sizeof(struct smbios_type_0);
+    p->header.handle = 0;
+
+    load_str_field_with_default(0, vendor_str, BX_APPNAME);
+    load_str_field_with_default(0, bios_version_str, BX_APPNAME);
+
+    p->bios_starting_address_segment = 0xe800;
+
+    load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR);
+
+    p->bios_rom_size = 0; /* FIXME */
+
+    memset(p->bios_characteristics, 0, 8);
+    p->bios_characteristics[0] = 0x08; /* BIOS characteristics not supported */
+    p->bios_characteristics_extension_bytes[0] = 0;
+    p->bios_characteristics_extension_bytes[1] = 0;
+
+    if (!smbios_load_field(0, offsetof(struct smbios_type_0,
+                                       system_bios_major_release),
+                           &p->system_bios_major_release))
+        p->system_bios_major_release = 1;
+
+    if (!smbios_load_field(0, offsetof(struct smbios_type_0,
+                                       system_bios_minor_release),
+                           &p->system_bios_minor_release))
+        p->system_bios_minor_release = 0;
+
+    p->embedded_controller_major_release = 0xff;
+    p->embedded_controller_minor_release = 0xff;
+
+    *end = 0;
+    end++;
+
+    return end;
+}
+
+/* Type 1 -- System Information */
+static void *
+smbios_init_type_1(void *start)
+{
+    struct smbios_type_1 *p = (struct smbios_type_1 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_1);
+    size_t size;
+    int str_index = 0;
+
+    p->header.type = 1;
+    p->header.length = sizeof(struct smbios_type_1);
+    p->header.handle = 0x100;
+
+    load_str_field_or_skip(1, manufacturer_str);
+    load_str_field_or_skip(1, product_name_str);
+    load_str_field_or_skip(1, version_str);
+    load_str_field_or_skip(1, serial_number_str);
+
+    size = smbios_load_field(1, offsetof(struct smbios_type_1,
+                                         uuid), &p->uuid);
+    if (size == 0)
+        memset(p->uuid, 0, 16);
+
+    p->wake_up_type = 0x06; /* power switch */
+
+    load_str_field_or_skip(1, sku_number_str);
+    load_str_field_or_skip(1, family_str);
+
+    *end = 0;
+    end++;
+    if (!str_index) {
+        *end = 0;
+        end++;
+    }
+
+    return end;
+}
+
+/* Type 3 -- System Enclosure */
+static void *
+smbios_init_type_3(void *start)
+{
+    struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+
+    p->header.type = 3;
+    p->header.length = sizeof(struct smbios_type_3);
+    p->header.handle = 0x300;
+
+    p->manufacturer_str = 0;
+    p->type = 0x01; /* other */
+    p->version_str = 0;
+    p->serial_number_str = 0;
+    p->asset_tag_number_str = 0;
+    p->boot_up_state = 0x03; /* safe */
+    p->power_supply_state = 0x03; /* safe */
+    p->thermal_state = 0x03; /* safe */
+    p->security_status = 0x02; /* unknown */
+    p->oem_defined = 0;
+    p->height = 0;
+    p->number_of_power_cords = 0;
+    p->contained_element_count = 0;
+
+    start += sizeof(struct smbios_type_3);
+    *((uint16_t *)start) = 0;
+
+    return start+2;
+}
+
+/* Type 4 -- Processor Information */
+static void *
+smbios_init_type_4(void *start, unsigned int cpu_number)
+{
+    struct smbios_type_4 *p = (struct smbios_type_4 *)start;
+
+    p->header.type = 4;
+    p->header.length = sizeof(struct smbios_type_4);
+    p->header.handle = 0x400 + cpu_number;
+
+    p->socket_designation_str = 1;
+    p->processor_type = 0x03; /* CPU */
+    p->processor_family = 0x01; /* other */
+    p->processor_manufacturer_str = 0;
+
+    p->processor_id[0] = cpuid_signature;
+    p->processor_id[1] = cpuid_features;
+
+    p->processor_version_str = 0;
+    p->voltage = 0;
+    p->external_clock = 0;
+
+    p->max_speed = 0; /* unknown */
+    p->current_speed = 0; /* unknown */
+
+    p->status = 0x41; /* socket populated, CPU enabled */
+    p->processor_upgrade = 0x01; /* other */
+
+    p->l1_cache_handle = 0xffff; /* cache information structure not provided */
+    p->l2_cache_handle = 0xffff;
+    p->l3_cache_handle = 0xffff;
+
+    start += sizeof(struct smbios_type_4);
+
+    memcpy((char *)start, "CPU  " "\0" "" "\0" "", 7);
+	((char *)start)[4] = cpu_number + '0';
+
+    return start+7;
+}
+
+/* Type 16 -- Physical Memory Array */
+static void *
+smbios_init_type_16(void *start, uint32_t memsize, int nr_mem_devs)
+{
+    struct smbios_type_16 *p = (struct smbios_type_16*)start;
+
+    p->header.type = 16;
+    p->header.length = sizeof(struct smbios_type_16);
+    p->header.handle = 0x1000;
+
+    p->location = 0x01; /* other */
+    p->use = 0x03; /* system memory */
+    p->error_correction = 0x01; /* other */
+    p->maximum_capacity = memsize * 1024;
+    p->memory_error_information_handle = 0xfffe; /* none provided */
+    p->number_of_memory_devices = nr_mem_devs;
+
+    start += sizeof(struct smbios_type_16);
+    *((uint16_t *)start) = 0;
+
+    return start + 2;
+}
+
+/* Type 17 -- Memory Device */
+static void *
+smbios_init_type_17(void *start, uint32_t memory_size_mb, int instance)
+{
+    struct smbios_type_17 *p = (struct smbios_type_17 *)start;
+
+    p->header.type = 17;
+    p->header.length = sizeof(struct smbios_type_17);
+    p->header.handle = 0x1100 + instance;
+
+    p->physical_memory_array_handle = 0x1000;
+    p->total_width = 64;
+    p->data_width = 64;
+/* TODO: should assert in case something is wrong   ASSERT((memory_size_mb & ~0x7fff) == 0); */
+    p->size = memory_size_mb;
+    p->form_factor = 0x09; /* DIMM */
+    p->device_set = 0;
+    p->device_locator_str = 1;
+    p->bank_locator_str = 0;
+    p->memory_type = 0x07; /* RAM */
+    p->type_detail = 0;
+
+    start += sizeof(struct smbios_type_17);
+    snprintf(start, 8, "DIMM %d", instance);
+    start += strlen(start) + 1;
+    *((uint8_t *)start) = 0;
+
+    return start+1;
+}
+
+/* Type 19 -- Memory Array Mapped Address */
+static void *
+smbios_init_type_19(void *start, uint32_t memory_size_mb, int instance)
+{
+    struct smbios_type_19 *p = (struct smbios_type_19 *)start;
+
+    p->header.type = 19;
+    p->header.length = sizeof(struct smbios_type_19);
+    p->header.handle = 0x1300 + instance;
+
+    p->starting_address = instance << 24;
+    p->ending_address = p->starting_address + (memory_size_mb << 10) - 1;
+    p->memory_array_handle = 0x1000;
+    p->partition_width = 1;
+
+    start += sizeof(struct smbios_type_19);
+    *((uint16_t *)start) = 0;
+
+    return start + 2;
+}
+
+/* Type 20 -- Memory Device Mapped Address */
+static void *
+smbios_init_type_20(void *start, uint32_t memory_size_mb, int instance)
+{
+    struct smbios_type_20 *p = (struct smbios_type_20 *)start;
+
+    p->header.type = 20;
+    p->header.length = sizeof(struct smbios_type_20);
+    p->header.handle = 0x1400 + instance;
+
+    p->starting_address = instance << 24;
+    p->ending_address = p->starting_address + (memory_size_mb << 10) - 1;
+    p->memory_device_handle = 0x1100 + instance;
+    p->memory_array_mapped_address_handle = 0x1300 + instance;
+    p->partition_row_position = 1;
+    p->interleave_position = 0;
+    p->interleaved_data_depth = 0;
+
+    start += sizeof(struct smbios_type_20);
+
+    *((uint16_t *)start) = 0;
+    return start+2;
+}
+
+/* Type 32 -- System Boot Information */
+static void *
+smbios_init_type_32(void *start)
+{
+    struct smbios_type_32 *p = (struct smbios_type_32 *)start;
+
+    p->header.type = 32;
+    p->header.length = sizeof(struct smbios_type_32);
+    p->header.handle = 0x2000;
+    memset(p->reserved, 0, 6);
+    p->boot_status = 0; /* no errors detected */
+
+    start += sizeof(struct smbios_type_32);
+    *((uint16_t *)start) = 0;
+
+    return start+2;
+}
+
+/* Type 127 -- End of Table */
+static void *
+smbios_init_type_127(void *start)
+{
+    struct smbios_type_127 *p = (struct smbios_type_127 *)start;
+
+    p->header.type = 127;
+    p->header.length = sizeof(struct smbios_type_127);
+    p->header.handle = 0x7f00;
+
+    start += sizeof(struct smbios_type_127);
+    *((uint16_t *)start) = 0;
+
+    return start + 2;
+}
+
+static int
+smbios_load_external(int type, char **p, unsigned *nr_structs,
+                     unsigned *max_struct_size)
+{
+#ifdef BX_QEMU
+    static uint64_t used_bitmap[4] = { 0 };
+    char *start = *p;
+    int i;
+
+    /* Check if we've already reported these tables */
+    if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
+        return 1;
+
+    /* Don't introduce spurious end markers */
+    if (type == 127)
+        return 0;
+
+    for (i = smbios_entries(); i > 0; i--) {
+        struct smbios_table table;
+        struct smbios_structure_header *header = (void *)*p;
+        int string;
+
+        qemu_cfg_read((uint8_t *)&table, sizeof(struct smbios_header));
+        table.header.length -= sizeof(struct smbios_header);
+
+        if (table.header.type != SMBIOS_TABLE_ENTRY) {
+            while (table.header.length--)
+                inb(QEMU_CFG_DATA_PORT);
+            continue;
+        }
+
+        qemu_cfg_read((uint8_t *)*p, sizeof(struct smbios_structure_header));
+        table.header.length -= sizeof(struct smbios_structure_header);
+
+        if (header->type != type) {
+            while (table.header.length--)
+                inb(QEMU_CFG_DATA_PORT);
+            continue;
+        }
+
+        *p += sizeof(struct smbios_structure_header);
+
+        /* Entries end with a double NULL char, if there's a string at
+         * the end (length is greater than formatted length), the string
+         * terminator provides the first NULL. */
+        string = header->length < table.header.length +
+                 sizeof(struct smbios_structure_header);
+
+        /* Read the rest and terminate the entry */
+        qemu_cfg_read((uint8_t *)*p, table.header.length);
+        *p += table.header.length;
+        *((uint8_t*)*p) = 0;
+        (*p)++;
+        if (!string) {
+            *((uint8_t*)*p) = 0;
+            (*p)++;
+        }
+
+        (*nr_structs)++;
+        if (*p - (char *)header > *max_struct_size)
+            *max_struct_size = *p - (char *)header;
+    }
+
+    if (start != *p) {
+        /* Mark that we've reported on this type */
+        used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+        return 1;
+    }
+
+#endif /* !BX_QEMU */
+    return 0;
+}
+
+void smbios_init(void)
+{
+    unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
+    char *start, *p, *q;
+    int memsize = (ram_end == ram_size) ? ram_size / (1024 * 1024) :
+                  (ram_end - (1ull << 32) + ram_size) / (1024 * 1024);
+    int i, nr_mem_devs;
+
+#ifdef BX_USE_EBDA_TABLES
+    ebda_cur_addr = align(ebda_cur_addr, 16);
+    start = (void *)(ebda_cur_addr);
+#else
+    bios_table_cur_addr = align(bios_table_cur_addr, 16);
+    start = (void *)(bios_table_cur_addr);
+#endif
+
+	p = (char *)start + sizeof(struct smbios_entry_point);
+
+#define add_struct(type, args...) do {                                    \
+    if (!smbios_load_external(type, &p, &nr_structs, &max_struct_size)) { \
+        q = smbios_init_type_##type(args);                                \
+        nr_structs++;                                                     \
+        if ((q - p) > max_struct_size)                                    \
+            max_struct_size = q - p;                                      \
+        p = q;                                                            \
+    }                                                                     \
+} while (0)
+
+    add_struct(0, p);
+    add_struct(1, p);
+    add_struct(3, p);
+    for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
+        add_struct(4, p, cpu_num);
+
+    /* Each 'memory device' covers up to 16GB of address space. */
+    nr_mem_devs = (memsize + 0x3fff) >> 14;
+    add_struct(16, p, memsize, nr_mem_devs);
+    for ( i = 0; i < nr_mem_devs; i++ )
+    {
+        uint32_t dev_memsize = ((i == (nr_mem_devs - 1))
+                                ? (((memsize-1) & 0x3fff)+1) : 0x4000);
+        add_struct(17, p, dev_memsize, i);
+        add_struct(19, p, dev_memsize, i);
+        add_struct(20, p, dev_memsize, i);
+    }
+
+    add_struct(32, p);
+    /* Add any remaining provided entries before the end marker */
+    for (i = 0; i < 256; i++)
+        smbios_load_external(i, &p, &nr_structs, &max_struct_size);
+    add_struct(127, p);
+
+#undef add_struct
+
+    smbios_entry_point_init(
+        start, max_struct_size,
+        (p - (char *)start) - sizeof(struct smbios_entry_point),
+        (uint32_t)(start + sizeof(struct smbios_entry_point)),
+        nr_structs);
+
+#ifdef BX_USE_EBDA_TABLES
+    ebda_cur_addr += (p - (char *)start);
+#else
+    bios_table_cur_addr += (p - (char *)start);
+#endif
+
+    BX_INFO("SMBIOS table addr=0x%08lx\n", (unsigned long)start);
+}
+
+static uint32_t find_resume_vector(void)
+{
+    unsigned long addr, start, end;
+
+#ifdef BX_USE_EBDA_TABLES
+    start = align(ebda_cur_addr, 16);
+    end = 0xa000 << 4;
+#else
+    if (bios_table_cur_addr == 0)
+        return 0;
+    start = align(bios_table_cur_addr, 16);
+    end = bios_table_end_addr;
+#endif
+
+    for (addr = start; addr < end; addr += 16) {
+        if (!memcmp((void*)addr, "RSD PTR ", 8)) {
+            struct rsdp_descriptor *rsdp = (void*)addr;
+            struct rsdt_descriptor_rev1 *rsdt = (void*)rsdp->rsdt_physical_address;
+            struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[0];
+            struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
+            return facs->firmware_waking_vector;
+        }
+    }
+
+    return 0;
+}
+
+static void find_440fx(PCIDevice *d)
+{
+    uint16_t vendor_id, device_id;
+
+    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+    device_id = pci_config_readw(d, PCI_DEVICE_ID);
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == PCI_DEVICE_ID_INTEL_82441)
+        i440_pcidev = *d;
+}
+
+static void reinit_piix4_pm(PCIDevice *d)
+{
+    uint16_t vendor_id, device_id;
+
+    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+    device_id = pci_config_readw(d, PCI_DEVICE_ID);
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == PCI_DEVICE_ID_INTEL_82371AB_3)
+        piix4_pm_enable(d);
+}
+
+void rombios32_init(uint32_t *s3_resume_vector, uint8_t *shutdown_flag)
+{
+    BX_INFO("Starting rombios32\n");
+    BX_INFO("Shutdown flag %x\n", *shutdown_flag);
+
+#ifdef BX_QEMU
+    qemu_cfg_port = qemu_cfg_port_probe();
+#endif
+
+    init_smp_msrs();
+
+    ram_probe();
+
+    cpu_probe();
+
+    setup_mtrr();
+
+    smp_probe();
+
+    find_bios_table_area();
+
+    if (*shutdown_flag == 0xfe) {
+        /* redirect bios read access to RAM */
+        pci_for_each_device(find_440fx);
+        bios_lock_shadow_ram(); /* bios is already copied */
+        *s3_resume_vector = find_resume_vector();
+        if (!*s3_resume_vector) {
+            BX_INFO("This is S3 resume but wakeup vector is NULL\n");
+        } else {
+            BX_INFO("S3 resume vector %p\n", *s3_resume_vector);
+            pci_for_each_device(reinit_piix4_pm);
+        }
+        return;
+    }
+
+    pci_bios_init();
+
+    if (bios_table_cur_addr != 0) {
+
+#ifdef BX_QEMU
+        irq0_override_probe();
+#endif
+        mptable_init();
+
+        smbios_init();
+
+        if (acpi_enabled)
+            acpi_bios_init();
+
+        bios_lock_shadow_ram();
+
+        BX_INFO("bios_table_cur_addr: 0x%08lx\n", bios_table_cur_addr);
+        if (bios_table_cur_addr > bios_table_end_addr)
+            BX_PANIC("bios_table_end_addr overflow!\n");
+#ifdef BX_USE_EBDA_TABLES
+        BX_INFO("ebda_cur_addr: 0x%08lx\n", ebda_cur_addr);
+        if (ebda_cur_addr > 0xA0000)
+            BX_PANIC("ebda_cur_addr overflow!\n");
+#endif
+    }
+}
diff --git a/kvm/bios/rombios32.ld b/kvm/bios/rombios32.ld
new file mode 100644
index 0000000..1fc99c3
--- /dev/null
+++ b/kvm/bios/rombios32.ld
@@ -0,0 +1,22 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start);
+SECTIONS
+{
+        . = 0x000e0000;
+        .text     : { *(.text)    }
+        .rodata    : { *(.rodata*) }
+        . = ALIGN(64);
+        fixup_start = .;
+        .fixup    : { *(.fixup) }
+        fixup_end = .;
+        . = ALIGN(4096);
+        _end = . ;
+        .data 0x700 : AT (_end) { __data_start = .; *(.data); __data_end = .;}
+        .bss      : { __bss_start = .; *(.bss) *(COMMON); __bss_end = .;}
+        /DISCARD/ : { *(.stab)
+                     *(.stabstr)
+                     *(.comment)
+                     *(.note)
+                  }
+}
diff --git a/kvm/bios/rombios32start.S b/kvm/bios/rombios32start.S
new file mode 100644
index 0000000..c9bc045
--- /dev/null
+++ b/kvm/bios/rombios32start.S
@@ -0,0 +1,119 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rombios32start.S,v 1.3 2006/10/02 06:29:38 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  32 bit Bochs BIOS init code
+//  Copyright (C) 2006 Fabrice Bellard
+//
+//  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 "rombios.h"
+
+.globl _start
+.globl smp_ap_boot_code_start
+.globl smp_ap_boot_code_end
+.global smm_relocation_start
+.global smm_relocation_end
+.global smm_code_start
+.global smm_code_end
+
+_start:
+  /* clear bss section */
+  xor %eax, %eax
+  mov $__bss_start, %edi
+  mov $__bss_end, %ecx
+  sub %edi, %ecx
+  rep stosb
+
+  /* copy data section */
+  mov $_end, %esi
+  mov $__data_start, %edi
+  mov $__data_end, %ecx
+  sub %edi, %ecx
+  rep movsb
+
+  jmp rombios32_init
+
+  .code16
+smp_ap_boot_code_start:
+  cli
+  xor %ax, %ax
+  mov %ax, %ds
+
+  mov $SMP_MSR_ADDR, %ebx
+11:
+  mov 0(%ebx), %ecx
+  test %ecx, %ecx
+  jz 12f
+  mov 4(%ebx), %eax
+  mov 8(%ebx), %edx
+  wrmsr
+  add $12, %ebx
+  jmp 11b
+12:
+
+  lock incw smp_cpus
+1:
+  hlt
+  jmp 1b
+smp_ap_boot_code_end:
+
+/* code to relocate SMBASE to 0xa0000 */
+smm_relocation_start:
+  mov $0x38000 + 0x7efc, %ebx
+  addr32 mov (%ebx), %al  /* revision ID to see if x86_64 or x86 */
+  cmp $0x64, %al
+  je 1f
+  mov $0x38000 + 0x7ef8, %ebx
+  jmp 2f
+1:
+  mov $0x38000 + 0x7f00, %ebx
+2:
+  movl $0xa0000, %eax
+  addr32 movl %eax, (%ebx)
+  /* indicate to the BIOS that the SMM code was executed */
+  mov $0x00, %al
+  movw $0xb3, %dx
+  outb %al, %dx
+  rsm
+smm_relocation_end:
+
+/* minimal SMM code to enable or disable ACPI */
+smm_code_start:
+  movw $0xb2, %dx
+  inb %dx, %al
+  cmp $0xf0, %al
+  jne 1f
+
+  /* ACPI disable */
+  mov $PM_IO_BASE + 0x04, %dx /* PMCNTRL */
+  inw %dx, %ax
+  andw $~1, %ax
+  outw %ax, %dx
+
+  jmp 2f
+
+1:
+  cmp $0xf1, %al
+  jne 2f
+
+  /* ACPI enable */
+  mov $PM_IO_BASE + 0x04, %dx /* PMCNTRL */
+  inw %dx, %ax
+  orw $1, %ax
+  outw %ax, %dx
+
+2:
+  rsm
+smm_code_end:
diff --git a/kvm/bios/usage.cc b/kvm/bios/usage.cc
new file mode 100644
index 0000000..8db9547
--- /dev/null
+++ b/kvm/bios/usage.cc
@@ -0,0 +1,99 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: usage.cc,v 1.4 2003/10/07 01:44:34 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+unsigned char bios[65536];
+
+  int
+main(int argc, char *argv[])
+{
+  int bios_file;
+  FILE * org_file;
+  unsigned org, last_org, offset;
+  int retval;
+  unsigned int to_read, index;
+  double elements, ratio;
+
+  if (argc !=3 ) {
+    fprintf(stderr, "Usage: usage bios-file org-file\n");
+    exit(1);
+    }
+
+  bios_file = open(argv[1], O_RDONLY);
+  org_file = fopen(argv[2], "r");
+
+  if ( (bios_file<0) | (org_file==NULL) ) {
+    fprintf(stderr, "problems opening files.\n");
+    exit(1);
+    }
+
+  printf("files opened OK\n");
+
+  to_read = 65536;
+  index   = 0;
+  while (to_read > 0) {
+    retval = read(bios_file, &bios[index], to_read);
+    if (retval <= 0) {
+      fprintf(stderr, "problem reading bios file\n");
+      exit(1);
+      }
+    to_read -= retval;
+    index   += retval;
+    }
+  printf("bios file read in OK\n");
+
+  last_org = 0;
+
+  while (1) {
+    retval = fscanf(org_file, "0x%x\n", &org);
+    if (retval <= 0) break;
+    printf("%04x .. %04x ", last_org, org-1);
+    for (offset=org-1; offset>last_org; offset--) {
+      if (bios[offset] != 0) break;
+      }
+    if (offset > last_org) {
+      elements = (1.0 + double(offset) - double(last_org));
+      }
+    else {
+      if (bios[last_org] == 0)
+        elements = 0.0;
+      else
+        elements = 1.0;
+      }
+
+    ratio = elements / (double(org) - double(last_org));
+    ratio *= 100.0;
+    printf("%6.2lf\n", ratio);
+    last_org = org;
+    }
+}
diff --git a/kvm/bios/vapic.S b/kvm/bios/vapic.S
new file mode 100644
index 0000000..cf2a474
--- /dev/null
+++ b/kvm/bios/vapic.S
@@ -0,0 +1,294 @@
+	.text
+	.code32
+	.align 4096
+
+vapic_size = 2*4096
+
+.macro fixup delta=-4
+777:
+	.pushsection .fixup, "a"
+	.long 777b + \delta  - vapic_base
+	.popsection
+.endm
+
+.macro reenable_vtpr
+	out %al, $0x7e
+.endm
+
+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
+
+.align 4096
+/*
+ * 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)
+ */
+vapic:
+. = . + vapic_size
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..73963e3
--- /dev/null
+++ b/kvm/include/ia64/asm/kvm.h
@@ -0,0 +1,303 @@
+#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
+#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 <asm/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_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_host.h b/kvm/include/ia64/asm/kvm_host.h
new file mode 100644
index 0000000..fb4f87d
--- /dev/null
+++ b/kvm/include/ia64/asm/kvm_host.h
@@ -0,0 +1,634 @@
+#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
+/*
+ * kvm_host.h: used for kvm module, and hold ia64-specific sections.
+ *
+ * Copyright (C) 2007, Intel Corporation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_KVM_HOST_H
+#define __ASM_KVM_HOST_H
+
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+
+/* define exit reasons from vmm to kvm*/
+#define EXIT_REASON_VM_PANIC		0
+#define EXIT_REASON_MMIO_INSTRUCTION	1
+#define EXIT_REASON_PAL_CALL		2
+#define EXIT_REASON_SAL_CALL		3
+#define EXIT_REASON_SWITCH_RR6		4
+#define EXIT_REASON_VM_DESTROY		5
+#define EXIT_REASON_EXTERNAL_INTERRUPT	6
+#define EXIT_REASON_IPI			7
+#define EXIT_REASON_PTC_G		8
+#define EXIT_REASON_DEBUG		20
+
+/*Define vmm address space and vm data space.*/
+#define KVM_VMM_SIZE (__IA64_UL_CONST(16)<<20)
+#define KVM_VMM_SHIFT 24
+#define KVM_VMM_BASE 0xD000000000000000
+#define VMM_SIZE (__IA64_UL_CONST(8)<<20)
+
+/*
+ * Define vm_buffer, used by PAL Services, base address.
+ * Note: vm_buffer is in the VMM-BLOCK, the size must be < 8M
+ */
+#define KVM_VM_BUFFER_BASE (KVM_VMM_BASE + VMM_SIZE)
+#define KVM_VM_BUFFER_SIZE (__IA64_UL_CONST(8)<<20)
+
+/*
+ * kvm guest's data area looks as follow:
+ *
+ *            +----------------------+	-------	KVM_VM_DATA_SIZE
+ *	      |	    vcpu[n]'s data   |	 |     ___________________KVM_STK_OFFSET
+ *     	      |			     |	 |    /			  |
+ *     	      |	       ..........    |	 |   /vcpu's struct&stack |
+ *     	      |	       ..........    |	 |  /---------------------|---- 0
+ *	      |	    vcpu[5]'s data   |	 | /	   vpd		  |
+ *	      |	    vcpu[4]'s data   |	 |/-----------------------|
+ *	      |	    vcpu[3]'s data   |	 /	   vtlb		  |
+ *	      |	    vcpu[2]'s data   |	/|------------------------|
+ *	      |	    vcpu[1]'s data   |/  |	   vhpt		  |
+ *	      |	    vcpu[0]'s data   |____________________________|
+ *            +----------------------+	 |
+ *	      |	   memory dirty log  |	 |
+ *            +----------------------+	 |
+ *	      |	   vm's data struct  |	 |
+ *            +----------------------+	 |
+ *	      |			     |	 |
+ *	      |			     |	 |
+ *	      |			     |	 |
+ *	      |			     |	 |
+ *	      |			     |	 |
+ *	      |			     |	 |
+ *	      |			     |	 |
+ *	      |	  vm's p2m table  |	 |
+ *	      |			     |	 |
+ *            |			     |	 |
+ *	      |			     |	 |  |
+ * vm's data->|			     |   |  |
+ *	      +----------------------+ ------- 0
+ * To support large memory, needs to increase the size of p2m.
+ * To support more vcpus, needs to ensure it has enough space to
+ * hold vcpus' data.
+ */
+
+#define KVM_VM_DATA_SHIFT	26
+#define KVM_VM_DATA_SIZE	(__IA64_UL_CONST(1) << KVM_VM_DATA_SHIFT)
+#define KVM_VM_DATA_BASE	(KVM_VMM_BASE + KVM_VM_DATA_SIZE)
+
+#define KVM_P2M_BASE		KVM_VM_DATA_BASE
+#define KVM_P2M_SIZE		(__IA64_UL_CONST(24) << 20)
+
+#define VHPT_SHIFT		16
+#define VHPT_SIZE		(__IA64_UL_CONST(1) << VHPT_SHIFT)
+#define VHPT_NUM_ENTRIES	(__IA64_UL_CONST(1) << (VHPT_SHIFT-5))
+
+#define VTLB_SHIFT		16
+#define VTLB_SIZE		(__IA64_UL_CONST(1) << VTLB_SHIFT)
+#define VTLB_NUM_ENTRIES	(1UL << (VHPT_SHIFT-5))
+
+#define VPD_SHIFT		16
+#define VPD_SIZE		(__IA64_UL_CONST(1) << VPD_SHIFT)
+
+#define VCPU_STRUCT_SHIFT	16
+#define VCPU_STRUCT_SIZE	(__IA64_UL_CONST(1) << VCPU_STRUCT_SHIFT)
+
+/*
+ * This must match KVM_IA64_VCPU_STACK_{SHIFT,SIZE} arch/ia64/include/asm/kvm.h
+ */
+#define KVM_STK_SHIFT		16
+#define KVM_STK_OFFSET		(__IA64_UL_CONST(1)<< KVM_STK_SHIFT)
+
+#define KVM_VM_STRUCT_SHIFT	19
+#define KVM_VM_STRUCT_SIZE	(__IA64_UL_CONST(1) << KVM_VM_STRUCT_SHIFT)
+
+#define KVM_MEM_DIRY_LOG_SHIFT	19
+#define KVM_MEM_DIRTY_LOG_SIZE (__IA64_UL_CONST(1) << KVM_MEM_DIRY_LOG_SHIFT)
+
+#ifndef __ASSEMBLY__
+
+/*Define the max vcpus and memory for Guests.*/
+#define KVM_MAX_VCPUS	(KVM_VM_DATA_SIZE - KVM_P2M_SIZE - KVM_VM_STRUCT_SIZE -\
+			KVM_MEM_DIRTY_LOG_SIZE) / sizeof(struct kvm_vcpu_data)
+#define KVM_MAX_MEM_SIZE (KVM_P2M_SIZE >> 3 << PAGE_SHIFT)
+
+#define VMM_LOG_LEN 256
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+#include <linux/kvm_types.h>
+
+#include <asm/pal.h>
+#include <asm/sal.h>
+#include <asm/page.h>
+
+struct kvm_vcpu_data {
+	char vcpu_vhpt[VHPT_SIZE];
+	char vcpu_vtlb[VTLB_SIZE];
+	char vcpu_vpd[VPD_SIZE];
+	char vcpu_struct[VCPU_STRUCT_SIZE];
+};
+
+struct kvm_vm_data {
+	char kvm_p2m[KVM_P2M_SIZE];
+	char kvm_vm_struct[KVM_VM_STRUCT_SIZE];
+	char kvm_mem_dirty_log[KVM_MEM_DIRTY_LOG_SIZE];
+	struct kvm_vcpu_data vcpu_data[KVM_MAX_VCPUS];
+};
+
+#define VCPU_BASE(n)	(KVM_VM_DATA_BASE + \
+				offsetof(struct kvm_vm_data, vcpu_data[n]))
+#define KVM_VM_BASE	(KVM_VM_DATA_BASE + \
+				offsetof(struct kvm_vm_data, kvm_vm_struct))
+#define KVM_MEM_DIRTY_LOG_BASE	KVM_VM_DATA_BASE + \
+				offsetof(struct kvm_vm_data, kvm_mem_dirty_log)
+
+#define VHPT_BASE(n) (VCPU_BASE(n) + offsetof(struct kvm_vcpu_data, vcpu_vhpt))
+#define VTLB_BASE(n) (VCPU_BASE(n) + offsetof(struct kvm_vcpu_data, vcpu_vtlb))
+#define VPD_BASE(n)  (VCPU_BASE(n) + offsetof(struct kvm_vcpu_data, vcpu_vpd))
+#define VCPU_STRUCT_BASE(n)	(VCPU_BASE(n) + \
+				offsetof(struct kvm_vcpu_data, vcpu_struct))
+
+/*IO section definitions*/
+#define IOREQ_READ      1
+#define IOREQ_WRITE     0
+
+#define STATE_IOREQ_NONE        0
+#define STATE_IOREQ_READY       1
+#define STATE_IOREQ_INPROCESS   2
+#define STATE_IORESP_READY      3
+
+/*Guest Physical address layout.*/
+#define GPFN_MEM        (0UL << 60) /* Guest pfn is normal mem */
+#define GPFN_FRAME_BUFFER   (1UL << 60) /* VGA framebuffer */
+#define GPFN_LOW_MMIO       (2UL << 60) /* Low MMIO range */
+#define GPFN_PIB        (3UL << 60) /* PIB base */
+#define GPFN_IOSAPIC        (4UL << 60) /* IOSAPIC base */
+#define GPFN_LEGACY_IO      (5UL << 60) /* Legacy I/O base */
+#define GPFN_GFW        (6UL << 60) /* Guest Firmware */
+#define GPFN_PHYS_MMIO      (7UL << 60) /* Directed MMIO Range */
+
+#define GPFN_IO_MASK        (7UL << 60) /* Guest pfn is I/O type */
+#define GPFN_INV_MASK       (1UL << 63) /* Guest pfn is invalid */
+#define INVALID_MFN       (~0UL)
+#define MEM_G   (1UL << 30)
+#define MEM_M   (1UL << 20)
+#define MMIO_START       (3 * MEM_G)
+#define MMIO_SIZE        (512 * MEM_M)
+#define VGA_IO_START     0xA0000UL
+#define VGA_IO_SIZE      0x20000
+#define LEGACY_IO_START  (MMIO_START + MMIO_SIZE)
+#define LEGACY_IO_SIZE   (64 * MEM_M)
+#define IO_SAPIC_START   0xfec00000UL
+#define IO_SAPIC_SIZE    0x100000
+#define PIB_START 0xfee00000UL
+#define PIB_SIZE 0x200000
+#define GFW_START        (4 * MEM_G - 16 * MEM_M)
+#define GFW_SIZE         (16 * MEM_M)
+
+/*Deliver mode, defined for ioapic.c*/
+#define dest_Fixed IOSAPIC_FIXED
+#define dest_LowestPrio IOSAPIC_LOWEST_PRIORITY
+
+#define NMI_VECTOR      		2
+#define ExtINT_VECTOR       		0
+#define NULL_VECTOR     		(-1)
+#define IA64_SPURIOUS_INT_VECTOR    	0x0f
+
+#define VCPU_LID(v) (((u64)(v)->vcpu_id) << 24)
+
+/*
+ *Delivery mode
+ */
+#define SAPIC_DELIV_SHIFT      8
+#define SAPIC_FIXED            0x0
+#define SAPIC_LOWEST_PRIORITY  0x1
+#define SAPIC_PMI              0x2
+#define SAPIC_NMI              0x4
+#define SAPIC_INIT             0x5
+#define SAPIC_EXTINT           0x7
+
+/*
+ * vcpu->requests bit members for arch
+ */
+#define KVM_REQ_PTC_G		32
+#define KVM_REQ_RESUME		33
+
+#define KVM_PAGES_PER_HPAGE	1
+
+struct kvm;
+struct kvm_vcpu;
+
+struct kvm_mmio_req {
+	uint64_t addr;          /*  physical address		*/
+	uint64_t size;          /*  size in bytes		*/
+	uint64_t data;          /*  data (or paddr of data)     */
+	uint8_t state:4;
+	uint8_t dir:1;          /*  1=read, 0=write             */
+};
+
+/*Pal data struct */
+struct kvm_pal_call{
+	/*In area*/
+	uint64_t gr28;
+	uint64_t gr29;
+	uint64_t gr30;
+	uint64_t gr31;
+	/*Out area*/
+	struct ia64_pal_retval ret;
+};
+
+/* Sal data structure */
+struct kvm_sal_call{
+	/*In area*/
+	uint64_t in0;
+	uint64_t in1;
+	uint64_t in2;
+	uint64_t in3;
+	uint64_t in4;
+	uint64_t in5;
+	uint64_t in6;
+	uint64_t in7;
+	struct sal_ret_values ret;
+};
+
+/*Guest change rr6*/
+struct kvm_switch_rr6 {
+	uint64_t old_rr;
+	uint64_t new_rr;
+};
+
+union ia64_ipi_a{
+	unsigned long val;
+	struct {
+		unsigned long rv  : 3;
+		unsigned long ir  : 1;
+		unsigned long eid : 8;
+		unsigned long id  : 8;
+		unsigned long ib_base : 44;
+	};
+};
+
+union ia64_ipi_d {
+	unsigned long val;
+	struct {
+		unsigned long vector : 8;
+		unsigned long dm  : 3;
+		unsigned long ig  : 53;
+	};
+};
+
+/*ipi check exit data*/
+struct kvm_ipi_data{
+	union ia64_ipi_a addr;
+	union ia64_ipi_d data;
+};
+
+/*global purge data*/
+struct kvm_ptc_g {
+	unsigned long vaddr;
+	unsigned long rr;
+	unsigned long ps;
+	struct kvm_vcpu *vcpu;
+};
+
+/*Exit control data */
+struct exit_ctl_data{
+	uint32_t exit_reason;
+	uint32_t vm_status;
+	union {
+		struct kvm_mmio_req	ioreq;
+		struct kvm_pal_call	pal_data;
+		struct kvm_sal_call	sal_data;
+		struct kvm_switch_rr6	rr_data;
+		struct kvm_ipi_data	ipi_data;
+		struct kvm_ptc_g	ptc_g_data;
+	} u;
+};
+
+union pte_flags {
+	unsigned long val;
+	struct {
+		unsigned long p    :  1; /*0      */
+		unsigned long      :  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      :  2; /* 50-51 */
+		unsigned long ed   :  1; /* 52    */
+	};
+};
+
+union ia64_pta {
+	unsigned long val;
+	struct {
+		unsigned long ve : 1;
+		unsigned long reserved0 : 1;
+		unsigned long size : 6;
+		unsigned long vf : 1;
+		unsigned long reserved1 : 6;
+		unsigned long base : 49;
+	};
+};
+
+struct thash_cb {
+	/* THASH base information */
+	struct thash_data	*hash; /* hash table pointer */
+	union ia64_pta		pta;
+	int           num;
+};
+
+struct kvm_vcpu_stat {
+};
+
+struct kvm_vcpu_arch {
+	int launched;
+	int last_exit;
+	int last_run_cpu;
+	int vmm_tr_slot;
+	int vm_tr_slot;
+	int sn_rtc_tr_slot;
+
+#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
+	int mp_state;
+
+#define MAX_PTC_G_NUM			3
+	int ptc_g_count;
+	struct kvm_ptc_g ptc_g_data[MAX_PTC_G_NUM];
+
+	/*halt timer to wake up sleepy vcpus*/
+	struct hrtimer hlt_timer;
+	long ht_active;
+
+	struct kvm_lapic *apic;    /* kernel irqchip context */
+	struct vpd *vpd;
+
+	/* Exit data for vmm_transition*/
+	struct exit_ctl_data exit_data;
+
+	cpumask_t cache_coherent_map;
+
+	unsigned long vmm_rr;
+	unsigned long host_rr6;
+	unsigned long psbits[8];
+	unsigned long cr_iipa;
+	unsigned long cr_isr;
+	unsigned long vsa_base;
+	unsigned long dirty_log_lock_pa;
+	unsigned long __gp;
+	/* 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;
+	/* purge all */
+	unsigned long ptce_base;
+	unsigned long ptce_count[2];
+	unsigned long ptce_stride[2];
+	/* itc/itm */
+	unsigned long last_itc;
+	long itc_offset;
+	unsigned long itc_check;
+	unsigned long timer_check;
+	unsigned int timer_pending;
+	unsigned int timer_fired;
+
+	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 */
+	int mode_flags;
+	struct thash_cb vtlb;
+	struct thash_cb vhpt;
+	char irq_check;
+	char irq_new_pending;
+
+	unsigned long opcode;
+	unsigned long cause;
+	char log_buf[VMM_LOG_LEN];
+	union context host;
+	union context guest;
+};
+
+struct kvm_vm_stat {
+	u64 remote_tlb_flush;
+};
+
+struct kvm_sal_data {
+	unsigned long boot_ip;
+	unsigned long boot_gp;
+};
+
+struct kvm_arch {
+	spinlock_t dirty_log_lock;
+
+	unsigned long	vm_base;
+	unsigned long	metaphysical_rr0;
+	unsigned long	metaphysical_rr4;
+	unsigned long	vmm_init_rr;
+
+	int		online_vcpus;
+	int		is_sn2;
+
+	struct kvm_ioapic *vioapic;
+	struct kvm_vm_stat stat;
+	struct kvm_sal_data rdv_sal_data;
+
+	struct list_head assigned_dev_head;
+	struct iommu_domain *iommu_domain;
+	struct hlist_head irq_ack_notifier_list;
+
+	unsigned long irq_sources_bitmap;
+	unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
+};
+
+union cpuid3_t {
+	u64 value;
+	struct {
+		u64 number : 8;
+		u64 revision : 8;
+		u64 model : 8;
+		u64 family : 8;
+		u64 archrev : 8;
+		u64 rv : 24;
+	};
+};
+
+struct kvm_pt_regs {
+	/* The following registers are saved by SAVE_MIN: */
+	unsigned long b6;  /* scratch */
+	unsigned long b7;  /* scratch */
+
+	unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */
+	unsigned long ar_ssd; /* reserved for future use (scratch) */
+
+	unsigned long r8;  /* scratch (return value register 0) */
+	unsigned long r9;  /* scratch (return value register 1) */
+	unsigned long r10; /* scratch (return value register 2) */
+	unsigned long r11; /* scratch (return value register 3) */
+
+	unsigned long cr_ipsr; /* interrupted task's psr */
+	unsigned long cr_iip;  /* interrupted task's instruction pointer */
+	unsigned long cr_ifs;  /* interrupted task's function state */
+
+	unsigned long ar_unat; /* interrupted task's NaT register (preserved) */
+	unsigned long ar_pfs;  /* prev function state  */
+	unsigned long ar_rsc;  /* RSE configuration */
+	/* The following two are valid only if cr_ipsr.cpl > 0: */
+	unsigned long ar_rnat;  /* RSE NaT */
+	unsigned long ar_bspstore; /* RSE bspstore */
+
+	unsigned long pr;  /* 64 predicate registers (1 bit each) */
+	unsigned long b0;  /* return pointer (bp) */
+	unsigned long loadrs;  /* size of dirty partition << 16 */
+
+	unsigned long r1;  /* the gp pointer */
+	unsigned long r12; /* interrupted task's memory stack pointer */
+	unsigned long r13; /* thread pointer */
+
+	unsigned long ar_fpsr;  /* floating point status (preserved) */
+	unsigned long r15;  /* scratch */
+
+	/* The remaining registers are NOT saved for system calls.  */
+	unsigned long r14;  /* scratch */
+	unsigned long r2;  /* scratch */
+	unsigned long r3;  /* scratch */
+	unsigned long r16;  /* scratch */
+	unsigned long r17;  /* scratch */
+	unsigned long r18;  /* scratch */
+	unsigned long r19;  /* scratch */
+	unsigned long r20;  /* scratch */
+	unsigned long r21;  /* scratch */
+	unsigned long r22;  /* scratch */
+	unsigned long r23;  /* scratch */
+	unsigned long r24;  /* scratch */
+	unsigned long r25;  /* scratch */
+	unsigned long r26;  /* scratch */
+	unsigned long r27;  /* scratch */
+	unsigned long r28;  /* scratch */
+	unsigned long r29;  /* scratch */
+	unsigned long r30;  /* scratch */
+	unsigned long r31;  /* scratch */
+	unsigned long ar_ccv;  /* compare/exchange value (scratch) */
+
+	/*
+	 * Floating point registers that the kernel considers scratch:
+	 */
+	struct ia64_fpreg f6;  /* scratch */
+	struct ia64_fpreg f7;  /* scratch */
+	struct ia64_fpreg f8;  /* scratch */
+	struct ia64_fpreg f9;  /* scratch */
+	struct ia64_fpreg f10;  /* scratch */
+	struct ia64_fpreg f11;  /* scratch */
+
+	unsigned long r4;  /* preserved */
+	unsigned long r5;  /* preserved */
+	unsigned long r6;  /* preserved */
+	unsigned long r7;  /* preserved */
+	unsigned long eml_unat;    /* used for emulating instruction */
+	unsigned long pad0;     /* alignment pad */
+};
+
+static inline struct kvm_pt_regs *vcpu_regs(struct kvm_vcpu *v)
+{
+	return (struct kvm_pt_regs *) ((unsigned long) v + KVM_STK_OFFSET) - 1;
+}
+
+typedef int kvm_vmm_entry(void);
+typedef void kvm_tramp_entry(union context *host, union context *guest);
+
+struct kvm_vmm_info{
+	struct module	*module;
+	kvm_vmm_entry 	*vmm_entry;
+	kvm_tramp_entry *tramp_entry;
+	unsigned long 	vmm_ivt;
+	unsigned long	patch_mov_ar;
+	unsigned long	patch_mov_ar_sn2;
+};
+
+int kvm_highest_pending_irq(struct kvm_vcpu *vcpu);
+int kvm_emulate_halt(struct kvm_vcpu *vcpu);
+int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
+void kvm_sal_emul(struct kvm_vcpu *vcpu);
+
+#endif /* __ASSEMBLY__*/
+
+#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..9931df9
--- /dev/null
+++ b/kvm/include/ia64/asm/kvm_para.h
@@ -0,0 +1,67 @@
+#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
+#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.
+ *
+ */
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+	return 0;
+}
+
+#endif
diff --git a/kvm/include/linux/kvm.h b/kvm/include/linux/kvm.h
new file mode 100644
index 0000000..ff1025d
--- /dev/null
+++ b/kvm/include/linux/kvm.h
@@ -0,0 +1,720 @@
+#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
+#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 <asm/types.h>
+
+#include <linux/ioctl.h>
+#include <asm/kvm.h>
+
+#define KVM_API_VERSION 12
+
+/* for KVM_TRACE_ENABLE */
+struct kvm_user_trace_setup {
+	__u32 buf_size; /* sub_buffer size of each per-cpu */
+	__u32 buf_nr; /* the number of sub_buffers of each per-cpu */
+};
+
+/* 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
+
+/* 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;
+		/* 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;
+};
+
+#define KVM_TRC_SHIFT           16
+/*
+ * kvm trace categories
+ */
+#define KVM_TRC_ENTRYEXIT       (1 << KVM_TRC_SHIFT)
+#define KVM_TRC_HANDLER         (1 << (KVM_TRC_SHIFT + 1)) /* only 12 bits */
+
+/*
+ * kvm trace action
+ */
+#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
+
+/* This structure represents a single trace buffer record. */
+struct kvm_trace_rec {
+	/* variable rec_val
+	 * is split into:
+	 * bits 0 - 27  -> event id
+	 * bits 28 -30  -> number of extra data args of size u32
+	 * bits 31      -> binary indicator for if tsc is in record
+	 */
+	__u32 rec_val;
+	__u32 pid;
+	__u32 vcpu_id;
+	union {
+		struct {
+			__u64 timestamp;
+			__u32 extra_u32[KVM_TRC_EXTRA_MAX];
+		} __attribute__((packed)) timestamp;
+		struct {
+			__u32 extra_u32[KVM_TRC_EXTRA_MAX];
+		} notimestamp;
+	} u;
+};
+
+#define TRACE_REC_EVENT_ID(val) \
+		(0x0fffffff & (val))
+#define TRACE_REC_NUM_DATA_ARGS(val) \
+		(0x70000000 & ((val) << 28))
+#define TRACE_REC_TCS(val) \
+		(0x80000000 & ((val) << 31))
+
+#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)
+/*
+ * ioctls for kvm trace
+ */
+#define KVM_TRACE_ENABLE          _IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
+#define KVM_TRACE_PAUSE           _IO(KVMIO,  0x07)
+#define KVM_TRACE_DISABLE         _IO(KVMIO,  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_PIT2 33
+#define KVM_CAP_PIT_STATE2 35
+#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
+
+#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
+
+/*
+ * ioctls for VM fds
+ */
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO, 0x40, struct kvm_memory_region)
+#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)
+/*
+ * 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)
+/* 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 _IOR(KVMIO, 0x70, \
+			    struct kvm_assigned_irq)
+#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_CREATE_PIT2		   _IOW(KVMIO, 0x77, struct kvm_pit_config)
+
+/*
+ * 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_DEBUG_GUEST
+#define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
+#define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
+#define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
+#define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)
+#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)
+
+/*
+ * Deprecated interfaces
+ */
+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_DEBUG_GUEST _IOW(KVMIO,  0x87, struct kvm_debug_guest)
+
+#define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
+#define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
+
+#define KVM_GET_PIT2   _IOR(KVMIO,   0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2   _IOW(KVMIO,   0xa0, struct kvm_pit_state2)
+
+#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)
+
+#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		512
+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
diff --git a/kvm/include/linux/kvm_host.h b/kvm/include/linux/kvm_host.h
new file mode 100644
index 0000000..0c3c5b1
--- /dev/null
+++ b/kvm/include/linux/kvm_host.h
@@ -0,0 +1,567 @@
+#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
+#ifndef __KVM_HOST_H
+#define __KVM_HOST_H
+
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <linux/types.h>
+#include <linux/hardirq.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/preempt.h>
+#include <linux/marker.h>
+#include <linux/msi.h>
+#include <asm/signal.h>
+
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+
+#include <linux/kvm_types.h>
+
+#include <asm/kvm_host.h>
+
+/*
+ * vcpu->requests bit members
+ */
+#define KVM_REQ_TLB_FLUSH          0
+#define KVM_REQ_MIGRATE_TIMER      1
+#define KVM_REQ_REPORT_TPR_ACCESS  2
+#define KVM_REQ_MMU_RELOAD         3
+#define KVM_REQ_TRIPLE_FAULT       4
+#define KVM_REQ_PENDING_TIMER      5
+#define KVM_REQ_UNHALT             6
+#define KVM_REQ_MMU_SYNC           7
+#define KVM_REQ_KVMCLOCK_UPDATE    8
+
+#define KVM_USERSPACE_IRQ_SOURCE_ID	0
+
+struct kvm_vcpu;
+extern struct kmem_cache *kvm_vcpu_cache;
+
+/*
+ * It would be nice to use something smarter than a linear search, TBD...
+ * Thankfully we dont expect many devices to register (famous last words :),
+ * so until then it will suffice.  At least its abstracted so we can change
+ * in one place.
+ */
+struct kvm_io_bus {
+	int                   dev_count;
+#define NR_IOBUS_DEVS 6
+	struct kvm_io_device *devs[NR_IOBUS_DEVS];
+};
+
+void kvm_io_bus_init(struct kvm_io_bus *bus);
+void kvm_io_bus_destroy(struct kvm_io_bus *bus);
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
+					  gpa_t addr, int len, int is_write);
+void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+			     struct kvm_io_device *dev);
+
+struct kvm_vcpu {
+	struct kvm *kvm;
+#ifdef CONFIG_PREEMPT_NOTIFIERS
+	struct preempt_notifier preempt_notifier;
+#endif
+	int vcpu_id;
+	struct mutex mutex;
+	int   cpu;
+	struct kvm_run *run;
+	int guest_mode;
+	unsigned long requests;
+	unsigned long guest_debug;
+	int fpu_active;
+	int guest_fpu_loaded;
+	wait_queue_head_t wq;
+	int sigset_active;
+	sigset_t sigset;
+	struct kvm_vcpu_stat stat;
+
+#ifdef CONFIG_HAS_IOMEM
+	int mmio_needed;
+	int mmio_read_completed;
+	int mmio_is_write;
+	int mmio_size;
+	unsigned char mmio_data[8];
+	gpa_t mmio_phys_addr;
+#endif
+
+	struct kvm_vcpu_arch arch;
+};
+
+struct kvm_memory_slot {
+	gfn_t base_gfn;
+	unsigned long npages;
+	unsigned long flags;
+	unsigned long *rmap;
+	unsigned long *dirty_bitmap;
+	struct {
+		unsigned long rmap_pde;
+		int write_count;
+	} *lpage_info;
+	unsigned long userspace_addr;
+	int user_alloc;
+};
+
+struct kvm_kernel_irq_routing_entry {
+	u32 gsi;
+	int (*set)(struct kvm_kernel_irq_routing_entry *e,
+		    struct kvm *kvm, int level);
+	union {
+		struct {
+			unsigned irqchip;
+			unsigned pin;
+		} irqchip;
+		struct msi_msg msi;
+	};
+	struct list_head link;
+};
+
+struct kvm {
+	struct mutex lock; /* protects the vcpus array and APIC accesses */
+	spinlock_t mmu_lock;
+	struct rw_semaphore slots_lock;
+	struct mm_struct *mm; /* userspace tied to this vm */
+	int nmemslots;
+	struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS +
+					KVM_PRIVATE_MEM_SLOTS];
+	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+	struct list_head vm_list;
+	struct kvm_io_bus mmio_bus;
+	struct kvm_io_bus pio_bus;
+	struct kvm_vm_stat stat;
+	struct kvm_arch arch;
+	atomic_t users_count;
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	struct kvm_coalesced_mmio_dev *coalesced_mmio_dev;
+	struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+#endif
+
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
+	struct list_head irq_routing; /* of kvm_kernel_irq_routing_entry */
+	struct hlist_head mask_notifier_list;
+#endif
+
+#ifdef KVM_ARCH_WANT_MMU_NOTIFIER
+	struct mmu_notifier mmu_notifier;
+	unsigned long mmu_notifier_seq;
+	long mmu_notifier_count;
+#endif
+};
+
+/* The guest did something we don't support. */
+#define pr_unimpl(vcpu, fmt, ...)					\
+ do {									\
+	if (printk_ratelimit())						\
+		printk(KERN_ERR "kvm: %i: cpu%i " fmt,			\
+		       current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \
+ } while (0)
+
+#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
+#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
+
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+void vcpu_load(struct kvm_vcpu *vcpu);
+void vcpu_put(struct kvm_vcpu *vcpu);
+
+int kvm_init(void *opaque, unsigned int vcpu_size,
+		  struct module *module);
+void kvm_exit(void);
+
+void kvm_get_kvm(struct kvm *kvm);
+void kvm_put_kvm(struct kvm *kvm);
+
+#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
+#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
+static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
+struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
+
+extern struct page *bad_page;
+extern pfn_t bad_pfn;
+
+int is_error_page(struct page *page);
+int is_error_pfn(pfn_t pfn);
+int kvm_is_error_hva(unsigned long addr);
+int kvm_set_memory_region(struct kvm *kvm,
+			  struct kvm_userspace_memory_region *mem,
+			  int user_alloc);
+int __kvm_set_memory_region(struct kvm *kvm,
+			    struct kvm_userspace_memory_region *mem,
+			    int user_alloc);
+int kvm_arch_set_memory_region(struct kvm *kvm,
+				struct kvm_userspace_memory_region *mem,
+				struct kvm_memory_slot old,
+				int user_alloc);
+void kvm_arch_flush_shadow(struct kvm *kvm);
+gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
+unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
+void kvm_release_page_clean(struct page *page);
+void kvm_release_page_dirty(struct page *page);
+void kvm_set_page_dirty(struct page *page);
+void kvm_set_page_accessed(struct page *page);
+
+pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
+void kvm_release_pfn_dirty(pfn_t);
+void kvm_release_pfn_clean(pfn_t pfn);
+void kvm_set_pfn_dirty(pfn_t pfn);
+void kvm_set_pfn_accessed(pfn_t pfn);
+void kvm_get_pfn(pfn_t pfn);
+
+int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
+			int len);
+int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
+			  unsigned long len);
+int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len);
+int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data,
+			 int offset, int len);
+int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,
+		    unsigned long len);
+int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);
+int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len);
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
+int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
+void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
+
+void kvm_vcpu_block(struct kvm_vcpu *vcpu);
+void kvm_resched(struct kvm_vcpu *vcpu);
+void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
+void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
+void kvm_flush_remote_tlbs(struct kvm *kvm);
+void kvm_reload_remote_mmus(struct kvm *kvm);
+
+long kvm_arch_dev_ioctl(struct file *filp,
+			unsigned int ioctl, unsigned long arg);
+long kvm_arch_vcpu_ioctl(struct file *filp,
+			 unsigned int ioctl, unsigned long arg);
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu);
+
+int kvm_dev_ioctl_check_extension(long ext);
+
+int kvm_get_dirty_log(struct kvm *kvm,
+			struct kvm_dirty_log *log, int *is_dirty);
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+				struct kvm_dirty_log *log);
+
+int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
+				   struct
+				   kvm_userspace_memory_region *mem,
+				   int user_alloc);
+long kvm_arch_vm_ioctl(struct file *filp,
+		       unsigned int ioctl, unsigned long arg);
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu);
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+				    struct kvm_translation *tr);
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs);
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs);
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+				  struct kvm_sregs *sregs);
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+				  struct kvm_sregs *sregs);
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+				    struct kvm_mp_state *mp_state);
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+				    struct kvm_mp_state *mp_state);
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					struct kvm_guest_debug *dbg);
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
+
+int kvm_arch_init(void *opaque);
+void kvm_arch_exit(void);
+
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu);
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu);
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id);
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu);
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu);
+
+int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu);
+void kvm_arch_hardware_enable(void *garbage);
+void kvm_arch_hardware_disable(void *garbage);
+int kvm_arch_hardware_setup(void);
+void kvm_arch_hardware_unsetup(void);
+void kvm_arch_check_processor_compat(void *rtn);
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
+
+void kvm_free_physmem(struct kvm *kvm);
+
+struct  kvm *kvm_arch_create_vm(void);
+void kvm_arch_destroy_vm(struct kvm *kvm);
+void kvm_free_all_assigned_devices(struct kvm *kvm);
+void kvm_arch_sync_events(struct kvm *kvm);
+
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
+
+int kvm_is_mmio_pfn(pfn_t pfn);
+
+struct kvm_irq_ack_notifier {
+	struct hlist_node link;
+	unsigned gsi;
+	void (*irq_acked)(struct kvm_irq_ack_notifier *kian);
+};
+
+#define KVM_ASSIGNED_MSIX_PENDING		0x1
+struct kvm_guest_msix_entry {
+	u32 vector;
+	u16 entry;
+	u16 flags;
+};
+
+struct kvm_assigned_dev_kernel {
+	struct kvm_irq_ack_notifier ack_notifier;
+	struct work_struct interrupt_work;
+	struct list_head list;
+	int assigned_dev_id;
+	int host_busnr;
+	int host_devfn;
+	unsigned int entries_nr;
+	int host_irq;
+	bool host_irq_disabled;
+	struct msix_entry *host_msix_entries;
+	int guest_irq;
+	struct kvm_guest_msix_entry *guest_msix_entries;
+	unsigned long irq_requested_type;
+	int irq_source_id;
+	int flags;
+	struct pci_dev *dev;
+	struct kvm *kvm;
+};
+
+struct kvm_irq_mask_notifier {
+	void (*func)(struct kvm_irq_mask_notifier *kimn, bool masked);
+	int irq;
+	struct hlist_node link;
+};
+
+void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
+				    struct kvm_irq_mask_notifier *kimn);
+void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
+				      struct kvm_irq_mask_notifier *kimn);
+void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
+
+#ifdef __KVM_HAVE_IOAPIC
+void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+				   union kvm_ioapic_redirect_entry *entry,
+				   unsigned long *deliver_bitmask);
+#endif
+int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
+void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
+void kvm_register_irq_ack_notifier(struct kvm *kvm,
+				   struct kvm_irq_ack_notifier *kian);
+void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
+int kvm_request_irq_source_id(struct kvm *kvm);
+void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
+
+#ifdef CONFIG_IOMMU_API
+int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
+			unsigned long npages);
+int kvm_iommu_map_guest(struct kvm *kvm);
+int kvm_iommu_unmap_guest(struct kvm *kvm);
+int kvm_assign_device(struct kvm *kvm,
+		      struct kvm_assigned_dev_kernel *assigned_dev);
+int kvm_deassign_device(struct kvm *kvm,
+			struct kvm_assigned_dev_kernel *assigned_dev);
+#else /* CONFIG_IOMMU_API */
+static inline int kvm_iommu_map_pages(struct kvm *kvm,
+				      gfn_t base_gfn,
+				      unsigned long npages)
+{
+	return 0;
+}
+
+static inline int kvm_iommu_map_guest(struct kvm *kvm)
+{
+	return -ENODEV;
+}
+
+static inline int kvm_iommu_unmap_guest(struct kvm *kvm)
+{
+	return 0;
+}
+
+static inline int kvm_assign_device(struct kvm *kvm,
+		struct kvm_assigned_dev_kernel *assigned_dev)
+{
+	return 0;
+}
+
+static inline int kvm_deassign_device(struct kvm *kvm,
+		struct kvm_assigned_dev_kernel *assigned_dev)
+{
+	return 0;
+}
+#endif /* CONFIG_IOMMU_API */
+
+static inline void kvm_guest_enter(void)
+{
+	account_system_vtime(current);
+	current->flags |= PF_VCPU;
+}
+
+static inline void kvm_guest_exit(void)
+{
+	account_system_vtime(current);
+	current->flags &= ~PF_VCPU;
+}
+
+static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+	return slot - kvm->memslots;
+}
+
+static inline gpa_t gfn_to_gpa(gfn_t gfn)
+{
+	return (gpa_t)gfn << PAGE_SHIFT;
+}
+
+static inline hpa_t pfn_to_hpa(pfn_t pfn)
+{
+	return (hpa_t)pfn << PAGE_SHIFT;
+}
+
+static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu)
+{
+	set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests);
+}
+
+enum kvm_stat_kind {
+	KVM_STAT_VM,
+	KVM_STAT_VCPU,
+};
+
+struct kvm_stats_debugfs_item {
+	const char *name;
+	int offset;
+	enum kvm_stat_kind kind;
+	struct dentry *dentry;
+};
+extern struct kvm_stats_debugfs_item debugfs_entries[];
+extern struct dentry *kvm_debugfs_dir;
+
+#define KVMTRACE_5D(evt, vcpu, d1, d2, d3, d4, d5, name) \
+	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+						vcpu, 5, d1, d2, d3, d4, d5)
+#define KVMTRACE_4D(evt, vcpu, d1, d2, d3, d4, name) \
+	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+						vcpu, 4, d1, d2, d3, d4, 0)
+#define KVMTRACE_3D(evt, vcpu, d1, d2, d3, name) \
+	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+						vcpu, 3, d1, d2, d3, 0, 0)
+#define KVMTRACE_2D(evt, vcpu, d1, d2, name) \
+	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+						vcpu, 2, d1, d2, 0, 0, 0)
+#define KVMTRACE_1D(evt, vcpu, d1, name) \
+	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+						vcpu, 1, d1, 0, 0, 0, 0)
+#define KVMTRACE_0D(evt, vcpu, name) \
+	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+						vcpu, 0, 0, 0, 0, 0, 0)
+
+#ifdef CONFIG_KVM_TRACE
+int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg);
+void kvm_trace_cleanup(void);
+#else
+static inline
+int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg)
+{
+	return -EINVAL;
+}
+#define kvm_trace_cleanup() ((void)0)
+#endif
+
+#ifdef KVM_ARCH_WANT_MMU_NOTIFIER
+static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_seq)
+{
+	if (unlikely(vcpu->kvm->mmu_notifier_count))
+		return 1;
+	/*
+	 * Both reads happen under the mmu_lock and both values are
+	 * modified under mmu_lock, so there's no need of smb_rmb()
+	 * here in between, otherwise mmu_notifier_count should be
+	 * read before mmu_notifier_seq, see
+	 * mmu_notifier_invalidate_range_end write side.
+	 */
+	if (vcpu->kvm->mmu_notifier_seq != mmu_seq)
+		return 1;
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
+
+#define KVM_MAX_IRQ_ROUTES 1024
+
+int kvm_setup_default_irq_routing(struct kvm *kvm);
+int kvm_set_irq_routing(struct kvm *kvm,
+			const struct kvm_irq_routing_entry *entries,
+			unsigned nr,
+			unsigned flags);
+void kvm_free_irq_routing(struct kvm *kvm);
+
+#else
+
+static inline void kvm_free_irq_routing(struct kvm *kvm) {}
+
+#endif
+
+#endif
diff --git a/kvm/include/linux/kvm_para.h b/kvm/include/linux/kvm_para.h
new file mode 100644
index 0000000..54ebbd5
--- /dev/null
+++ b/kvm/include/linux/kvm_para.h
@@ -0,0 +1,80 @@
+#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
+#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_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/linux/kvm_types.h b/kvm/include/linux/kvm_types.h
new file mode 100644
index 0000000..c65f89e
--- /dev/null
+++ b/kvm/include/linux/kvm_types.h
@@ -0,0 +1,110 @@
+#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
+/*
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __KVM_TYPES_H__
+#define __KVM_TYPES_H__
+
+#include <asm/types.h>
+
+/*
+ * Address types:
+ *
+ *  gva - guest virtual address
+ *  gpa - guest physical address
+ *  gfn - guest frame number
+ *  hva - host virtual address
+ *  hpa - host physical address
+ *  hfn - host frame number
+ */
+
+typedef unsigned long  gva_t;
+typedef u64            gpa_t;
+typedef unsigned long  gfn_t;
+
+typedef unsigned long  hva_t;
+typedef u64            hpa_t;
+typedef unsigned long  hfn_t;
+
+typedef hfn_t pfn_t;
+
+union kvm_ioapic_redirect_entry {
+	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;
+};
+
+struct kvm_lapic_irq {
+	u32 vector;
+	u32 delivery_mode;
+	u32 dest_mode;
+	u32 level;
+	u32 trig_mode;
+	u32 shorthand;
+	u32 dest_id;
+};
+
+#endif /* __KVM_TYPES_H__ */
diff --git a/kvm/include/powerpc/asm/kvm.h b/kvm/include/powerpc/asm/kvm.h
new file mode 100644
index 0000000..c4f1ed1
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm.h
@@ -0,0 +1,102 @@
+#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
+/*
+ * 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_44x.h b/kvm/include/powerpc/asm/kvm_44x.h
new file mode 100644
index 0000000..956f252
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_44x.h
@@ -0,0 +1,108 @@
+#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
+/*
+ * 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 __ASM_44X_H__
+#define __ASM_44X_H__
+
+#include <linux/kvm_host.h>
+
+#define PPC44x_TLB_SIZE 64
+
+/* If the guest is expecting it, this can be as large as we like; we'd just
+ * need to find some way of advertising it. */
+#define KVM44x_GUEST_TLB_SIZE 64
+
+struct kvmppc_44x_tlbe {
+	u32 tid; /* Only the low 8 bits are used. */
+	u32 word0;
+	u32 word1;
+	u32 word2;
+};
+
+struct kvmppc_44x_shadow_ref {
+	struct page *page;
+	u16 gtlb_index;
+	u8 writeable;
+	u8 tid;
+};
+
+struct kvmppc_vcpu_44x {
+	/* Unmodified copy of the guest's TLB. */
+	struct kvmppc_44x_tlbe guest_tlb[KVM44x_GUEST_TLB_SIZE];
+
+	/* References to guest pages in the hardware TLB. */
+	struct kvmppc_44x_shadow_ref shadow_refs[PPC44x_TLB_SIZE];
+
+	/* State of the shadow TLB at guest context switch time. */
+	struct kvmppc_44x_tlbe shadow_tlb[PPC44x_TLB_SIZE];
+	u8 shadow_tlb_mod[PPC44x_TLB_SIZE];
+
+	struct kvm_vcpu vcpu;
+};
+
+static inline struct kvmppc_vcpu_44x *to_44x(struct kvm_vcpu *vcpu)
+{
+	return container_of(vcpu, struct kvmppc_vcpu_44x, vcpu);
+}
+
+void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid);
+void kvmppc_44x_tlb_put(struct kvm_vcpu *vcpu);
+void kvmppc_44x_tlb_load(struct kvm_vcpu *vcpu);
+
+#endif /* __ASM_44X_H__ */
diff --git a/kvm/include/powerpc/asm/kvm_asm.h b/kvm/include/powerpc/asm/kvm_asm.h
new file mode 100644
index 0000000..84ff858
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_asm.h
@@ -0,0 +1,100 @@
+#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
+/*
+ * 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_ASM_H__
+#define __POWERPC_KVM_ASM_H__
+
+/* IVPR must be 64KiB-aligned. */
+#define VCPU_SIZE_ORDER 4
+#define VCPU_SIZE_LOG   (VCPU_SIZE_ORDER + 12)
+#define VCPU_TLB_PGSZ   PPC44x_TLB_64K
+#define VCPU_SIZE_BYTES (1<<VCPU_SIZE_LOG)
+
+#define BOOKE_INTERRUPT_CRITICAL 0
+#define BOOKE_INTERRUPT_MACHINE_CHECK 1
+#define BOOKE_INTERRUPT_DATA_STORAGE 2
+#define BOOKE_INTERRUPT_INST_STORAGE 3
+#define BOOKE_INTERRUPT_EXTERNAL 4
+#define BOOKE_INTERRUPT_ALIGNMENT 5
+#define BOOKE_INTERRUPT_PROGRAM 6
+#define BOOKE_INTERRUPT_FP_UNAVAIL 7
+#define BOOKE_INTERRUPT_SYSCALL 8
+#define BOOKE_INTERRUPT_AP_UNAVAIL 9
+#define BOOKE_INTERRUPT_DECREMENTER 10
+#define BOOKE_INTERRUPT_FIT 11
+#define BOOKE_INTERRUPT_WATCHDOG 12
+#define BOOKE_INTERRUPT_DTLB_MISS 13
+#define BOOKE_INTERRUPT_ITLB_MISS 14
+#define BOOKE_INTERRUPT_DEBUG 15
+
+/* E500 */
+#define BOOKE_INTERRUPT_SPE_UNAVAIL 32
+#define BOOKE_INTERRUPT_SPE_FP_DATA 33
+#define BOOKE_INTERRUPT_SPE_FP_ROUND 34
+#define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35
+
+#define RESUME_FLAG_NV          (1<<0)  /* Reload guest nonvolatile state? */
+#define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
+
+#define RESUME_GUEST            0
+#define RESUME_GUEST_NV         RESUME_FLAG_NV
+#define RESUME_HOST             RESUME_FLAG_HOST
+#define RESUME_HOST_NV          (RESUME_FLAG_HOST|RESUME_FLAG_NV)
+
+#endif /* __POWERPC_KVM_ASM_H__ */
diff --git a/kvm/include/powerpc/asm/kvm_e500.h b/kvm/include/powerpc/asm/kvm_e500.h
new file mode 100644
index 0000000..094b453
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_e500.h
@@ -0,0 +1,107 @@
+#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
+/*
+ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu, <yu.liu@freescale.com>
+ *
+ * Description:
+ * This file is derived from arch/powerpc/include/asm/kvm_44x.h,
+ * by Hollis Blanchard <hollisb@us.ibm.com>.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_KVM_E500_H__
+#define __ASM_KVM_E500_H__
+
+#include <linux/kvm_host.h>
+
+#define BOOKE_INTERRUPT_SIZE 36
+
+#define E500_PID_NUM   3
+#define E500_TLB_NUM   2
+
+struct tlbe{
+	u32 mas1;
+	u32 mas2;
+	u32 mas3;
+	u32 mas7;
+};
+
+struct kvmppc_vcpu_e500 {
+	/* Unmodified copy of the guest's TLB. */
+	struct tlbe *guest_tlb[E500_TLB_NUM];
+	/* TLB that's actually used when the guest is running. */
+	struct tlbe *shadow_tlb[E500_TLB_NUM];
+	/* Pages which are referenced in the shadow TLB. */
+	struct page **shadow_pages[E500_TLB_NUM];
+
+	unsigned int guest_tlb_size[E500_TLB_NUM];
+	unsigned int shadow_tlb_size[E500_TLB_NUM];
+	unsigned int guest_tlb_nv[E500_TLB_NUM];
+
+	u32 host_pid[E500_PID_NUM];
+	u32 pid[E500_PID_NUM];
+
+	u32 mas0;
+	u32 mas1;
+	u32 mas2;
+	u32 mas3;
+	u32 mas4;
+	u32 mas5;
+	u32 mas6;
+	u32 mas7;
+	u32 l1csr1;
+	u32 hid0;
+	u32 hid1;
+
+	struct kvm_vcpu vcpu;
+};
+
+static inline struct kvmppc_vcpu_e500 *to_e500(struct kvm_vcpu *vcpu)
+{
+	return container_of(vcpu, struct kvmppc_vcpu_e500, vcpu);
+}
+
+#endif /* __ASM_KVM_E500_H__ */
diff --git a/kvm/include/powerpc/asm/kvm_host.h b/kvm/include/powerpc/asm/kvm_host.h
new file mode 100644
index 0000000..e69fb50
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_host.h
@@ -0,0 +1,232 @@
+#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
+/*
+ * 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 __POWERPC_KVM_HOST_H__
+#define __POWERPC_KVM_HOST_H__
+
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <asm/kvm_asm.h>
+
+#define KVM_MAX_VCPUS 1
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+
+/* We don't currently support large pages. */
+#define KVM_PAGES_PER_HPAGE (1<<31)
+
+struct kvm;
+struct kvm_run;
+struct kvm_vcpu;
+
+struct kvm_vm_stat {
+	u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+	u32 sum_exits;
+	u32 mmio_exits;
+	u32 dcr_exits;
+	u32 signal_exits;
+	u32 light_exits;
+	/* Account for special types of light exits: */
+	u32 itlb_real_miss_exits;
+	u32 itlb_virt_miss_exits;
+	u32 dtlb_real_miss_exits;
+	u32 dtlb_virt_miss_exits;
+	u32 syscall_exits;
+	u32 isi_exits;
+	u32 dsi_exits;
+	u32 emulated_inst_exits;
+	u32 dec_exits;
+	u32 ext_intr_exits;
+	u32 halt_wakeup;
+};
+
+enum kvm_exit_types {
+	MMIO_EXITS,
+	DCR_EXITS,
+	SIGNAL_EXITS,
+	ITLB_REAL_MISS_EXITS,
+	ITLB_VIRT_MISS_EXITS,
+	DTLB_REAL_MISS_EXITS,
+	DTLB_VIRT_MISS_EXITS,
+	SYSCALL_EXITS,
+	ISI_EXITS,
+	DSI_EXITS,
+	EMULATED_INST_EXITS,
+	EMULATED_MTMSRWE_EXITS,
+	EMULATED_WRTEE_EXITS,
+	EMULATED_MTSPR_EXITS,
+	EMULATED_MFSPR_EXITS,
+	EMULATED_MTMSR_EXITS,
+	EMULATED_MFMSR_EXITS,
+	EMULATED_TLBSX_EXITS,
+	EMULATED_TLBWE_EXITS,
+	EMULATED_RFI_EXITS,
+	DEC_EXITS,
+	EXT_INTR_EXITS,
+	HALT_WAKEUP,
+	USR_PR_INST,
+	FP_UNAVAIL,
+	DEBUG_EXITS,
+	TIMEINGUEST,
+	__NUMBER_OF_KVM_EXIT_TYPES
+};
+
+/* allow access to big endian 32bit upper/lower parts and 64bit var */
+struct kvmppc_exit_timing {
+	union {
+		u64 tv64;
+		struct {
+			u32 tbu, tbl;
+		} tv32;
+	};
+};
+
+struct kvm_arch {
+};
+
+struct kvm_vcpu_arch {
+	u32 host_stack;
+	u32 host_pid;
+
+	u64 fpr[32];
+	ulong gpr[32];
+
+	ulong pc;
+	u32 cr;
+	ulong ctr;
+	ulong lr;
+	ulong xer;
+
+	ulong msr;
+	u32 mmucr;
+	ulong sprg0;
+	ulong sprg1;
+	ulong sprg2;
+	ulong sprg3;
+	ulong sprg4;
+	ulong sprg5;
+	ulong sprg6;
+	ulong sprg7;
+	ulong srr0;
+	ulong srr1;
+	ulong csrr0;
+	ulong csrr1;
+	ulong dsrr0;
+	ulong dsrr1;
+	ulong dear;
+	ulong esr;
+	u32 dec;
+	u32 decar;
+	u32 tbl;
+	u32 tbu;
+	u32 tcr;
+	u32 tsr;
+	u32 ivor[64];
+	ulong ivpr;
+	u32 pir;
+
+	u32 shadow_pid;
+	u32 pid;
+	u32 swap_pid;
+
+	u32 pvr;
+	u32 ccr0;
+	u32 ccr1;
+	u32 dbcr0;
+	u32 dbcr1;
+	u32 dbsr;
+
+#ifdef CONFIG_KVM_EXIT_TIMING
+	struct kvmppc_exit_timing timing_exit;
+	struct kvmppc_exit_timing timing_last_enter;
+	u32 last_exit_type;
+	u32 timing_count_type[__NUMBER_OF_KVM_EXIT_TYPES];
+	u64 timing_sum_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+	u64 timing_sum_quad_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+	u64 timing_min_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+	u64 timing_max_duration[__NUMBER_OF_KVM_EXIT_TYPES];
+	u64 timing_last_exit;
+	struct dentry *debugfs_exit_timing;
+#endif
+
+	u32 last_inst;
+	ulong fault_dear;
+	ulong fault_esr;
+	gpa_t paddr_accessed;
+
+	u8 io_gpr; /* GPR used as IO source/target */
+	u8 mmio_is_bigendian;
+	u8 dcr_needed;
+	u8 dcr_is_write;
+
+	u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
+
+	struct timer_list dec_timer;
+	unsigned long pending_exceptions;
+};
+
+#endif /* __POWERPC_KVM_HOST_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..eb598a6
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_para.h
@@ -0,0 +1,77 @@
+#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
+/*
+ * 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/powerpc/asm/kvm_ppc.h b/kvm/include/powerpc/asm/kvm_ppc.h
new file mode 100644
index 0000000..93915b3
--- /dev/null
+++ b/kvm/include/powerpc/asm/kvm_ppc.h
@@ -0,0 +1,137 @@
+#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
+/*
+ * 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_PPC_H__
+#define __POWERPC_KVM_PPC_H__
+
+/* This file exists just so we can dereference kvm_vcpu, avoiding nested header
+ * dependencies. */
+
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+enum emulation_result {
+	EMULATE_DONE,         /* no further processing */
+	EMULATE_DO_MMIO,      /* kvm_run filled with MMIO request */
+	EMULATE_DO_DCR,       /* kvm_run filled with DCR request */
+	EMULATE_FAIL,         /* can't emulate this instruction */
+};
+
+extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
+extern char kvmppc_handlers_start[];
+extern unsigned long kvmppc_handler_len;
+
+extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
+extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                              unsigned int rt, unsigned int bytes,
+                              int is_bigendian);
+extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                               u32 val, unsigned int bytes, int is_bigendian);
+
+extern int kvmppc_emulate_instruction(struct kvm_run *run,
+                                      struct kvm_vcpu *vcpu);
+extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
+extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
+
+/* Core-specific hooks */
+
+extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
+                           unsigned int gtlb_idx);
+extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode);
+extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid);
+extern void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu);
+extern int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr);
+extern int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr);
+extern gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index,
+                              gva_t eaddr);
+extern void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu);
+extern void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu);
+
+extern struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm,
+                                                unsigned int id);
+extern void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu);
+extern int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu);
+extern int kvmppc_core_check_processor_compat(void);
+extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
+                                      struct kvm_translation *tr);
+
+extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
+extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu);
+
+extern void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu);
+extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu);
+extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu);
+extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu);
+extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
+                                       struct kvm_interrupt *irq);
+
+extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                                  unsigned int op, int *advance);
+extern int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs);
+extern int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt);
+
+extern int kvmppc_booke_init(void);
+extern void kvmppc_booke_exit(void);
+
+extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
+
+#endif /* __POWERPC_KVM_PPC_H__ */
diff --git a/kvm/include/x86/asm/kvm.h b/kvm/include/x86/asm/kvm.h
new file mode 100644
index 0000000..411063c
--- /dev/null
+++ b/kvm/include/x86/asm/kvm.h
@@ -0,0 +1,292 @@
+#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
+#ifndef _ASM_X86_KVM_H
+#define _ASM_X86_KVM_H
+
+/*
+ * KVM x86 specific structures and definitions
+ *
+ */
+
+#include <asm/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
+
+/* 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
+
+/* 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];
+};
+#endif /* _ASM_X86_KVM_H */
diff --git a/kvm/include/x86/asm/kvm_host.h b/kvm/include/x86/asm/kvm_host.h
new file mode 100644
index 0000000..07e1058
--- /dev/null
+++ b/kvm/include/x86/asm/kvm_host.h
@@ -0,0 +1,835 @@
+#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
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This header defines architecture specific interfaces, x86 version
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _ASM_X86_KVM_HOST_H
+#define _ASM_X86_KVM_HOST_H
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/mmu_notifier.h>
+
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+#include <linux/kvm_types.h>
+
+#include <asm/pvclock-abi.h>
+#include <asm/desc.h>
+#include <asm/mtrr.h>
+#include <asm/msr-index.h>
+
+#define KVM_MAX_VCPUS 16
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+#define KVM_PIO_PAGE_OFFSET 1
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 2
+
+#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
+#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
+#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS |	\
+				  0xFFFFFF0000000000ULL)
+
+#define KVM_GUEST_CR0_MASK				   \
+	(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \
+	 | X86_CR0_NW | X86_CR0_CD)
+#define KVM_VM_CR0_ALWAYS_ON						\
+	(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \
+	 | X86_CR0_MP)
+#define KVM_GUEST_CR4_MASK						\
+	(X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
+#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
+#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
+
+#define INVALID_PAGE (~(hpa_t)0)
+#define UNMAPPED_GVA (~(gpa_t)0)
+
+/* shadow tables are PAE even on non-PAE hosts */
+#define KVM_HPAGE_SHIFT 21
+#define KVM_HPAGE_SIZE (1UL << KVM_HPAGE_SHIFT)
+#define KVM_HPAGE_MASK (~(KVM_HPAGE_SIZE - 1))
+
+#define KVM_PAGES_PER_HPAGE (KVM_HPAGE_SIZE / PAGE_SIZE)
+
+#define DE_VECTOR 0
+#define DB_VECTOR 1
+#define BP_VECTOR 3
+#define OF_VECTOR 4
+#define BR_VECTOR 5
+#define UD_VECTOR 6
+#define NM_VECTOR 7
+#define DF_VECTOR 8
+#define TS_VECTOR 10
+#define NP_VECTOR 11
+#define SS_VECTOR 12
+#define GP_VECTOR 13
+#define PF_VECTOR 14
+#define MF_VECTOR 16
+#define MC_VECTOR 18
+
+#define SELECTOR_TI_MASK (1 << 2)
+#define SELECTOR_RPL_MASK 0x03
+
+#define IOPL_SHIFT 12
+
+#define KVM_ALIAS_SLOTS 4
+
+#define KVM_PERMILLE_MMU_PAGES 20
+#define KVM_MIN_ALLOC_MMU_PAGES 64
+#define KVM_MMU_HASH_SHIFT 10
+#define KVM_NUM_MMU_PAGES (1 << KVM_MMU_HASH_SHIFT)
+#define KVM_MIN_FREE_MMU_PAGES 5
+#define KVM_REFILL_PAGES 25
+#define KVM_MAX_CPUID_ENTRIES 40
+#define KVM_NR_FIXED_MTRR_REGION 88
+#define KVM_NR_VAR_MTRR 8
+
+extern spinlock_t kvm_lock;
+extern struct list_head vm_list;
+
+struct kvm_vcpu;
+struct kvm;
+
+enum kvm_reg {
+	VCPU_REGS_RAX = 0,
+	VCPU_REGS_RCX = 1,
+	VCPU_REGS_RDX = 2,
+	VCPU_REGS_RBX = 3,
+	VCPU_REGS_RSP = 4,
+	VCPU_REGS_RBP = 5,
+	VCPU_REGS_RSI = 6,
+	VCPU_REGS_RDI = 7,
+#ifdef CONFIG_X86_64
+	VCPU_REGS_R8 = 8,
+	VCPU_REGS_R9 = 9,
+	VCPU_REGS_R10 = 10,
+	VCPU_REGS_R11 = 11,
+	VCPU_REGS_R12 = 12,
+	VCPU_REGS_R13 = 13,
+	VCPU_REGS_R14 = 14,
+	VCPU_REGS_R15 = 15,
+#endif
+	VCPU_REGS_RIP,
+	NR_VCPU_REGS
+};
+
+enum {
+	VCPU_SREG_ES,
+	VCPU_SREG_CS,
+	VCPU_SREG_SS,
+	VCPU_SREG_DS,
+	VCPU_SREG_FS,
+	VCPU_SREG_GS,
+	VCPU_SREG_TR,
+	VCPU_SREG_LDTR,
+};
+
+#include <asm/kvm_x86_emulate.h>
+
+#define KVM_NR_MEM_OBJS 40
+
+#define KVM_NR_DB_REGS	4
+
+#define DR6_BD		(1 << 13)
+#define DR6_BS		(1 << 14)
+#define DR6_FIXED_1	0xffff0ff0
+#define DR6_VOLATILE	0x0000e00f
+
+#define DR7_BP_EN_MASK	0x000000ff
+#define DR7_GE		(1 << 9)
+#define DR7_GD		(1 << 13)
+#define DR7_FIXED_1	0x00000400
+#define DR7_VOLATILE	0xffff23ff
+
+/*
+ * We don't want allocation failures within the mmu code, so we preallocate
+ * enough memory for a single page fault in a cache.
+ */
+struct kvm_mmu_memory_cache {
+	int nobjs;
+	void *objects[KVM_NR_MEM_OBJS];
+};
+
+#define NR_PTE_CHAIN_ENTRIES 5
+
+struct kvm_pte_chain {
+	u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES];
+	struct hlist_node link;
+};
+
+/*
+ * kvm_mmu_page_role, below, is defined as:
+ *
+ *   bits 0:3 - total guest paging levels (2-4, or zero for real mode)
+ *   bits 4:7 - page table level for this shadow (1-4)
+ *   bits 8:9 - page table quadrant for 2-level guests
+ *   bit   16 - direct mapping of virtual to physical mapping at gfn
+ *              used for real mode and two-dimensional paging
+ *   bits 17:19 - common access permissions for all ptes in this shadow page
+ */
+union kvm_mmu_page_role {
+	unsigned word;
+	struct {
+		unsigned glevels:4;
+		unsigned level:4;
+		unsigned quadrant:2;
+		unsigned pad_for_nice_hex_output:6;
+		unsigned direct:1;
+		unsigned access:3;
+		unsigned invalid:1;
+		unsigned cr4_pge:1;
+		unsigned nxe:1;
+	};
+};
+
+struct kvm_mmu_page {
+	struct list_head link;
+	struct hlist_node hash_link;
+
+	struct list_head oos_link;
+
+	/*
+	 * The following two entries are used to key the shadow page in the
+	 * hash table.
+	 */
+	gfn_t gfn;
+	union kvm_mmu_page_role role;
+
+	u64 *spt;
+	/* hold the gfn of each spte inside spt */
+	gfn_t *gfns;
+	/*
+	 * One bit set per slot which has memory
+	 * in this shadow page.
+	 */
+	DECLARE_BITMAP(slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
+	int multimapped;         /* More than one parent_pte? */
+	int root_count;          /* Currently serving as active root */
+	bool unsync;
+	unsigned int unsync_children;
+	union {
+		u64 *parent_pte;               /* !multimapped */
+		struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */
+	};
+	DECLARE_BITMAP(unsync_child_bitmap, 512);
+};
+
+struct kvm_pv_mmu_op_buffer {
+	void *ptr;
+	unsigned len;
+	unsigned processed;
+	char buf[512] __aligned(sizeof(long));
+};
+
+struct kvm_pio_request {
+	unsigned long count;
+	int cur_count;
+	gva_t guest_gva;
+	int in;
+	int port;
+	int size;
+	int string;
+	int down;
+	int rep;
+};
+
+/*
+ * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
+ * 32-bit).  The kvm_mmu structure abstracts the details of the current mmu
+ * mode.
+ */
+struct kvm_mmu {
+	void (*new_cr3)(struct kvm_vcpu *vcpu);
+	int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+	void (*free)(struct kvm_vcpu *vcpu);
+	gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva);
+	void (*prefetch_page)(struct kvm_vcpu *vcpu,
+			      struct kvm_mmu_page *page);
+	int (*sync_page)(struct kvm_vcpu *vcpu,
+			 struct kvm_mmu_page *sp);
+	void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
+	hpa_t root_hpa;
+	int root_level;
+	int shadow_root_level;
+	union kvm_mmu_page_role base_role;
+
+	u64 *pae_root;
+	u64 rsvd_bits_mask[2][4];
+};
+
+struct kvm_vcpu_arch {
+	u64 host_tsc;
+	int interrupt_window_open;
+	unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
+	DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS);
+	/*
+	 * rip and regs accesses must go through
+	 * kvm_{register,rip}_{read,write} functions.
+	 */
+	unsigned long regs[NR_VCPU_REGS];
+	u32 regs_avail;
+	u32 regs_dirty;
+
+	unsigned long cr0;
+	unsigned long cr2;
+	unsigned long cr3;
+	unsigned long cr4;
+	unsigned long cr8;
+	u32 hflags;
+	u64 pdptrs[4]; /* pae */
+	u64 shadow_efer;
+	u64 apic_base;
+	struct kvm_lapic *apic;    /* kernel irqchip context */
+	int32_t apic_arb_prio;
+	int mp_state;
+	int sipi_vector;
+	u64 ia32_misc_enable_msr;
+	bool tpr_access_reporting;
+
+	struct kvm_mmu mmu;
+	/* only needed in kvm_pv_mmu_op() path, but it's hot so
+	 * put it here to avoid allocation */
+	struct kvm_pv_mmu_op_buffer mmu_op_buffer;
+
+	struct kvm_mmu_memory_cache mmu_pte_chain_cache;
+	struct kvm_mmu_memory_cache mmu_rmap_desc_cache;
+	struct kvm_mmu_memory_cache mmu_page_cache;
+	struct kvm_mmu_memory_cache mmu_page_header_cache;
+
+	gfn_t last_pt_write_gfn;
+	int   last_pt_write_count;
+	u64  *last_pte_updated;
+	gfn_t last_pte_gfn;
+
+	struct {
+		gfn_t gfn;	/* presumed gfn during guest pte update */
+		pfn_t pfn;	/* pfn corresponding to that gfn */
+		int largepage;
+		unsigned long mmu_seq;
+	} update_pte;
+
+	struct i387_fxsave_struct host_fx_image;
+	struct i387_fxsave_struct guest_fx_image;
+
+	gva_t mmio_fault_cr2;
+	struct kvm_pio_request pio;
+	void *pio_data;
+
+	struct kvm_queued_exception {
+		bool pending;
+		bool has_error_code;
+		u8 nr;
+		u32 error_code;
+	} exception;
+
+	struct kvm_queued_interrupt {
+		bool pending;
+		u8 nr;
+	} interrupt;
+
+	struct {
+		int active;
+		u8 save_iopl;
+		struct kvm_save_segment {
+			u16 selector;
+			unsigned long base;
+			u32 limit;
+			u32 ar;
+		} tr, es, ds, fs, gs;
+	} rmode;
+	int halt_request; /* real mode on Intel only */
+
+	int cpuid_nent;
+	struct kvm_cpuid_entry2 cpuid_entries[KVM_MAX_CPUID_ENTRIES];
+	/* emulate context */
+
+	struct x86_emulate_ctxt emulate_ctxt;
+
+	gpa_t time;
+	struct pvclock_vcpu_time_info hv_clock;
+	unsigned int hv_clock_tsc_khz;
+	unsigned int time_offset;
+	struct page *time_page;
+
+	bool nmi_pending;
+	bool nmi_injected;
+	bool nmi_window_open;
+
+	struct mtrr_state_type mtrr_state;
+	u32 pat;
+
+	int switch_db_regs;
+	unsigned long host_db[KVM_NR_DB_REGS];
+	unsigned long host_dr6;
+	unsigned long host_dr7;
+	unsigned long db[KVM_NR_DB_REGS];
+	unsigned long dr6;
+	unsigned long dr7;
+	unsigned long eff_db[KVM_NR_DB_REGS];
+};
+
+struct kvm_mem_alias {
+	gfn_t base_gfn;
+	unsigned long npages;
+	gfn_t target_gfn;
+};
+
+struct kvm_arch{
+	int naliases;
+	struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
+
+	unsigned int n_free_mmu_pages;
+	unsigned int n_requested_mmu_pages;
+	unsigned int n_alloc_mmu_pages;
+	struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
+	/*
+	 * Hash table of struct kvm_mmu_page.
+	 */
+	struct list_head active_mmu_pages;
+	struct list_head assigned_dev_head;
+	struct iommu_domain *iommu_domain;
+	struct kvm_pic *vpic;
+	struct kvm_ioapic *vioapic;
+	struct kvm_pit *vpit;
+	struct hlist_head irq_ack_notifier_list;
+	int vapics_in_nmi_mode;
+
+	unsigned int tss_addr;
+	struct page *apic_access_page;
+
+	gpa_t wall_clock;
+
+	struct page *ept_identity_pagetable;
+	bool ept_identity_pagetable_done;
+
+	unsigned long irq_sources_bitmap;
+	unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
+	u64 vm_init_tsc;
+};
+
+struct kvm_vm_stat {
+	u32 mmu_shadow_zapped;
+	u32 mmu_pte_write;
+	u32 mmu_pte_updated;
+	u32 mmu_pde_zapped;
+	u32 mmu_flooded;
+	u32 mmu_recycled;
+	u32 mmu_cache_miss;
+	u32 mmu_unsync;
+	u32 remote_tlb_flush;
+	u32 lpages;
+};
+
+struct kvm_vcpu_stat {
+	u32 pf_fixed;
+	u32 pf_guest;
+	u32 tlb_flush;
+	u32 invlpg;
+
+	u32 exits;
+	u32 io_exits;
+	u32 mmio_exits;
+	u32 signal_exits;
+	u32 irq_window_exits;
+	u32 nmi_window_exits;
+	u32 halt_exits;
+	u32 halt_wakeup;
+	u32 request_irq_exits;
+	u32 request_nmi_exits;
+	u32 irq_exits;
+	u32 host_state_reload;
+	u32 efer_reload;
+	u32 fpu_reload;
+	u32 insn_emulation;
+	u32 insn_emulation_fail;
+	u32 hypercalls;
+	u32 irq_injections;
+	u32 nmi_injections;
+};
+
+struct descriptor_table {
+	u16 limit;
+	unsigned long base;
+} __attribute__((packed));
+
+struct kvm_x86_ops {
+	int (*cpu_has_kvm_support)(void);          /* __init */
+	int (*disabled_by_bios)(void);             /* __init */
+	void (*hardware_enable)(void *dummy);      /* __init */
+	void (*hardware_disable)(void *dummy);
+	void (*check_processor_compatibility)(void *rtn);
+	int (*hardware_setup)(void);               /* __init */
+	void (*hardware_unsetup)(void);            /* __exit */
+	bool (*cpu_has_accelerated_tpr)(void);
+
+	/* Create, but do not attach this VCPU */
+	struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
+	void (*vcpu_free)(struct kvm_vcpu *vcpu);
+	int (*vcpu_reset)(struct kvm_vcpu *vcpu);
+
+	void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
+	void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
+	void (*vcpu_put)(struct kvm_vcpu *vcpu);
+
+	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
+			       struct kvm_guest_debug *dbg);
+	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+	u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
+	void (*get_segment)(struct kvm_vcpu *vcpu,
+			    struct kvm_segment *var, int seg);
+	int (*get_cpl)(struct kvm_vcpu *vcpu);
+	void (*set_segment)(struct kvm_vcpu *vcpu,
+			    struct kvm_segment *var, int seg);
+	void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
+	void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu);
+	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
+	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
+	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
+	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
+	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+	unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr);
+	void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value,
+		       int *exception);
+	void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
+	unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
+	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+
+	void (*tlb_flush)(struct kvm_vcpu *vcpu);
+
+	void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+	int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+	void (*patch_hypercall)(struct kvm_vcpu *vcpu,
+				unsigned char *hypercall_addr);
+	int (*get_irq)(struct kvm_vcpu *vcpu);
+	void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
+	void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
+				bool has_error_code, u32 error_code);
+	bool (*exception_injected)(struct kvm_vcpu *vcpu);
+	void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
+	void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
+				       struct kvm_run *run);
+	int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
+	int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
+	int (*get_tdp_level)(void);
+	int (*get_mt_mask_shift)(void);
+};
+
+extern struct kvm_x86_ops *kvm_x86_ops;
+
+int kvm_mmu_module_init(void);
+void kvm_mmu_module_exit(void);
+
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
+int kvm_mmu_create(struct kvm_vcpu *vcpu);
+int kvm_mmu_setup(struct kvm_vcpu *vcpu);
+void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte);
+void kvm_mmu_set_base_ptes(u64 base_pte);
+void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
+		u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 mt_mask);
+
+int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
+unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm);
+void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages);
+
+int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
+
+int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
+			  const void *val, int bytes);
+int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
+		  gpa_t addr, unsigned long *ret);
+
+extern bool tdp_enabled;
+
+enum emulation_result {
+	EMULATE_DONE,       /* no further processing */
+	EMULATE_DO_MMIO,      /* kvm_run filled with mmio request */
+	EMULATE_FAIL,         /* can't emulate this instruction */
+};
+
+#define EMULTYPE_NO_DECODE	    (1 << 0)
+#define EMULTYPE_TRAP_UD	    (1 << 1)
+#define EMULTYPE_SKIP		    (1 << 2)
+int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
+			unsigned long cr2, u16 error_code, int emulation_type);
+void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
+void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
+void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
+void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
+		   unsigned long *rflags);
+
+unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
+		     unsigned long *rflags);
+void kvm_enable_efer_bits(u64);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+
+struct x86_emulate_ctxt;
+
+int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+		     int size, unsigned port);
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+			   int size, unsigned long count, int down,
+			    gva_t address, int rep, unsigned port);
+void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
+int kvm_emulate_halt(struct kvm_vcpu *vcpu);
+int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
+int emulate_clts(struct kvm_vcpu *vcpu);
+int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr,
+		    unsigned long *dest);
+int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
+		    unsigned long value);
+
+void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
+int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+				int type_bits, int seg);
+
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason);
+
+void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
+void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
+void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8);
+unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu);
+void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
+
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+
+void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr);
+void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
+void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
+			   u32 error_code);
+
+int kvm_pic_set_irq(void *opaque, int irq, int level);
+
+void kvm_inject_nmi(struct kvm_vcpu *vcpu);
+
+void fx_init(struct kvm_vcpu *vcpu);
+
+int emulator_write_emulated(unsigned long addr,
+			    const void *val,
+			    unsigned int bytes,
+			    struct kvm_vcpu *vcpu);
+
+unsigned long segment_base(u16 selector);
+
+void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu);
+void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
+		       const u8 *new, int bytes,
+		       bool guest_initiated);
+int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+int kvm_mmu_load(struct kvm_vcpu *vcpu);
+void kvm_mmu_unload(struct kvm_vcpu *vcpu);
+void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu);
+
+int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
+
+int kvm_fix_hypercall(struct kvm_vcpu *vcpu);
+
+int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code);
+void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva);
+
+void kvm_enable_tdp(void);
+void kvm_disable_tdp(void);
+
+int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
+int complete_pio(struct kvm_vcpu *vcpu);
+
+struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn);
+
+static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
+{
+	struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
+
+	return (struct kvm_mmu_page *)page_private(page);
+}
+
+static inline u16 kvm_read_fs(void)
+{
+	u16 seg;
+	asm("mov %%fs, %0" : "=g"(seg));
+	return seg;
+}
+
+static inline u16 kvm_read_gs(void)
+{
+	u16 seg;
+	asm("mov %%gs, %0" : "=g"(seg));
+	return seg;
+}
+
+static inline u16 kvm_read_ldt(void)
+{
+	u16 ldt;
+	asm("sldt %0" : "=g"(ldt));
+	return ldt;
+}
+
+static inline void kvm_load_fs(u16 sel)
+{
+	asm("mov %0, %%fs" : : "rm"(sel));
+}
+
+static inline void kvm_load_gs(u16 sel)
+{
+	asm("mov %0, %%gs" : : "rm"(sel));
+}
+
+static inline void kvm_load_ldt(u16 sel)
+{
+	asm("lldt %0" : : "rm"(sel));
+}
+
+static inline void kvm_get_idt(struct descriptor_table *table)
+{
+	asm("sidt %0" : "=m"(*table));
+}
+
+static inline void kvm_get_gdt(struct descriptor_table *table)
+{
+	asm("sgdt %0" : "=m"(*table));
+}
+
+static inline unsigned long kvm_read_tr_base(void)
+{
+	u16 tr;
+	asm("str %0" : "=g"(tr));
+	return segment_base(tr);
+}
+
+#ifdef CONFIG_X86_64
+static inline unsigned long read_msr(unsigned long msr)
+{
+	u64 value;
+
+	rdmsrl(msr, value);
+	return value;
+}
+#endif
+
+static inline void kvm_fx_save(struct i387_fxsave_struct *image)
+{
+	asm("fxsave (%0)":: "r" (image));
+}
+
+static inline void kvm_fx_restore(struct i387_fxsave_struct *image)
+{
+	asm("fxrstor (%0)":: "r" (image));
+}
+
+static inline void kvm_fx_finit(void)
+{
+	asm("finit");
+}
+
+static inline u32 get_rdx_init_val(void)
+{
+	return 0x600; /* P6 family */
+}
+
+static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)
+{
+	kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
+}
+
+#define MSR_IA32_TIME_STAMP_COUNTER		0x010
+
+#define TSS_IOPB_BASE_OFFSET 0x66
+#define TSS_BASE_SIZE 0x68
+#define TSS_IOPB_SIZE (65536 / 8)
+#define TSS_REDIRECTION_SIZE (256 / 8)
+#define RMODE_TSS_SIZE							\
+	(TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
+
+enum {
+	TASK_SWITCH_CALL = 0,
+	TASK_SWITCH_IRET = 1,
+	TASK_SWITCH_JMP = 2,
+	TASK_SWITCH_GATE = 3,
+};
+
+#define HF_GIF_MASK		(1 << 0)
+#define HF_HIF_MASK		(1 << 1)
+#define HF_VINTR_MASK		(1 << 2)
+
+/*
+ * Hardware virtualization extension instructions may fault if a
+ * reboot turns off virtualization while processes are running.
+ * Trap the fault and ignore the instruction if that happens.
+ */
+asmlinkage void kvm_handle_fault_on_reboot(void);
+
+#define __kvm_handle_fault_on_reboot(insn) \
+	"666: " insn "\n\t" \
+	".pushsection .fixup, \"ax\" \n" \
+	"667: \n\t" \
+	__ASM_SIZE(push) " $666b \n\t"	      \
+	"jmp kvm_handle_fault_on_reboot \n\t" \
+	".popsection \n\t" \
+	".pushsection __ex_table, \"a\" \n\t" \
+	_ASM_PTR " 666b, 667b \n\t" \
+	".popsection"
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+int kvm_age_hva(struct kvm *kvm, unsigned long hva);
+int cpuid_maxphyaddr(struct kvm_vcpu *vcpu);
+
+#endif /* _ASM_X86_KVM_HOST_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..7a30a52
--- /dev/null
+++ b/kvm/include/x86/asm/kvm_para.h
@@ -0,0 +1,187 @@
+#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
+#ifndef _ASM_X86_KVM_PARA_H
+#define _ASM_X86_KVM_PARA_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/include/x86/asm/kvm_x86_emulate.h b/kvm/include/x86/asm/kvm_x86_emulate.h
new file mode 100644
index 0000000..1768674
--- /dev/null
+++ b/kvm/include/x86/asm/kvm_x86_emulate.h
@@ -0,0 +1,221 @@
+#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
+/******************************************************************************
+ * x86_emulate.h
+ *
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ *
+ * Copyright (c) 2005 Keir Fraser
+ *
+ * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
+ */
+
+#ifndef _ASM_X86_KVM_X86_EMULATE_H
+#define _ASM_X86_KVM_X86_EMULATE_H
+
+struct x86_emulate_ctxt;
+
+/*
+ * x86_emulate_ops:
+ *
+ * These operations represent the instruction emulator's interface to memory.
+ * There are two categories of operation: those that act on ordinary memory
+ * regions (*_std), and those that act on memory regions known to require
+ * special treatment or emulation (*_emulated).
+ *
+ * The emulator assumes that an instruction accesses only one 'emulated memory'
+ * location, that this location is the given linear faulting address (cr2), and
+ * that this is one of the instruction's data operands. Instruction fetches and
+ * stack operations are assumed never to access emulated memory. The emulator
+ * automatically deduces which operand of a string-move operation is accessing
+ * emulated memory, and assumes that the other operand accesses normal memory.
+ *
+ * NOTES:
+ *  1. The emulator isn't very smart about emulated vs. standard memory.
+ *     'Emulated memory' access addresses should be checked for sanity.
+ *     'Normal memory' accesses may fault, and the caller must arrange to
+ *     detect and handle reentrancy into the emulator via recursive faults.
+ *     Accesses may be unaligned and may cross page boundaries.
+ *  2. If the access fails (cannot emulate, or a standard access faults) then
+ *     it is up to the memop to propagate the fault to the guest VM via
+ *     some out-of-band mechanism, unknown to the emulator. The memop signals
+ *     failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
+ *     then immediately bail.
+ *  3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
+ *     cmpxchg8b_emulated need support 8-byte accesses.
+ *  4. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
+ */
+/* Access completed successfully: continue emulation as normal. */
+#define X86EMUL_CONTINUE        0
+/* Access is unhandleable: bail from emulation and return error to caller. */
+#define X86EMUL_UNHANDLEABLE    1
+/* Terminate emulation but return success to the caller. */
+#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
+#define X86EMUL_RETRY_INSTR     2 /* retry the instruction for some reason */
+#define X86EMUL_CMPXCHG_FAILED  2 /* cmpxchg did not see expected value */
+struct x86_emulate_ops {
+	/*
+	 * read_std: Read bytes of standard (non-emulated/special) memory.
+	 *           Used for instruction fetch, stack operations, and others.
+	 *  @addr:  [IN ] Linear address from which to read.
+	 *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
+	 *  @bytes: [IN ] Number of bytes to read from memory.
+	 */
+	int (*read_std)(unsigned long addr, void *val,
+			unsigned int bytes, struct kvm_vcpu *vcpu);
+
+	/*
+	 * read_emulated: Read bytes from emulated/special memory area.
+	 *  @addr:  [IN ] Linear address from which to read.
+	 *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
+	 *  @bytes: [IN ] Number of bytes to read from memory.
+	 */
+	int (*read_emulated)(unsigned long addr,
+			     void *val,
+			     unsigned int bytes,
+			     struct kvm_vcpu *vcpu);
+
+	/*
+	 * write_emulated: Read bytes from emulated/special memory area.
+	 *  @addr:  [IN ] Linear address to which to write.
+	 *  @val:   [IN ] Value to write to memory (low-order bytes used as
+	 *                required).
+	 *  @bytes: [IN ] Number of bytes to write to memory.
+	 */
+	int (*write_emulated)(unsigned long addr,
+			      const void *val,
+			      unsigned int bytes,
+			      struct kvm_vcpu *vcpu);
+
+	/*
+	 * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
+	 *                   emulated/special memory area.
+	 *  @addr:  [IN ] Linear address to access.
+	 *  @old:   [IN ] Value expected to be current at @addr.
+	 *  @new:   [IN ] Value to write to @addr.
+	 *  @bytes: [IN ] Number of bytes to access using CMPXCHG.
+	 */
+	int (*cmpxchg_emulated)(unsigned long addr,
+				const void *old,
+				const void *new,
+				unsigned int bytes,
+				struct kvm_vcpu *vcpu);
+
+};
+
+/* Type, address-of, and value of an instruction's operand. */
+struct operand {
+	enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
+	unsigned int bytes;
+	unsigned long val, orig_val, *ptr;
+};
+
+struct fetch_cache {
+	u8 data[15];
+	unsigned long start;
+	unsigned long end;
+};
+
+struct decode_cache {
+	u8 twobyte;
+	u8 b;
+	u8 lock_prefix;
+	u8 rep_prefix;
+	u8 op_bytes;
+	u8 ad_bytes;
+	u8 rex_prefix;
+	struct operand src;
+	struct operand src2;
+	struct operand dst;
+	bool has_seg_override;
+	u8 seg_override;
+	unsigned int d;
+	unsigned long regs[NR_VCPU_REGS];
+	unsigned long eip;
+	/* modrm */
+	u8 modrm;
+	u8 modrm_mod;
+	u8 modrm_reg;
+	u8 modrm_rm;
+	u8 use_modrm_ea;
+	bool rip_relative;
+	unsigned long modrm_ea;
+	void *modrm_ptr;
+	unsigned long modrm_val;
+	struct fetch_cache fetch;
+};
+
+struct x86_emulate_ctxt {
+	/* Register state before/after emulation. */
+	struct kvm_vcpu *vcpu;
+
+	unsigned long eflags;
+	/* Emulated execution mode, represented by an X86EMUL_MODE value. */
+	int mode;
+	u32 cs_base;
+
+	/* decode cache */
+	struct decode_cache decode;
+};
+
+/* Repeat String Operation Prefix */
+#define REPE_PREFIX	1
+#define REPNE_PREFIX	2
+
+/* Execution mode, passed to the emulator. */
+#define X86EMUL_MODE_REAL     0	/* Real mode.             */
+#define X86EMUL_MODE_PROT16   2	/* 16-bit protected mode. */
+#define X86EMUL_MODE_PROT32   4	/* 32-bit protected mode. */
+#define X86EMUL_MODE_PROT64   8	/* 64-bit (long) mode.    */
+
+/* Host execution mode. */
+#if defined(CONFIG_X86_32)
+#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
+#elif defined(CONFIG_X86_64)
+#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
+#endif
+
+int x86_decode_insn(struct x86_emulate_ctxt *ctxt,
+		    struct x86_emulate_ops *ops);
+int x86_emulate_insn(struct x86_emulate_ctxt *ctxt,
+		     struct x86_emulate_ops *ops);
+
+#endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/kvm/include/x86/asm/svm.h b/kvm/include/x86/asm/svm.h
new file mode 100644
index 0000000..5a34c94
--- /dev/null
+++ b/kvm/include/x86/asm/svm.h
@@ -0,0 +1,365 @@
+#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
+#ifndef __SVM_H
+#define __SVM_H
+
+enum {
+	INTERCEPT_INTR,
+	INTERCEPT_NMI,
+	INTERCEPT_SMI,
+	INTERCEPT_INIT,
+	INTERCEPT_VINTR,
+	INTERCEPT_SELECTIVE_CR0,
+	INTERCEPT_STORE_IDTR,
+	INTERCEPT_STORE_GDTR,
+	INTERCEPT_STORE_LDTR,
+	INTERCEPT_STORE_TR,
+	INTERCEPT_LOAD_IDTR,
+	INTERCEPT_LOAD_GDTR,
+	INTERCEPT_LOAD_LDTR,
+	INTERCEPT_LOAD_TR,
+	INTERCEPT_RDTSC,
+	INTERCEPT_RDPMC,
+	INTERCEPT_PUSHF,
+	INTERCEPT_POPF,
+	INTERCEPT_CPUID,
+	INTERCEPT_RSM,
+	INTERCEPT_IRET,
+	INTERCEPT_INTn,
+	INTERCEPT_INVD,
+	INTERCEPT_PAUSE,
+	INTERCEPT_HLT,
+	INTERCEPT_INVLPG,
+	INTERCEPT_INVLPGA,
+	INTERCEPT_IOIO_PROT,
+	INTERCEPT_MSR_PROT,
+	INTERCEPT_TASK_SWITCH,
+	INTERCEPT_FERR_FREEZE,
+	INTERCEPT_SHUTDOWN,
+	INTERCEPT_VMRUN,
+	INTERCEPT_VMMCALL,
+	INTERCEPT_VMLOAD,
+	INTERCEPT_VMSAVE,
+	INTERCEPT_STGI,
+	INTERCEPT_CLGI,
+	INTERCEPT_SKINIT,
+	INTERCEPT_RDTSCP,
+	INTERCEPT_ICEBP,
+	INTERCEPT_WBINVD,
+	INTERCEPT_MONITOR,
+	INTERCEPT_MWAIT,
+	INTERCEPT_MWAIT_COND,
+};
+
+
+struct __attribute__ ((__packed__)) vmcb_control_area {
+	u16 intercept_cr_read;
+	u16 intercept_cr_write;
+	u16 intercept_dr_read;
+	u16 intercept_dr_write;
+	u32 intercept_exceptions;
+	u64 intercept;
+	u8 reserved_1[44];
+	u64 iopm_base_pa;
+	u64 msrpm_base_pa;
+	u64 tsc_offset;
+	u32 asid;
+	u8 tlb_ctl;
+	u8 reserved_2[3];
+	u32 int_ctl;
+	u32 int_vector;
+	u32 int_state;
+	u8 reserved_3[4];
+	u32 exit_code;
+	u32 exit_code_hi;
+	u64 exit_info_1;
+	u64 exit_info_2;
+	u32 exit_int_info;
+	u32 exit_int_info_err;
+	u64 nested_ctl;
+	u8 reserved_4[16];
+	u32 event_inj;
+	u32 event_inj_err;
+	u64 nested_cr3;
+	u64 lbr_ctl;
+	u8 reserved_5[832];
+};
+
+
+#define TLB_CONTROL_DO_NOTHING 0
+#define TLB_CONTROL_FLUSH_ALL_ASID 1
+
+#define V_TPR_MASK 0x0f
+
+#define V_IRQ_SHIFT 8
+#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
+
+#define V_INTR_PRIO_SHIFT 16
+#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
+
+#define V_IGN_TPR_SHIFT 20
+#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
+
+#define V_INTR_MASKING_SHIFT 24
+#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
+
+#define SVM_INTERRUPT_SHADOW_MASK 1
+
+#define SVM_IOIO_STR_SHIFT 2
+#define SVM_IOIO_REP_SHIFT 3
+#define SVM_IOIO_SIZE_SHIFT 4
+#define SVM_IOIO_ASIZE_SHIFT 7
+
+#define SVM_IOIO_TYPE_MASK 1
+#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT)
+#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT)
+#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
+#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
+
+struct __attribute__ ((__packed__)) vmcb_seg {
+	u16 selector;
+	u16 attrib;
+	u32 limit;
+	u64 base;
+};
+
+struct __attribute__ ((__packed__)) vmcb_save_area {
+	struct vmcb_seg es;
+	struct vmcb_seg cs;
+	struct vmcb_seg ss;
+	struct vmcb_seg ds;
+	struct vmcb_seg fs;
+	struct vmcb_seg gs;
+	struct vmcb_seg gdtr;
+	struct vmcb_seg ldtr;
+	struct vmcb_seg idtr;
+	struct vmcb_seg tr;
+	u8 reserved_1[43];
+	u8 cpl;
+	u8 reserved_2[4];
+	u64 efer;
+	u8 reserved_3[112];
+	u64 cr4;
+	u64 cr3;
+	u64 cr0;
+	u64 dr7;
+	u64 dr6;
+	u64 rflags;
+	u64 rip;
+	u8 reserved_4[88];
+	u64 rsp;
+	u8 reserved_5[24];
+	u64 rax;
+	u64 star;
+	u64 lstar;
+	u64 cstar;
+	u64 sfmask;
+	u64 kernel_gs_base;
+	u64 sysenter_cs;
+	u64 sysenter_esp;
+	u64 sysenter_eip;
+	u64 cr2;
+	u8 reserved_6[32];
+	u64 g_pat;
+	u64 dbgctl;
+	u64 br_from;
+	u64 br_to;
+	u64 last_excp_from;
+	u64 last_excp_to;
+};
+
+struct __attribute__ ((__packed__)) vmcb {
+	struct vmcb_control_area control;
+	struct vmcb_save_area save;
+};
+
+#define SVM_CPUID_FEATURE_SHIFT 2
+#define SVM_CPUID_FUNC 0x8000000a
+
+#define SVM_VM_CR_SVM_DISABLE 4
+
+#define SVM_SELECTOR_S_SHIFT 4
+#define SVM_SELECTOR_DPL_SHIFT 5
+#define SVM_SELECTOR_P_SHIFT 7
+#define SVM_SELECTOR_AVL_SHIFT 8
+#define SVM_SELECTOR_L_SHIFT 9
+#define SVM_SELECTOR_DB_SHIFT 10
+#define SVM_SELECTOR_G_SHIFT 11
+
+#define SVM_SELECTOR_TYPE_MASK (0xf)
+#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT)
+#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT)
+#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT)
+#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT)
+#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT)
+#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT)
+#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT)
+
+#define SVM_SELECTOR_WRITE_MASK (1 << 1)
+#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK
+#define SVM_SELECTOR_CODE_MASK (1 << 3)
+
+#define INTERCEPT_CR0_MASK 1
+#define INTERCEPT_CR3_MASK (1 << 3)
+#define INTERCEPT_CR4_MASK (1 << 4)
+#define INTERCEPT_CR8_MASK (1 << 8)
+
+#define INTERCEPT_DR0_MASK 1
+#define INTERCEPT_DR1_MASK (1 << 1)
+#define INTERCEPT_DR2_MASK (1 << 2)
+#define INTERCEPT_DR3_MASK (1 << 3)
+#define INTERCEPT_DR4_MASK (1 << 4)
+#define INTERCEPT_DR5_MASK (1 << 5)
+#define INTERCEPT_DR6_MASK (1 << 6)
+#define INTERCEPT_DR7_MASK (1 << 7)
+
+#define SVM_EVTINJ_VEC_MASK 0xff
+
+#define SVM_EVTINJ_TYPE_SHIFT 8
+#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_VALID (1 << 31)
+#define SVM_EVTINJ_VALID_ERR (1 << 11)
+
+#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK
+
+#define	SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
+#define	SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
+#define	SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT
+#define	SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT
+
+#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
+#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
+
+#define SVM_EXITINFOSHIFT_TS_REASON_IRET 36
+#define SVM_EXITINFOSHIFT_TS_REASON_JMP 38
+
+#define	SVM_EXIT_READ_CR0 	0x000
+#define	SVM_EXIT_READ_CR3 	0x003
+#define	SVM_EXIT_READ_CR4 	0x004
+#define	SVM_EXIT_READ_CR8 	0x008
+#define	SVM_EXIT_WRITE_CR0 	0x010
+#define	SVM_EXIT_WRITE_CR3 	0x013
+#define	SVM_EXIT_WRITE_CR4 	0x014
+#define	SVM_EXIT_WRITE_CR8 	0x018
+#define	SVM_EXIT_READ_DR0 	0x020
+#define	SVM_EXIT_READ_DR1 	0x021
+#define	SVM_EXIT_READ_DR2 	0x022
+#define	SVM_EXIT_READ_DR3 	0x023
+#define	SVM_EXIT_READ_DR4 	0x024
+#define	SVM_EXIT_READ_DR5 	0x025
+#define	SVM_EXIT_READ_DR6 	0x026
+#define	SVM_EXIT_READ_DR7 	0x027
+#define	SVM_EXIT_WRITE_DR0 	0x030
+#define	SVM_EXIT_WRITE_DR1 	0x031
+#define	SVM_EXIT_WRITE_DR2 	0x032
+#define	SVM_EXIT_WRITE_DR3 	0x033
+#define	SVM_EXIT_WRITE_DR4 	0x034
+#define	SVM_EXIT_WRITE_DR5 	0x035
+#define	SVM_EXIT_WRITE_DR6 	0x036
+#define	SVM_EXIT_WRITE_DR7 	0x037
+#define SVM_EXIT_EXCP_BASE      0x040
+#define SVM_EXIT_INTR		0x060
+#define SVM_EXIT_NMI		0x061
+#define SVM_EXIT_SMI		0x062
+#define SVM_EXIT_INIT		0x063
+#define SVM_EXIT_VINTR		0x064
+#define SVM_EXIT_CR0_SEL_WRITE	0x065
+#define SVM_EXIT_IDTR_READ	0x066
+#define SVM_EXIT_GDTR_READ	0x067
+#define SVM_EXIT_LDTR_READ	0x068
+#define SVM_EXIT_TR_READ	0x069
+#define SVM_EXIT_IDTR_WRITE	0x06a
+#define SVM_EXIT_GDTR_WRITE	0x06b
+#define SVM_EXIT_LDTR_WRITE	0x06c
+#define SVM_EXIT_TR_WRITE	0x06d
+#define SVM_EXIT_RDTSC		0x06e
+#define SVM_EXIT_RDPMC		0x06f
+#define SVM_EXIT_PUSHF		0x070
+#define SVM_EXIT_POPF		0x071
+#define SVM_EXIT_CPUID		0x072
+#define SVM_EXIT_RSM		0x073
+#define SVM_EXIT_IRET		0x074
+#define SVM_EXIT_SWINT		0x075
+#define SVM_EXIT_INVD		0x076
+#define SVM_EXIT_PAUSE		0x077
+#define SVM_EXIT_HLT		0x078
+#define SVM_EXIT_INVLPG		0x079
+#define SVM_EXIT_INVLPGA	0x07a
+#define SVM_EXIT_IOIO		0x07b
+#define SVM_EXIT_MSR		0x07c
+#define SVM_EXIT_TASK_SWITCH	0x07d
+#define SVM_EXIT_FERR_FREEZE	0x07e
+#define SVM_EXIT_SHUTDOWN	0x07f
+#define SVM_EXIT_VMRUN		0x080
+#define SVM_EXIT_VMMCALL	0x081
+#define SVM_EXIT_VMLOAD		0x082
+#define SVM_EXIT_VMSAVE		0x083
+#define SVM_EXIT_STGI		0x084
+#define SVM_EXIT_CLGI		0x085
+#define SVM_EXIT_SKINIT		0x086
+#define SVM_EXIT_RDTSCP		0x087
+#define SVM_EXIT_ICEBP		0x088
+#define SVM_EXIT_WBINVD		0x089
+#define SVM_EXIT_MONITOR	0x08a
+#define SVM_EXIT_MWAIT		0x08b
+#define SVM_EXIT_MWAIT_COND	0x08c
+#define SVM_EXIT_NPF  		0x400
+
+#define SVM_EXIT_ERR		-1
+
+#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */
+
+#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
+#define SVM_VMRUN  ".byte 0x0f, 0x01, 0xd8"
+#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"
+#define SVM_CLGI   ".byte 0x0f, 0x01, 0xdd"
+#define SVM_STGI   ".byte 0x0f, 0x01, 0xdc"
+#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"
+
+#endif
+
diff --git a/kvm/include/x86/asm/virtext.h b/kvm/include/x86/asm/virtext.h
new file mode 100644
index 0000000..e6f17fb
--- /dev/null
+++ b/kvm/include/x86/asm/virtext.h
@@ -0,0 +1,172 @@
+#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
+/* CPU virtualization extensions handling
+ *
+ * This should carry the code for handling CPU virtualization extensions
+ * that needs to live in the kernel core.
+ *
+ * Author: Eduardo Habkost <ehabkost@redhat.com>
+ *
+ * Copyright (C) 2008, Red Hat Inc.
+ *
+ * Contains code from KVM, Copyright (C) 2006 Qumranet, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef _ASM_X86_VIRTEX_H
+#define _ASM_X86_VIRTEX_H
+
+#include <asm/processor.h>
+#include <asm/system.h>
+
+#include <asm/vmx.h>
+#include <asm/svm.h>
+
+/*
+ * VMX functions:
+ */
+
+static inline int cpu_has_vmx(void)
+{
+	unsigned long ecx = cpuid_ecx(1);
+	return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
+}
+
+
+/** Disable VMX on the current CPU
+ *
+ * vmxoff causes a undefined-opcode exception if vmxon was not run
+ * on the CPU previously. Only call this function if you know VMX
+ * is enabled.
+ */
+static inline void cpu_vmxoff(void)
+{
+	asm volatile (ASM_VMX_VMXOFF : : : "cc");
+	write_cr4(read_cr4() & ~X86_CR4_VMXE);
+}
+
+static inline int cpu_vmx_enabled(void)
+{
+	return read_cr4() & X86_CR4_VMXE;
+}
+
+/** Disable VMX if it is enabled on the current CPU
+ *
+ * You shouldn't call this if cpu_has_vmx() returns 0.
+ */
+static inline void __cpu_emergency_vmxoff(void)
+{
+	if (cpu_vmx_enabled())
+		cpu_vmxoff();
+}
+
+/** Disable VMX if it is supported and enabled on the current CPU
+ */
+static inline void cpu_emergency_vmxoff(void)
+{
+	if (cpu_has_vmx())
+		__cpu_emergency_vmxoff();
+}
+
+
+
+
+/*
+ * SVM functions:
+ */
+
+/** Check if the CPU has SVM support
+ *
+ * You can use the 'msg' arg to get a message describing the problem,
+ * if the function returns zero. Simply pass NULL if you are not interested
+ * on the messages; gcc should take care of not generating code for
+ * the messages on this case.
+ */
+static inline int cpu_has_svm(const char **msg)
+{
+	uint32_t eax, ebx, ecx, edx;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+		if (msg)
+			*msg = "not amd";
+		return 0;
+	}
+
+	cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+	if (eax < SVM_CPUID_FUNC) {
+		if (msg)
+			*msg = "can't execute cpuid_8000000a";
+		return 0;
+	}
+
+	cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+	if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
+		if (msg)
+			*msg = "svm not available";
+		return 0;
+	}
+	return 1;
+}
+
+
+/** Disable SVM on the current CPU
+ *
+ * You should call this only if cpu_has_svm() returned true.
+ */
+static inline void cpu_svm_disable(void)
+{
+	uint64_t efer;
+
+	wrmsrl(MSR_VM_HSAVE_PA, 0);
+	rdmsrl(MSR_EFER, efer);
+	wrmsrl(MSR_EFER, efer & ~EFER_SVME);
+}
+
+/** Makes sure SVM is disabled, if it is supported on the CPU
+ */
+static inline void cpu_emergency_svm_disable(void)
+{
+	if (cpu_has_svm(NULL))
+		cpu_svm_disable();
+}
+
+#endif /* _ASM_X86_VIRTEX_H */
diff --git a/kvm/include/x86/asm/vmx.h b/kvm/include/x86/asm/vmx.h
new file mode 100644
index 0000000..df8d4f9
--- /dev/null
+++ b/kvm/include/x86/asm/vmx.h
@@ -0,0 +1,423 @@
+#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
+#ifndef VMX_H
+#define VMX_H
+
+/*
+ * vmx.h: VMX Architecture related definitions
+ * Copyright (c) 2004, 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.
+ *
+ * A few random additions are:
+ * Copyright (C) 2006 Qumranet
+ *    Avi Kivity <avi@qumranet.com>
+ *    Yaniv Kamay <yaniv@qumranet.com>
+ *
+ */
+
+/*
+ * Definitions of Primary Processor-Based VM-Execution Controls.
+ */
+#define CPU_BASED_VIRTUAL_INTR_PENDING          0x00000004
+#define CPU_BASED_USE_TSC_OFFSETING             0x00000008
+#define CPU_BASED_HLT_EXITING                   0x00000080
+#define CPU_BASED_INVLPG_EXITING                0x00000200
+#define CPU_BASED_MWAIT_EXITING                 0x00000400
+#define CPU_BASED_RDPMC_EXITING                 0x00000800
+#define CPU_BASED_RDTSC_EXITING                 0x00001000
+#define CPU_BASED_CR3_LOAD_EXITING		0x00008000
+#define CPU_BASED_CR3_STORE_EXITING		0x00010000
+#define CPU_BASED_CR8_LOAD_EXITING              0x00080000
+#define CPU_BASED_CR8_STORE_EXITING             0x00100000
+#define CPU_BASED_TPR_SHADOW                    0x00200000
+#define CPU_BASED_VIRTUAL_NMI_PENDING		0x00400000
+#define CPU_BASED_MOV_DR_EXITING                0x00800000
+#define CPU_BASED_UNCOND_IO_EXITING             0x01000000
+#define CPU_BASED_USE_IO_BITMAPS                0x02000000
+#define CPU_BASED_USE_MSR_BITMAPS               0x10000000
+#define CPU_BASED_MONITOR_EXITING               0x20000000
+#define CPU_BASED_PAUSE_EXITING                 0x40000000
+#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS   0x80000000
+/*
+ * Definitions of Secondary Processor-Based VM-Execution Controls.
+ */
+#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
+#define SECONDARY_EXEC_ENABLE_EPT               0x00000002
+#define SECONDARY_EXEC_ENABLE_VPID              0x00000020
+#define SECONDARY_EXEC_WBINVD_EXITING		0x00000040
+
+
+#define PIN_BASED_EXT_INTR_MASK                 0x00000001
+#define PIN_BASED_NMI_EXITING                   0x00000008
+#define PIN_BASED_VIRTUAL_NMIS                  0x00000020
+
+#define VM_EXIT_HOST_ADDR_SPACE_SIZE            0x00000200
+#define VM_EXIT_ACK_INTR_ON_EXIT                0x00008000
+#define VM_EXIT_SAVE_IA32_PAT			0x00040000
+#define VM_EXIT_LOAD_IA32_PAT			0x00080000
+
+#define VM_ENTRY_IA32E_MODE                     0x00000200
+#define VM_ENTRY_SMM                            0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR             0x00000800
+#define VM_ENTRY_LOAD_IA32_PAT			0x00004000
+
+/* VMCS Encodings */
+enum vmcs_field {
+	VIRTUAL_PROCESSOR_ID            = 0x00000000,
+	GUEST_ES_SELECTOR               = 0x00000800,
+	GUEST_CS_SELECTOR               = 0x00000802,
+	GUEST_SS_SELECTOR               = 0x00000804,
+	GUEST_DS_SELECTOR               = 0x00000806,
+	GUEST_FS_SELECTOR               = 0x00000808,
+	GUEST_GS_SELECTOR               = 0x0000080a,
+	GUEST_LDTR_SELECTOR             = 0x0000080c,
+	GUEST_TR_SELECTOR               = 0x0000080e,
+	HOST_ES_SELECTOR                = 0x00000c00,
+	HOST_CS_SELECTOR                = 0x00000c02,
+	HOST_SS_SELECTOR                = 0x00000c04,
+	HOST_DS_SELECTOR                = 0x00000c06,
+	HOST_FS_SELECTOR                = 0x00000c08,
+	HOST_GS_SELECTOR                = 0x00000c0a,
+	HOST_TR_SELECTOR                = 0x00000c0c,
+	IO_BITMAP_A                     = 0x00002000,
+	IO_BITMAP_A_HIGH                = 0x00002001,
+	IO_BITMAP_B                     = 0x00002002,
+	IO_BITMAP_B_HIGH                = 0x00002003,
+	MSR_BITMAP                      = 0x00002004,
+	MSR_BITMAP_HIGH                 = 0x00002005,
+	VM_EXIT_MSR_STORE_ADDR          = 0x00002006,
+	VM_EXIT_MSR_STORE_ADDR_HIGH     = 0x00002007,
+	VM_EXIT_MSR_LOAD_ADDR           = 0x00002008,
+	VM_EXIT_MSR_LOAD_ADDR_HIGH      = 0x00002009,
+	VM_ENTRY_MSR_LOAD_ADDR          = 0x0000200a,
+	VM_ENTRY_MSR_LOAD_ADDR_HIGH     = 0x0000200b,
+	TSC_OFFSET                      = 0x00002010,
+	TSC_OFFSET_HIGH                 = 0x00002011,
+	VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
+	VIRTUAL_APIC_PAGE_ADDR_HIGH     = 0x00002013,
+	APIC_ACCESS_ADDR		= 0x00002014,
+	APIC_ACCESS_ADDR_HIGH		= 0x00002015,
+	EPT_POINTER                     = 0x0000201a,
+	EPT_POINTER_HIGH                = 0x0000201b,
+	GUEST_PHYSICAL_ADDRESS          = 0x00002400,
+	GUEST_PHYSICAL_ADDRESS_HIGH     = 0x00002401,
+	VMCS_LINK_POINTER               = 0x00002800,
+	VMCS_LINK_POINTER_HIGH          = 0x00002801,
+	GUEST_IA32_DEBUGCTL             = 0x00002802,
+	GUEST_IA32_DEBUGCTL_HIGH        = 0x00002803,
+	GUEST_IA32_PAT			= 0x00002804,
+	GUEST_IA32_PAT_HIGH		= 0x00002805,
+	GUEST_PDPTR0                    = 0x0000280a,
+	GUEST_PDPTR0_HIGH               = 0x0000280b,
+	GUEST_PDPTR1                    = 0x0000280c,
+	GUEST_PDPTR1_HIGH               = 0x0000280d,
+	GUEST_PDPTR2                    = 0x0000280e,
+	GUEST_PDPTR2_HIGH               = 0x0000280f,
+	GUEST_PDPTR3                    = 0x00002810,
+	GUEST_PDPTR3_HIGH               = 0x00002811,
+	HOST_IA32_PAT			= 0x00002c00,
+	HOST_IA32_PAT_HIGH		= 0x00002c01,
+	PIN_BASED_VM_EXEC_CONTROL       = 0x00004000,
+	CPU_BASED_VM_EXEC_CONTROL       = 0x00004002,
+	EXCEPTION_BITMAP                = 0x00004004,
+	PAGE_FAULT_ERROR_CODE_MASK      = 0x00004006,
+	PAGE_FAULT_ERROR_CODE_MATCH     = 0x00004008,
+	CR3_TARGET_COUNT                = 0x0000400a,
+	VM_EXIT_CONTROLS                = 0x0000400c,
+	VM_EXIT_MSR_STORE_COUNT         = 0x0000400e,
+	VM_EXIT_MSR_LOAD_COUNT          = 0x00004010,
+	VM_ENTRY_CONTROLS               = 0x00004012,
+	VM_ENTRY_MSR_LOAD_COUNT         = 0x00004014,
+	VM_ENTRY_INTR_INFO_FIELD        = 0x00004016,
+	VM_ENTRY_EXCEPTION_ERROR_CODE   = 0x00004018,
+	VM_ENTRY_INSTRUCTION_LEN        = 0x0000401a,
+	TPR_THRESHOLD                   = 0x0000401c,
+	SECONDARY_VM_EXEC_CONTROL       = 0x0000401e,
+	VM_INSTRUCTION_ERROR            = 0x00004400,
+	VM_EXIT_REASON                  = 0x00004402,
+	VM_EXIT_INTR_INFO               = 0x00004404,
+	VM_EXIT_INTR_ERROR_CODE         = 0x00004406,
+	IDT_VECTORING_INFO_FIELD        = 0x00004408,
+	IDT_VECTORING_ERROR_CODE        = 0x0000440a,
+	VM_EXIT_INSTRUCTION_LEN         = 0x0000440c,
+	VMX_INSTRUCTION_INFO            = 0x0000440e,
+	GUEST_ES_LIMIT                  = 0x00004800,
+	GUEST_CS_LIMIT                  = 0x00004802,
+	GUEST_SS_LIMIT                  = 0x00004804,
+	GUEST_DS_LIMIT                  = 0x00004806,
+	GUEST_FS_LIMIT                  = 0x00004808,
+	GUEST_GS_LIMIT                  = 0x0000480a,
+	GUEST_LDTR_LIMIT                = 0x0000480c,
+	GUEST_TR_LIMIT                  = 0x0000480e,
+	GUEST_GDTR_LIMIT                = 0x00004810,
+	GUEST_IDTR_LIMIT                = 0x00004812,
+	GUEST_ES_AR_BYTES               = 0x00004814,
+	GUEST_CS_AR_BYTES               = 0x00004816,
+	GUEST_SS_AR_BYTES               = 0x00004818,
+	GUEST_DS_AR_BYTES               = 0x0000481a,
+	GUEST_FS_AR_BYTES               = 0x0000481c,
+	GUEST_GS_AR_BYTES               = 0x0000481e,
+	GUEST_LDTR_AR_BYTES             = 0x00004820,
+	GUEST_TR_AR_BYTES               = 0x00004822,
+	GUEST_INTERRUPTIBILITY_INFO     = 0x00004824,
+	GUEST_ACTIVITY_STATE            = 0X00004826,
+	GUEST_SYSENTER_CS               = 0x0000482A,
+	HOST_IA32_SYSENTER_CS           = 0x00004c00,
+	CR0_GUEST_HOST_MASK             = 0x00006000,
+	CR4_GUEST_HOST_MASK             = 0x00006002,
+	CR0_READ_SHADOW                 = 0x00006004,
+	CR4_READ_SHADOW                 = 0x00006006,
+	CR3_TARGET_VALUE0               = 0x00006008,
+	CR3_TARGET_VALUE1               = 0x0000600a,
+	CR3_TARGET_VALUE2               = 0x0000600c,
+	CR3_TARGET_VALUE3               = 0x0000600e,
+	EXIT_QUALIFICATION              = 0x00006400,
+	GUEST_LINEAR_ADDRESS            = 0x0000640a,
+	GUEST_CR0                       = 0x00006800,
+	GUEST_CR3                       = 0x00006802,
+	GUEST_CR4                       = 0x00006804,
+	GUEST_ES_BASE                   = 0x00006806,
+	GUEST_CS_BASE                   = 0x00006808,
+	GUEST_SS_BASE                   = 0x0000680a,
+	GUEST_DS_BASE                   = 0x0000680c,
+	GUEST_FS_BASE                   = 0x0000680e,
+	GUEST_GS_BASE                   = 0x00006810,
+	GUEST_LDTR_BASE                 = 0x00006812,
+	GUEST_TR_BASE                   = 0x00006814,
+	GUEST_GDTR_BASE                 = 0x00006816,
+	GUEST_IDTR_BASE                 = 0x00006818,
+	GUEST_DR7                       = 0x0000681a,
+	GUEST_RSP                       = 0x0000681c,
+	GUEST_RIP                       = 0x0000681e,
+	GUEST_RFLAGS                    = 0x00006820,
+	GUEST_PENDING_DBG_EXCEPTIONS    = 0x00006822,
+	GUEST_SYSENTER_ESP              = 0x00006824,
+	GUEST_SYSENTER_EIP              = 0x00006826,
+	HOST_CR0                        = 0x00006c00,
+	HOST_CR3                        = 0x00006c02,
+	HOST_CR4                        = 0x00006c04,
+	HOST_FS_BASE                    = 0x00006c06,
+	HOST_GS_BASE                    = 0x00006c08,
+	HOST_TR_BASE                    = 0x00006c0a,
+	HOST_GDTR_BASE                  = 0x00006c0c,
+	HOST_IDTR_BASE                  = 0x00006c0e,
+	HOST_IA32_SYSENTER_ESP          = 0x00006c10,
+	HOST_IA32_SYSENTER_EIP          = 0x00006c12,
+	HOST_RSP                        = 0x00006c14,
+	HOST_RIP                        = 0x00006c16,
+};
+
+#define VMX_EXIT_REASONS_FAILED_VMENTRY         0x80000000
+
+#define EXIT_REASON_EXCEPTION_NMI       0
+#define EXIT_REASON_EXTERNAL_INTERRUPT  1
+#define EXIT_REASON_TRIPLE_FAULT        2
+
+#define EXIT_REASON_PENDING_INTERRUPT   7
+#define EXIT_REASON_NMI_WINDOW		8
+#define EXIT_REASON_TASK_SWITCH         9
+#define EXIT_REASON_CPUID               10
+#define EXIT_REASON_HLT                 12
+#define EXIT_REASON_INVLPG              14
+#define EXIT_REASON_RDPMC               15
+#define EXIT_REASON_RDTSC               16
+#define EXIT_REASON_VMCALL              18
+#define EXIT_REASON_VMCLEAR             19
+#define EXIT_REASON_VMLAUNCH            20
+#define EXIT_REASON_VMPTRLD             21
+#define EXIT_REASON_VMPTRST             22
+#define EXIT_REASON_VMREAD              23
+#define EXIT_REASON_VMRESUME            24
+#define EXIT_REASON_VMWRITE             25
+#define EXIT_REASON_VMOFF               26
+#define EXIT_REASON_VMON                27
+#define EXIT_REASON_CR_ACCESS           28
+#define EXIT_REASON_DR_ACCESS           29
+#define EXIT_REASON_IO_INSTRUCTION      30
+#define EXIT_REASON_MSR_READ            31
+#define EXIT_REASON_MSR_WRITE           32
+#define EXIT_REASON_MWAIT_INSTRUCTION   36
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
+#define EXIT_REASON_APIC_ACCESS         44
+#define EXIT_REASON_EPT_VIOLATION       48
+#define EXIT_REASON_EPT_MISCONFIG       49
+#define EXIT_REASON_WBINVD		54
+
+/*
+ * Interruption-information format
+ */
+#define INTR_INFO_VECTOR_MASK           0xff            /* 7:0 */
+#define INTR_INFO_INTR_TYPE_MASK        0x700           /* 10:8 */
+#define INTR_INFO_DELIVER_CODE_MASK     0x800           /* 11 */
+#define INTR_INFO_UNBLOCK_NMI		0x1000		/* 12 */
+#define INTR_INFO_VALID_MASK            0x80000000      /* 31 */
+#define INTR_INFO_RESVD_BITS_MASK       0x7ffff000
+
+#define VECTORING_INFO_VECTOR_MASK           	INTR_INFO_VECTOR_MASK
+#define VECTORING_INFO_TYPE_MASK        	INTR_INFO_INTR_TYPE_MASK
+#define VECTORING_INFO_DELIVER_CODE_MASK    	INTR_INFO_DELIVER_CODE_MASK
+#define VECTORING_INFO_VALID_MASK       	INTR_INFO_VALID_MASK
+
+#define INTR_TYPE_EXT_INTR              (0 << 8) /* external interrupt */
+#define INTR_TYPE_NMI_INTR		(2 << 8) /* NMI */
+#define INTR_TYPE_HARD_EXCEPTION	(3 << 8) /* processor exception */
+#define INTR_TYPE_SOFT_INTR             (4 << 8) /* software interrupt */
+#define INTR_TYPE_SOFT_EXCEPTION	(6 << 8) /* software exception */
+
+/* GUEST_INTERRUPTIBILITY_INFO flags. */
+#define GUEST_INTR_STATE_STI		0x00000001
+#define GUEST_INTR_STATE_MOV_SS		0x00000002
+#define GUEST_INTR_STATE_SMI		0x00000004
+#define GUEST_INTR_STATE_NMI		0x00000008
+
+/*
+ * Exit Qualifications for MOV for Control Register Access
+ */
+#define CONTROL_REG_ACCESS_NUM          0x7     /* 2:0, number of control reg.*/
+#define CONTROL_REG_ACCESS_TYPE         0x30    /* 5:4, access type */
+#define CONTROL_REG_ACCESS_REG          0xf00   /* 10:8, general purpose reg. */
+#define LMSW_SOURCE_DATA_SHIFT 16
+#define LMSW_SOURCE_DATA  (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */
+#define REG_EAX                         (0 << 8)
+#define REG_ECX                         (1 << 8)
+#define REG_EDX                         (2 << 8)
+#define REG_EBX                         (3 << 8)
+#define REG_ESP                         (4 << 8)
+#define REG_EBP                         (5 << 8)
+#define REG_ESI                         (6 << 8)
+#define REG_EDI                         (7 << 8)
+#define REG_R8                         (8 << 8)
+#define REG_R9                         (9 << 8)
+#define REG_R10                        (10 << 8)
+#define REG_R11                        (11 << 8)
+#define REG_R12                        (12 << 8)
+#define REG_R13                        (13 << 8)
+#define REG_R14                        (14 << 8)
+#define REG_R15                        (15 << 8)
+
+/*
+ * Exit Qualifications for MOV for Debug Register Access
+ */
+#define DEBUG_REG_ACCESS_NUM            0x7     /* 2:0, number of debug reg. */
+#define DEBUG_REG_ACCESS_TYPE           0x10    /* 4, direction of access */
+#define TYPE_MOV_TO_DR                  (0 << 4)
+#define TYPE_MOV_FROM_DR                (1 << 4)
+#define DEBUG_REG_ACCESS_REG(eq)        (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */
+
+
+/* segment AR */
+#define SEGMENT_AR_L_MASK (1 << 13)
+
+#define AR_TYPE_ACCESSES_MASK 1
+#define AR_TYPE_READABLE_MASK (1 << 1)
+#define AR_TYPE_WRITEABLE_MASK (1 << 2)
+#define AR_TYPE_CODE_MASK (1 << 3)
+#define AR_TYPE_MASK 0x0f
+#define AR_TYPE_BUSY_64_TSS 11
+#define AR_TYPE_BUSY_32_TSS 11
+#define AR_TYPE_BUSY_16_TSS 3
+#define AR_TYPE_LDT 2
+
+#define AR_UNUSABLE_MASK (1 << 16)
+#define AR_S_MASK (1 << 4)
+#define AR_P_MASK (1 << 7)
+#define AR_L_MASK (1 << 13)
+#define AR_DB_MASK (1 << 14)
+#define AR_G_MASK (1 << 15)
+#define AR_DPL_SHIFT 5
+#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3)
+
+#define AR_RESERVD_MASK 0xfffe0f00
+
+#define TSS_PRIVATE_MEMSLOT			(KVM_MEMORY_SLOTS + 0)
+#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT	(KVM_MEMORY_SLOTS + 1)
+#define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT	(KVM_MEMORY_SLOTS + 2)
+
+#define VMX_NR_VPIDS				(1 << 16)
+#define VMX_VPID_EXTENT_SINGLE_CONTEXT		1
+#define VMX_VPID_EXTENT_ALL_CONTEXT		2
+
+#define VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
+#define VMX_EPT_EXTENT_CONTEXT			1
+#define VMX_EPT_EXTENT_GLOBAL			2
+#define VMX_EPT_EXTENT_INDIVIDUAL_BIT		(1ull << 24)
+#define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
+#define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
+#define VMX_EPT_DEFAULT_GAW			3
+#define VMX_EPT_MAX_GAW				0x4
+#define VMX_EPT_MT_EPTE_SHIFT			3
+#define VMX_EPT_GAW_EPTP_SHIFT			3
+#define VMX_EPT_DEFAULT_MT			0x6ull
+#define VMX_EPT_READABLE_MASK			0x1ull
+#define VMX_EPT_WRITABLE_MASK			0x2ull
+#define VMX_EPT_EXECUTABLE_MASK			0x4ull
+#define VMX_EPT_IGMT_BIT    			(1ull << 6)
+
+#define VMX_EPT_IDENTITY_PAGETABLE_ADDR		0xfffbc000ul
+
+
+#define ASM_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"
+#define ASM_VMX_VMRESUME          ".byte 0x0f, 0x01, 0xc3"
+#define ASM_VMX_VMPTRLD_RAX       ".byte 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMREAD_RDX_RAX    ".byte 0x0f, 0x78, 0xd0"
+#define ASM_VMX_VMWRITE_RAX_RDX   ".byte 0x0f, 0x79, 0xd0"
+#define ASM_VMX_VMWRITE_RSP_RDX   ".byte 0x0f, 0x79, 0xd4"
+#define ASM_VMX_VMXOFF            ".byte 0x0f, 0x01, 0xc4"
+#define ASM_VMX_VMXON_RAX         ".byte 0xf3, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_INVEPT		  ".byte 0x66, 0x0f, 0x38, 0x80, 0x08"
+#define ASM_VMX_INVVPID		  ".byte 0x66, 0x0f, 0x38, 0x81, 0x08"
+
+
+
+#endif
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..3b1dccf
--- /dev/null
+++ b/kvm/scripts/make-release
@@ -0,0 +1,60 @@
+#!/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"
+
+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..3bf8801
--- /dev/null
+++ b/kvm/scripts/qemu-ifup
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+switch=$(/sbin/ip route list | awk '/^default / { print $NF }')
+/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/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..d9fbf17
--- /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..2f59bb5
--- /dev/null
+++ b/kvm/user/config-x86-common.mak
@@ -0,0 +1,68 @@
+#This is a make file with common rules for both x86 & x86-64
+
+CFLAGS += -I../include/x86
+
+all: kvmctl kvmtrace test_cases
+
+kvmctl_objs= main.o iotable.o ../libkvm/libkvm.a
+balloon_ctl: balloon_ctl.o
+
+cflatobjs += \
+	test/lib/x86/io.o \
+	test/lib/x86/smp.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)/irq.flat: $(TEST_DIR)/print.o
+ 
+$(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)/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)/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
diff --git a/kvm/user/config-x86_64.mak b/kvm/user/config-x86_64.mak
new file mode 100644
index 0000000..d88f54c
--- /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)/irq.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..61f1057
--- /dev/null
+++ b/kvm/user/flat.lds
@@ -0,0 +1,17 @@
+OUTPUT_FORMAT(binary)
+
+SECTIONS
+{
+    . = 1M;
+    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..1f96cb8
--- /dev/null
+++ b/kvm/user/test/lib/libcflat.h
@@ -0,0 +1,36 @@
+/*
+ * 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>
+
+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/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/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..92ebada
--- /dev/null
+++ b/kvm/user/test/lib/x86/smp.c
@@ -0,0 +1,150 @@
+
+#include <libcflat.h>
+#include "smp.h"
+#include "fake-apic.h"
+
+#define IPI_VECTOR 0x20
+
+static int apic_read(int reg)
+{
+    unsigned short port = APIC_BASE + reg;
+    unsigned v;
+
+    asm volatile ("in %1, %0" : "=a"(v) : "d"(port));
+    return v;
+}
+
+static void apic_write(int reg, unsigned v)
+{
+    unsigned short port = APIC_BASE + reg;
+
+    asm volatile ("out %0, %1" : : "a"(v), "d"(port));
+}
+
+static int apic_get_cpu_count()
+{
+    return apic_read(APIC_REG_NCPU);
+}
+
+static int apic_get_id()
+{
+    return apic_read(APIC_REG_ID);
+}
+
+static void apic_set_ipi_vector(int vector)
+{
+    apic_write(APIC_REG_IPI_VECTOR, vector);
+}
+
+static void apic_send_ipi(int cpu)
+{
+    apic_write(APIC_REG_SEND_IPI, cpu);
+}
+
+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);
+    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 apic_get_cpu_count();
+}
+
+int smp_id(void)
+{
+    return apic_get_id();
+}
+
+void on_cpu(int cpu, void (*function)(void *data), void *data)
+{
+    spin_lock(&ipi_lock);
+    if (cpu == apic_get_id())
+	function(data);
+    else {
+	ipi_function = function;
+	ipi_data = data;
+	apic_send_ipi(cpu);
+	while (!ipi_done)
+	    ;
+	ipi_done = 0;
+    }
+    spin_unlock(&ipi_lock);
+}
+
+static void (*smp_main_func)(void);
+static volatile int smp_main_running;
+
+asm ("smp_init_entry: \n"
+     "incl smp_main_running \n"
+     "sti \n"
+     "call *smp_main_func");
+
+void smp_init(void (*smp_main)(void))
+{
+    int i;
+    void smp_init_entry(void);
+    void ipi_entry(void);
+
+    apic_set_ipi_vector(IPI_VECTOR);
+    set_ipi_descriptor(smp_init_entry);
+    smp_main_func = smp_main;
+    for (i = 1; i < cpu_count(); ++i) {
+	apic_send_ipi(i);
+	while (smp_main_running < i)
+	    ;
+    }
+    set_ipi_descriptor(ipi_entry);
+}
diff --git a/kvm/user/test/lib/x86/smp.h b/kvm/user/test/lib/x86/smp.h
new file mode 100644
index 0000000..bcf76a3
--- /dev/null
+++ b/kvm/user/test/lib/x86/smp.h
@@ -0,0 +1,16 @@
+#ifndef __SMP_H
+#define __SMP_H
+
+struct spinlock {
+    int v;
+};
+
+void smp_init(void (*smp_main)(void));
+
+int cpu_count(void);
+int smp_id(void);
+void on_cpu(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..272a4ef
--- /dev/null
+++ b/kvm/user/test/x86/access.c
@@ -0,0 +1,604 @@
+
+#include "libcflat.h"
+#include "smp.h"
+
+#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");
+    smp_init((void(*)(void))ac_test_run);
+    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..7794615
--- /dev/null
+++ b/kvm/user/test/x86/apic.c
@@ -0,0 +1,351 @@
+#include "libcflat.h"
+#include "apic.h"
+#include "vm.h"
+
+static void *g_apic;
+static void *g_ioapic;
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned u32;
+typedef unsigned long ulong;
+
+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 rflags;
+    ulong cs;
+    ulong rip;
+    ulong func;
+    ulong regs[sizeof(ulong)*2];
+} 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 report(const char *msg, int pass)
+{
+    ++g_tests;
+    printf("%s: %s\n", msg, (pass ? "PASS" : "FAIL"));
+    if (!pass)
+        ++g_fail;
+}
+
+static u32 apic_read(unsigned reg)
+{
+    return *(volatile u32 *)(g_apic + reg);
+}
+
+static void apic_write(unsigned reg, u32 val)
+{
+    *(volatile u32 *)(g_apic + reg) = val;
+}
+
+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);
+}
+
+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_write(APIC_ICR,
+               APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec);
+    asm volatile ("nop");
+    report("self ipi", ipi_count == 1);
+}
+
+static void ioapic_write_reg(unsigned reg, u32 value)
+{
+    *(volatile u32 *)g_ioapic = reg;
+    *(volatile u32 *)(g_ioapic + 0x10) = value;
+}
+
+typedef 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;
+} ioapic_redir_entry_t;
+
+static 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]);
+}
+
+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);
+}
+
+static void enable_apic(void)
+{
+    apic_write(0xf0, 0x1ff); /* spurious vector register */
+}
+
+int main()
+{
+    setup_vm();
+
+    g_apic = vmap(0xfee00000, 0x1000);
+    g_ioapic = vmap(0xfec00000, 0x1000);
+
+    test_lapic_existence();
+
+    enable_apic();
+    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/apic.h b/kvm/user/test/x86/apic.h
new file mode 100644
index 0000000..c061e3d
--- /dev/null
+++ b/kvm/user/test/x86/apic.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/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..69a6262
--- /dev/null
+++ b/kvm/user/test/x86/cstart.S
@@ -0,0 +1,10 @@
+
+
+.bss
+
+.section .init
+	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..432a3dc
--- /dev/null
+++ b/kvm/user/test/x86/cstart64.S
@@ -0,0 +1,168 @@
+
+#include "fake-apic.h"
+
+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
+	.quad 0x1e7 | (i << 21)
+	i = i + 1
+	.endr
+
+.align 4096
+ptl3:
+	.quad ptl2 + 7
+
+.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
+	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_init_ipi:
+	call prepare_64
+	jmpl $8, $ap_start64
+
+.code64
+ap_start64:
+	call load_tss
+	sti
+	nop
+
+1:	hlt
+	jmp 1b
+
+start64:
+	call load_tss
+	call smp_init
+	call main
+	mov %eax, %edi
+	call exit
+
+load_tss:
+	mov $0, %eax
+	mov %ax, %ss
+	mov $(APIC_BASE + APIC_REG_ID), %dx
+	in %dx, %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:
+	lea boot_idt + ipi_vector * 8, %rdi
+	mov $smp_init_ipi, %eax
+	mov %ax, (%rdi)
+	mov %cs, %ax
+	mov %ax, 2(%rdi)
+	movw $0x8e00, 4(%rdi)
+	shr $16, %eax
+	mov %ax, 6(%rdi)
+
+	mov $(APIC_BASE + APIC_REG_IPI_VECTOR), %dx
+	mov $ipi_vector, %eax
+	out %eax, %dx
+
+	mov $(APIC_BASE + APIC_REG_NCPU), %dx
+	in %dx, %eax
+	mov %eax, %ecx
+	mov $1, %esi
+smp_loop:
+	cmp %esi, %ecx
+	je smp_init_done
+
+	mov $(APIC_BASE + APIC_REG_SEND_IPI), %dx
+	mov %esi, %eax
+	out %eax, %dx
+
+	inc %esi
+	jmp smp_loop
+smp_init_done:
+	ret
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/irq.S b/kvm/user/test/x86/irq.S
new file mode 100644
index 0000000..0425db6
--- /dev/null
+++ b/kvm/user/test/x86/irq.S
@@ -0,0 +1,118 @@
+// irq test program.  assumes outb $irq, $0xff generates an interrupt $irq.
+
+#include "print.h"
+	
+.text
+	PRINT "irq test"
+	mov $stack_top, %rsp
+
+	call setup_gdt
+	
+	mov %ds, %ax
+	mov %ax, %ds  // check ds descriptor is okay
+
+	mov $irq_handler, %rdx
+	mov $0x20, %eax
+	call setup_idt_entry
+
+	lidt idt_descriptor
+
+	PRINT "software interrupt"
+	int $0x20
+
+	sti
+	nop
+
+	PRINT "injecting interrupt with interrupts enabled"
+	
+	mov $0x20, %al
+	outb %al, $0xff // inject interrupt
+
+	nop
+	nop
+	nop
+	PRINT "after injection"
+
+	cli
+
+	PRINT "injecting interrupt with interrupts disabled"
+	
+	mov $0x20, %al
+	outb %al, $0xff // inject interrupt
+
+	// no interrupt here (disabled)
+	nop
+	nop
+	PRINT "enabling interrupts"
+	nop
+	nop
+	sti
+	out %al, $0x80 // blocked by sti
+	// interrupt here
+	out %al, $0x80 
+
+	PRINT "after injection"
+	nop
+	nop
+	
+	hlt
+	
+irq_handler:
+	PRINT "interrupt handler"
+	iretq
+	
+setup_idt_entry:	// %rax: irq %rdx: handler
+	shl $4, %rax
+	mov %dx, idt(%rax)
+	shr $16, %rdx
+	mov %cs, 2+idt(%rax)
+	mov %dx, 6+idt(%rax)
+	shr $16, %rdx
+	mov %edx, 8+idt(%rax)
+	movw $0x8e00, 4+idt(%rax)
+	ret
+
+setup_gdt:
+	mov $0, %eax
+	mov %cs, %ax
+	andl $~7, %eax
+	movl $0xffff, gdt(%rax)
+	movl $0xaf9b00, 4+gdt(%rax)
+
+	mov $0, %eax
+	mov %ds, %ax
+	andl $~7, %eax
+	movl $0xffff, gdt(%rax)
+	movl $0x8f9300, 4+gdt(%rax)
+
+	lgdt gdt_descriptor
+	ret
+	
+.data
+	
+.align 16
+
+idt:	
+	. = . + 256 * 16
+
+idt_descriptor:
+	.word . - idt - 1
+	.quad idt
+
+.align 8
+	
+gdt:
+	. = . + 256 * 8
+
+gdt_descriptor:
+	.word . - gdt - 1
+	.quad gdt 
+
+	
+.align 4096
+stack_base:
+	. = . + 4096
+stack_top:
+	
+
+
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..755b5d1
--- /dev/null
+++ b/kvm/user/test/x86/realmode.c
@@ -0,0 +1,518 @@
+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 ("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_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 start(void)
+{
+	test_null();
+
+	test_shld();
+	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);
+}
+
+asm(
+	".data \n\t"
+	". = . + 4096 \n\t"
+	"stacktop: \n\t"
+	".text \n\t"
+	"init: \n\t"
+	"xor %ax, %ax \n\t"
+	"mov %ax, %ds \n\t"
+	"mov %ax, %es \n\t"
+	"mov %ax, %ss \n\t"
+	"mov $0x4000, %cx \n\t"
+	"xor %esi, %esi \n\t"
+	"mov %esi, %edi \n\t"
+	"rep/addr32/cs/movsl \n\t"
+	"mov $stacktop, %sp\n\t"
+	"ljmp $0, $start \n\t"
+	".pushsection .boot, \"ax\" \n\t"
+	"ljmp $0xf000, $init \n\t"
+	".popsection"
+	);
diff --git a/kvm/user/test/x86/realmode.lds b/kvm/user/test/x86/realmode.lds
new file mode 100644
index 0000000..c9cdd7d
--- /dev/null
+++ b/kvm/user/test/x86/realmode.lds
@@ -0,0 +1,16 @@
+OUTPUT_FORMAT(binary)
+
+SECTIONS
+{
+    . = 0;
+    stext = .;
+    .text : { *(.init) *(.text) }
+    . = ALIGN(4K);
+    .data : { *(.data) *(.rodata*) }
+    . = ALIGN(16);
+    .bss : { *(.bss) }
+    . = 0xfff0;
+    .boot : { *(.boot) }
+    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..7b1ba49
--- /dev/null
+++ b/kvm/user/test/x86/smptest.c
@@ -0,0 +1,31 @@
+#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());
+}
+
+static void smp_main(void)
+{
+    printf("smp main %d\n", smp_id());
+    while (1)
+	asm volatile ("hlt" : : : "memory");
+}
+
+int main()
+{
+    int ncpus;
+    int i;
+
+    smp_init(smp_main);
+    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..204b1fd
--- /dev/null
+++ b/kvm/user/test/x86/tsc.c
@@ -0,0 +1,40 @@
+#include "libcflat.h"
+
+typedef unsigned long long u64;
+
+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..03c7354
--- /dev/null
+++ b/kvm/user/test/x86/vm.c
@@ -0,0 +1,268 @@
+
+#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;
+
+    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..981d6c1
--- /dev/null
+++ b/kvm/user/test/x86/vmexit.c
@@ -0,0 +1,39 @@
+
+#include "libcflat.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;
+}
+
+#define N (1 << 22)
+
+#ifdef __x86_64__
+#  define R "r"
+#else
+#  define R "e"
+#endif
+
+int main()
+{
+	int i;
+	unsigned long long t1, t2;
+
+	t1 = rdtsc();
+	for (i = 0; i < N; ++i)
+		asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
+			      : : : "eax", "ecx", "edx");
+	t2 = rdtsc();
+	printf("vmexit latency: %d\n", (int)((t2 - t1) / N));
+	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 ed1ce6e..61e0ed3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -44,6 +44,9 @@
 #include "migration.h"
 #include "kvm.h"
 #include "acl.h"
+#include "exec-all.h"
+
+#include "qemu-kvm.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -374,6 +377,7 @@
 #endif
         if (env->halted)
             monitor_printf(mon, " (halted)");
+        monitor_printf(mon," thread_id=%d", env->thread_id);
         monitor_printf(mon, "\n");
     }
 }
@@ -384,6 +388,23 @@
         monitor_printf(mon, "Invalid CPU index\n");
 }
 
+static void do_cpu_set_nr(Monitor *mon, int value, const char *status)
+{
+    int state;
+
+    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);
@@ -1421,7 +1442,7 @@
 
 static void do_info_kvm(Monitor *mon)
 {
-#ifdef CONFIG_KVM
+#if defined(USE_KVM) || defined(CONFIG_KVM)
     monitor_printf(mon, "kvm support: ");
     if (kvm_enabled())
         monitor_printf(mon, "enabled\n");
@@ -1556,7 +1577,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/net.c b/net.c
index 7466961..effd9a2 100644
--- a/net.c
+++ b/net.c
@@ -110,6 +110,7 @@
 #define memalign(align, size) malloc(size)
 #endif
 
+// FIXME: #include "qemu-kvm.h"
 #include "qemu-common.h"
 #include "net.h"
 #include "monitor.h"
@@ -434,7 +435,7 @@
 }
 
 static int
-qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size)
+qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size, int raw)
 {
     VLANClientState *vc;
     int ret = -1;
@@ -453,7 +454,11 @@
             continue;
         }
 
-        len = vc->receive(vc, buf, size);
+        if (raw && vc->receive_raw) {
+            len = vc->receive_raw(vc, buf, size);
+        } else {
+            len = vc->receive(vc, buf, size);
+        }
 
         ret = (ret >= 0) ? ret : len;
     }
@@ -484,7 +489,8 @@
         packet = TAILQ_FIRST(&vc->vlan->send_queue);
         TAILQ_REMOVE(&vc->vlan->send_queue, packet, entry);
 
-        ret = qemu_deliver_packet(packet->sender, packet->data, packet->size);
+        ret = qemu_deliver_packet(packet->sender, packet->data,
+                                  packet->size, packet->raw);
         if (ret == 0 && packet->sent_cb != NULL) {
             TAILQ_INSERT_HEAD(&vc->vlan->send_queue, packet, entry);
             break;
@@ -498,7 +504,7 @@
 }
 
 static void qemu_enqueue_packet(VLANClientState *sender,
-                                const uint8_t *buf, int size,
+                                const uint8_t *buf, int size, int raw,
                                 NetPacketSent *sent_cb)
 {
     VLANPacket *packet;
@@ -506,15 +512,16 @@
     packet = qemu_malloc(sizeof(VLANPacket) + size);
     packet->sender = sender;
     packet->size = size;
+    packet->raw = raw;
     packet->sent_cb = sent_cb;
     memcpy(packet->data, buf, size);
 
     TAILQ_INSERT_TAIL(&sender->vlan->send_queue, packet, entry);
 }
 
-ssize_t qemu_send_packet_async(VLANClientState *sender,
-                               const uint8_t *buf, int size,
-                               NetPacketSent *sent_cb)
+static ssize_t qemu_send_packet_async2(VLANClientState *sender,
+                                       const uint8_t *buf, int size, int raw,
+                                       NetPacketSent *sent_cb)
 {
     int ret;
 
@@ -528,13 +535,13 @@
 #endif
 
     if (sender->vlan->delivering) {
-        qemu_enqueue_packet(sender, buf, size, NULL);
+        qemu_enqueue_packet(sender, buf, size, raw, NULL);
         return size;
     }
 
-    ret = qemu_deliver_packet(sender, buf, size);
+    ret = qemu_deliver_packet(sender, buf, size, raw);
     if (ret == 0 && sent_cb != NULL) {
-        qemu_enqueue_packet(sender, buf, size, sent_cb);
+        qemu_enqueue_packet(sender, buf, size, raw, sent_cb);
         return 0;
     }
 
@@ -543,9 +550,21 @@
     return ret;
 }
 
-void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
+ssize_t qemu_send_packet_async(VLANClientState *sender,
+                               const uint8_t *buf, int size,
+                               NetPacketSent *sent_cb)
 {
-    qemu_send_packet_async(vc, buf, size, NULL);
+    return qemu_send_packet_async2(sender, buf, size, 0, sent_cb);
+}
+
+ssize_t qemu_send_packet(VLANClientState *sender, const uint8_t *buf, int size)
+{
+    return qemu_send_packet_async2(sender, buf, size, 0, NULL);
+}
+
+ssize_t qemu_send_packet_raw(VLANClientState *sender, const uint8_t *buf, int size)
+{
+    return qemu_send_packet_async2(sender, buf, size, 1, NULL);
 }
 
 static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
@@ -624,6 +643,7 @@
     packet->sender = sender;
     packet->sent_cb = sent_cb;
     packet->size = 0;
+    packet->raw = 0;
 
     for (i = 0; i < iovcnt; i++) {
         size_t len = iov[i].iov_len;
@@ -1264,16 +1284,38 @@
 
 #endif /* CONFIG_SLIRP */
 
-#if !defined(_WIN32)
+#ifdef _WIN32
+
+int tap_has_vnet_hdr(void *opaque)
+{
+    return 0;
+}
+
+void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr)
+{
+}
+
+#else /* !defined(_WIN32) */
+
+/* Maximum GSO packet size (64k) plus plenty of room for
+ * the ethernet and virtio_net headers
+ */
+#define TAP_BUFSIZE (4096 + 65536)
+
+#ifdef IFF_VNET_HDR
+#include <linux/virtio_net.h>
+#endif
 
 typedef struct TAPState {
     VLANClientState *vc;
     int fd;
     char down_script[1024];
     char down_script_arg[128];
-    uint8_t buf[4096];
+    uint8_t buf[TAP_BUFSIZE];
     unsigned int read_poll : 1;
     unsigned int write_poll : 1;
+    unsigned int has_vnet_hdr : 1;
+    unsigned int using_vnet_hdr : 1;
 } TAPState;
 
 static int launch_script(const char *setup_script, const char *ifname, int fd);
@@ -1332,14 +1374,48 @@
 
 static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
+    struct iovec iov[2];
+    int i = 0;
+
+#ifdef IFF_VNET_HDR
     TAPState *s = vc->opaque;
-    ssize_t len;
+    struct virtio_net_hdr hdr = { 0, };
 
-    do {
-        len = write(s->fd, buf, size);
-    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
+        iov[i].iov_base = &hdr;
+        iov[i].iov_len  = sizeof(hdr);
+        i++;
+    }
+#endif
 
-    return len;
+    iov[i].iov_base = (char *) buf;
+    iov[i].iov_len  = size;
+    i++;
+
+    return tap_receive_iov(vc, iov, i);
+}
+
+static ssize_t tap_receive_raw(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    struct iovec iov[2];
+    int i = 0;
+
+#ifdef IFF_VNET_HDR
+    TAPState *s = vc->opaque;
+    struct virtio_net_hdr hdr = { 0, };
+
+    if (s->has_vnet_hdr && s->using_vnet_hdr) {
+        iov[i].iov_base = &hdr;
+        iov[i].iov_len  = sizeof(hdr);
+        i++;
+    }
+#endif
+
+    iov[i].iov_base = (char *) buf;
+    iov[i].iov_len  = size;
+    i++;
+
+    return tap_receive_iov(vc, iov, i);
 }
 
 static int tap_can_send(void *opaque)
@@ -1377,13 +1453,21 @@
 {
     TAPState *s = opaque;
     int size;
+    uint8_t *buf = s->buf;
 
     size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
     if (size <= 0) {
         return;
     }
 
-    size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed);
+#ifdef IFF_VNET_HDR
+    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
+        buf += sizeof(struct virtio_net_hdr);
+        size -= sizeof(struct virtio_net_hdr);
+    }
+#endif
+
+    size = qemu_send_packet_async(s->vc, buf, size, tap_send_completed);
     if (size == 0) {
         tap_read_poll(s, 0);
     }
@@ -1423,6 +1507,70 @@
 }
 #endif /* TUNSETSNDBUF */
 
+int tap_has_vnet_hdr(void *opaque)
+{
+    VLANClientState *vc = opaque;
+    TAPState *s = vc->opaque;
+
+    if (vc->receive != tap_receive)
+        return 0;
+
+    return s ? s->has_vnet_hdr : 0;
+}
+
+void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr)
+{
+    VLANClientState *vc = opaque;
+    TAPState *s = vc->opaque;
+
+    if (vc->receive != tap_receive)
+        return;
+
+    if (!s || !s->has_vnet_hdr)
+        return;
+
+    s->using_vnet_hdr = using_vnet_hdr != 0;
+}
+
+static int tap_probe_vnet_hdr(int fd)
+{
+#if defined(TUNGETIFF) && defined(IFF_VNET_HDR)
+    struct ifreq ifr;
+
+    if (ioctl(fd, TUNGETIFF, &ifr) != 0) {
+        fprintf(stderr, "TUNGETIFF ioctl() failed: %s\n", strerror(errno));
+        return 0;
+    }
+
+    return ifr.ifr_flags & IFF_VNET_HDR;
+#else
+    return 0;
+#endif
+}
+
+#ifdef TUNSETOFFLOAD
+static void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6,
+			    int ecn)
+{
+    TAPState *s = vc->opaque;
+    unsigned int offload = 0;
+
+    if (csum) {
+	offload |= TUN_F_CSUM;
+	if (tso4)
+	    offload |= TUN_F_TSO4;
+	if (tso6)
+	    offload |= TUN_F_TSO6;
+	if ((tso4 || tso6) && ecn)
+	    offload |= TUN_F_TSO_ECN;
+    }
+
+    if (ioctl(s->fd, TUNSETOFFLOAD, offload) != 0)
+	fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
+		strerror(errno));
+}
+#endif /* TUNSETOFFLOAD */
+
 static void tap_cleanup(VLANClientState *vc)
 {
     TAPState *s = vc->opaque;
@@ -1443,14 +1591,21 @@
 static TAPState *net_tap_fd_init(VLANState *vlan,
                                  const char *model,
                                  const char *name,
-                                 int fd)
+                                 int fd,
+                                 int vnet_hdr)
 {
     TAPState *s;
 
     s = qemu_mallocz(sizeof(TAPState));
     s->fd = fd;
+    s->has_vnet_hdr = vnet_hdr != 0;
     s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
                                  tap_receive_iov, tap_cleanup, s);
+    s->vc->receive_raw = tap_receive_raw;
+#ifdef TUNSETOFFLOAD
+    s->vc->set_offload = tap_set_offload;
+    tap_set_offload(s->vc, 0, 0, 0, 0);
+#endif
     tap_read_poll(s, 1);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
     return s;
@@ -1599,7 +1754,7 @@
     return tap_fd;
 }
 
-static int tap_open(char *ifname, int ifname_size)
+static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
 {
     char  dev[10]="";
     int fd;
@@ -1618,7 +1773,7 @@
     return -1;
 }
 #else
-static int tap_open(char *ifname, int ifname_size)
+static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
 {
     struct ifreq ifr;
     int fd, ret;
@@ -1630,6 +1785,19 @@
     }
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+#if defined(TUNGETFEATURES) && defined(IFF_VNET_HDR)
+    {
+        unsigned int features;
+
+        if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
+            features & IFF_VNET_HDR) {
+            *vnet_hdr = 1;
+            ifr.ifr_flags |= IFF_VNET_HDR;
+        }
+    }
+#endif
+
     if (ifname[0] != '\0')
         pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
     else
@@ -1696,13 +1864,15 @@
 {
     TAPState *s;
     int fd;
+    int vnet_hdr;
     char ifname[128];
 
     if (ifname1 != NULL)
         pstrcpy(ifname, sizeof(ifname), ifname1);
     else
         ifname[0] = '\0';
-    TFR(fd = tap_open(ifname, sizeof(ifname)));
+    vnet_hdr = 0;
+    TFR(fd = tap_open(ifname, sizeof(ifname), &vnet_hdr));
     if (fd < 0)
         return NULL;
 
@@ -1712,7 +1882,7 @@
         launch_script(setup_script, ifname, fd)) {
         return NULL;
     }
-    s = net_tap_fd_init(vlan, model, name, fd);
+    s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "ifname=%s,script=%s,downscript=%s",
              ifname, setup_script, down_script);
@@ -2671,7 +2841,7 @@
                 goto out;
             }
             fcntl(fd, F_SETFL, O_NONBLOCK);
-            s = net_tap_fd_init(vlan, device, name, fd);
+            s = net_tap_fd_init(vlan, device, name, fd, tap_probe_vnet_hdr(fd));
             if (!s) {
                 close(fd);
             }
diff --git a/net.h b/net.h
index bab02f5..57ab031 100644
--- a/net.h
+++ b/net.h
@@ -13,9 +13,11 @@
 typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
 typedef void (NetCleanup) (VLANClientState *);
 typedef void (LinkStatusChanged)(VLANClientState *);
+typedef void (SetOffload)(VLANClientState *, int, int, int, int);
 
 struct VLANClientState {
     NetReceive *receive;
+    NetReceive *receive_raw;
     NetReceiveIOV *receive_iov;
     /* Packets may still be sent if this returns zero.  It's used to
        rate-limit the slirp code.  */
@@ -23,6 +25,7 @@
     NetCleanup *cleanup;
     LinkStatusChanged *link_status_changed;
     int link_down;
+    SetOffload *set_offload;
     void *opaque;
     struct VLANClientState *next;
     struct VLANState *vlan;
@@ -39,6 +42,7 @@
     TAILQ_ENTRY(VLANPacket) entry;
     VLANClientState *sender;
     int size;
+    int raw;
     NetPacketSent *sent_cb;
     uint8_t data[0];
 };
@@ -68,7 +72,8 @@
                           int iovcnt);
 ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov,
                                 int iovcnt, NetPacketSent *sent_cb);
-void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size);
 ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf,
                                int size, NetPacketSent *sent_cb);
 void qemu_purge_queued_packets(VLANClientState *vc);
@@ -84,6 +89,9 @@
 
 void do_info_usernet(Monitor *mon);
 
+int tap_has_vnet_hdr(void *opaque);
+void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr);
+
 /* NIC info */
 
 #define MAX_NICS 8
diff --git a/osdep.c b/osdep.c
index 410e436..f37c22c 100644
--- a/osdep.c
+++ b/osdep.c
@@ -224,7 +224,11 @@
     if (kqemu_allowed)
         return kqemu_vmalloc(size);
 #endif
+#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/bios.bin b/pc-bios/bios.bin
index e4323c0..dff17ce 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
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 e7ad4b1..d3dd870 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -30,7 +30,7 @@
 CFLAGS += -fno-stack-protector
 endif
 
-build-all: multiboot.bin
+build-all: multiboot.bin extboot.bin
 
 %.o: %.S
 	$(CC) $(CFLAGS) -o $@ -c $<
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/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/qemu-common.h b/qemu-common.h
index 6a15f89..d478b47 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -193,6 +193,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-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..b8a2587
--- /dev/null
+++ b/qemu-kvm-ia64.c
@@ -0,0 +1,147 @@
+#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_qemu_init_env(CPUState *cenv)
+{
+    return 0;
+}
+
+int kvm_arch_halt(void *opaque, 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;
+}
+
+void kvm_arch_update_regs_for_sipi(CPUState *env)
+{
+}
+
+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..d5436b6
--- /dev/null
+++ b/qemu-kvm-x86.c
@@ -0,0 +1,1690 @@
+/*
+ * 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, 0xfffbd000);
+		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, unsigned long 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, 0xfffbc000);
+		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;
+
+	return 0;
+}
+
+#ifdef KVM_EXIT_TPR_ACCESS
+
+static int kvm_handle_tpr_access(kvm_vcpu_context_t vcpu)
+{
+	struct kvm_run *run = vcpu->run;
+	kvm_tpr_access_report(cpu_single_env,
+                         run->tpr_access.rip,
+                         run->tpr_access.is_write);
+    return 0;
+}
+
+
+int kvm_enable_vapic(kvm_vcpu_context_t vcpu, uint64_t vapic)
+{
+	int r;
+	struct kvm_vapic_addr va = {
+		.vapic_addr = vapic,
+	};
+
+	r = ioctl(vcpu->fd, KVM_SET_VAPIC_ADDR, &va);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_enable_vapic");
+		return r;
+	}
+	return 0;
+}
+
+#endif
+
+int kvm_arch_run(kvm_vcpu_context_t vcpu)
+{
+	int r = 0;
+	struct kvm_run *run = vcpu->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(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 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(kvm_vcpu_context_t vcpu, struct kvm_lapic_state *s)
+{
+	int r;
+	if (!kvm_irqchip_in_kernel(vcpu->kvm))
+		return 0;
+	r = ioctl(vcpu->fd, KVM_GET_LAPIC, s);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_get_lapic");
+	}
+	return r;
+}
+
+int kvm_set_lapic(kvm_vcpu_context_t vcpu, struct kvm_lapic_state *s)
+{
+	int r;
+	if (!kvm_irqchip_in_kernel(vcpu->kvm))
+		return 0;
+	r = ioctl(vcpu->fd, 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)
+{
+	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(kvm_vcpu_context_t vcpu)
+{
+#define SHOW_CODE_LEN 50
+	int fd = vcpu->fd;
+	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;
+	kvm_context_t kvm = vcpu->kvm;
+
+	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_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;
+
+	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(kvm_vcpu_context_t vcpu, struct kvm_msr_entry *msrs, int n)
+{
+    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r, e;
+
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = ioctl(vcpu->fd, KVM_GET_MSRS, kmsrs);
+    e = errno;
+    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
+    free(kmsrs);
+    errno = e;
+    return r;
+}
+
+int kvm_set_msrs(kvm_vcpu_context_t vcpu, struct kvm_msr_entry *msrs, int n)
+{
+    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r, e;
+
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = ioctl(vcpu->fd, KVM_SET_MSRS, kmsrs);
+    e = errno;
+    free(kmsrs);
+    errno = e;
+    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(kvm_vcpu_context_t vcpu, uint64_t *mcg_cap)
+{
+#ifdef KVM_CAP_MCE
+    return ioctl(vcpu->fd, KVM_X86_SETUP_MCE, mcg_cap);
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_set_mce(kvm_vcpu_context_t vcpu, struct kvm_x86_mce *m)
+{
+#ifdef KVM_CAP_MCE
+    return ioctl(vcpu->fd, 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(kvm_vcpu_context_t vcpu)
+{
+	int fd = vcpu->fd;
+	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_vcpu_context_t vcpu)
+{
+	return vcpu->run->apic_base;
+}
+
+void kvm_set_cr8(kvm_vcpu_context_t vcpu, uint64_t cr8)
+{
+	vcpu->run->cr8 = cr8;
+}
+
+__u64 kvm_get_cr8(kvm_vcpu_context_t vcpu)
+{
+	return vcpu->run->cr8;
+}
+
+int kvm_setup_cpuid(kvm_vcpu_context_t vcpu, 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 = ioctl(vcpu->fd, KVM_SET_CPUID, cpuid);
+
+	free(cpuid);
+	return r;
+}
+
+int kvm_setup_cpuid2(kvm_vcpu_context_t vcpu, 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 = ioctl(vcpu->fd, 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 = 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(kvm_vcpu_context_t vcpu, 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;
+	r = ioctl(vcpu->fd, 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_vcpu_context_t vcpu)
+{
+	return tpr_access_reporting(vcpu, 1);
+}
+
+int kvm_disable_tpr_access_reporting(kvm_vcpu_context_t vcpu)
+{
+	return tpr_access_reporting(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 = 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);
+}
+
+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;
+    }
+
+    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;
+        default:
+            printf("Warning unknown msr index 0x%x\n", entry->index);
+            return 1;
+        }
+        return 0;
+}
+
+#ifdef TARGET_X86_64
+#define MSR_COUNT 10
+#else
+#define MSR_COUNT 6
+#endif
+
+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[MSR_COUNT];
+    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->kvm_cpu_state.vcpu_ctx, &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->kvm_cpu_state.vcpu_ctx, &fpu);
+
+    memcpy(sregs.interrupt_bitmap, env->interrupt_bitmap, sizeof(sregs.interrupt_bitmap));
+
+    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->kvm_cpu_state.vcpu_ctx, &sregs);
+
+    /* msrs */
+    n = 0;
+    /* Remember to increase MSR_COUNT 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
+
+    rc = kvm_set_msrs(env->kvm_cpu_state.vcpu_ctx, 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->kvm_cpu_state.vcpu_ctx, &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->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_save_regs(CPUState *env)
+{
+    struct kvm_regs regs;
+    struct kvm_fpu fpu;
+    struct kvm_sregs sregs;
+    struct kvm_msr_entry msrs[MSR_COUNT];
+    uint32_t hflags;
+    uint32_t i, n, rc;
+
+    kvm_get_regs(env->kvm_cpu_state.vcpu_ctx, &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->kvm_cpu_state.vcpu_ctx, &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->kvm_cpu_state.vcpu_ctx, &sregs);
+
+    memcpy(env->interrupt_bitmap, sregs.interrupt_bitmap, sizeof(env->interrupt_bitmap));
+
+    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 MSR_COUNT 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
+    rc = kvm_get_msrs(env->kvm_cpu_state.vcpu_ctx, 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;
+        }
+    }
+}
+
+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_qemu_init_env(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);
+
+
+#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->kvm_cpu_state.vcpu_ctx, 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->kvm_cpu_state.vcpu_ctx, &mcg_cap))
+                perror("kvm_setup_mce FAILED");
+            else
+                cenv->mcg_cap = mcg_cap;
+        }
+    }
+#endif
+
+    return 0;
+}
+
+int kvm_arch_halt(void *opaque, kvm_vcpu_context_t vcpu)
+{
+    CPUState *env = cpu_single_env;
+
+    if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+	  (env->eflags & IF_MASK)) &&
+	!(env->interrupt_request & CPU_INTERRUPT_NMI)) {
+            env->halted = 1;
+    }
+    return 1;
+}
+
+void kvm_arch_pre_kvm_run(void *opaque, CPUState *env)
+{
+    if (!kvm_irqchip_in_kernel(kvm_context))
+	kvm_set_cr8(env->kvm_cpu_state.vcpu_ctx, cpu_get_apic_tpr(env));
+}
+
+void kvm_arch_post_kvm_run(void *opaque, CPUState *env)
+{
+    cpu_single_env = env;
+
+    env->eflags = kvm_get_interrupt_flag(env->kvm_cpu_state.vcpu_ctx)
+	? env->eflags | IF_MASK : env->eflags & ~IF_MASK;
+
+    cpu_set_apic_tpr(env, kvm_get_cr8(env->kvm_cpu_state.vcpu_ctx));
+    cpu_set_apic_base(env, kvm_get_apic_base(env->kvm_cpu_state.vcpu_ctx));
+}
+
+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->kvm_cpu_state.vcpu_ctx) &&
+        (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->kvm_cpu_state.vcpu_ctx, 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->kvm_cpu_state.vcpu_ctx);
+    if (r < 0)
+        printf("cpu %d fail inject NMI\n", env->cpu_index);
+}
+#endif /* KVM_CAP_USER_NMI */
+
+void kvm_arch_update_regs_for_sipi(CPUState *env)
+{
+    SegmentCache cs = env->segs[R_CS];
+
+    kvm_arch_save_regs(env);
+    env->segs[R_CS] = cs;
+    env->eip = 0;
+    kvm_arch_load_regs(env);
+}
+
+void kvm_arch_cpu_reset(CPUState *env)
+{
+    kvm_arch_load_regs(env);
+    if (!cpu_is_bsp(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;
+	}
+    }
+}
+
+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
+
+void kvm_arch_do_ioperm(void *_data)
+{
+    struct ioperm_data *data = _data;
+    ioperm(data->start_port, data->num, data->turn_on);
+}
+
+/*
+ * 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)
+{
+    kvm_arch_save_regs(env);
+    if (env->interrupt_request & CPU_INTERRUPT_INIT)
+        do_cpu_init(env);
+    if (env->interrupt_request & CPU_INTERRUPT_SIPI)
+        do_cpu_sipi(env);
+    kvm_arch_load_regs(env);
+}
diff --git a/qemu-kvm.c b/qemu-kvm.c
new file mode 100644
index 0000000..32dce4a
--- /dev/null
+++ b/qemu-kvm.c
@@ -0,0 +1,2621 @@
+/*
+ * 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 <signal.h>
+
+#define false 0
+#define true 1
+
+#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;
+
+/* The list of ioperm_data */
+static LIST_HEAD(, ioperm_data) ioperm_head;
+
+//#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(void *opaque, void *data,
+                     struct kvm_debug_exit_arch *arch_info)
+{
+    int handle = kvm_arch_debug(arch_info);
+    CPUState *env = data;
+
+    if (handle) {
+	kvm_debug_cpu_requested = env;
+	env->stopped = 1;
+    }
+    return handle;
+}
+#endif
+
+int kvm_mmio_read(void *opaque, uint64_t addr, uint8_t *data, int len)
+{
+	cpu_physical_memory_rw(addr, data, len, 0);
+	return 0;
+}
+
+int kvm_mmio_write(void *opaque, uint64_t addr, uint8_t *data, int len)
+{
+	cpu_physical_memory_rw(addr, data, len, 1);
+	return 0;
+}
+
+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 %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 = 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
+    TAILQ_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;
+}
+
+kvm_vcpu_context_t kvm_create_vcpu(CPUState *env, int id)
+{
+	long mmap_size;
+	int r;
+	kvm_vcpu_context_t vcpu_ctx = qemu_malloc(sizeof(struct kvm_vcpu_context));
+    kvm_context_t kvm = kvm_context;
+
+	vcpu_ctx->kvm = kvm;
+	vcpu_ctx->id = id;
+
+	r = kvm_vm_ioctl(kvm_state, KVM_CREATE_VCPU, id);
+	if (r < 0) {
+		fprintf(stderr, "kvm_create_vcpu: %m\n");
+		goto err;
+	}
+	vcpu_ctx->fd = r;
+
+    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;
+	}
+	vcpu_ctx->run = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+			      vcpu_ctx->fd, 0);
+	if (vcpu_ctx->run == MAP_FAILED) {
+		fprintf(stderr, "mmap vcpu area: %m\n");
+		goto err_fd;
+	}
+	return vcpu_ctx;
+err_fd:
+	close(vcpu_ctx->fd);
+err:
+	free(vcpu_ctx);
+	return NULL;
+}
+
+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
+}
+
+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)(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 = 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 %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 = 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((slots[i].len / 4096 + 7) / 8 + 2);
+			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_io(kvm_vcpu_context_t vcpu)
+{
+	struct kvm_run *run = vcpu->run;
+	kvm_context_t kvm = vcpu->kvm;
+	uint16_t addr = run->io.port;
+	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:
+				*(uint8_t *)p = cpu_inb(kvm->opaque, addr);
+				break;
+			case 2:
+				*(uint16_t *)p = cpu_inw(kvm->opaque, addr);
+				break;
+			case 4:
+				*(uint32_t *)p = cpu_inl(kvm->opaque, addr);
+				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:
+				 cpu_outb(kvm->opaque, addr, *(uint8_t *)p);
+				break;
+			case 2:
+				cpu_outw(kvm->opaque, addr, *(uint16_t *)p);
+				break;
+			case 4:
+				cpu_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_vcpu_context_t vcpu, void *env)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    struct kvm_run *run = vcpu->run;
+    kvm_context_t kvm = vcpu->kvm;
+
+    return kvm_debug(kvm->opaque, env, &run->debug.arch);
+#else
+    return 0;
+#endif
+}
+
+int kvm_get_regs(kvm_vcpu_context_t vcpu, struct kvm_regs *regs)
+{
+    return ioctl(vcpu->fd, KVM_GET_REGS, regs);
+}
+
+int kvm_set_regs(kvm_vcpu_context_t vcpu, struct kvm_regs *regs)
+{
+    return ioctl(vcpu->fd, KVM_SET_REGS, regs);
+}
+
+int kvm_get_fpu(kvm_vcpu_context_t vcpu, struct kvm_fpu *fpu)
+{
+    return ioctl(vcpu->fd, KVM_GET_FPU, fpu);
+}
+
+int kvm_set_fpu(kvm_vcpu_context_t vcpu, struct kvm_fpu *fpu)
+{
+    return ioctl(vcpu->fd, KVM_SET_FPU, fpu);
+}
+
+int kvm_get_sregs(kvm_vcpu_context_t vcpu, struct kvm_sregs *sregs)
+{
+    return ioctl(vcpu->fd, KVM_GET_SREGS, sregs);
+}
+
+int kvm_set_sregs(kvm_vcpu_context_t vcpu, struct kvm_sregs *sregs)
+{
+    return ioctl(vcpu->fd, KVM_SET_SREGS, sregs);
+}
+
+#ifdef KVM_CAP_MP_STATE
+int kvm_get_mpstate(kvm_vcpu_context_t vcpu, struct kvm_mp_state *mp_state)
+{
+    int r;
+
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_MP_STATE);
+    if (r > 0)
+        return ioctl(vcpu->fd, KVM_GET_MP_STATE, mp_state);
+    return -ENOSYS;
+}
+
+int kvm_set_mpstate(kvm_vcpu_context_t vcpu, struct kvm_mp_state *mp_state)
+{
+    int r;
+
+    r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_MP_STATE);
+    if (r > 0)
+        return ioctl(vcpu->fd, KVM_SET_MP_STATE, mp_state);
+    return -ENOSYS;
+}
+#endif
+
+static int handle_mmio(kvm_vcpu_context_t vcpu)
+{
+	unsigned long addr = vcpu->run->mmio.phys_addr;
+	kvm_context_t kvm = vcpu->kvm;
+	struct kvm_run *kvm_run = vcpu->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;
+
+	if (kvm_run->mmio.is_write)
+		return kvm_mmio_write(kvm->opaque, addr, data,
+					kvm_run->mmio.len);
+	else
+		return kvm_mmio_read(kvm->opaque, addr, data,
+					kvm_run->mmio.len);
+}
+
+int handle_io_window(kvm_context_t kvm)
+{
+    return 1;
+}
+
+int handle_halt(kvm_vcpu_context_t vcpu)
+{
+	return kvm_arch_halt(vcpu->kvm->opaque, vcpu);
+}
+
+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_kvm_run(kvm->opaque, env);
+}
+
+int pre_kvm_run(kvm_context_t kvm, CPUState *env)
+{
+    kvm_arch_pre_kvm_run(kvm->opaque, env);
+
+    pthread_mutex_unlock(&qemu_mutex);
+    return 0;
+}
+
+int kvm_get_interrupt_flag(kvm_vcpu_context_t vcpu)
+{
+	return vcpu->run->if_flag;
+}
+
+int kvm_is_ready_for_interrupt_injection(kvm_vcpu_context_t vcpu)
+{
+	return vcpu->run->ready_for_interrupt_injection;
+}
+
+int kvm_run(kvm_vcpu_context_t vcpu, void *env)
+{
+	int r;
+	int fd = vcpu->fd;
+	struct kvm_run *run = vcpu->run;
+	kvm_context_t kvm = vcpu->kvm;
+
+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->coalesced_mmio) {
+	        struct kvm_coalesced_mmio_ring *ring = (void *)run +
+						kvm->coalesced_mmio * PAGE_SIZE;
+		while (ring->first != ring->last) {
+			kvm_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:
+			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(vcpu);
+			kvm_show_code(vcpu);
+			abort();
+			break;
+		case KVM_EXIT_IO:
+			r = handle_io(vcpu);
+			break;
+		case KVM_EXIT_DEBUG:
+			r = handle_debug(vcpu, env);
+			break;
+		case KVM_EXIT_MMIO:
+			r = handle_mmio(vcpu);
+			break;
+		case KVM_EXIT_HLT:
+			r = handle_halt(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_s390_handle_intercept(kvm, vcpu,
+				run);
+			break;
+		case KVM_EXIT_S390_RESET:
+			r = kvm_s390_handle_reset(kvm, vcpu, run);
+			break;
+#endif
+		default:
+			if (kvm_arch_run(vcpu)) {
+				fprintf(stderr, "unhandled vm exit: 0x%x\n",
+							run->exit_reason);
+				kvm_show_regs(vcpu);
+				abort();
+			}
+			break;
+		}
+	}
+more:
+	if (!r)
+		goto again;
+	return r;
+}
+
+int kvm_inject_irq(kvm_vcpu_context_t vcpu, unsigned irq)
+{
+	struct kvm_interrupt intr;
+
+	intr.irq = irq;
+	return ioctl(vcpu->fd, KVM_INTERRUPT, &intr);
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(kvm_vcpu_context_t vcpu, struct kvm_guest_debug *dbg)
+{
+	return ioctl(vcpu->fd, KVM_SET_GUEST_DEBUG, dbg);
+}
+#endif
+
+int kvm_set_signal_mask(kvm_vcpu_context_t vcpu, const sigset_t *sigset)
+{
+	struct kvm_signal_mask *sigmask;
+	int r;
+
+	if (!sigset) {
+		r = ioctl(vcpu->fd, KVM_SET_SIGNAL_MASK, NULL);
+		if (r == -1)
+			r = -errno;
+		return r;
+	}
+	sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
+
+	sigmask->len = 8;
+	memcpy(sigmask->sigset, sigset, sizeof(*sigset));
+	r = ioctl(vcpu->fd, 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(void)
+{
+        int r = 0;
+#ifdef KVM_CAP_SYNC_MMU
+        r = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_SYNC_MMU);
+#endif
+        return r;
+}
+
+int kvm_inject_nmi(kvm_vcpu_context_t vcpu)
+{
+#ifdef KVM_CAP_USER_NMI
+	return ioctl(vcpu->fd, 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 = kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+	if (r > 0) {
+		kvm->coalesced_mmio = r;
+		return 0;
+	}
+#endif
+	return r;
+}
+
+int kvm_coalesce_mmio_region(target_phys_addr_t addr, ram_addr_t size)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+	kvm_context_t kvm = kvm_context;
+	struct kvm_coalesced_mmio_zone zone;
+	int r;
+
+	if (kvm->coalesced_mmio) {
+
+		zone.addr = addr;
+		zone.size = size;
+
+		r = kvm_vm_ioctl(kvm_state, KVM_REGISTER_COALESCED_MMIO, &zone);
+		if (r < 0) {
+			perror("kvm_register_coalesced_mmio_zone");
+			return r;
+		}
+		return 0;
+	}
+#endif
+	return -ENOSYS;
+}
+
+int kvm_uncoalesce_mmio_region(target_phys_addr_t addr, ram_addr_t size)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+	kvm_context_t kvm = kvm_context;
+	struct kvm_coalesced_mmio_zone zone;
+	int r;
+
+	if (kvm->coalesced_mmio) {
+
+		zone.addr = addr;
+		zone.size = size;
+
+		r = kvm_vm_ioctl(kvm_state, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+		if (r < 0) {
+			perror("kvm_unregister_coalesced_mmio_zone");
+			return r;
+		}
+		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)
+{
+	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;
+    static const struct timespec ts = {
+        .tv_sec = 0,
+        .tv_nsec = 100000,
+    };
+
+    pthread_cond_timedwait(cond, &qemu_mutex, &ts);
+    cpu_single_env = env;
+}
+
+static void sig_ipi_handler(int n)
+{
+}
+
+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);
+}
+
+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);
+    env->halted = (env->mp_state == KVM_MP_STATE_HALTED);
+}
+
+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->kvm_cpu_state.vcpu_ctx, 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_main_loop_wait(CPUState *env, int timeout)
+{
+    struct timespec ts;
+    int r, e;
+    siginfo_t siginfo;
+    sigset_t waitset;
+
+    pthread_mutex_unlock(&qemu_mutex);
+
+    ts.tv_sec = timeout / 1000;
+    ts.tv_nsec = (timeout % 1000) * 1000000;
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+
+    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);
+    }
+
+    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);
+    
+    kvm_set_signal_mask(env->kvm_cpu_state.vcpu_ctx, &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)
+{
+    setup_kernel_sigmask(env);
+
+    pthread_mutex_lock(&qemu_mutex);
+
+    kvm_qemu_init_env(env);
+#ifdef TARGET_I386
+    kvm_tpr_vcpu_start(env);
+#endif
+
+    cpu_single_env = env;
+    kvm_arch_load_regs(env);
+
+    while (1) {
+        int run_cpu = !is_cpu_stopped(env);
+        if (run_cpu && !kvm_irqchip_in_kernel(kvm_context)) {
+            process_irqchip_events(env);
+            run_cpu = !env->halted;
+        }
+        if (run_cpu) {
+            kvm_main_loop_wait(env, 0);
+            kvm_cpu_exec(env);
+	} 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;
+    struct ioperm_data *data = NULL;
+
+    current_env = env;
+    env->thread_id = kvm_get_thread_id();
+    sigfillset(&signals);
+    sigprocmask(SIG_BLOCK, &signals, NULL);
+    env->kvm_cpu_state.vcpu_ctx = kvm_create_vcpu(env, env->cpu_index);
+
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+    /* do ioperm for io ports of assigned devices */
+    LIST_FOREACH(data, &ioperm_head, entries)
+	on_vcpu(env, kvm_arch_do_ioperm, data);
+#endif
+
+    /* signal VCPU creation */
+    pthread_mutex_lock(&qemu_mutex);
+    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);
+    pthread_mutex_unlock(&qemu_mutex);
+
+    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)
+{
+#ifdef TARGET_I386
+    kvm_tpr_opt_setup();
+#endif
+    qemu_add_vm_change_state_handler(kvm_vm_state_change_handler, NULL);
+
+    signal(SIG_IPI, sig_ipi_handler);
+    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_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);
+    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_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()
+{
+    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;
+}
+
+int kvm_qemu_check_extension(int ext)
+{
+    return kvm_check_extension(kvm_state, ext);
+}
+
+int kvm_qemu_init_env(CPUState *cenv)
+{
+    return kvm_arch_qemu_init_env(cenv);
+}
+
+#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;
+
+    dbg_data->err = kvm_set_guest_debug(cpu_single_env->kvm_cpu_state.vcpu_ctx,
+		    &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);
+            if (kvm_dirty_bitmap == NULL) {
+                perror("Failed to allocate dirty pages bitmap");
+                r=-1;
+            }
+            else {
+                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);
+    }
+}
+
+int kvm_get_phys_ram_page_bitmap(unsigned char *bitmap)
+{
+    unsigned int bsize  = BITMAP_SIZE(phys_ram_size);
+    unsigned int brsize = BITMAP_SIZE(ram_size);
+    unsigned int extra_pages = (phys_ram_size - ram_size) / TARGET_PAGE_SIZE;
+    unsigned int extra_bytes = (extra_pages +7)/8;
+    unsigned int hole_start = BITMAP_SIZE(0xa0000);
+    unsigned int hole_end   = BITMAP_SIZE(0xc0000);
+
+    memset(bitmap, 0xFF, brsize + extra_bytes);
+    memset(bitmap + hole_start, 0, hole_end - hole_start);
+    memset(bitmap + brsize + extra_bytes, 0, bsize - brsize - extra_bytes);
+
+    return 0;
+}
+
+#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;
+}
+
+#ifdef USE_KVM_DEVICE_ASSIGNMENT
+void kvm_add_ioperm_data(struct ioperm_data *data)
+{
+    LIST_INSERT_HEAD(&ioperm_head, data, entries);
+}
+
+void kvm_remove_ioperm_data(unsigned long start_port, unsigned long num)
+{
+    struct ioperm_data *data;
+
+    data = LIST_FIRST(&ioperm_head);
+    while (data) {
+        struct ioperm_data *next = LIST_NEXT(data, entries);
+
+        if (data->start_port == start_port && data->num == num) {
+            LIST_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;
+};
+
+static void kvm_do_inject_x86_mce(void *_data)
+{
+    struct kvm_x86_mce_data *data = _data;
+    int r;
+
+    r = kvm_set_mce(data->env->kvm_cpu_state.vcpu_ctx, data->mce);
+    if (r < 0)
+        perror("kvm_set_mce FAILED");
+}
+#endif
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc)
+{
+#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,
+    };
+
+    on_vcpu(cenv, kvm_do_inject_x86_mce, &data);
+#endif
+}
+#endif
diff --git a/qemu-kvm.h b/qemu-kvm.h
new file mode 100644
index 0000000..eb48ff8
--- /dev/null
+++ b/qemu-kvm.h
@@ -0,0 +1,1216 @@
+/*
+ * 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
+
+#include "cpu.h"
+
+#include <signal.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;
+	/// 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;
+};
+
+struct kvm_vcpu_context
+{
+	int fd;
+	struct kvm_run *run;
+	struct kvm_context *kvm;
+	uint32_t id;
+};
+
+typedef struct kvm_context *kvm_context_t;
+typedef struct kvm_vcpu_context *kvm_vcpu_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(kvm_vcpu_context_t vcpu);
+
+
+void kvm_show_code(kvm_vcpu_context_t vcpu);
+
+int handle_halt(kvm_vcpu_context_t vcpu);
+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 handle_debug(kvm_vcpu_context_t vcpu, void *env);
+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(kvm_vcpu_context_t, struct kvm_msr_entry *msrs, int n);
+int kvm_set_msrs(kvm_vcpu_context_t, 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(kvm_vcpu_context_t vcpu, uint64_t *mcg_cap);
+struct kvm_x86_mce;
+int kvm_set_mce(kvm_vcpu_context_t vcpu, struct kvm_x86_mce *mce);
+#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 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
+ */
+kvm_vcpu_context_t kvm_create_vcpu(CPUState *env, int id);
+
+/*!
+ * \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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t vcpu, struct kvm_sregs *regs);
+
+#ifdef KVM_CAP_MP_STATE
+/*!
+ *  * \brief Read VCPU MP state
+ *
+ */
+int kvm_get_mpstate(kvm_vcpu_context_t vcpu, struct kvm_mp_state *mp_state);
+
+/*!
+ *  * \brief Write VCPU MP state
+ *
+ */
+int kvm_set_mpstate(kvm_vcpu_context_t vcpu, struct kvm_mp_state *mp_state);
+/*!
+ *  * \brief Reset VCPU MP state
+ *
+ */
+static inline int kvm_reset_mpstate(kvm_vcpu_context_t vcpu)
+{
+    struct kvm_mp_state mp_state = {.mp_state = KVM_MP_STATE_UNINITIALIZED};
+    return kvm_set_mpstate(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_vcpu_context_t vcpu, unsigned irq);
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(kvm_vcpu_context_t, 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t vcpu, 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(kvm_vcpu_context_t 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*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);
+
+#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_vcpu_context_t 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_vcpu_context_t 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_vcpu_context_t vcpu);
+
+#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
+ */
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc);
+
+/*!
+ * \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(kvm_vcpu_context_t 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_vcpu_context_t vcpu);
+
+int kvm_enable_vapic(kvm_vcpu_context_t 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 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; }
+static inline void kvm_inject_x86_mce(
+    CPUState *cenv, int bank,uint64_t status,
+    uint64_t mcg_status, uint64_t addr, uint64_t misc) { }
+
+
+extern int kvm_allowed;
+
+#endif /* !CONFIG_KVM */
+
+
+int kvm_main_loop(void);
+int kvm_qemu_init(void);
+int kvm_init_ap(void);
+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);
+int kvm_qemu_init_env(CPUState *env);
+int kvm_qemu_check_extension(int ext);
+void kvm_apic_init(CPUState *env);
+/* called from vcpu initialization */
+void qemu_kvm_load_lapic(CPUState *env);
+
+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);
+int kvm_get_phys_ram_page_bitmap(unsigned char *bitmap);
+
+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);
+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);
+
+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_qemu_init_env(CPUState *cenv);
+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);
+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_update_regs_for_sipi(CPUState *env);
+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;
+    TAILQ_ENTRY(kvm_sw_breakpoint) entry;
+};
+
+TAILQ_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);
+
+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);
+
+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);
+
+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 USE_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))
+#define BITMAP_SIZE(m) (ALIGN(((m)>>TARGET_PAGE_BITS), HOST_LONG_BITS) / 8)
+
+#ifdef CONFIG_KVM
+#include "sys-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;
+    LIST_ENTRY(ioperm_data) entries;
+};
+
+void qemu_kvm_cpu_stop(CPUState *env);
+int kvm_arch_halt(void *opaque, kvm_vcpu_context_t vcpu);
+int handle_tpr_access(void *opaque, kvm_vcpu_context_t vcpu,
+			     uint64_t rip, int is_write);
+int kvm_has_sync_mmu(void);
+
+#define kvm_enabled() (kvm_allowed)
+#define qemu_kvm_irqchip_in_kernel() kvm_irqchip_in_kernel(kvm_context)
+#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_irqchip_in_kernel() (0)
+#define qemu_kvm_pit_in_kernel() (0)
+#define qemu_kvm_has_gsi_routing() (0)
+#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 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
+
+void kvm_mutex_unlock(void);
+void kvm_mutex_lock(void);
+
+static inline void qemu_mutex_unlock_iothread(void)
+{
+    if (kvm_enabled())
+	kvm_mutex_unlock();
+}
+
+static inline void qemu_mutex_lock_iothread(void)
+{
+    if (kvm_enabled())
+	kvm_mutex_lock();
+}
+
+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; }
+
+static inline void kvm_arch_get_registers(CPUState *env)
+{
+    kvm_save_registers(env);
+    kvm_save_mpstate(env);
+}
+
+static inline void kvm_arch_put_registers(CPUState *env)
+{
+    kvm_load_registers(env);
+    kvm_load_mpstate(env);
+}
+
+static inline void cpu_synchronize_state(CPUState *env, int modified)
+{
+    if (kvm_enabled()) {
+        if (modified)
+            kvm_arch_put_registers(env);
+        else
+            kvm_arch_get_registers(env);
+    }
+}
+
+uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
+                                      int reg);
+
+
+static inline int kvm_set_migration_log(int enable)
+{
+    return kvm_physical_memory_set_dirty_tracking(enable);
+}
+
+#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;
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
+#endif
+    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_check_extension(KVMState *s, unsigned int ext);
+
+#endif
+
+#endif
diff --git a/qemu-lock.h b/qemu-lock.h
index 49e2203..029fae0 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 11bdb2c..0dc2ad7 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -511,7 +511,7 @@
 ETEXI
 
 #if defined(TARGET_I386)
-    { "pci_add", "sss?", pci_device_hot_add, "auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...", "hot-add PCI device" },
+    { "pci_add", "sss?", pci_device_hot_add, "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]", "hot-add PCI device" },
 #endif
 STEXI
 @item pci_add
@@ -646,6 +646,13 @@
 used by another monitor command.
 ETEXI
 
+    { "cpu_set", "is", do_cpu_set_nr,
+      "cpu [online|offline]", "change cpu state" },
+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 a58287c..3038acd 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -93,6 +93,7 @@
     "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
     "       [,cache=writethrough|writeback|none][,format=f][,serial=s]\n"
     "       [,addr=A]\n"
+    "       [,boot=on|off]\n"
     "                use 'file' as a drive image\n")
 STEXI
 @item -drive @var{option}[,@var{option}[,@var{option}[,...]]]
@@ -1661,3 +1662,34 @@
 DEF("old-param", 0, QEMU_OPTION_old_param,
     "-old-param      old param mode\n")
 #endif
+
+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/sysemu.h b/sysemu.h
index ce25109..1c87216 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -42,6 +42,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);
@@ -118,6 +119,7 @@
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
+extern uint8_t irq0override;
 extern DisplayType display_type;
 extern const char *keyboard_layout;
 extern int win2k_install_hack;
@@ -133,6 +135,7 @@
 extern int semihosting_enabled;
 extern int old_param;
 extern int boot_menu;
+extern long hpagesize;
 
 #ifdef CONFIG_KQEMU
 extern int kqemu_allowed;
@@ -184,6 +187,7 @@
 
 extern int nb_drives;
 extern DriveInfo drives_table[MAX_DRIVES+1];
+extern int extboot_drive;
 
 extern int drive_get_index(BlockInterfaceType type, int bus, int unit);
 extern int drive_get_max_bus(BlockInterfaceType type);
@@ -207,6 +211,7 @@
 extern int drive_init(struct drive_opt *arg, int snapshot, void *machine);
 
 /* acpi */
+void qemu_system_cpu_hot_add(int cpu, int state);
 typedef void (*qemu_system_device_hot_add_t)(int pcibus, int slot, int state);
 void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback);
 void qemu_system_device_hot_add(int pcibus, int slot, int state);
diff --git a/target-i386/fake-exec.c b/target-i386/fake-exec.c
new file mode 100644
index 0000000..737286d
--- /dev/null
+++ b/target-i386/fake-exec.c
@@ -0,0 +1,54 @@
+/*
+ * 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 flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void optimize_flags_init(void)
+{
+}
diff --git a/target-i386/helper.c b/target-i386/helper.c
index dd89885..4785ff0 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[] = {
@@ -1504,6 +1506,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);
+        return;
+    }
+
     if (bank >= bank_num || !(status & MCI_STATUS_VAL))
         return;
 
@@ -1568,7 +1575,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__
@@ -1709,8 +1716,29 @@
         *edx = env->cpuid_ext2_features;
 
         if (kvm_enabled()) {
-            /* Nested SVM not yet supported in KVM */
-            *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);
@@ -1837,8 +1865,6 @@
     kqemu_init(env);
 #endif
 
-    qemu_init_vcpu(env);
-
     return env;
 }
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 2d4ebaf..6037b20 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -24,6 +24,7 @@
 #include "cpu.h"
 #include "gdbstub.h"
 
+#ifdef KVM_UPSTREAM
 //#define DEBUG_KVM
 
 #ifdef DEBUG_KVM
@@ -477,6 +478,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);
@@ -610,6 +612,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;
@@ -653,6 +656,9 @@
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
+        case MSR_VM_HSAVE_PA:
+            env->vm_hsave = msrs[i].data;
+            break;
         }
     }
 
@@ -977,3 +983,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 8bf13cc..ca32a92 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -6,6 +6,7 @@
 
 #include "exec-all.h"
 #include "kvm.h"
+#include "qemu-kvm.h"
 
 static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)
 {
@@ -32,7 +33,10 @@
     int32_t pending_irq;
     int i, bit;
 
-    cpu_synchronize_state(env, 0);
+    if (kvm_enabled()) {
+        kvm_save_registers(env);
+        kvm_arch_save_mpstate(env);
+    }
 
     for(i = 0; i < CPU_NB_REGS; i++)
         qemu_put_betls(f, &env->regs[i]);
@@ -119,7 +123,6 @@
     qemu_put_be64s(f, &env->kernelgsbase);
 #endif
     qemu_put_be32s(f, &env->smbase);
-
     qemu_put_be64s(f, &env->pat);
     qemu_put_be32s(f, &env->hflags2);
     
@@ -161,7 +164,7 @@
 
     /* MCE */
     qemu_put_be64s(f, &env->mcg_cap);
-    if (env->mcg_cap) {
+    if (env->mcg_cap && !kvm_enabled()) {
         qemu_put_be64s(f, &env->mcg_status);
         qemu_put_be64s(f, &env->mcg_ctl);
         for (i = 0; i < (env->mcg_cap & 0xff); i++) {
@@ -364,7 +367,7 @@
 
     if (version_id >= 10) {
         qemu_get_be64s(f, &env->mcg_cap);
-        if (env->mcg_cap) {
+        if (env->mcg_cap && !kvm_enabled()) {
             qemu_get_be64s(f, &env->mcg_status);
             qemu_get_be64s(f, &env->mcg_ctl);
             for (i = 0; i < (env->mcg_cap & 0xff); i++) {
@@ -381,5 +384,26 @@
     env->hflags = hflags;
     tlb_flush(env, 1);
     cpu_synchronize_state(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;
+        if (version_id < 9) {
+            for (i = 0; i < sizeof(env->interrupt_bitmap)/8; i++) {
+                qemu_get_be64s(f, &env->interrupt_bitmap[i]);
+            }
+            qemu_get_be64s(f, &env->tsc);
+            kvm_load_registers(env);
+            kvm_load_tsc(env);
+            if (version_id >= 5) {
+                qemu_get_be32s(f, &env->mp_state);
+                kvm_arch_load_mpstate(env);
+            }
+        } else {
+            kvm_load_registers(env);
+            kvm_load_tsc(env);
+            kvm_arch_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 69c1d58..d697bd2 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) */
@@ -1591,4 +1592,11 @@
     *flags = env->hflags;
 }
 
+/* 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 b7162df..6ffe9ce 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 99ba3eb..ec8e197 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 710d52e..26bced8 100644
--- a/vl.c
+++ b/vl.c
@@ -161,6 +161,8 @@
 #include "kvm.h"
 #include "balloon.h"
 #include "qemu-option.h"
+#include "qemu-kvm.h"
+#include "hw/device-assignment.h"
 
 #include "disas.h"
 
@@ -187,6 +189,7 @@
    to store the VM snapshots */
 DriveInfo drives_table[MAX_DRIVES+1];
 int nb_drives;
+int extboot_drive = -1;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 static DisplayState *display_state;
 DisplayType display_type = DT_DEFAULT;
@@ -223,10 +226,14 @@
 #endif
 int usb_enabled = 0;
 int singlestep = 0;
+const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE];
+int assigned_devices_index;
 int smp_cpus = 1;
 const char *vnc_display;
 int acpi_enabled = 1;
+#ifdef TARGET_I386
 int no_hpet = 0;
+#endif
 int virtio_balloon = 1;
 const char *virtio_balloon_devaddr;
 int fd_bootchk = 1;
@@ -234,6 +241,7 @@
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
+uint8_t irq0override = 1;
 #ifndef _WIN32
 int daemonize = 0;
 #endif
@@ -242,6 +250,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
@@ -252,6 +266,7 @@
 const char *prom_envs[MAX_PROM_ENVS];
 #endif
 int nb_drives_opt;
+const char *nvram = NULL;
 struct drive_opt drives_opt[MAX_DRIVES];
 int boot_menu;
 
@@ -2017,6 +2032,7 @@
                                            "media", "snapshot", "file",
                                            "cache", "format", "serial",
                                            "werror", "addr",
+                                           "boot",
                                            NULL };
 
     if (check_params(buf, sizeof(buf), params, str) < 0) {
@@ -2202,6 +2218,19 @@
         }
     }
 
+    if (get_param_value(buf, sizeof(buf), "boot", str)) {
+	if (!strcmp(buf, "on")) {
+	    if (extboot_drive != -1) {
+		fprintf(stderr, "qemu: two bootable drives specified\n");
+		return -1;
+	    }
+	    extboot_drive = nb_drives;
+	} else if (strcmp(buf, "off")) {
+	    fprintf(stderr, "qemu: '%s' invalid boot option\n", str);
+	    return -1;
+	}
+    }
+
     if (arg->file == NULL)
         get_param_value(file, sizeof(file), "file", str);
     else
@@ -2812,6 +2841,7 @@
         ioh->opaque = opaque;
         ioh->deleted = 0;
     }
+    qemu_notify_event();
     return 0;
 }
 
@@ -2938,6 +2968,8 @@
     if (qemu_get_be32(f) != last_ram_offset)
         return -EINVAL;
     for(i = 0; i < last_ram_offset; i+= TARGET_PAGE_SIZE) {
+        if (kvm_enabled() && (i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
+            continue;
         ret = ram_get_page(f, qemu_get_ram_ptr(i), TARGET_PAGE_SIZE);
         if (ret)
             return ret;
@@ -3024,6 +3056,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;
 
@@ -3153,6 +3194,8 @@
     if (ram_decompress_open(s, f) < 0)
         return -EINVAL;
     for(i = 0; i < last_ram_offset; i+= BDRV_HASH_BLOCK_SIZE) {
+        if (kvm_enabled() && (i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
+            continue;
         if (ram_decompress_buf(s, buf, 1) < 0) {
             fprintf(stderr, "Error while reading ram block header\n");
             goto error;
@@ -3467,6 +3510,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;
@@ -3551,6 +3601,9 @@
     } else {
         reset_requested = 1;
     }
+    if (cpu_single_env) {
+        cpu_single_env->stopped = 1;
+    }
     qemu_notify_event();
 }
 
@@ -3697,6 +3750,10 @@
 {
     CPUState *env = cpu_single_env;
 
+    if (kvm_enabled()) {
+        qemu_kvm_notify_work();
+        return;
+    }
     if (env) {
         cpu_exit(env);
 #ifdef USE_KQEMU
@@ -3706,8 +3763,10 @@
      }
 }
 
+#ifdef KVM_UPSTREAM
 #define qemu_mutex_lock_iothread() do { } while (0)
 #define qemu_mutex_unlock_iothread() do { } while (0)
+#endif
 
 void vm_stop(int reason)
 {
@@ -4127,6 +4186,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);
@@ -4328,6 +4389,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);
@@ -4933,6 +5000,7 @@
     }
 
     usb_devices_index = 0;
+    assigned_devices_index = 0;
 
     nb_net_clients = 0;
     nb_bt_opts = 0;
@@ -5437,12 +5505,44 @@
                 break;
 #endif
 #ifdef CONFIG_KVM
+#ifdef KVM_UPSTREAM
             case QEMU_OPTION_enable_kvm:
                 kvm_allowed = 1;
 #ifdef CONFIG_KQEMU
                 kqemu_allowed = 0;
 #endif
+#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;
@@ -5515,6 +5615,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);
 		 {
@@ -5609,6 +5723,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:
@@ -5714,6 +5831,20 @@
     }
 #endif
 
+    if (kvm_enabled()) {
+        int ret;
+
+        ret = kvm_init(smp_cpus);
+        if (ret < 0) {
+#if defined(KVM_UPSTREAM) || defined(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;
+        }
+    }
+
 #ifdef CONFIG_KQEMU
     if (smp_cpus > 1)
         kqemu_allowed = 0;
@@ -5885,16 +6016,6 @@
         }
     }
 
-    if (kvm_enabled()) {
-        int ret;
-
-        ret = kvm_init(smp_cpus);
-        if (ret < 0) {
-            fprintf(stderr, "failed to initialize KVM\n");
-            exit(1);
-        }
-    }
-
     if (monitor_device) {
         monitor_hd = qemu_chr_open("monitor", monitor_device, NULL);
         if (!monitor_hd) {