diff --git a/pc-bios/xenner/xenner32-pae.lds b/pc-bios/xenner/xenner32-pae.lds
new file mode 100644
index 0000000..6d56ae4
--- /dev/null
+++ b/pc-bios/xenner/xenner32-pae.lds
@@ -0,0 +1,37 @@
+OUTPUT_FORMAT("elf32-i386")
+
+SECTIONS
+{
+    . = 0xff000000;
+    _vstart = .;
+
+    /* code */
+    .text : AT(ADDR(.text) - 0xff000000) { *(.text) }
+    . = ALIGN(4k);
+    .exfix  : { *(.exfix)  }
+
+    /* data, ro */
+    . = ALIGN(4k);
+    .note.gnu.build-id : { *(.note.gnu.build-id) }
+    . = ALIGN(4k);
+    _estart = .;
+    .extab  : { *(.extab)  }
+    _estop  = .;
+    . = ALIGN(4k);
+    .rodata : { *(.rodata) }
+
+    /* data, rw */
+    . = ALIGN(4k);
+    .pt  : { *(.pt) }
+    . = ALIGN(4k);
+    .pgdata : { *(.pgdata) }
+    . = ALIGN(4k);
+    .data   : { *(.data)   }
+
+    /* bss */
+    . = ALIGN(4k);
+    .bss    : { *(.bss)    }
+
+    . = ALIGN(4k);
+    _vstop  = .;
+}
diff --git a/pc-bios/xenner/xenner32.S b/pc-bios/xenner/xenner32.S
new file mode 100644
index 0000000..052a91b
--- /dev/null
+++ b/pc-bios/xenner/xenner32.S
@@ -0,0 +1,441 @@
+
+#define	ENTRY(name) \
+	.globl name; \
+	.align 16; \
+	name:
+
+	.macro PUSH_ERROR
+	sub $4, %esp		/* space for error code */
+	.endm
+
+	.macro PUSH_TRAP_EBP trapno
+	sub $4, %esp		/* space for trap number */
+	push %ebp
+	mov $\trapno, %ebp
+	mov %ebp, %ss:4(%esp)	/* save trap number on stack */
+	.endm
+
+	.macro PUSH_REGS
+	mov  %es,%ebp
+	push %ebp
+	mov  %ds,%ebp
+	push %ebp
+	mov $0xe010,%ebp	/* ring0 data flat */
+	mov %ebp,%ds
+	mov %ebp,%es
+
+	push %edi
+	push %esi
+	push %edx
+	push %ecx
+	push %ebx
+	push %eax
+	push %esp	       /* struct regs pointer */
+	.endm
+
+	.macro POP_REGS
+	pop %eax		/* dummy (struct regs pointer) */
+	pop %eax
+	pop %ebx
+	pop %ecx
+	pop %edx
+	pop %esi
+	pop %edi
+	pop %ebp
+	mov %ebp,%ds
+	pop %ebp
+	mov %ebp,%es
+	pop %ebp
+	.endm
+
+	.macro RETURN
+	add $8, %esp		/* remove error code & trap number */
+	iret			/* jump back */
+	.endm
+
+	.macro DO_TRAP trapno func
+	PUSH_TRAP_EBP \trapno
+	PUSH_REGS
+	call \func
+	POP_REGS
+	RETURN
+	.endm
+
+/* ------------------------------------------------------------------ */
+
+	.code32
+	.text
+
+/* --- 16-bit boot entry point --- */
+
+ENTRY(boot)
+	.code16
+
+	cli
+
+	/* load the GDT */
+	lgdt	(gdt_desc - boot)
+
+	/* turn on paging */
+	mov	$0x1, %eax
+	mov	%eax, %cr0
+
+	/* enable boot page table */
+	mov	$(emu_boot_pgd - boot), %eax
+	mov	%eax, %cr3
+
+	/* set PSE, maybe PAE */
+#ifdef CONFIG_PAE
+	mov	$0x30, %eax
+#else
+	mov	$0x10, %eax
+#endif
+	mov	%eax, %cr4
+
+	/* turn on paging */
+	mov	$0x80000001, %eax
+	mov	%eax, %cr0
+
+	ljmp	$0x8, $(boot32 - boot)
+
+
+.align 4, 0
+gdt:
+.byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* dummy */
+.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xcf, 0x00 /* code32 */
+.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00 /* data32 */
+
+gdt_desc:
+.short  (3 * 8) - 1
+.long   (gdt - boot)
+
+
+/* --- boot entry point --- */
+
+boot32:
+	.code32
+
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+
+	jmp	*(boot32_ind - boot)
+
+boot32_ind:
+	.long boot32_real
+
+boot32_real:
+
+	/* switch to the real page table */
+
+	mov	$(emu_pgd - boot), %eax
+	mov	%eax, %cr3
+
+	lea boot_stack_high, %esp	/* setup stack */
+	sub $64, %esp			/* sizeof(struct regs_32) */
+	push %esp		       /* struct regs pointer */
+	cmp $0, %ebx
+	jne secondary
+	call do_boot
+	POP_REGS
+	RETURN
+
+secondary:
+	push %ebx
+	call do_boot_secondary
+	pop %ebx
+	POP_REGS
+	RETURN
+
+/* --- traps/faults handled by emu --- */
+
+ENTRY(debug_int1)
+	PUSH_ERROR
+	DO_TRAP 1 do_int1
+
+ENTRY(debug_int3)
+	PUSH_ERROR
+	DO_TRAP 3 do_int3
+
+ENTRY(illegal_instruction)
+	PUSH_ERROR
+	DO_TRAP 6 do_illegal_instruction
+
+ENTRY(no_device)
+	PUSH_ERROR
+	DO_TRAP 7 do_lazy_fpu
+
+ENTRY(double_fault)
+	DO_TRAP 8 do_double_fault
+
+ENTRY(general_protection)
+	DO_TRAP 13 do_general_protection
+
+ENTRY(page_fault)
+	DO_TRAP 14 do_page_fault
+
+/* --- traps/faults forwarded to guest --- */
+
+ENTRY(division_by_zero)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 0
+	jmp guest_forward
+
+ENTRY(nmi)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 2
+	jmp guest_forward
+
+ENTRY(overflow)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 4
+	jmp guest_forward
+
+ENTRY(bound_check)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 5
+	jmp guest_forward
+
+ENTRY(coprocessor)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 9
+	jmp guest_forward
+
+ENTRY(invalid_tss)
+	PUSH_TRAP_EBP 10
+	jmp guest_forward
+
+ENTRY(segment_not_present)
+	PUSH_TRAP_EBP 11
+	jmp guest_forward
+
+ENTRY(stack_fault)
+	PUSH_TRAP_EBP 12
+	jmp guest_forward
+
+ENTRY(floating_point)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 16
+	jmp guest_forward
+
+ENTRY(alignment)
+	PUSH_TRAP_EBP 17
+	jmp guest_forward
+
+ENTRY(machine_check)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 18
+	jmp guest_forward
+
+ENTRY(simd_floating_point)
+	PUSH_ERROR
+	PUSH_TRAP_EBP 19
+	jmp guest_forward
+
+guest_forward:
+	PUSH_REGS
+	call do_guest_forward
+	POP_REGS
+	RETURN
+
+/* --- interrupts 32 ... 255 --- */
+
+ENTRY(smp_flush_tlb)
+	PUSH_ERROR
+	DO_TRAP -1 do_smp_flush_tlb
+
+ENTRY(xen_hypercall)
+	PUSH_ERROR
+	PUSH_TRAP_EBP -1
+	PUSH_REGS
+	call do_hypercall
+	POP_REGS
+	add $8, %esp		/* remove error code & trap number */
+	cmp $-1, -4(%esp)
+	jne 1f
+	out %al, $0xe0	  /* let userspace handle it */
+1:
+	iret
+
+ENTRY(irq_entries)
+vector=0
+.rept 256
+	.align 16
+	PUSH_ERROR
+	PUSH_TRAP_EBP vector
+	jmp irq_common
+vector=vector+1
+.endr
+
+ENTRY(irq_common)
+	PUSH_REGS
+	call do_irq
+	POP_REGS
+	RETURN
+
+/* --- helpers --- */
+
+ENTRY(broken_memcpy_pf)
+	mov 4(%esp),%edi
+	mov 8(%esp),%esi
+	mov 12(%esp),%ecx
+	cld
+1:	rep movsb
+	xor %eax,%eax
+8:	ret
+
+	.section .exfix, "ax"
+9:	mov $-1, %eax
+	jmp 8b
+	.previous
+
+	.section .extab, "a"
+	.align 4
+	.long 1b,9b
+	.previous
+
+ENTRY(broken_copy32_pf)
+	mov 4(%esp),%edi
+	mov 8(%esp),%esi
+1:	mov (%esi),%eax
+2:	mov %eax,(%edi)
+	xor %eax,%eax
+8:	ret
+
+	.section .exfix, "ax"
+9:	mov $-1, %eax
+	jmp 8b
+	.previous
+
+	.section .extab, "a"
+	.align 4
+	.long 1b,9b
+	.long 2b,9b
+	.previous
+
+ENTRY(broken_copy64_pf)
+	mov 4(%esp),%edi
+	mov 8(%esp),%esi
+1:	mov (%esi), %ebx
+2:	mov 4(%esi), %ecx
+3:	mov (%edi), %eax
+4:	mov 4(%edi), %edx
+5:	cmpxchg8b (%edi)
+	xor %eax,%eax
+8:	ret
+
+	.section .exfix, "ax"
+9:	mov $-1, %eax
+	jmp 8b
+	.previous
+
+	.section .extab, "a"
+	.align 4
+	.long 1b,9b
+	.long 2b,9b
+	.long 3b,9b
+	.long 4b,9b
+	.previous
+
+ENTRY(instructions)
+	.byte  0x0f, 0x11, 0x00, 0x0f,  0x11, 0x48, 0x10, 0x0f
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+/* some 16 bit code for smp boot */
+
+	.code16
+	.align 4096
+ENTRY(sipi)
+	mov $0x00060000, %eax  /* EMUDEV_CMD_INIT_SECONDARY_VCPU */
+	outl %eax, $0xe8       /* EMUDEV_REG_COMMAND */
+	hlt
+	.code32
+
+/* data section */
+
+	.data
+	.globl boot_stack_low, boot_stack_high
+	.globl cpu_ptr
+	.align 4096
+boot_stack_low:
+cpu_ptr:
+	.long 0
+	.align 4096
+boot_stack_high:
+
+/* boot page tables */
+
+#define pageflags 0x063 /* preset, rw, accessed, dirty */
+#define largepage 0x080 /* pse */
+
+#ifdef CONFIG_PAE
+
+	.section .pt, "aw"
+	.globl emu_pgd_pae,emu_pmd_pae,emu_boot_pmd,emu_pgd,emu_pmd
+
+	.align 4096
+emu_pgd_pae:
+emu_pgd:
+	.fill 3,8,0
+	.long emu_pmd_pae - 0xff000000 + 0x001
+	.long 0
+	.fill 508,8,0
+
+	.align 4096
+emu_pmd_pae:
+emu_pmd:
+	.fill 504,8,0
+	.quad pageflags + largepage
+	.fill 7,8,0
+
+	/* boot page tables */
+
+	.align 4096
+emu_boot_pgd:
+	.long emu_boot_pmd - 0xff000000 + 0x001
+	.long 0
+	.fill 2,8,0
+	.long emu_boot_pmd - 0xff000000 + 0x001
+	.long 0
+	.fill 508,8,0
+
+	.align 4096
+emu_boot_pmd:
+	.quad pageflags + largepage
+	.fill 503,8,0
+	.quad pageflags + largepage
+	.fill 7,8,0
+
+#else
+
+	.section .pt, "aw"
+	.globl emu_pgd_32,emu_boot_pgd,emu_pgd,emu_pmd
+
+	.align 4096
+emu_pgd_32:
+emu_pgd:
+emu_pmd:
+	.fill 1020,4,0
+	.long pageflags + largepage
+	.fill 3,4,0
+
+	/* boot page tables */
+
+	.align 4096
+emu_boot_pgd:
+	.long pageflags + largepage
+	.fill 1019,4,0
+	.long pageflags + largepage
+	.fill 3,4,0
+
+#endif
diff --git a/pc-bios/xenner/xenner32.h b/pc-bios/xenner/xenner32.h
new file mode 100644
index 0000000..5b4a6d4
--- /dev/null
+++ b/pc-bios/xenner/xenner32.h
@@ -0,0 +1,191 @@
+#include <xen/foreign/x86_32.h>
+
+struct regs_32 {
+    /* pushed onto stack before calling into C code */
+    uint32_t eax;
+    uint32_t ebx;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t esi;
+    uint32_t edi;
+    uint32_t ds;
+    uint32_t es;
+    uint32_t ebp;
+    uint32_t trapno;
+    /* trap / fault / int created */
+    uint32_t error;
+    uint32_t eip;
+    uint32_t cs;
+    uint32_t eflags;
+    uint32_t esp;
+    uint32_t ss;
+};
+
+/* 32bit defines */
+#define EMUNAME   "xenner32"
+#define regs      regs_32
+#define fix_sel   fix_sel32
+#define fix_desc  fix_desc32
+#define ureg_t    uint32_t
+#define sreg_t    int32_t
+#define PRIxREG   PRIx32
+#define rax       eax
+#define rbx       ebx
+#define rcx       ecx
+#define rdx       edx
+#define rsi       esi
+#define rdi       edi
+#define rbp       ebp
+#define rsp       esp
+#define rip       eip
+#define rflags    eflags
+#define tss(_v)   ((0xe000 >> 3) + 8 + (((_v)->id) << 1))
+#define ldt(_v)   ((0xe000 >> 3) + 9 + (((_v)->id) << 1))
+
+/* xenner32.S */
+extern uint32_t emu_pgd_32[];
+extern uint64_t emu_pgd_pae[];
+extern uint64_t emu_pmd_pae[];
+extern pte_t emu_pmd[];
+
+/* xenner-data.c */
+#define MAPS_MAX 256
+extern page_aligned uint32_t maps_32[];
+extern page_aligned uint64_t maps_pae[];
+extern uint32_t maps_refcnt[MAPS_MAX];
+
+extern struct descriptor_32 page_aligned xen_idt[256];
+
+/* xenner-mm.c */
+void *map_page(unsigned long maddr);
+void *fixmap_page(struct xen_cpu *cpu, unsigned long maddr);
+void free_page(void *ptr);
+pte_t *find_pte_lpt(uint32_t va);
+pte_t *find_pte_map(struct xen_cpu *cpu, uint32_t va);
+void pgtable_walk(struct xen_cpu *cpu, uint32_t va);
+
+/* xenner-hcall.c */
+asmlinkage void do_hypercall(struct regs_32 *regs);
+
+/* macros */
+#define context_is_emu(_r)       (((_r)->cs & 0x03) == 0x00)
+#define context_is_kernel(_v,_r) (((_r)->cs & 0x03) == 0x01)
+#define context_is_user(_v,_r)   (((_r)->cs & 0x03) == 0x03)
+
+/* inline asm bits */
+static inline int wrmsr_safe(uint32_t msr, uint32_t ax, uint32_t dx)
+{
+    int ret;
+    asm volatile("91:  wrmsr               \n"
+                 "    xorl %0,%0           \n"
+                 "92:  nop                 \n"
+                 ".section .exfix, \"ax\"  \n"
+                 "93:  mov $-1,%0          \n"
+                 "    jmp 92b              \n"
+                 ".previous                \n"
+                 ".section .extab, \"a\"   \n"
+                 "    .align 4             \n"
+                 "    .long 91b,93b        \n"
+                 ".previous                \n"
+                 : "=r" (ret)
+                 : "c" (msr), "a" (ax), "d" (dx));
+    return ret;
+}
+
+static inline int memcpy_pf(void *dest, const void *src, size_t bytes)
+{
+    int ret;
+
+    asm volatile("    cld                  \n"
+                 "91: rep movsb            \n"
+                 "    xor %[ret],%[ret]    \n"
+                 "98:                      \n"
+
+                 ".section .exfix, \"ax\"  \n"
+                 "99: mov $-1, %[ret]      \n"
+                 "    jmp 98b              \n"
+                 ".previous                \n"
+
+                 ".section .extab, \"a\"   \n"
+                 "    .align 4             \n"
+                 "    .long 91b,99b        \n"
+                 ".previous                \n"
+                 : [ ret ] "=r" (ret),
+                   [ esi ] "+S" (src),
+                   [ edi ] "+D" (dest),
+                   [ ecx ] "+c" (bytes)
+                 :
+                 : "memory" );
+    return ret;
+}
+
+static inline int copy32_pf(uint32_t *dest, const uint32_t *src)
+{
+    int ret;
+
+    asm volatile("91: mov (%[src]),%%ecx   \n"
+                 "92: mov %%ecx,(%[dst])   \n"
+                 "    xor %[ret],%[ret]    \n"
+                 "98:                      \n"
+
+                 ".section .exfix, \"ax\"  \n"
+                 "99: mov $-1, %[ret]      \n"
+                 "    jmp 98b              \n"
+                 ".previous                \n"
+
+                 ".section .extab, \"a\"   \n"
+                 "    .align 4             \n"
+                 "    .long 91b,99b        \n"
+                 "    .long 92b,99b        \n"
+                 ".previous                \n"
+
+                 : [ ret ] "=r" (ret)
+                 : [ src ] "r" (src),
+                   [ dst ] "r" (dest)
+                 : "ecx", "memory" );
+    return ret;
+}
+
+static inline int copy64_pf(uint64_t *dest, const uint64_t *src)
+{
+    int ret;
+
+    asm volatile("91: mov (%[src]), %%ebx    \n"
+                 "92: mov 4(%[src]), %%ecx   \n"
+                 "93: mov (%[dst]), %%eax    \n"
+                 "94: mov 4(%[dst]), %%edx   \n"
+                 "95: cmpxchg8b (%[dst])     \n"
+                 "    xor %[ret],%[ret]      \n"
+                 "98:                        \n"
+
+                 ".section .exfix, \"ax\"    \n"
+                 "99: mov $-1, %[ret]        \n"
+                 "    jmp 98b                \n"
+                 ".previous                  \n"
+
+                 ".section .extab, \"a\"     \n"
+                 "    .align 4               \n"
+                 "    .long 91b,99b          \n"
+                 "    .long 92b,99b          \n"
+                 "    .long 93b,99b          \n"
+                 "    .long 94b,99b          \n"
+                 "    .long 95b,99b          \n"
+                 ".previous                  \n"
+                 : [ ret ] "=r" (ret)
+                 : [ src ] "r" (src),
+                   [ dst ] "r" (dest)
+                 : "eax", "ebx", "ecx", "edx", "memory");
+    return ret;
+}
+
+/* PAE agnosticity */
+
+static inline int copypt_pf(pte_t *dest, const pte_t *src)
+{
+#ifdef CONFIG_PAE
+    return copy64_pf(dest, src);
+#else
+    return copy32_pf(dest, src);
+#endif
+}
+
diff --git a/pc-bios/xenner/xenner32.lds b/pc-bios/xenner/xenner32.lds
new file mode 100644
index 0000000..6d56ae4
--- /dev/null
+++ b/pc-bios/xenner/xenner32.lds
@@ -0,0 +1,37 @@
+OUTPUT_FORMAT("elf32-i386")
+
+SECTIONS
+{
+    . = 0xff000000;
+    _vstart = .;
+
+    /* code */
+    .text : AT(ADDR(.text) - 0xff000000) { *(.text) }
+    . = ALIGN(4k);
+    .exfix  : { *(.exfix)  }
+
+    /* data, ro */
+    . = ALIGN(4k);
+    .note.gnu.build-id : { *(.note.gnu.build-id) }
+    . = ALIGN(4k);
+    _estart = .;
+    .extab  : { *(.extab)  }
+    _estop  = .;
+    . = ALIGN(4k);
+    .rodata : { *(.rodata) }
+
+    /* data, rw */
+    . = ALIGN(4k);
+    .pt  : { *(.pt) }
+    . = ALIGN(4k);
+    .pgdata : { *(.pgdata) }
+    . = ALIGN(4k);
+    .data   : { *(.data)   }
+
+    /* bss */
+    . = ALIGN(4k);
+    .bss    : { *(.bss)    }
+
+    . = ALIGN(4k);
+    _vstop  = .;
+}
