diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 63e0460..c3ed74f 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -33,6 +33,8 @@ obj-y += hvm.o
 obj-y += device.o
 obj-y += decode.o
 obj-y += processor.o
+obj-y += efi.o
+obj-y += efi-shared.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 9b88aeb..9882519 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -24,6 +24,8 @@
 #include <asm/page.h>
 #include <asm/asm_defns.h>
 #include <asm/early_printk.h>
+#include <efi/efierr.h>
+#include <asm/arm64/efibind.h>
 
 #define PT_PT     0xf7f /* nG=1 AF=1 SH=11 AP=01 NS=1 ATTR=111 T=1 P=1 */
 #define PT_MEM    0xf7d /* nG=1 AF=1 SH=11 AP=01 NS=1 ATTR=111 T=0 P=1 */
@@ -100,7 +102,6 @@
          */
 
         .global start
-efi_stub_entry:  /* Dummy symbol so we can compile before actual stub added */
 start:
 #ifdef CONFIG_EFI_STUB
         /*
@@ -667,6 +668,65 @@ GLOBAL(lookup_processor_type)
         mov  x0, #0
         ret
 
+
+
+ENTRY(efi_stub_entry)
+	stp	x29, x30, [sp, #-32]!
+
+	/*
+	 * Call efi_entry to do the real work.
+	 * x0 and x1 are already set up by firmware.
+	 *
+	 * unsigned long efi_entry(EFI_HANDLE handle,
+	 *  			   EFI_SYSTEM_TABLE *sys_table);
+	 */
+
+	bl	efi_entry
+	cmp	x0, EFI_STUB_ERROR
+	b.eq	efi_load_fail
+
+	/*
+	 * efi_entry() will return here with device tree address in x0.
+	 *  Save value in register which is preserved by __flush_dcache_all.
+	 */
+	mov	x20, x0
+
+	/* Turn off Dcache and MMU */
+	mrs	x0, CurrentEL
+	cmp	x0, #PSR_MODE_EL2t
+	ccmp	x0, #PSR_MODE_EL2h, #0x4, ne
+	b.ne	1f
+	mrs	x0, sctlr_el2
+	bic	x0, x0, #1 << 0	// clear SCTLR.M
+	bic	x0, x0, #1 << 2	// clear SCTLR.C
+	msr	sctlr_el2, x0
+	isb
+	b	2f
+1:
+	mrs	x0, sctlr_el1
+	bic	x0, x0, #1 << 0	// clear SCTLR.M
+	bic	x0, x0, #1 << 2	// clear SCTLR.C
+	msr	sctlr_el1, x0
+	isb
+2:
+/*	bl	__flush_dcache_all */  /* RFRANZ_TODO */
+
+	/* Jump to XEN entry point */
+	mov	x0, x20
+	mov	x1, xzr
+	mov	x2, xzr
+	mov	x3, xzr
+	b	real_start
+
+efi_load_fail:
+	mov	x0, #EFI_LOAD_ERROR
+	ldp	x29, x30, [sp], #32
+	ret
+
+ENDPROC(efi_stub_entry)
+
+
+
 /*
  * Local variables:
  * mode: ASM
diff --git a/xen/arch/arm/efi-shared.c b/xen/arch/arm/efi-shared.c
new file mode 120000
index 0000000..096ee3a
--- /dev/null
+++ b/xen/arch/arm/efi-shared.c
@@ -0,0 +1 @@
+../x86/efi/efi-shared.c
\ No newline at end of file
diff --git a/xen/arch/arm/efi.c b/xen/arch/arm/efi.c
new file mode 100644
index 0000000..d13e718
--- /dev/null
+++ b/xen/arch/arm/efi.c
@@ -0,0 +1,686 @@
+#include "efi.h"
+#include <efi/efiprot.h>
+#include <efi/eficon.h>
+#include <efi/efipciio.h>
+#include <efi/efi-shared.h>
+#include <public/xen.h>
+#include <xen/compile.h>
+#include <xen/ctype.h>
+#include <xen/init.h>
+#include <xen/keyhandler.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/pfn.h>
+#if EFI_PAGE_SIZE != PAGE_SIZE
+# error Cannot use xen/pfn.h here!
+#endif
+#include <xen/string.h>
+#include <xen/stringify.h>
+#include <xen/libfdt/libfdt.h>
+
+/*
+ * This define and the code associated with it is a temporary, and will
+ * be replaced by changes to the XEN kernel to use the EFI memory map
+ * that is passed in the device tree instead of the normal FDT memory map.
+ * The XEN kernel changes are largely indpendent of the stub, so this code
+ * has been added to allow review and some testing of the stub code while
+ * the XEN kernel code is being developed.
+ */
+#define ADD_EFI_MEMORY_TO_FDT
+
+#define DEVICE_TREE_GUID \
+{0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}}
+
+extern CHAR16 __initdata newline[];
+extern SIMPLE_TEXT_OUTPUT_INTERFACE *__initdata StdOut;
+extern SIMPLE_TEXT_OUTPUT_INTERFACE *__initdata StdERR;
+extern EFI_BOOT_SERVICES *__initdata efi_bs;
+
+
+static EFI_HANDLE __initdata efi_ih;
+
+static struct file __initdata cfg;
+static struct file __initdata kernel;
+static struct file __initdata ramdisk;
+static struct file __initdata dtb;
+
+static unsigned long mmap_size;
+static EFI_MEMORY_DESCRIPTOR *mmap_ptr;
+
+static void *new_fdt;
+
+#ifdef ADD_EFI_MEMORY_TO_FDT
+static int IsLinuxReservedRegion(int MemoryType)
+{
+    switch ( MemoryType )
+    {
+        case EfiMemoryMappedIO:
+        case EfiMemoryMappedIOPortSpace:
+        case EfiRuntimeServicesCode:
+        case EfiRuntimeServicesData:
+        case EfiUnusableMemory:
+        case EfiACPIReclaimMemory:
+        case EfiACPIMemoryNVS:
+        case EfiLoaderData:
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+
+static EFI_STATUS __init efi_process_memory_map(EFI_MEMORY_DESCRIPTOR *map,
+                                                unsigned long mmap_size,
+                                                unsigned long desc_size,
+                                                void *fdt)
+{
+    int Index;
+    int err;
+
+    EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
+
+    /* Go through the list and add the reserved region to the Device Tree */
+    for ( Index = 0; Index < (mmap_size / desc_size); Index++ )
+    {
+        if ( IsLinuxReservedRegion(desc_ptr->Type) )
+        {
+            err = fdt_add_mem_rsv(fdt, desc_ptr->PhysicalStart, desc_ptr->NumberOfPages * EFI_PAGE_SIZE);
+            if ( err != 0 )
+                PrintStr(L"Warning: Fail to add 'memreserve'\n\n");
+        }
+        desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size);
+    }
+
+    return EFI_SUCCESS;
+
+}
+#endif
+
+static EFI_STATUS __init efi_get_memory_map(EFI_SYSTEM_TABLE *sys_table_arg,
+                                            EFI_MEMORY_DESCRIPTOR **map,
+                                            unsigned long *mmap_size,
+                                            unsigned long *desc_size,
+                                            UINT32 *desc_ver,
+                                            unsigned long *key_ptr)
+{
+    EFI_MEMORY_DESCRIPTOR *m = NULL;
+    EFI_STATUS status;
+    unsigned long key;
+    u32 desc_version;
+
+    *mmap_size = sizeof(*m) * 32;
+again:
+    /*
+     * Add an additional 2 efi_memory_desc_t because we're doing an
+         * allocation which may be in a new descriptor region, and this
+         * may create additional entries.
+     */
+    *mmap_size += 2 * sizeof(*m);
+    status = sys_table_arg->BootServices->AllocatePool(EfiLoaderData,
+                                                       *mmap_size, (void **)&m);
+    if ( status != EFI_SUCCESS )
+        goto fail;
+
+    *desc_size = 0;
+    key = 0;
+    status = sys_table_arg->BootServices->GetMemoryMap(mmap_size, m,
+                                                       &key, desc_size, &desc_version);
+    if ( status == EFI_BUFFER_TOO_SMALL )
+    {
+        sys_table_arg->BootServices->FreePool(m);
+        goto again;
+    }
+
+    if ( status != EFI_SUCCESS )
+        sys_table_arg->BootServices->FreePool(m);
+
+    if ( key_ptr && status == EFI_SUCCESS )
+        *key_ptr = key;
+    if ( desc_ver && status == EFI_SUCCESS )
+        *desc_ver = desc_version;
+
+fail:
+    *map = m;
+    return status;
+}
+
+
+static void __init *lookup_fdt_config_table(EFI_SYSTEM_TABLE *sys_table)
+{
+    const EFI_GUID fdt_guid = DEVICE_TREE_GUID;
+    EFI_CONFIGURATION_TABLE *tables;
+    void *fdt;
+    int i;
+
+    tables = sys_table->ConfigurationTable;
+    fdt = NULL;
+
+    for ( i = 0; i < sys_table->NumberOfTableEntries; i++ ) if ( match_guid(&tables[i].VendorGuid, &fdt_guid) == 0 )
+        {
+            fdt = tables[i].VendorTable;
+            break;
+        }
+    return fdt;
+}
+
+/*
+ * Get (or set if not present) the #addr-cells and #size cells
+ * properties of the chose node.  We need to know these to properly
+ * construct the address ranges used to describe the files loaded
+ * by the stub.
+ */
+static int setup_chosen_node(void *fdt, int *addr_cells, int *size_cells)
+{
+    int node;
+    const struct fdt_property *prop;
+    int len;
+    uint32_t val;
+
+    if (!fdt || !addr_cells || !size_cells)
+        return -1;
+
+
+    /* locate chosen node, which is where we add XEN module info. */
+    node = fdt_subnode_offset(fdt, 0, "chosen");
+    if (node < 0)
+    {
+            node = fdt_add_subnode(fdt, 0, "chosen");
+            if (node < 0)
+                return node;
+    }
+
+    /* Get or set #address-cells and #size-cells */
+    prop = fdt_get_property(fdt, node, "#address-cells", &len);
+    if (!prop)
+    {
+        PrintStr(L"No #address-cells in chosen node, setting to 2\r\n");
+        val = cpu_to_fdt32(2);
+        if (fdt_setprop(fdt, node, "#address-cells", &val, sizeof(val)))
+            return -1;
+        *addr_cells = 2;
+    }
+    else
+        *addr_cells = fdt32_to_cpu(*((uint32_t *)prop->data));
+
+    prop = fdt_get_property(fdt, node, "#size-cells", &len);
+    if (!prop)
+    {
+        PrintStr(L"No #size-cells in chosen node, setting to 2\r\n");
+        val = cpu_to_fdt32(2);
+        if (fdt_setprop(fdt, node, "#size-cells", &val, sizeof(val)))
+            return -1;
+        *size_cells = 2;
+    }
+    else
+        *size_cells = fdt32_to_cpu(*((uint32_t *)prop->data));
+
+    /*
+     * Make sure ranges is empty if it exists, otherwise create empty ranges
+     * property.
+     */
+    prop = fdt_get_property(fdt, node, "ranges", &len);
+    if (!prop)
+    {
+        PrintStr(L"No ranges in chosen node, creating empty\r\n");
+        val = cpu_to_fdt32(2);
+        if (fdt_setprop(fdt, node, "#size-cells", &val, 0))
+            return -1;
+    }
+    else
+    {
+        if (fdt32_to_cpu(prop->len))
+        {
+            PrintStr(L"Non-empty ranges in chosen node, aborting\r\n");
+            return -1;
+        }
+    }
+    return node;
+}
+
+
+/*
+ * Set a single 'reg' property taking into account the
+ * configured addr and size cell sizes.
+ */
+static int fdt_set_reg(void *fdt, int node, int addr_cells, int size_cells,
+                       uint64_t addr, uint64_t len)
+{
+    uint8_t data[16]; /* at most 2 64 bit words */
+    void *p = data;
+
+    /* Make sure that the values provided can be represented in
+     * the reg property.
+     */
+    if (addr_cells == 1 && (addr >> 32))
+        return -1;
+    if (size_cells == 1 && (len >> 32))
+        return -1;
+
+    if (addr_cells == 1)
+    {
+        *(uint32_t *)p = cpu_to_fdt32(addr);
+        p += sizeof(uint32_t);
+    }
+    else if (addr_cells == 2)
+    {
+        *(uint64_t *)p = cpu_to_fdt64(addr);
+        p += sizeof(uint64_t);
+    }
+    else
+        return -1;
+
+
+    if (size_cells == 1)
+    {
+        *(uint32_t *)p = cpu_to_fdt32(len);
+        p += sizeof(uint32_t);
+    }
+    else if (size_cells == 2)
+    {
+        *(uint64_t *)p = cpu_to_fdt64(len);
+        p += sizeof(uint64_t);
+    }
+    else
+        return -1;
+
+    return(fdt_setprop(fdt, node, "reg", data, p - (void *)data));
+}
+
+/*
+ * Add the FDT nodes for the standard EFI information, which consist
+ * of the System table address, the address of the final EFI memory map,
+ * and memory map information.
+ */
+static EFI_STATUS fdt_add_uefi_nodes(EFI_SYSTEM_TABLE *sys_table, void *fdt,
+                               EFI_MEMORY_DESCRIPTOR *memory_map,
+                               unsigned long map_size, unsigned long desc_size,
+                               u32 desc_ver)
+{
+    int node;
+    int status;
+    u32 fdt_val32;
+    u64 fdt_val64;
+
+#ifndef ADD_EFI_MEMORY_TO_FDT
+    int prev;
+    /*
+     * Delete any memory nodes present.  The EFI memory map is the only
+     * memory description provided to XEN.
+     */
+    prev = 0;
+    for (;;)
+    {
+        const char *type;
+        int len;
+
+        node = fdt_next_node(fdt, prev, NULL);
+        if (node < 0)
+        break;
+
+        type = fdt_getprop(fdt, node, "device_type", &len);
+        if (type && strncmp(type, "memory", len) == 0)
+        {
+            fdt_del_node(fdt, node);
+            continue;
+        }
+
+        prev = node;
+    }
+#endif
+
+    node = fdt_subnode_offset(fdt, 0, "chosen");
+    if ( node < 0 )
+    {
+        node = fdt_add_subnode(fdt, 0, "chosen");
+        if ( node < 0 )
+        {
+            status = node; /* node is error code when negative */
+            goto fdt_set_fail;
+        }
+    }
+
+    /* Add FDT entries for EFI runtime services in chosen node. */
+    node = fdt_subnode_offset(fdt, 0, "chosen");
+    fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
+    status = fdt_setprop(fdt, node, "linux,uefi-system-table",
+                         &fdt_val64, sizeof(fdt_val64));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
+                         &fdt_val64,  sizeof(fdt_val64));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val32 = cpu_to_fdt32(map_size);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
+                         &fdt_val32,  sizeof(fdt_val32));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val32 = cpu_to_fdt32(desc_size);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
+                         &fdt_val32, sizeof(fdt_val32));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val32 = cpu_to_fdt32(desc_ver);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
+                         &fdt_val32, sizeof(fdt_val32));
+    if ( status )
+        goto fdt_set_fail;
+
+    return EFI_SUCCESS;
+
+fdt_set_fail:
+    if ( status == -FDT_ERR_NOSPACE )
+        return EFI_BUFFER_TOO_SMALL;
+
+    return EFI_LOAD_ERROR;
+}
+
+
+
+/*
+ * Allocates new memory for a larger FDT, and frees existing memory if
+ * struct file size is non-zero.  Updates file struct with new memory
+ * address/size for later freeing.  If fdtfile.ptr is NULL, an empty FDT
+ * is created.
+ */
+static void __init *fdt_increase_size(struct file *fdtfile, int add_size)
+{
+    EFI_STATUS status;
+    EFI_PHYSICAL_ADDRESS fdt_addr;
+    int fdt_size;
+    int pages;
+    void *new_fdt;
+
+
+    if ( fdtfile->ptr )
+        fdt_size = fdt_totalsize(fdtfile->ptr);
+    else
+    {
+        /* RFRANZ_TODO - missing fdt_create_empty_tree() in libfdt. */
+        return NULL;
+    }
+
+    pages = PFN_UP(fdt_size) + PFN_UP(add_size);
+    status = efi_bs->AllocatePages(AllocateAnyPages, EfiLoaderData,
+                                   pages, &fdt_addr);
+
+    if ( status != EFI_SUCCESS )
+        return NULL;
+
+    new_fdt = (void *)fdt_addr;
+
+    if ( fdt_open_into(dtb.ptr, new_fdt, pages * EFI_PAGE_SIZE) )
+        return NULL;
+
+    /*
+     * Now that we have the new FDT allocated and copied, free the
+     * original and update the struct file so that the error handling
+     * code will free it.  If the original FDT came from a configuration
+     * table, we don't own that memory and can't free it.
+     */
+    if ( dtb.size )
+        efi_bs->FreePages(dtb.addr, PFN_UP(dtb.size));
+
+    /* Update 'file' info for new memory so we clean it up on error exits */
+    dtb.addr = fdt_addr;
+    dtb.size = pages * EFI_PAGE_SIZE;
+    return new_fdt;
+}
+
+
+/*
+ * Allocate a new FDT with enough space for EFI and XEN related updates,
+ * populating with content from a FDT specified in the configuration file
+ * or configuration table if present.  If neither is available, create an
+ * empty FDT.
+ */
+static void __init *create_new_fdt(EFI_SYSTEM_TABLE *SystemTable,
+                            EFI_FILE_HANDLE dir_handle, struct file *cfgfile,
+                            const char *section)
+{
+    union string name = { NULL };
+
+    /* load dtb from config file or configuration table */
+    name.s = get_value(cfgfile, section, "dtb");
+    if ( name.s )
+    {
+        truncate_string(name.s);
+        read_file(dir_handle, s2w(&name), &dtb);
+        efi_bs->FreePool(name.w);
+    }
+    else
+    {
+        /* Get DTB from configuration table. */
+        dtb.ptr = lookup_fdt_config_table(SystemTable);
+        if ( dtb.ptr )
+        {
+            /* Set dtb.size to zero so config table memory is not freed. */
+            dtb.size = 0;
+        }
+        else
+        {
+            /*
+             * No FDT was provided, so create an empty one to populate with
+             * the EFI and module related params.
+             *
+             * RFRANZ_TODO: libfdt in XEN is missing fdt_create_empty_tree()
+             * likely need libfdt update to support this.
+             */
+            blexit(L"No FDT specified.");
+        }
+    }
+
+
+    /*
+     * Allocate space for new FDT, making sure we have enough space
+     * for the fields we are adding, so we don't have to deal
+     * with increasing the size again later, which complicates
+     * things.  Use the size of the configuration file as an uppper
+     * bound on how much size can be added based on configuration
+     * file contents.
+     */
+    return fdt_increase_size(&dtb, cfg.size + EFI_PAGE_SIZE);
+}
+
+
+#define COMPAT_BUF_SIZE 500 /* FDT string buffer size. */
+unsigned long efi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+    EFI_GUID loaded_image_guid = LOADED_IMAGE_PROTOCOL;
+    EFI_LOADED_IMAGE *loaded_image;
+    EFI_FILE_HANDLE dir_handle;
+    EFI_STATUS status;
+    union string section = { NULL }, cmdline = { NULL }, name = { NULL };
+    CHAR16 * file_name,*cfg_file_name = NULL,*image_name = NULL;
+    bool_t base_video = 0;
+    int node;
+    int chosen;
+    int addr_len, size_len;
+    char *options;
+    char compat_buf[COMPAT_BUF_SIZE];
+    int compat_len = 0;
+    unsigned long desc_size;
+    UINT32 desc_ver = 0;
+    unsigned long map_key = 0;
+
+    efi_ih = ImageHandle;
+    efi_bs = SystemTable->BootServices;
+    StdOut = SystemTable->ConOut;
+
+    /* Check if we were booted by the EFI firmware */
+    if ( SystemTable->Hdr.Signature != EFI_SYSTEM_TABLE_SIGNATURE )
+        goto fail;
+
+    /* Get loaded image protocol */
+    status = efi_bs->HandleProtocol(ImageHandle, &loaded_image_guid,
+                                    (void **)&loaded_image);
+    if ( status != EFI_SUCCESS )
+        blexit(L"ERROR - no loaded image protocol\r\n");
+
+    PrintStr(L"Xen " __stringify(XEN_VERSION)"." __stringify(XEN_SUBVERSION)
+             XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n");
+
+    if ( (unsigned long)loaded_image->ImageBase & ((1 << 20) - 1) )
+        blexit(L"Xen must be loaded at a 2MByte boundary.");
+
+    /* Get the file system interface. */
+    dir_handle = get_parent_handle(loaded_image, &file_name);
+
+    handle_cmdline(loaded_image, &cfg_file_name, &base_video, &image_name,
+                   &section.w, &cmdline.w);
+
+    if ( cmdline.w )
+        w2s(&cmdline);
+
+    /* Open and read config file */
+    read_config_file(&dir_handle, &cfg, cfg_file_name,
+                     &section, file_name);
+
+    new_fdt = create_new_fdt(SystemTable, dir_handle, &cfg, section.s);
+    if ( !new_fdt )
+        blexit(L"Unable to create new FDT\r\n");
+
+    chosen = setup_chosen_node(new_fdt, &addr_len, &size_len);
+    if ( chosen < 0 )
+        blexit(L"Unable to setup chosen node\r\n");
+
+
+    name.s = get_value(&cfg, section.s, "kernel");
+    if ( !name.s )
+        blexit(L"No Dom0 kernel image specified.");
+    options = truncate_string(name.s);
+    if ( options )
+        fdt_setprop_string(new_fdt, chosen, "xen,dom0-bootargs", options);
+    s2w(&name);
+    read_file(dir_handle, name.w, &kernel);
+
+    node = fdt_add_subnode(new_fdt, chosen, "kernel");
+    if ( node < 0 )
+        blexit(L"Error adding dom0 FDT node.");
+
+    compat_len = 0;
+    compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, "xen,linux-zimage") + 1;
+    if ( compat_len > COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, "xen,multiboot-module") + 1;
+    if ( compat_len > COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    if ( fdt_setprop(new_fdt, node, "compatible", compat_buf, compat_len) < 0 )
+        blexit(L"unable to set compatible property.");
+    fdt_set_reg(new_fdt, node, addr_len, size_len, kernel.addr, kernel.size);
+    efi_bs->FreePool(name.w);
+
+
+    name.s = get_value(&cfg, section.s, "ramdisk");
+    if ( name.s )
+    {
+        truncate_string(name.s);
+        read_file(dir_handle, s2w(&name), &ramdisk);
+
+        node = fdt_add_subnode(new_fdt, chosen, "ramdisk");
+        if ( node < 0 )
+            blexit(L"Error adding ramdisk FDT node.");
+
+        compat_len = 0;
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, "xen,linux-initrd") + 1;
+        if ( compat_len > COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, "xen,multiboot-module") + 1;
+        if ( compat_len > COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+        if ( fdt_setprop(new_fdt, node, "compatible", compat_buf, compat_len) < 0 )
+            blexit(L"unable to set compatible property.");
+        fdt_set_reg(new_fdt, node, addr_len, size_len, ramdisk.addr, ramdisk.size);
+        efi_bs->FreePool(name.w);
+    }
+
+
+    /*
+     * cmdline has remaining options from EFI command line.  Prepend these
+     * to the options from the configuration file.  Put the image name at
+     * the beginning of the bootargs.
+     *
+     */
+    if ( image_name )
+    {
+        name.w = image_name;
+        w2s(&name);
+    }
+    else
+        name.s = "xen";
+
+    compat_len = 0;
+    compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, "%s", name.s);
+    if ( compat_len >= COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    if ( cmdline.s )
+    {
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, " %s", cmdline.s);
+        if ( compat_len >= COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+    }
+    name.s = get_value(&cfg, section.s, "options");
+    if ( name.s )
+    {
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - compat_len, " %s", name.s);
+        if ( compat_len >= COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+    }
+
+
+    if ( fdt_setprop_string(new_fdt, chosen, "xen,xen-bootargs", compat_buf) < 0 )
+        blexit(L"unable to set xen,xen-bootargs property.");
+
+    status = efi_get_memory_map(SystemTable, &mmap_ptr, &mmap_size, &desc_size, &desc_ver, &map_key);
+    if ( status != EFI_SUCCESS )
+        blexit(L"unable to get EFI memory map");
+
+#ifdef ADD_EFI_MEMORY_TO_FDT
+    efi_process_memory_map(mmap_ptr, mmap_size, desc_size, new_fdt);
+#endif
+
+    status = fdt_add_uefi_nodes(SystemTable, new_fdt, mmap_ptr, mmap_size, desc_size, desc_ver);
+    if ( status != EFI_SUCCESS )
+    {
+        if ( status == EFI_BUFFER_TOO_SMALL )
+            PrintStr(L"ERROR: FDT buffer too small\r\n");
+        blexit(L"Unable to create new FDT with UEFI nodes");
+    }
+
+    status = efi_bs->ExitBootServices(ImageHandle, map_key);
+    if ( status != EFI_SUCCESS )
+        blexit(L"Unable to exit boot services.");
+
+    return((unsigned long)new_fdt);
+
+
+fail:
+    blexit(L"ERROR: Unable to start XEN\r\n");
+}
+
+
+void __init noreturn blexit(const CHAR16 *str)
+{
+    if ( str )
+        PrintStr((CHAR16 *)str);
+    PrintStr(newline);
+
+    if ( cfg.addr )
+        efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
+    if ( kernel.addr )
+        efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size));
+    if ( ramdisk.addr )
+        efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size));
+    if ( dtb.addr && dtb.size )
+        efi_bs->FreePages(dtb.addr, PFN_UP(dtb.size));
+    if ( mmap_ptr )
+        efi_bs->FreePool(mmap_ptr);
+
+    efi_bs->Exit(efi_ih, EFI_SUCCESS, 0, NULL);
+    unreachable(); /* not reached */
+}
