diff mbox

[Xen-devel,V2,12/12] Add EFI stub for arm64

Message ID 1405989815-25236-13-git-send-email-roy.franz@linaro.org
State New
Headers show

Commit Message

Roy Franz July 22, 2014, 12:43 a.m. UTC
This patch adds the EFI stub for arm64.  A PE/COFF header is added in head.S.
PE/COFF linker support is not available for arm64, so a native build is not
possible.  Also, this allows the binary to be both a PE/COFF EFI application,
and a normal Image file bootable like a Linux kernel.  The arm and arm64 Linux
kernels use the same methodology to create a single image that is both an EFI
application and a zImage/Image file.

The EFI stub processes the XEN EFI configuration file to load the dom0 kernel,
ramdisk, etc and constructs a device tree for XEN to use, then transfers
control to the normal XEN image entry point.  Device tree description of memory
is no longer used, as the stub uses the EFI memory map to populate bootinfo
memory banks.


Signed-off-by: Roy Franz <roy.franz@linaro.org>
---
 xen/arch/arm/Makefile               |   5 +
 xen/arch/arm/Rules.mk               |   1 +
 xen/arch/arm/arm64/head.S           | 185 +++++++++-
 xen/arch/arm/efi/Makefile           |   2 +
 xen/arch/arm/efi/efi.c              | 714 ++++++++++++++++++++++++++++++++++++
 xen/arch/arm/xen.lds.S              |   1 +
 xen/include/asm-arm/arm64/efibind.h | 216 +++++++++++
 xen/include/asm-arm/efibind.h       |   2 +
 xen/include/asm-arm/setup.h         |   2 +-
 9 files changed, 1123 insertions(+), 5 deletions(-)
 create mode 100644 xen/arch/arm/efi/Makefile
 create mode 100644 xen/arch/arm/efi/efi.c
 create mode 100644 xen/include/asm-arm/arm64/efibind.h
 create mode 100644 xen/include/asm-arm/efibind.h

Comments

Ian Campbell July 29, 2014, 9:46 a.m. UTC | #1
On Mon, 2014-07-21 at 17:43 -0700, Roy Franz wrote:

Overall looks good, thanks, I've a bunch of mostly minor comments.

> +ifeq ($(EFI),y)
> +AFLAGS += -DCONFIG_EFI_STUB

AFAICT this is only used in arm64/head.S where there is no need for the
stub to be conditional.

So this can go away, unless there is some common code which I'm missing.


> @@ -84,7 +86,6 @@
>  #endif /* !CONFIG_EARLY_PRINTK */
>  
>          /*.aarch64*/
> -

Spurious change.

>          /*
>           * Kernel startup entry point.
>           * ---------------------------
> @@ -101,11 +102,22 @@
>  
>          .global start
>  start:
> +#ifdef CONFIG_EFI_STUB

As I said above I don't think this needs to be conditional.

> @@ -561,9 +685,62 @@ putn:   ret
>   * TODO: For now, the implementation return NULL every time
>   */
>  GLOBAL(lookup_processor_type)
> -        mov  x0, #0
> +        mov   x0, #0
> +        ret
> +
> +
> +

Please avoid multiple blank lines, just one will do.

> +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.
> +         * EFI mandates a 1:1 (unity) VA->PA mapping,
> +         * so we can turn off the MMU before entering
> +         * XEN.
> +         *
> +         * 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.
> +         */
> +
> +

The comment should abut the mov which it refers to please.

> +        mov   x20, x0
> +        bl    __flush_dcache_all
> +        ic      ialluis

iall... is indented a bit to far.

> diff --git a/xen/arch/arm/efi/Makefile b/xen/arch/arm/efi/Makefile
> new file mode 100644
> index 0000000..74863ba
> --- /dev/null
> +++ b/xen/arch/arm/efi/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(EFI) += efi.o

I assume you don't recurse into here unless efi == y? So you can use
obj-y I think.


> diff --git a/xen/arch/arm/efi/efi.c b/xen/arch/arm/efi/efi.c
> new file mode 100644
> index 0000000..832b324
> --- /dev/null
> +++ b/xen/arch/arm/efi/efi.c
> @@ -0,0 +1,714 @@
> +#include <asm/efibind.h>
> +#include <efi/efidef.h>
> +#include <efi/efierr.h>
> +#include <efi/eficon.h>
> +#include <efi/efidevp.h>
> +#include <efi/eficapsule.h>
> +#include <efi/efiapi.h>
> +#include <xen/efi.h>
> +#include <xen/spinlock.h>
> +#include <asm/page.h>
> +#include <efi/efiprot.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>

Do you really use all of these? e.g. I don't see why keyhandler is
needed. I didn't check the others.

> +#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>
> +#include <asm/setup.h>
> +
> 
> +void __init noreturn blexit(const CHAR16 *str);

Should this be static?

> +#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;

Put externs in a header please. Aren't these defined in common code and
therefore belong in a common header?

> +/*
> + * Hacky way to make sure EFI allocations end up in memory that XEN
> + * includes in its mappings.

This was due to the discard_initial_modules thing, right?

> + * RFRANZ_TODO - this needs to be resolved properly.
> + */
> +static EFI_PHYSICAL_ADDRESS max_addr = 0xffffffff;
> +
> +static void *new_fdt;
> +
> +static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map,
> +                                                unsigned long mmap_size,
> +                                                unsigned long desc_size)
> +{
> +    int Index;
> +    int i = 0;
> +
> +    EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
> +
> +    for ( Index = 0; Index < (mmap_size / desc_size); Index++ )

Perhaps this is my ignorance of EFI showing, but is Index really not
used within the loop?

It almost looks like you want a test on desc_ptr for the end of the list
or something?

> +    {
> +        if ( desc_ptr->Type == EfiConventionalMemory
> +             || desc_ptr->Type == EfiBootServicesCode
> +             || desc_ptr->Type == EfiBootServicesData )
> +        {
> +            bootinfo.mem.bank[i].start = desc_ptr->PhysicalStart;
> +            bootinfo.mem.bank[i].size = desc_ptr->NumberOfPages * EFI_PAGE_SIZE;

Having both Index and i is a bit confusing. How about s/i/bank/? Or
perhaps
	        
	struct thingumy *bank;

	if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
	{
             exhausted...
        }
        bank = &bootinfo.mem.bank[bootinfo.mem.nr_banks++];
        bank->start = ...

?

> +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;
> +
> +    *map = NULL;
> +    *mmap_size = EFI_PAGE_SIZE;
> +again:
> +    *mmap_size += EFI_PAGE_SIZE;  /* Page size is allocation granularity */

These two assignments together mean that on the first pass you will
allocate two pages, is that what you intended?

> +    status = sys_table_arg->BootServices->AllocatePool(EfiLoaderData,
> +                                                       *mmap_size, (void **)&m);

I don't think you need the cast here.


> +    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));

Are the bindings for linux,uefi-* described somewhere?

These are used entirely within the stub->kernel (Xen or Linux) interface
boundary, right? Since they are "internal" I wonder if we should use
"xen,uefi-*" (with the same semantics as linux,uefi-*) to avoid any
potential confusion in the future?

If there is any requirement for these to be exposed outside of the
Xen<->Stub interface then we would be better off using the linux naming
to remain compatible.

> +    pages = PFN_UP(fdt_size) + PFN_UP(add_size);

pages = PFN_UP(fdt_size + add_size) ?


> +    /*
> +     * 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

Too many pppps.

> +     * bound on how much size can be added based on configuration
> +     * file contents.

The size of the configuration file doesn't seem like a very good
estimate, it doesn't account for the linux,uefi-* properties and
a /chosen/module node could be larger than the string in the cfg file
needed to specify it. I suppose the extra EFI_PAGE_SIZE slop, plus the
rounding up to a page probably accounts for this sufficiently.

FWIW in the equivalent Xen side code we just allocate guessed size and
if it isn't enough throw it away and try again from scratch with a
larger size, rather than trying to increase the size on the fly which as
you say gets complicated.

> +    /* Check if we were booted by the EFI firmware */
> +    if ( SystemTable->Hdr.Signature != EFI_SYSTEM_TABLE_SIGNATURE )
> +        goto fail;

You only use goto fail once in this function AFAICT, everywhere else
calls blexit directly with a specific error message. I think you may as
well do the same here.

> +
> +    /* 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.");

This restriction has been relaxed to only require 4K alignment now. See
ca59618967fe "xen: arm: Handle 4K aligned hypervisor load address".

> +    compat_len = 0;
> +    compat_len += snprintf(compat_buf + compat_len,
> +                           COMPAT_BUF_SIZE - compat_len,
> +                           "multiboot,kernel") + 1;
> +    if ( compat_len > COMPAT_BUF_SIZE )
> +        blexit(L"FDT string overflow");
> +    compat_len += snprintf(compat_buf + compat_len,
> +                           COMPAT_BUF_SIZE - compat_len,
> +                           "multiboot,module") + 1;
> +    if ( compat_len > COMPAT_BUF_SIZE )
> +        blexit(L"FDT string overflow");

In most places we use
	const char *compat = "multiboot,module\0" "multiboot,kernel";
to avoid the faffing around with buffers, snprintf and off by one errors. 

> +    /*
> +     * 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.

Is the prepending of the image name an EFI-ism?

> +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);

Is EFI_SUCCESS correct? I thought this was an error path.

> +
> +//
> +// When build similiar to FW, then link everything together as

"similar" (cut-n-paste error from elsewhere?)

> +// one big module.

> diff --git a/xen/include/asm-arm/efibind.h b/xen/include/asm-arm/efibind.h
> new file mode 100644
> index 0000000..09dca7a
> --- /dev/null
> +++ b/xen/include/asm-arm/efibind.h
> @@ -0,0 +1,2 @@
> +#include <xen/types.h>
> +#include <asm/arm64/efibind.h>

Should this include some sort of CONFIG_ARM_64 based guard against using
this code from an arm32 build?

#ifndef CONFIG_ARM_64
#error "EFI is arm64 only"
#endif

perhaps?

Ian.
diff mbox

Patch

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index c13206f..4af6925 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -1,5 +1,6 @@ 
 subdir-$(arm32) += arm32
 subdir-$(arm64) += arm64
+subdir-$(EFI) += efi
 subdir-y += platforms
 
 obj-$(EARLY_PRINTK) += early_printk.o
@@ -37,6 +38,10 @@  obj-y += processor.o
 
 #obj-bin-y += ....o
 
+ifeq ($(EFI),y)
+AFLAGS += -DCONFIG_EFI_STUB
+endif
+
 ifdef CONFIG_DTB_FILE
 obj-y += dtb.o
 AFLAGS += -DCONFIG_DTB_FILE=\"$(CONFIG_DTB_FILE)\"
diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk
index 8658176..19bef80 100644
--- a/xen/arch/arm/Rules.mk
+++ b/xen/arch/arm/Rules.mk
@@ -31,6 +31,7 @@  CFLAGS += -mcpu=generic
 CFLAGS += -mgeneral-regs-only # No fp registers etc
 arm32 := n
 arm64 := y
+EFI := y
 endif
 
 ifneq ($(call cc-option,$(CC),-fvisibility=hidden,n),n)
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 7d53143..ac822d3 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 */
@@ -84,7 +86,6 @@ 
 #endif /* !CONFIG_EARLY_PRINTK */
 
         /*.aarch64*/
-
         /*
          * Kernel startup entry point.
          * ---------------------------
@@ -101,11 +102,22 @@ 
 
         .global start
 start:
+#ifdef CONFIG_EFI_STUB
         /*
          * DO NOT MODIFY. Image header expected by Linux boot-loaders.
          */
-        b       real_start           /* branch to kernel start, magic */
+efi_head:
+        /*
+         * This add instruction has no meaningful effect except that
+         * its opcode forms the magic "MZ" signature of a PE/COFF file
+         * that is required for UEFI applications.
+         */
+        add     x13, x18, #0x16
+        b       real_start           /* branch to kernel start */
+#else
+        b       real_start           /* branch to kernel start */
         .long   0                    /* reserved */
+#endif
         .quad   0                    /* Image load offset from start of RAM */
         .quad   0                    /* reserved */
         .quad   0                    /* reserved */
@@ -116,7 +128,119 @@  start:
         .byte   0x52
         .byte   0x4d
         .byte   0x64
+#ifdef CONFIG_EFI_STUB
+        .long   pe_header - efi_head        /* Offset to the PE header. */
+#else
         .word   0                    /* reserved */
+#endif
+
+#ifdef CONFIG_EFI_STUB
+        /*
+         * Add the PE/COFF header to the file.  The address of this header
+         * is at offset 0x3c in the file, and is part of Linux "Image"
+         * header.  The arm64 Linux Image format is designed to support
+         * being both an 'Image' format binary and a PE/COFF binary.
+         * The PE/COFF format is defined by Microsoft, and is available
+         * from: http://msdn.microsoft.com/en-us/gg463119.aspx
+         * Version 8.3 adds support for arm64 and UEFI usage.
+         */
+
+        .align  3
+pe_header:
+        .ascii  "PE"
+        .short  0
+coff_header:
+        .short  0xaa64                          /* AArch64 */
+        .short  2                               /* nr_sections */
+        .long   0                               /* TimeDateStamp */
+        .long   0                               /* PointerToSymbolTable */
+        .long   1                               /* NumberOfSymbols */
+        .short  section_table - optional_header /* SizeOfOptionalHeader */
+        .short  0x206                           /* Characteristics. */
+                                                /* IMAGE_FILE_DEBUG_STRIPPED | */
+                                                /* IMAGE_FILE_EXECUTABLE_IMAGE | */
+                                                /* IMAGE_FILE_LINE_NUMS_STRIPPED */
+optional_header:
+        .short  0x20b                           /* PE32+ format */
+        .byte   0x02                            /* MajorLinkerVersion */
+        .byte   0x14                            /* MinorLinkerVersion */
+        .long   _end - real_start               /* SizeOfCode */
+        .long   0                               /* SizeOfInitializedData */
+        .long   0                               /* SizeOfUninitializedData */
+        .long   efi_stub_entry - efi_head       /* AddressOfEntryPoint */
+        .long   real_start - efi_head           /* BaseOfCode */
+
+extra_header_fields:
+        .quad   0                               /* ImageBase */
+        .long   0x200000                        /* SectionAlignment (2MByte) */
+        .long   0x8                             /* FileAlignment */
+        .short  0                               /* MajorOperatingSystemVersion */
+        .short  0                               /* MinorOperatingSystemVersion */
+        .short  0                               /* MajorImageVersion */
+        .short  0                               /* MinorImageVersion */
+        .short  0                               /* MajorSubsystemVersion */
+        .short  0                               /* MinorSubsystemVersion */
+        .long   0                               /* Win32VersionValue */
+
+        .long   _end - efi_head                 /* SizeOfImage */
+
+        /* Everything before the kernel image is considered part of the header */
+        .long   real_start - efi_head           /* SizeOfHeaders */
+        .long   0                               /* CheckSum */
+        .short  0xa                             /* Subsystem (EFI application) */
+        .short  0                               /* DllCharacteristics */
+        .quad   0                               /* SizeOfStackReserve */
+        .quad   0                               /* SizeOfStackCommit */
+        .quad   0                               /* SizeOfHeapReserve */
+        .quad   0                               /* SizeOfHeapCommit */
+        .long   0                               /* LoaderFlags */
+        .long   0x6                             /* NumberOfRvaAndSizes */
+
+        .quad   0                               /* ExportTable */
+        .quad   0                               /* ImportTable */
+        .quad   0                               /* ResourceTable */
+        .quad   0                               /* ExceptionTable */
+        .quad   0                               /* CertificationTable */
+        .quad   0                               /* BaseRelocationTable */
+
+        /* Section table */
+section_table:
+
+        /*
+         * The EFI application loader requires a relocation section
+         * because EFI applications must be relocatable.  This is a
+         * dummy section as far as we are concerned.
+         */
+        .ascii  ".reloc"
+        .byte   0
+        .byte   0                               /* end of 0 padding of section name */
+        .long   0
+        .long   0
+        .long   0                               /* SizeOfRawData */
+        .long   0                               /* PointerToRawData */
+        .long   0                               /* PointerToRelocations */
+        .long   0                               /* PointerToLineNumbers */
+        .short  0                               /* NumberOfRelocations */
+        .short  0                               /* NumberOfLineNumbers */
+        .long   0x42100040                      /* Characteristics (section flags) */
+
+
+        .ascii  ".text"
+        .byte   0
+        .byte   0
+        .byte   0                               /* end of 0 padding of section name */
+        .long   _end - real_start               /* VirtualSize */
+        .long   real_start - efi_head           /* VirtualAddress */
+        .long   __init_end_efi - real_start     /* SizeOfRawData */
+        .long   real_start - efi_head           /* PointerToRawData */
+
+        .long   0                /* PointerToRelocations (0 for executables) */
+        .long   0                /* PointerToLineNumbers (0 for executables) */
+        .short  0                /* NumberOfRelocations  (0 for executables) */
+        .short  0                /* NumberOfLineNumbers  (0 for executables) */
+        .long   0xe0500020       /* Characteristics (section flags) */
+        .align  5
+#endif
 
 real_start:
         msr   DAIFSet, 0xf           /* Disable all interrupts */
@@ -345,7 +469,7 @@  paging:
         dsb   sy
 #if defined(CONFIG_EARLY_PRINTK) /* Fixmap is only used by early printk */
         /* Non-boot CPUs don't need to rebuild the fixmap itself, just
-	 * the mapping from boot_second to xen_fixmap */
+         * the mapping from boot_second to xen_fixmap */
         cbnz  x22, 1f
 
         /* Add UART to the fixmap table */
@@ -561,9 +685,62 @@  putn:   ret
  * TODO: For now, the implementation return NULL every time
  */
 GLOBAL(lookup_processor_type)
-        mov  x0, #0
+        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.
+         * EFI mandates a 1:1 (unity) VA->PA mapping,
+         * so we can turn off the MMU before entering
+         * XEN.
+         *
+         * 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
+        bl    __flush_dcache_all
+        ic      ialluis
+
+        /* Turn off Dcache and MMU */
+        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
+
+        /* 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/Makefile b/xen/arch/arm/efi/Makefile
new file mode 100644
index 0000000..74863ba
--- /dev/null
+++ b/xen/arch/arm/efi/Makefile
@@ -0,0 +1,2 @@ 
+obj-$(EFI) += efi.o
+CFLAGS += -fshort-wchar
diff --git a/xen/arch/arm/efi/efi.c b/xen/arch/arm/efi/efi.c
new file mode 100644
index 0000000..832b324
--- /dev/null
+++ b/xen/arch/arm/efi/efi.c
@@ -0,0 +1,714 @@ 
+#include <asm/efibind.h>
+#include <efi/efidef.h>
+#include <efi/efierr.h>
+#include <efi/eficon.h>
+#include <efi/efidevp.h>
+#include <efi/eficapsule.h>
+#include <efi/efiapi.h>
+#include <xen/efi.h>
+#include <xen/spinlock.h>
+#include <asm/page.h>
+#include <efi/efiprot.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>
+#include <asm/setup.h>
+
+
+void __init noreturn blexit(const CHAR16 *str);
+
+#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;
+
+/*
+ * Hacky way to make sure EFI allocations end up in memory that XEN
+ * includes in its mappings.
+ * RFRANZ_TODO - this needs to be resolved properly.
+ */
+static EFI_PHYSICAL_ADDRESS max_addr = 0xffffffff;
+
+static void *new_fdt;
+
+static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map,
+                                                unsigned long mmap_size,
+                                                unsigned long desc_size)
+{
+    int Index;
+    int i = 0;
+
+    EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
+
+    for ( Index = 0; Index < (mmap_size / desc_size); Index++ )
+    {
+        if ( desc_ptr->Type == EfiConventionalMemory
+             || desc_ptr->Type == EfiBootServicesCode
+             || desc_ptr->Type == EfiBootServicesData )
+        {
+            bootinfo.mem.bank[i].start = desc_ptr->PhysicalStart;
+            bootinfo.mem.bank[i].size = desc_ptr->NumberOfPages * EFI_PAGE_SIZE;
+            if ( ++i >= NR_MEM_BANKS )
+            {
+                PrintStr(L"Warning: bootinfo mem banks exhausted\r\n");
+                break;
+            }
+        }
+        desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size);
+    }
+
+    bootinfo.mem.nr_banks = i;
+    return EFI_SUCCESS;
+
+}
+
+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;
+
+    *map = NULL;
+    *mmap_size = EFI_PAGE_SIZE;
+again:
+    *mmap_size += EFI_PAGE_SIZE;  /* Page size is allocation granularity */
+    status = sys_table_arg->BootServices->AllocatePool(EfiLoaderData,
+                                                       *mmap_size, (void **)&m);
+    if ( status != EFI_SUCCESS )
+        return status;
+
+    *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);
+        return status;
+    }
+
+    if ( key_ptr && status == EFI_SUCCESS )
+        *key_ptr = key;
+    if ( desc_ver && status == EFI_SUCCESS )
+        *desc_ver = desc_version;
+
+    *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) )
+        {
+            fdt = tables[i].VendorTable;
+            break;
+        }
+    }
+    return fdt;
+}
+
+/*
+ * Get (or set if not present) the #addr-cells and #size cells
+ * properties of the chosen node.  We need to know these to
+ * properly construct the address ranges used to describe the files
+ * loaded by the stub.
+ */
+static int __init 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 __init 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 __init 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;
+    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;
+    }
+
+    /* Add FDT entries for EFI runtime services in chosen node. */
+    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;
+        }
+    }
+
+    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
+        fdt_size = 0;
+
+    pages = PFN_UP(fdt_size) + PFN_UP(add_size);
+    fdt_addr = max_addr;
+    status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData,
+                                   pages, &fdt_addr);
+
+    if ( status != EFI_SUCCESS )
+        return NULL;
+
+    new_fdt = (void *)fdt_addr;
+
+    if ( fdt_size )
+    {
+        if ( fdt_open_into(dtb.ptr, new_fdt, pages * EFI_PAGE_SIZE) )
+            return NULL;
+    }
+    else
+    {
+        /*
+         * Create an empty FDT if not provided one, which is the expected case
+         * when booted from the UEFI shell on an ACPI only system.  We will use
+         * the FDT to pass the EFI information to XEN, as well as nodes for
+         * any modules the stub loads.  The ACPI tables are part of the UEFI
+         * system table that is passed in the FDT.
+         */
+        PrintStr(L"before fdt_create_empty_tree\r\n");
+        if ( fdt_create_empty_tree(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, max_addr);
+        PrintStr(L"Using FDT from file ");
+        PrintStr(name.w);
+        PrintStr(L"\r\n");
+        efi_bs->FreePool(name.w);
+    }
+    else
+    {
+        /* Get DTB from configuration table. */
+        dtb.ptr = lookup_fdt_config_table(SystemTable);
+        if ( dtb.ptr )
+        {
+            PrintStr(L"Using FDT from EFI configuration table\r\n");
+            /* Set dtb.size to zero so config table memory is not freed. */
+            dtb.size = 0;
+        }
+    }
+
+    /*
+     * 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, max_addr);
+
+    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,
+                           "multiboot,kernel") + 1;
+    if ( compat_len > COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    compat_len += snprintf(compat_buf + compat_len,
+                           COMPAT_BUF_SIZE - compat_len,
+                           "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, max_addr);
+
+        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,
+                               "multiboot,ramdisk") + 1;
+        if ( compat_len > COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+        compat_len += snprintf(compat_buf + compat_len,
+                               COMPAT_BUF_SIZE - compat_len,
+                               "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");
+    }
+
+
+    /* Free config file buffer */
+    efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
+    cfg.addr = 0;
+
+    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");
+
+
+    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.");
+
+    /*
+     *  Put available EFI memory into bootinfo memory map.
+     */
+    efi_process_memory_map_bootinfo(mmap_ptr, mmap_size, desc_size);
+
+    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 */
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
index be55dad..62b9d5b 100644
--- a/xen/arch/arm/xen.lds.S
+++ b/xen/arch/arm/xen.lds.S
@@ -135,6 +135,7 @@  SECTIONS
        *(.xsm_initcall.init)
        __xsm_initcall_end = .;
   } :text
+  __init_end_efi = .;
   . = ALIGN(STACK_SIZE);
   __init_end = .;
 
diff --git a/xen/include/asm-arm/arm64/efibind.h b/xen/include/asm-arm/arm64/efibind.h
new file mode 100644
index 0000000..2b0bf40
--- /dev/null
+++ b/xen/include/asm-arm/arm64/efibind.h
@@ -0,0 +1,216 @@ 
+/*++
+
+Copyright (c) 1998  Intel Corporation
+
+Module Name:
+
+    efefind.h
+
+Abstract:
+
+    EFI to compile bindings
+
+
+
+
+Revision History
+
+--*/
+
+#ifndef __GNUC__
+#pragma pack()
+#endif
+
+#define EFIERR(a)           (0x8000000000000000 | a)
+#define EFI_ERROR_MASK      0x8000000000000000
+#define EFIERR_OEM(a)       (0xc000000000000000 | a)
+
+#define BAD_POINTER         0xFBFBFBFBFBFBFBFB
+#define MAX_ADDRESS         0xFFFFFFFFFFFFFFFF
+
+#define EFI_STUB_ERROR      MAX_ADDRESS
+
+#ifndef __ASSEMBLY__
+//
+// Basic int types of various widths
+//
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L )
+
+    // No ANSI C 1999/2000 stdint.h integer width declarations
+
+    #if defined(__GNUC__)
+        typedef unsigned long long  uint64_t __attribute__((aligned (8)));
+        typedef long long           int64_t __attribute__((aligned (8)));
+        typedef unsigned int        uint32_t;
+        typedef int                 int32_t;
+        typedef unsigned short      uint16_t;
+        typedef short               int16_t;
+        typedef unsigned char       uint8_t;
+        typedef char                int8_t;
+    #elif defined(UNIX_LP64)
+
+        /*  Use LP64 programming model from C_FLAGS for integer width declarations */
+
+       typedef unsigned long       uint64_t;
+       typedef long                int64_t;
+       typedef unsigned int        uint32_t;
+       typedef int                 int32_t;
+       typedef unsigned short      uint16_t;
+       typedef short               int16_t;
+       typedef unsigned char       uint8_t;
+       typedef char                int8_t;
+    #else
+
+       /*  Assume P64 programming model from C_FLAGS for integer width declarations */
+
+       typedef unsigned long long  uint64_t __attribute__((aligned (8)));
+       typedef long long           int64_t __attribute__((aligned (8)));
+       typedef unsigned int        uint32_t;
+       typedef int                 int32_t;
+       typedef unsigned short      uint16_t;
+       typedef short               int16_t;
+       typedef unsigned char       uint8_t;
+       typedef char                int8_t;
+    #endif
+#endif
+
+//
+// Basic EFI types of various widths
+//
+
+#ifndef __WCHAR_TYPE__
+# define __WCHAR_TYPE__ short
+#endif
+
+typedef uint64_t   UINT64;
+typedef int64_t    INT64;
+
+#ifndef _BASETSD_H_
+    typedef uint32_t   UINT32;
+    typedef int32_t    INT32;
+#endif
+
+typedef uint16_t   UINT16;
+typedef int16_t    INT16;
+typedef uint8_t    UINT8;
+typedef int8_t     INT8;
+typedef __WCHAR_TYPE__ WCHAR;
+
+#undef VOID
+#define VOID    void
+
+
+typedef int64_t    INTN;
+typedef uint64_t   UINTN;
+
+#define POST_CODE(_Data)
+
+
+#define BREAKPOINT()        while (TRUE);    // Make it hang on Bios[Dbg]32
+
+//
+// Pointers must be aligned to these address to function
+//
+
+#define MIN_ALIGNMENT_SIZE  4
+
+#define ALIGN_VARIABLE(Value ,Adjustment) \
+            (UINTN)Adjustment = 0; \
+            if((UINTN)Value % MIN_ALIGNMENT_SIZE) \
+                (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \
+            Value = (UINTN)Value + (UINTN)Adjustment
+
+
+//
+// Define macros to build data structure signatures from characters.
+//
+
+#define EFI_SIGNATURE_16(A,B)             ((A) | (B<<8))
+#define EFI_SIGNATURE_32(A,B,C,D)         (EFI_SIGNATURE_16(A,B)     | (EFI_SIGNATURE_16(C,D)     << 16))
+#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32))
+
+#define EXPORTAPI
+
+
+//
+// EFIAPI - prototype calling convention for EFI function pointers
+// BOOTSERVICE - prototype for implementation of a boot service interface
+// RUNTIMESERVICE - prototype for implementation of a runtime service interface
+// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service
+// RUNTIME_CODE - pragma macro for declaring runtime code
+//
+
+#ifndef EFIAPI                  // Forces EFI calling conventions reguardless of compiler options
+        #define EFIAPI          // Substitute expresion to force C calling convention
+#endif
+
+#define BOOTSERVICE
+//#define RUNTIMESERVICE(proto,a)    alloc_text("rtcode",a); proto a
+//#define RUNTIMEFUNCTION(proto,a)   alloc_text("rtcode",a); proto a
+#define RUNTIMESERVICE
+#define RUNTIMEFUNCTION
+
+
+#define RUNTIME_CODE(a)         alloc_text("rtcode", a)
+#define BEGIN_RUNTIME_DATA()    data_seg("rtdata")
+#define END_RUNTIME_DATA()      data_seg("")
+
+#define VOLATILE    volatile
+
+#define MEMORY_FENCE()
+
+
+//
+// When build similiar to FW, then link everything together as
+// one big module.
+//
+
+#define EFI_DRIVER_ENTRY_POINT(InitFunction)    \
+    UINTN                                       \
+    InitializeDriver (                          \
+        VOID    *ImageHandle,                   \
+        VOID    *SystemTable                    \
+        )                                       \
+    {                                           \
+        return InitFunction(ImageHandle,        \
+                SystemTable);                   \
+    }                                           \
+                                                \
+    EFI_STATUS efi_main(                        \
+        EFI_HANDLE image,                       \
+        EFI_SYSTEM_TABLE *systab                \
+        ) __attribute__((weak,                  \
+                alias ("InitializeDriver")));
+
+#define LOAD_INTERNAL_DRIVER(_if, type, name, entry)    \
+        (_if)->LoadInternal(type, name, entry)
+
+
+//
+// Some compilers don't support the forward reference construct:
+//  typedef struct XXXXX
+//
+// The following macro provide a workaround for such cases.
+//
+#ifdef NO_INTERFACE_DECL
+#define INTERFACE_DECL(x)
+#else
+#ifdef __GNUC__
+#define INTERFACE_DECL(x) struct x
+#else
+#define INTERFACE_DECL(x) typedef struct x
+#endif
+#endif
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/efibind.h b/xen/include/asm-arm/efibind.h
new file mode 100644
index 0000000..09dca7a
--- /dev/null
+++ b/xen/include/asm-arm/efibind.h
@@ -0,0 +1,2 @@ 
+#include <xen/types.h>
+#include <asm/arm64/efibind.h>
diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h
index 36e5704..40814e6 100644
--- a/xen/include/asm-arm/setup.h
+++ b/xen/include/asm-arm/setup.h
@@ -3,7 +3,7 @@ 
 
 #include <public/version.h>
 
-#define NR_MEM_BANKS 8
+#define NR_MEM_BANKS 32
 
 #define MAX_MODULES 5 /* Current maximum useful modules */