diff --git a/hw/xenner_dom_builder.c b/hw/xenner_dom_builder.c
new file mode 100644
index 0000000..b4d55dd
--- /dev/null
+++ b/hw/xenner_dom_builder.c
@@ -0,0 +1,406 @@
+/*
+ *  Copyright (C) Red Hat 2007
+ *  Copyright (C) Novell Inc. 2010
+ *
+ *  Author(s): Gerd Hoffmann <kraxel@redhat.com>
+ *             Alexander Graf <agraf@suse.de>
+ *
+ *  Xenner Domain Builder
+ *
+ *  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; under 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/mman.h>
+
+#include <xen/io/protocols.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "kvm.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+#include "xen_interfaces.h"
+#include "xen_domainbuild.h"
+#include "xenner.h"
+#include "xenner_emudev.h"
+#include "loader.h"
+#include "elf.h"
+#include "apic.h"
+
+#define XEN_ELFNOTE_INFO            0
+#define XEN_ELFNOTE_ENTRY           1
+#define XEN_ELFNOTE_HYPERCALL_PAGE  2
+#define XEN_ELFNOTE_VIRT_BASE       3
+#define XEN_ELFNOTE_PADDR_OFFSET    4
+#define XEN_ELFNOTE_XEN_VERSION     5
+#define XEN_ELFNOTE_GUEST_OS        6
+#define XEN_ELFNOTE_GUEST_VERSION   7
+#define XEN_ELFNOTE_LOADER          8
+#define XEN_ELFNOTE_PAE_MODE        9
+#define XEN_ELFNOTE_FEATURES       10
+#define XEN_ELFNOTE_BSD_SYMTAB     11
+#define XEN_ELFNOTE_HV_START_LOW   12
+#define XEN_ELFNOTE_L1_MFN_VALID   13
+#define XEN_ELFNOTE_SUSPEND_CANCEL 14
+#define XEN_ELFNOTE_INIT_P2M       15
+
+
+typedef struct DomParams {
+    uint64_t virt_hypercall;
+    uint64_t virt_base;
+    uint64_t virt_entry;
+    int pae;
+    int bits;
+} DomParams;
+
+#define MEGABYTE        (uint64_t)0x100000ULL
+#define MB_TO_PG(x)     (MEGABYTE * x / TARGET_PAGE_SIZE)
+#define PG_TO_MB(x)     (x * TARGET_PAGE_SIZE / MEGABYTE)
+
+static uint64_t note_numeric(uint8_t *desc, uint32_t desc_len)
+{
+    uint64_t r = 0;
+
+    switch (desc_len) {
+        case sizeof(uint8_t):
+            r = *desc;
+            break;
+        case sizeof(uint16_t):
+            r = lduw_p(desc);
+            break;
+        case sizeof(uint32_t):
+            r = ldl_p(desc);
+            break;
+        case sizeof(uint64_t):
+            r = ldq_p(desc);
+            break;
+    }
+
+    return r;
+}
+
+static void dombuild_note(void *opaque, uint8_t *name, uint32_t name_len,
+                          uint8_t *desc, uint32_t desc_len, uint32_t type)
+{
+    DomParams *params = (DomParams *)opaque;
+
+    if (name_len != 4) {
+        return;
+    }
+
+    if (!((name[0] == 'X') && (name[1] == 'e') && (name[2] == 'n'))) {
+        return;
+    }
+
+    switch (type) {
+        case XEN_ELFNOTE_HYPERCALL_PAGE:
+            params->virt_hypercall = note_numeric(desc, desc_len);
+            break;
+        case XEN_ELFNOTE_VIRT_BASE:
+            params->virt_base = note_numeric(desc, desc_len);
+            break;
+        case XEN_ELFNOTE_ENTRY:
+            params->virt_entry = note_numeric(desc, desc_len);
+            break;
+        case XEN_ELFNOTE_PAE_MODE:
+            params->pae = !strncmp((char*)desc, "yes", desc_len);
+            break;
+    }
+}
+
+static void dombuild_xen_guest_key(DomParams *params, char *key, char *value)
+{
+    if (!strncmp(key, "HYPERCALL_PAGE", strlen("HYPERCALL_PAGE"))) {
+        params->virt_hypercall = (strtoull(value, NULL, 0) << PAGE_SHIFT) +
+                                 params->virt_base;
+    }
+
+    if (!strncmp(key, "VIRT_BASE", strlen("VIRT_BASE"))) {
+        params->virt_base = strtoull(value, NULL, 0);
+    }
+
+    if (!strncmp(key, "VIRT_ENTRY", strlen("VIRT_ENTRY"))) {
+        params->virt_entry = strtoull(value, NULL, 0);
+    }
+
+    if (!strncmp(key, "PAE", strlen("PAE"))) {
+        params->pae = !strncmp(value, "yes", 3);
+    }
+}
+
+static void dombuild_section(void *opaque, uint8_t *_name, uint32_t len,
+                             uint8_t *_content)
+{
+    DomParams *params = (DomParams *)opaque;
+    char *entry, *next_entry;
+    char *name = (void*)_name;
+    char *content = (void*)_content;
+
+    if (strlen(name) != strlen("__xen_guest")) {
+        return;
+    }
+
+    if (strncmp(name, "__xen_guest", strlen("__xen_guest"))) {
+        return;
+    }
+
+    /* Example contents of section __xen_guest (without line break):
+     *
+     * GUEST_OS=Mini-OS,XEN_VER=xen-3.0,VIRT_BASE=0x0,ELF_PADDR_OFFSET=0x0,
+     * HYPERCALL_PAGE=0x2,LOADER=generic
+     *
+     */
+
+    entry = (char *)content;
+    while (entry) {
+        char *comma, *equalsign, *key, *value;
+
+        comma = strchr(entry, ',');
+        if (comma) {
+            *comma = '\0';
+            next_entry = comma + 1;
+        } else {
+            next_entry = NULL;
+        }
+
+        /* entry now contains KEY=VALUE */
+        equalsign = strchr(entry, '=');
+        if (equalsign) {
+            /* well-formed entry */
+
+            *equalsign = '\0';
+            key = entry;
+            value = equalsign + 1;
+
+            dombuild_xen_guest_key(params, key, value);
+        }
+
+        /* process next entry */
+        entry = next_entry;
+    }
+}
+
+static uint64_t mfn_to_pfn(uint64_t mfn, uint64_t mfn_guest)
+{
+    return mfn - mfn_guest;
+}
+
+static uint64_t dombuild_translate(void *opaque, uint64_t addr)
+{
+    xen_pfn_t *offset = opaque;
+
+    /* offset the kernel into physical memory */
+    addr += *offset * PAGE_SIZE;
+
+    return addr;
+}
+
+static void dombuild_header_notify(void *opaque, void *header, int bits)
+{
+    DomParams *params = opaque;
+
+    params->bits = bits;
+}
+
+
+static void xenner_cpu_reset(void *opaque)
+{
+    uint8_t boot_buf[] = { 0xea, 0x00, 0x00, 0x00, 0x00 };
+
+    /* install the stage0 boot loader */
+    cpu_physical_memory_rw(0xfffffff0, boot_buf, sizeof(boot_buf), 1);
+}
+
+int xenner_domain_build_pv(const char *kernel,
+                           const char *initrd,
+                           const char *cmdline)
+{
+    const char *emu_file;
+    xen_pfn_t pg_total, pg_emu, pg_m2p, pg_guest;
+    xen_pfn_t mfn_emu, mfn_m2p, mfn_guest;
+    uint64_t emu_entry, emu_low, emu_high;
+    int emu_size;
+    DomParams dom_params;
+    uint64_t elf_entry;
+    uint64_t elf_low, elf_high;
+    int kernel_size;
+    ElfHandlers handlers = elf_default_handlers;
+    target_phys_addr_t cur_addr;
+    int long_mode;
+    int console_evtchn, xenstore_evtchn;
+    uint64_t console_mfn, xenstore_mfn, start_info_pfn;
+    uint64_t init_pt_pfn, cmdline_pfn = 0, initrd_len = 0;
+    uint64_t mfn_list_pfn;
+
+    pg_total = ram_size / PAGE_SIZE;
+    pg_emu   = MB_TO_PG(4);
+    pg_m2p   = MB_TO_PG(4);
+    /* every page entry occupies one long */
+    while (pg_m2p < pg_total / (sizeof(target_phys_addr_t) * 8)) {
+        pg_m2p += MB_TO_PG(2);
+    }
+    mfn_guest  = pg_emu + pg_m2p;
+
+    memset(&dom_params, 0, sizeof(DomParams));
+    handlers.note_fn = dombuild_note;
+    handlers.note_opaque = &dom_params;
+    handlers.section_fn = dombuild_section;
+    handlers.section_opaque = &dom_params;
+    handlers.translate_fn = dombuild_translate;
+    handlers.translate_opaque = &mfn_guest;
+    handlers.header_notify_fn = dombuild_header_notify;
+    handlers.header_notify_opaque = &dom_params;
+    kernel_size = load_elf(kernel, &handlers, &elf_entry,
+                           &elf_low, &elf_high, 0, ELF_MACHINE, 0);
+    if (kernel_size < 0) {
+        fprintf(stderr, "Error while loading elf kernel\n");
+        exit(1);
+    }
+
+#if 0
+    printf("virt base: %#lx\n", dom_params.virt_base);
+    printf("virt hypercall: %#lx\n", dom_params.virt_hypercall);
+    printf("virt entry: %#lx\n", dom_params.virt_entry);
+    printf("guest bitness: %d%s\n", dom_params.bits,
+           dom_params.pae ? " pae" : "");
+#endif
+
+    cur_addr = (elf_high + 0x100000) & ~0xfffffULL;
+
+    if (initrd) {
+        int r;
+
+        xenner_set_config(EMUDEV_CONF_PFN_INITRD,
+                          mfn_to_pfn(cur_addr >> PAGE_SHIFT, mfn_guest));
+
+        r = load_image_targphys(initrd, cur_addr, 0);
+        cur_addr += r;
+        initrd_len = r;
+
+        if (r < 0) {
+            fprintf(stderr, "failed to load initrd\n");
+            exit(1);
+        }
+    }
+
+    /* memory setup */
+    if (dom_params.bits == 64) {
+        /* 64bit */
+        emu_file = "xenner64.elf";
+        long_mode = 1;
+    } else if (dom_params.pae) {
+        /* 32bit, PAE */
+        if (pg_total > MB_TO_PG(16384)) {
+            pg_total = MB_TO_PG(16384);
+        }
+        emu_file = "xenner32-pae.elf";
+        long_mode = 0;
+    } else {
+        /* 32bit, non-PAE */
+        if (pg_total > MB_TO_PG(4096)) {
+            pg_total = MB_TO_PG(4096);
+        }
+        emu_file = "xenner32.elf";
+        long_mode = 0;
+    }
+
+    mfn_emu    = 0;
+    mfn_m2p    = pg_emu;
+    pg_guest   = pg_total - mfn_guest;
+
+    emu_file = qemu_find_file(QEMU_FILE_TYPE_BIOS, emu_file);
+    emu_size = load_elf(emu_file, NULL, &emu_entry, &emu_low, &emu_high,
+                        0, ELF_MACHINE, 0);
+
+    if (emu_size < 0) {
+        fprintf(stderr, "Couldn't load xenner image\n");
+        exit(1);
+    }
+
+    cur_addr = (cur_addr + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+    mfn_list_pfn = mfn_to_pfn(cur_addr >> PAGE_SHIFT, mfn_guest);
+    cur_addr += (pg_guest * (long_mode ? 8 : 4) + ~PAGE_MASK) & PAGE_MASK;
+
+    start_info_pfn = mfn_to_pfn(cur_addr >> PAGE_SHIFT, mfn_guest);
+    cur_addr += PAGE_SIZE;
+
+    console_mfn = (cur_addr >> PAGE_SHIFT);
+    cur_addr += PAGE_SIZE;
+
+    xenstore_mfn = (cur_addr >> PAGE_SHIFT);
+    cur_addr += PAGE_SIZE;
+
+    if (cmdline) {
+        cpu_physical_memory_rw(cur_addr, (void*)cmdline, strlen(cmdline) + 1, 1);
+        cmdline_pfn = mfn_to_pfn(cur_addr >> PAGE_SHIFT, mfn_guest);
+        cur_addr += PAGE_SIZE;
+    }
+
+    cur_addr = (cur_addr + ((4 * 1024 * 1024) - 1)) & ~((4 * 1024 * 1024) - 1);
+
+    init_pt_pfn = mfn_to_pfn(cur_addr >> PAGE_SHIFT, mfn_guest);
+    cur_addr += PAGE_SIZE * 100;
+
+    xenner_set_config(EMUDEV_CONF_MFN_CONSOLE,     console_mfn);
+    xenner_set_config(EMUDEV_CONF_MFN_XENSTORE,    xenstore_mfn);
+    xenner_set_config(EMUDEV_CONF_PFN_START_INFO,  start_info_pfn);
+    xenner_set_config(EMUDEV_CONF_PFN_INIT_PT,     init_pt_pfn);
+    xenner_set_config(EMUDEV_CONF_PFN_MFN_LIST,    mfn_list_pfn);
+    xenner_set_config(EMUDEV_CONF_PV_VIRT_ENTRY,   dom_params.virt_entry);
+    xenner_set_config(EMUDEV_CONF_PV_VIRT_BASE,    dom_params.virt_base);
+    xenner_set_config(EMUDEV_CONF_HYPERCALL_PAGE,  dom_params.virt_hypercall);
+
+    xenner_set_config(EMUDEV_CONF_DEBUG_LEVEL,      0);
+    xenner_set_config(EMUDEV_CONF_EMU_START_PFN,    mfn_emu);
+    xenner_set_config(EMUDEV_CONF_EMU_PAGE_COUNT,   pg_emu);
+    xenner_set_config(EMUDEV_CONF_M2P_START_PFN,    mfn_m2p);
+    xenner_set_config(EMUDEV_CONF_M2P_PAGE_COUNT,   pg_m2p);
+    xenner_set_config(EMUDEV_CONF_GUEST_START_PFN,  mfn_guest);
+    xenner_set_config(EMUDEV_CONF_TOTAL_PAGE_COUNT, pg_total);
+    xenner_set_config(EMUDEV_CONF_GUEST_PAGE_COUNT, pg_guest);
+    xenner_set_config(EMUDEV_CONF_NR_VCPUS,         smp_cpus);
+
+    xenner_set_config(EMUDEV_CONF_INITRD_LEN,       initrd_len);
+    xenner_set_config(EMUDEV_CONF_PFN_CMDLINE,      cmdline_pfn);
+
+    /* guest setup */
+
+    console_evtchn  = xenner_guest_evtchn_alloc();
+    xenstore_evtchn = xenner_guest_evtchn_alloc();
+
+    xenner_set_config(EMUDEV_CONF_EVTCH_CONSOLE,    console_evtchn);
+    xenner_set_config(EMUDEV_CONF_EVTCH_XENSTORE,   xenstore_evtchn);
+
+    /* default frontent protocol */
+    if (long_mode) {
+        xen_protocol = XEN_IO_PROTO_ABI_X86_32;
+    } else {
+        xen_protocol = XEN_IO_PROTO_ABI_X86_32;
+    }
+
+    xenstore_domain_init1(kernel, initrd, cmdline);
+    xenstore_domain_init2(xenstore_evtchn,
+                          xenstore_mfn,
+                          console_evtchn,
+                          console_mfn);
+
+    xenner_guest_store_setup(xenstore_mfn,
+                             xenstore_evtchn);
+
+    qemu_register_reset(xenner_cpu_reset, NULL);
+    xenner_cpu_reset(NULL);
+
+    return 0;
+}
