diff --git a/pc-bios/xenner/xenner64.S b/pc-bios/xenner/xenner64.S
new file mode 100644
index 0000000..b140214
--- /dev/null
+++ b/pc-bios/xenner/xenner64.S
@@ -0,0 +1,400 @@
+#define	ENTRY(name) \
+	.globl name; \
+	.align 16; \
+	name:
+
+	.macro PUSH_ERROR
+	sub $8, %rsp		/* space for error code */
+	.endm
+
+	.macro PUSH_TRAP_RBP trapno
+	sub $8, %rsp		/* space for trap number */
+	push %rbp
+	mov $\trapno, %rbp
+	mov %rbp, 8(%rsp)	/* save trap number on stack */
+	.endm
+
+	.macro PUSH_REGS
+	push %rdi
+	push %rsi
+	push %r15
+	push %r14
+	push %r13
+	push %r12
+	push %r11
+	push %r10
+	push %r9
+	push %r8
+	push %rdx
+	push %rcx
+	push %rbx
+	push %rax
+	mov  %rsp,%rdi		/* struct regs pointer */
+	.endm
+
+	.macro POP_REGS
+	pop %rax
+	pop %rbx
+	pop %rcx
+	pop %rdx
+	pop %r8
+	pop %r9
+	pop %r10
+	pop %r11
+	pop %r12
+	pop %r13
+	pop %r14
+	pop %r15
+	pop %rsi
+	pop %rdi
+	pop %rbp
+	.endm
+
+	.macro RETURN
+	add $16, %rsp		/* remove error code & trap number */
+	iretq			/* jump back */
+	.endm
+
+	.macro DO_TRAP trapno func
+	PUSH_TRAP_RBP \trapno
+	PUSH_REGS
+	call \func
+	POP_REGS
+	RETURN
+	.endm
+
+/* ------------------------------------------------------------------ */
+
+	.code64
+	.text
+
+/* --- 16-bit boot entry point --- */
+
+ENTRY(boot)
+	.code16
+
+	cli
+
+	/* load the GDT */
+	lgdt	(gdt_desc - boot)
+
+	/* turn on long mode and paging */
+	mov	$0x1, %eax
+	mov	%eax, %cr0
+
+	/* enable pagetables */
+	mov	$(boot_pgd - boot), %eax
+	mov	%eax, %cr3
+
+	/* set PSE,  PAE */
+	mov	$0x30, %eax
+	mov	%eax, %cr4
+
+	/* long mode */
+	mov	$0xc0000080, %ecx
+	rdmsr
+	or	$0x101, %eax
+	wrmsr
+
+	/* turn on long mode and paging */
+	mov	$0x80010001, %eax
+	mov	%eax, %cr0
+
+	ljmp	$0x8, $(boot64 - boot)
+
+
+.align 4, 0
+gdt:
+.byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* dummy */
+.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xaf, 0x00 /* code64 */
+.byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xaf, 0x00 /* data64 */
+
+gdt_desc:
+.short  (3 * 8) - 1
+.long   (gdt - boot)
+
+
+/* --- 64-bit entry point --- */
+
+boot64:
+	.code64
+
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+	mov %ax, %ss
+
+	jmpq	*(boot64_ind - boot)
+
+boot64_ind:
+	.quad boot64_real
+
+boot64_real:
+
+	/* switch to real pagetables */
+	mov	$(emu_pgd - boot), %rax
+	mov	%rax, %cr3
+
+	lea boot_stack_high(%rip), %rsp	/* setup stack */
+	sub $176, %rsp			/* sizeof(struct regs_64) */
+	mov  %rsp,%rdi			/* struct regs pointer */
+	cmp $0, %rbx
+	jne secondary
+	call do_boot
+	POP_REGS
+	RETURN
+
+secondary:
+	mov  %rdi,%rsi
+	mov  %rbx,%rdi
+	call do_boot_secondary
+	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_RBP 0
+	jmp guest_forward
+
+ENTRY(nmi)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 2
+	jmp guest_forward
+
+ENTRY(overflow)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 4
+	jmp guest_forward
+
+ENTRY(bound_check)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 5
+	jmp guest_forward
+
+ENTRY(coprocessor)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 9
+	jmp guest_forward
+
+ENTRY(invalid_tss)
+	PUSH_TRAP_RBP 10
+	jmp guest_forward
+
+ENTRY(segment_not_present)
+	PUSH_TRAP_RBP 11
+	jmp guest_forward
+
+ENTRY(stack_fault)
+	PUSH_TRAP_RBP 12
+	jmp guest_forward
+
+ENTRY(floating_point)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 16
+	jmp guest_forward
+
+ENTRY(alignment)
+	PUSH_TRAP_RBP 17
+	jmp guest_forward
+
+ENTRY(machine_check)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 18
+	jmp guest_forward
+
+ENTRY(simd_floating_point)
+	PUSH_ERROR
+	PUSH_TRAP_RBP 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(int_80)
+	PUSH_ERROR
+	DO_TRAP -1 do_int_80
+
+ENTRY(irq_entries)
+vector=0
+.rept 256
+	.align 16
+	PUSH_ERROR
+	PUSH_TRAP_RBP vector
+	jmp irq_common
+vector=vector+1
+.endr
+
+ENTRY(irq_common)
+	PUSH_REGS
+	call do_irq
+	POP_REGS
+	RETURN
+
+/* --- syscall --- */
+
+ENTRY(trampoline_syscall)
+	/* we arrive here via per-cpu trampoline
+	 * which sets up the stack for us */
+	PUSH_ERROR
+	PUSH_TRAP_RBP -1
+	PUSH_REGS
+	call do_syscall
+	POP_REGS
+
+	add $16, %rsp			/* remove error code + trapno */
+	cmp $-1, -8(%rsp)
+	je syscall_vmexit
+	cmp $-2, -8(%rsp)
+	je syscall_iretq
+
+syscall_default:
+	/* default sysret path */
+	popq %rcx			/* rip    */
+	popq %r11			/* cs     */
+	popq %r11			/* rflags */
+	popq %rsp			/* rsp    */
+	sysretq
+
+syscall_vmexit:
+	/* bounce hypercall to userspace */
+	popq %rcx			/* rip    */
+	popq %r11			/* cs     */
+	popq %r11			/* rflags */
+	popq %rsp			/* rsp    */
+	out %al, $0xe0			/* let userspace handle it */
+	sysretq
+
+syscall_iretq:
+	/* return from syscall via iretq */
+	iretq
+
+/* helpers */
+
+ENTRY(broken_memcpy_pf)
+	mov %rdx,%rcx
+	cld
+1:	rep movsb
+	xor %rax,%rax
+8:	ret
+
+	.section .exfix, "ax"
+9:	mov $-1, %rax
+	jmp 8b
+	.previous
+
+	.section .extab, "a"
+	.align 8
+	.quad 1b,9b
+	.previous
+
+/* 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
+	.code64
+
+/* emu boot stack, including syscall trampoline template */
+
+	.data
+	.globl boot_stack_low, boot_stack_high
+	.globl cpu_ptr
+	.globl trampoline_start, trampoline_patch, trampoline_stop
+	.align 4096
+boot_stack_low:
+cpu_ptr:
+	.quad 0
+trampoline_start:
+	movq %rsp, boot_stack_high-16(%rip)
+	leaq boot_stack_high-16(%rip), %rsp
+	push %r11				/* rflags	 */
+	mov  $0xdeadbeef, %r11			/* C code must fix cs & ss */
+	movq %r11, boot_stack_high-8(%rip)	/* ss	     */
+	push %r11				/* cs	     */
+	push %rcx				/* rip	    */
+
+	.byte 0x49, 0xbb			/* mov data, %r11 ...	 */
+trampoline_patch:
+	.quad 0					/* ... data, for jump to ...  */
+	jmpq *%r11				/* ... trampoline_syscall     */
+trampoline_stop:
+	.align 4096
+boot_stack_high:
+
+/* boot page tables */
+
+#define pageflags 0x063 /* preset, rw, accessed, dirty */
+#define largepage 0x080 /* pse */
+
+	.section .pt, "aw"
+	.globl emu_pgd
+
+	.align 4096
+boot_pgd:
+	.quad emu_pud - 0xffff830000000000 + pageflags
+	.fill 261,8,0
+	.quad emu_pud - 0xffff830000000000 + pageflags
+	.fill 249,8,0
+
+	.align 4096
+emu_pgd:
+	.fill 262,8,0
+	.quad emu_pud - 0xffff830000000000 + pageflags
+	.fill 249,8,0
+
+	.align 4096
+emu_pud:
+	.quad emu_pmd - 0xffff830000000000 + pageflags
+	.fill 511,8,0
+
+	.align 4096
+emu_pmd:
+i = 0
+	.rept 512
+	.quad pageflags + largepage | (i << 21)
+	i = i + 1
+	.endr
+	.align 4096
diff --git a/pc-bios/xenner/xenner64.h b/pc-bios/xenner/xenner64.h
new file mode 100644
index 0000000..92d956e
--- /dev/null
+++ b/pc-bios/xenner/xenner64.h
@@ -0,0 +1,117 @@
+#include <xen/foreign/x86_64.h>
+
+struct regs_64 {
+    /* pushed onto stack before calling into C code */
+    uint64_t rax;
+    uint64_t rbx;
+    uint64_t rcx;
+    uint64_t rdx;
+    uint64_t r8;
+    uint64_t r9;
+    uint64_t r10;
+    uint64_t r11;
+    uint64_t r12;
+    uint64_t r13;
+    uint64_t r14;
+    uint64_t r15;
+    uint64_t rsi;
+    uint64_t rdi;
+    uint64_t rbp;
+    uint64_t trapno;
+    /* trap / fault / int created */
+    uint64_t error;
+    uint64_t rip;
+    uint64_t cs;
+    uint64_t rflags;
+    uint64_t rsp;
+    uint64_t ss;
+};
+
+/* 64bit defines */
+#define EMUNAME   "xenner64"
+#define regs      regs_64
+#define fix_sel   fix_sel64
+#define fix_desc  fix_desc64
+#define ureg_t    uint64_t
+#define sreg_t    int64_t
+#define PRIxREG   PRIx64
+#define tss(_v)   ((0xe000 >> 3) +  8 + (((_v)->id) << 2))
+#define ldt(_v)   ((0xe000 >> 3) + 10 + (((_v)->id) << 2))
+
+/* xenner-data.c */
+extern struct idt_64 page_aligned xen_idt[256];
+
+/* xenner-main.c */
+asmlinkage void do_int_80(struct regs_64 *regs);
+
+/* xenner-hcall.c */
+void switch_mode(struct xen_cpu *cpu);
+int is_kernel(struct xen_cpu *cpu);
+asmlinkage void do_syscall(struct regs_64 *regs);
+
+/* xenner-mm.c */
+void pgtable_walk(int level, uint64_t va, uint64_t root_mfn);
+int pgtable_fixup_flag(struct xen_cpu *cpu, uint64_t va, uint32_t flag);
+int pgtable_is_present(uint64_t va, uint64_t root_mfn);
+void *map_page(uint64_t maddr);
+void *fixmap_page(struct xen_cpu *cpu, uint64_t maddr);
+static inline void free_page(void *ptr) {}
+uint64_t *find_pte_64(uint64_t va);
+
+/* macros */
+#define context_is_emu(_r)       (((_r)->cs & 0x03) == 0x00)
+#define context_is_kernel(_v,_r) (((_r)->cs & 0x03) == 0x03 && is_kernel(_v))
+#define context_is_user(_v,_r)   (((_r)->cs & 0x03) == 0x03 && !is_kernel(_v))
+
+#define addr_is_emu(va)     (((va) >= XEN_M2P_64) && ((va) < XEN_DOM_64))
+#define addr_is_kernel(va)  ((va) >= XEN_DOM_64)
+#define addr_is_user(va)    ((va) < XEN_M2P_64)
+
+/* inline asm bits */
+static inline int wrmsr_safe(uint32_t msr, uint32_t ax, uint32_t dx)
+{
+    int ret;
+    asm volatile("1:  wrmsr                \n"
+                 "    xorl %0,%0           \n"
+                 "2:  nop                  \n"
+
+                 ".section .exfix, \"ax\"  \n"
+                 "3:  mov $-1,%0           \n"
+                 "    jmp 2b               \n"
+                 ".previous                \n"
+
+                 ".section .extab, \"a\"   \n"
+                 "    .align 8             \n"
+                 "    .quad 1b,3b          \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 8             \n"
+                 "    .quad 91b,99b        \n"
+                 ".previous                \n"
+                 : [ ret ] "=a" (ret),
+                   [ rsi ] "+S" (src),
+                   [ rdi ] "+D" (dest),
+                   [ rcx ] "+c" (bytes)
+                 :
+                 : "memory" );
+    return ret;
+}
diff --git a/pc-bios/xenner/xenner64.lds b/pc-bios/xenner/xenner64.lds
new file mode 100644
index 0000000..0b580a9
--- /dev/null
+++ b/pc-bios/xenner/xenner64.lds
@@ -0,0 +1,38 @@
+OUTPUT_FORMAT("elf64-x86-64")
+
+SECTIONS
+{
+    . = 0xffff830000000000;
+    _vstart = .;
+    phys_startup_64 = 0x0;
+
+    /* code */
+    .text : AT(ADDR(.text) - 0xffff830000000000) { *(.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  = .;
+}
