References: fate#311376, fate#311529, bnc#578927, bnc#628554

# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1309249175 -3600
# Node ID 8b7d00f2abb21b504f6f8e1a6cc235cee8eb0858
# Parent  b8d22c658bd213bf9da0a9d05312b63524652daf
x86-64: EFI boot code

Besides introducing the relevant code paralleling parts of what is
under xen/arch/x86/boot/, this adjusts the build logic so that with a
single compilation two images (gzip-compressed ELF and EFI
application)
can get created. The EFI part of this depends on a new enough compiler
(supposedly gcc 4.4.x and above, but so far only tested to work with
4.5.x) and a properly configured linker (must support the i386pep
emulation). If either functionality is found to not be available, the
EFI part of the build will simply be skipped.

The patch adds all code to allow Xen and the (accordingly enabled)
Dom0  kernel to boot, but doesn't allow Dom0 to make use of EFI
runtime calls (this will be the subject of the next patch).

Parts of the code were lifted from an earlier never published OS
project of ours - whether respective license information needs to be
added to the respective source file is unclear to me (I was told
internally that adding a GPLv2 license header can be done if needed by
the community).

Signed-off-by: Jan Beulich <jbeulich@novell.com>

# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1309549342 -3600
# Node ID 638f31a30b6ccb3fe26f79b991bed4cd03995809
# Parent  7631c461132000979f05759705c055eb3c975c0b
x86/EFI: adjust installation logic

We should always install xen.efi into /usr/lib64/efi/; installation
into /boot/efi/efi/$(EFI_VENDOR) remains dependent upon specifying
EFI_VENDOR.

Signed-off-by: Jan Beulich <jbeulich@novell.com>

# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1310127785 -3600
# Node ID 88823213a4780ebced6d7adcb1ffd2dda6a339ca
# Parent  d1a2861b9caa1a428a531c0d68b372df872d5b0d
x86-64/EFI: discard .comment.* sections

The SuSE version of gcc produces a non-standard section named
.comment.SUSE.OPTs, but the PE32+ handling in binutils can't really
deal with any section to be placed at virtual address zero (and not
needing to be loaded). Even if binutils did, at least the UEFI
implementation in EDK 1.06 doesn't look at the section characteristics
at all, and hence would attempt to load such a section, and fail or
corrupt other data.

Signed-off-by: Jan Beulich <jbeulich@novell.com>

# HG changeset patch
# User Daniel De Graaf <dgdegra@tycho.nsa.gov>
# Date 1345016534 -7200
# Node ID 02b4d5fedb7bac4f98964d32fd9ed1d17b1db4b1
# Parent  af7143d97fa2f9954afca79528e482a192d3edd2
x86-64/EFI: add CFLAGS to check compile

Without this, the compilation of check.c could fail due to compiler
features such as -fstack-protector being enabled, which causes a
missing __stack_chk_fail symbol error.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>

Rather than using plain CFLAGS here, remove CFLAGS-y from them to
particularly get rid of the -MF argument referencing (the undefined
here) $(@F).

The use of CFLAGS at once allows dropping the explicit use of -Werror.

Signed-off-by: Jan Beulich <jbeulich@suse.com>

Index: xen-4.1.4-testing/xen/Makefile
===================================================================
--- xen-4.1.4-testing.orig/xen/Makefile
+++ xen-4.1.4-testing/xen/Makefile
@@ -12,6 +12,8 @@ export XEN_DOMAIN	?= $(shell ([ -x /bin/
 export BASEDIR := $(CURDIR)
 export XEN_ROOT := $(BASEDIR)/..
 
+EFI_MOUNTPOINT ?= /boot/efi
+
 .PHONY: default
 default: build
 
@@ -33,6 +35,18 @@ _install: $(TARGET).gz
 	ln -f -s $(notdir $(TARGET))-$(XEN_FULLVERSION).gz $(DESTDIR)/boot/$(notdir $(TARGET))-$(XEN_VERSION).gz
 	ln -f -s $(notdir $(TARGET))-$(XEN_FULLVERSION).gz $(DESTDIR)/boot/$(notdir $(TARGET)).gz
 	$(INSTALL_DATA) $(TARGET)-syms $(DESTDIR)/boot/$(notdir $(TARGET))-syms-$(XEN_FULLVERSION)
+	if [ -r $(TARGET).efi ]; then \
+		[ -d $(DESTDIR)$(LIBDIR)/efi ] || $(INSTALL_DIR) $(DESTDIR)$(LIBDIR)/efi; \
+		$(INSTALL_DATA) $(TARGET).efi $(DESTDIR)$(LIBDIR)/efi/$(notdir $(TARGET))-$(XEN_FULLVERSION).efi; \
+		ln -sf $(notdir $(TARGET))-$(XEN_FULLVERSION).efi $(DESTDIR)$(LIBDIR)/efi/$(notdir $(TARGET))-$(XEN_VERSION).$(XEN_SUBVERSION).efi; \
+		ln -sf $(notdir $(TARGET))-$(XEN_FULLVERSION).efi $(DESTDIR)$(LIBDIR)/efi/$(notdir $(TARGET))-$(XEN_VERSION).efi; \
+		ln -sf $(notdir $(TARGET))-$(XEN_FULLVERSION).efi $(DESTDIR)$(LIBDIR)/efi/$(notdir $(TARGET)).efi; \
+		if [ -n '$(EFI_MOUNTPOINT)' -a -n '$(EFI_VENDOR)' ]; then \
+			$(INSTALL_DATA) $(TARGET).efi $(DESTDIR)$(EFI_MOUNTPOINT)/efi/$(EFI_VENDOR)/$(notdir $(TARGET))-$(XEN_FULLVERSION).efi; \
+		elif [ "$(DESTDIR)" = "$(patsubst $(shell cd $(XEN_ROOT) && pwd)/%,%,$(DESTDIR))" ]; then \
+			echo 'EFI installation only partially done (EFI_VENDOR not set)' >&2; \
+		fi; \
+	fi
 
 .PHONY: _debug
 _debug:
Index: xen-4.1.4-testing/xen/arch/x86/Makefile
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/Makefile
+++ xen-4.1.4-testing/xen/arch/x86/Makefile
@@ -61,14 +61,21 @@ obj-$(crash_debug) += gdbstub.o
 
 x86_emulate.o: x86_emulate/x86_emulate.c x86_emulate/x86_emulate.h
 
-$(TARGET): $(TARGET)-syms boot/mkelf32
+efi-$(x86_64) := $(shell if [ ! -r $(BASEDIR)/include/xen/compile.h -o \
+                                -O $(BASEDIR)/include/xen/compile.h ]; then \
+                         echo '$(TARGET).efi'; fi)
+
+$(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32
 	./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 \
 	`$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'`
 
-ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(ALL_OBJS)
+ALL_EFI_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o efi/boot.o efi/runtime.o efi/compat.o $(ALL_OBJS)
+ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
+
+$(BASEDIR)/common/symbols-dummy.o:
+	$(MAKE) -f $(BASEDIR)/Rules.mk -C $(BASEDIR)/common symbols-dummy.o
 
-$(TARGET)-syms: $(ALL_OBJS) xen.lds
-	$(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/common/symbols-dummy.o
+$(TARGET)-syms: $(ALL_OBJS) xen.lds $(BASEDIR)/common/symbols-dummy.o
 	$(LD) $(LDFLAGS) -T xen.lds -N $(ALL_OBJS) \
 	    $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0
 	$(NM) -n $(@D)/.$(@F).0 | $(BASEDIR)/tools/symbols >$(@D)/.$(@F).0.S
@@ -81,6 +88,39 @@ $(TARGET)-syms: $(ALL_OBJS) xen.lds
 	    $(@D)/.$(@F).1.o -o $@
 	rm -f $(@D)/.$(@F).[0-9]*
 
+EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10
+EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 --strip-debug
+EFI_LDFLAGS += --section-alignment=0x200000 --file-alignment=0x20
+EFI_LDFLAGS += --major-image-version=$(XEN_VERSION)
+EFI_LDFLAGS += --minor-image-version=$(XEN_SUBVERSION)
+EFI_LDFLAGS += --major-os-version=2 --minor-os-version=0
+EFI_LDFLAGS += --major-subsystem-version=2 --minor-subsystem-version=0
+
+$(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p')
+$(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p')
+# Don't use $(wildcard ...) here - at least make 3.80 expands this too early!
+$(TARGET).efi: guard = $(if $(shell echo efi/dis* | grep disabled),:)
+$(TARGET).efi: $(ALL_EFI_OBJS) efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbols-dummy.o efi/mkreloc
+	$(foreach base, $(VIRT_BASE) $(ALT_BASE), \
+	          $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $(ALL_EFI_OBJS) efi/relocs-dummy.o \
+	                $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).$(base).0 &&) :
+	$(guard) efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S
+	$(guard) $(NM) -n $(@D)/.$(@F).$(VIRT_BASE).0 | $(guard) $(BASEDIR)/tools/symbols >$(@D)/.$(@F).0s.S
+	$(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o
+	$(foreach base, $(VIRT_BASE) $(ALT_BASE), \
+	          $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $(ALL_EFI_OBJS) \
+	                $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o -o $(@D)/.$(@F).$(base).1 &&) :
+	$(guard) efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S
+	$(guard) $(NM) -n $(@D)/.$(@F).$(VIRT_BASE).1 | $(guard) $(BASEDIR)/tools/symbols >$(@D)/.$(@F).1s.S
+	$(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o
+	$(guard) $(LD) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T efi.lds -N $(ALL_EFI_OBJS) \
+	                $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o -o $@
+	if $(guard) false; then rm -f $@; echo 'EFI support disabled'; fi
+	rm -f $(@D)/.$(@F).[0-9]*
+
+efi/boot.o efi/runtime.o efi/compat.o: $(BASEDIR)/arch/x86/efi/built_in.o
+efi/boot.o efi/runtime.o efi/compat.o: ;
+
 asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c
 	$(CC) $(CFLAGS) -S -o $@ $<
 
@@ -89,11 +129,20 @@ xen.lds: xen.lds.S
 	sed -e 's/xen\.lds\.o:/xen\.lds:/g' <.xen.lds.d >.xen.lds.d.new
 	mv -f .xen.lds.d.new .xen.lds.d
 
+efi.lds: xen.lds.S
+	$(CC) -P -E -Ui386 -DEFI $(AFLAGS) -o $@ $<
+	sed -e 's/efi\.lds\.o:/efi\.lds:/g' <.$(@F).d >.$(@F).d.new
+	mv -f .$(@F).d.new .$(@F).d
+
 boot/mkelf32: boot/mkelf32.c
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
 
+efi/mkreloc: efi/mkreloc.c
+	$(HOSTCC) $(HOSTCFLAGS) -g -o $@ $<
+
 .PHONY: clean
 clean::
 	rm -f asm-offsets.s xen.lds boot/*.o boot/*~ boot/core boot/mkelf32
 	rm -f $(BASEDIR)/.xen-syms.[0-9]* boot/.*.d
+	rm -f $(BASEDIR)/.xen.efi.[0-9]* efi/*.o efi/mkreloc
 	rm -f boot/reloc.S boot/reloc.lnk boot/reloc.bin
Index: xen-4.1.4-testing/xen/arch/x86/boot/trampoline.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/trampoline.S
+++ xen-4.1.4-testing/xen/arch/x86/boot/trampoline.S
@@ -38,6 +38,7 @@ trampoline_gdt:
         .long   0x0000ffff | ((BOOT_TRAMPOLINE & 0x00ffff) << 16)
         .long   0x00009200 | ((BOOT_TRAMPOLINE & 0xff0000) >> 16)
 
+        .globl cpuid_ext_features
 cpuid_ext_features:
         .long   0
 
Index: xen-4.1.4-testing/xen/arch/x86/boot/x86_64.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/x86_64.S
+++ xen-4.1.4-testing/xen/arch/x86/boot/x86_64.S
@@ -84,11 +84,13 @@ multiboot_ptr:
         .long   0
 
         .word   0
+        .globl  gdt_descr
 gdt_descr:
         .word   LAST_RESERVED_GDT_BYTE
         .quad   boot_cpu_gdt_table - FIRST_RESERVED_GDT_BYTE
 
         .word   0,0,0
+        .globl  idt_descr
 idt_descr:
         .word   256*16-1
         .quad   idt_table
Index: xen-4.1.4-testing/xen/arch/x86/dmi_scan.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/dmi_scan.c
+++ xen-4.1.4-testing/xen/arch/x86/dmi_scan.c
@@ -11,6 +11,7 @@
 #include <xen/dmi.h>
 #include <xen/pci.h>
 #include <xen/pci_regs.h>
+#include <xen/efi.h>
 
 #define bt_ioremap(b,l)  ((void *)__acpi_map_table(b,l))
 #define bt_iounmap(b,l)  ((void)0)
@@ -124,11 +125,39 @@ static inline bool_t __init dmi_checksum
 	return sum == 0;
 }
 
+static u32 __initdata efi_dmi_address;
+static u32 __initdata efi_dmi_size;
+
+/*
+ * Important: This function gets called while still in EFI
+ * (pseudo-)physical mode.
+ */
+void __init dmi_efi_get_table(void *smbios)
+{
+	struct smbios_eps *eps = smbios;
+
+	if (memcmp(eps->anchor, "_SM_", 4) &&
+	    dmi_checksum(eps, eps->length) &&
+	    memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 &&
+	    dmi_checksum(&eps->dmi, sizeof(eps->dmi))) {
+		efi_dmi_address = eps->dmi.address;
+		efi_dmi_size = eps->dmi.size;
+	}
+}
+
 int __init dmi_get_table(u32 *base, u32 *len)
 {
 	struct dmi_eps eps;
 	char __iomem *p, *q;
 
+	if (efi_enabled) {
+		if (!efi_dmi_size)
+			return -1;
+		*base = efi_dmi_address;
+		*len = efi_dmi_size;
+		return 0;
+	}
+
 	p = maddr_to_virt(0xF0000);
 	for (q = p; q < p + 0x10000; q += 16) {
 		memcpy_fromio(&eps, q, 15);
@@ -180,6 +209,39 @@ static int __init dmi_iterate(void (*dec
 	return -1;
 }
 
+static int __init dmi_efi_iterate(void (*decode)(struct dmi_header *))
+{
+	struct smbios_eps eps;
+	const struct smbios_eps __iomem *p;
+	int ret = -1;
+
+	if (efi.smbios == EFI_INVALID_TABLE_ADDR)
+		return -1;
+
+	p = bt_ioremap(efi.smbios, sizeof(eps));
+	if (!p)
+		return -1;
+	memcpy_fromio(&eps, p, sizeof(eps));
+	bt_iounmap(p, sizeof(eps));
+
+	if (memcmp(eps.anchor, "_SM_", 4))
+		return -1;
+
+	p = bt_ioremap(efi.smbios, eps.length);
+	if (!p)
+		return -1;
+	if (dmi_checksum(p, eps.length) &&
+	    memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
+	    dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
+		printk(KERN_INFO "SMBIOS %d.%d present.\n",
+		       eps.major, eps.minor);
+		ret = _dmi_iterate(&eps.dmi, p, decode);
+	}
+	bt_iounmap(p, eps.length);
+
+	return ret;
+}
+
 static char *dmi_ident[DMI_STRING_MAX];
 
 /*
@@ -504,8 +566,8 @@ static void __init dmi_decode(struct dmi
 
 void __init dmi_scan_machine(void)
 {
-	int err = dmi_iterate(dmi_decode);
-	if(err == 0)
+	if ((!efi_enabled ? dmi_iterate(dmi_decode) :
+	                    dmi_efi_iterate(dmi_decode)) == 0)
  		dmi_check_system(dmi_blacklist);
 	else
 		printk(KERN_INFO "DMI not present.\n");
Index: xen-4.1.4-testing/xen/arch/x86/efi/Makefile
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/Makefile
@@ -0,0 +1,17 @@
+CFLAGS += -fshort-wchar -mno-sse
+
+obj-y += stub.o
+
+create = test -e $(1) || touch -t 199901010000 $(1)
+
+efi := $(filter y,$(x86_64)$(shell rm -f disabled))
+efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y),$(CFLAGS)) -c check.c 2>disabled && echo y))
+efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y))
+efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.o); $(call create,runtime.o)))
+
+extra-$(efi) += boot.o relocs-dummy.o runtime.o compat.o
+
+stub.o: $(extra-y)
+
+clean::
+	rm -f disabled *.efi
Index: xen-4.1.4-testing/xen/arch/x86/efi/boot.c
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/boot.c
@@ -0,0 +1,1221 @@
+#include "efi.h"
+#include <efi/efiprot.h>
+#include <public/xen.h>
+#include <xen/compile.h>
+#include <xen/ctype.h>
+#include <xen/dmi.h>
+#include <xen/init.h>
+#include <xen/keyhandler.h>
+#include <xen/lib.h>
+#include <xen/multiboot.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/vga.h>
+#include <asm/e820.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+extern char start[];
+extern u32 cpuid_ext_features;
+
+union string {
+    CHAR16 *w;
+    char *s;
+    const char *cs;
+};
+
+struct file {
+    UINTN size;
+    union {
+        EFI_PHYSICAL_ADDRESS addr;
+        void *ptr;
+    };
+};
+
+static EFI_BOOT_SERVICES *__initdata efi_bs;
+static EFI_HANDLE __initdata efi_ih;
+
+static SIMPLE_TEXT_OUTPUT_INTERFACE __initdata *StdOut;
+static SIMPLE_TEXT_OUTPUT_INTERFACE __initdata *StdErr;
+
+static UINT32 __initdata mdesc_ver;
+
+static struct file __initdata cfg;
+static struct file __initdata kernel;
+static struct file __initdata ramdisk;
+static struct file __initdata xsm;
+
+static multiboot_info_t __initdata mbi = {
+    .flags = MBI_MODULES | MBI_LOADERNAME
+};
+static module_t __initdata mb_modules[3];
+
+static CHAR16 __initdata newline[] = L"\r\n";
+
+#define PrintStr(s) StdOut->OutputString(StdOut, s)
+#define PrintErr(s) StdErr->OutputString(StdErr, s)
+
+static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer)
+{
+    if ( Val >= 10 )
+        Buffer = FormatDec(Val / 10, Buffer);
+    *Buffer = (CHAR16)(L'0' + Val % 10);
+    return Buffer + 1;
+}
+
+static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer)
+{
+    if ( Width > 1 || Val >= 0x10 )
+        Buffer = FormatHex(Val >> 4, Width ? Width - 1 : 0, Buffer);
+    *Buffer = (CHAR16)((Val &= 0xf) < 10 ? L'0' + Val : L'a' + Val - 10);
+    return Buffer + 1;
+}
+
+static void __init DisplayUint(UINT64 Val, INTN Width)
+{
+    CHAR16 PrintString[32], *end;
+
+    if (Width < 0)
+        end = FormatDec(Val, PrintString);
+    else
+    {
+        PrintStr(L"0x");
+        end = FormatHex(Val, Width, PrintString);
+    }
+    *end = 0;
+    PrintStr(PrintString);
+}
+
+static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s)
+{
+    CHAR16 *r = d;
+
+    while ( (*d++ = *s++) != 0 )
+        ;
+    return r;
+}
+
+static int __init wstrcmp(const CHAR16 *s1, const CHAR16 *s2)
+{
+    while ( *s1 && *s1 == *s2 )
+    {
+        ++s1;
+        ++s2;
+    }
+    return *s1 - *s2;
+}
+
+static int __init wstrncmp(const CHAR16 *s1, const CHAR16 *s2, UINTN n)
+{
+    while ( n && *s1 && *s1 == *s2 )
+    {
+        --n;
+        ++s1;
+        ++s2;
+    }
+    return n ? *s1 - *s2 : 0;
+}
+
+static CHAR16 *__init s2w(union string *str)
+{
+    const char *s = str->s;
+    CHAR16 *w;
+    void *ptr;
+
+    if ( efi_bs->AllocatePool(EfiLoaderData, (strlen(s) + 1) * sizeof(*w),
+                              &ptr) != EFI_SUCCESS )
+        return NULL;
+
+    w = str->w = ptr;
+    do {
+        *w = *s++;
+    } while ( *w++ );
+
+    return str->w;
+}
+
+static char *__init w2s(const union string *str)
+{
+    const CHAR16 *w = str->w;
+    char *s = str->s;
+
+    do {
+        if ( *w > 0x007f )
+            return NULL;
+        *s = *w++;
+    } while ( *s++ );
+
+    return str->s;
+}
+
+static bool_t __init match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2)
+{
+    return guid1->Data1 == guid2->Data1 &&
+           guid1->Data2 == guid2->Data2 &&
+           guid1->Data3 == guid2->Data3 &&
+           !memcmp(guid1->Data4, guid2->Data4, sizeof(guid1->Data4));
+}
+
+static void __init __attribute__((__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 ( xsm.addr )
+        efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size));
+
+    efi_bs->Exit(efi_ih, EFI_SUCCESS, 0, NULL);
+    for( ; ; ); /* not reached */
+}
+
+/* generic routine for printing error messages */
+static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode)
+{
+    StdOut = StdErr;
+    PrintErr((CHAR16 *)mesg);
+    PrintErr(L": ");
+
+    switch (ErrCode)
+    {
+    case EFI_NOT_FOUND:
+        mesg = L"Not found";
+        break;
+    case EFI_NO_MEDIA:
+        mesg = L"The device has no media";
+        break;
+    case EFI_MEDIA_CHANGED:
+        mesg = L"Media changed";
+        break;
+    case EFI_DEVICE_ERROR:
+        mesg = L"Device error";
+        break;
+    case EFI_VOLUME_CORRUPTED:
+        mesg = L"Volume corrupted";
+        break;
+    case EFI_ACCESS_DENIED:
+        mesg = L"Access denied";
+        break;
+    case EFI_OUT_OF_RESOURCES:
+        mesg = L"Out of resources";
+        break;
+    case EFI_VOLUME_FULL:
+        mesg = L"Volume is full";
+        break;
+    default:
+        PrintErr(L"ErrCode: ");
+        DisplayUint(ErrCode, 0);
+        mesg = NULL;
+        break;
+    }
+    blexit(mesg);
+}
+
+static void __init place_string(u32 *addr, const char *s)
+{
+    static char *__initdata alloc = start;
+
+    if ( s && *s )
+    {
+        size_t len1 = strlen(s) + 1;
+        const char *old = (char *)(long)*addr;
+        size_t len2 = *addr ? strlen(old) + 1 : 0;
+
+        alloc -= len1 + len2;
+        /*
+         * Insert new string before already existing one. This is needed
+         * for options passed on the command line to override options from
+         * the configuration file.
+         */
+        memcpy(alloc, s, len1);
+        if ( *addr )
+        {
+            alloc[len1 - 1] = ' ';
+            memcpy(alloc + len1, old, len2);
+        }
+    }
+    *addr = (long)alloc;
+}
+
+static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv,
+                                    CHAR16 *cmdline, UINTN cmdsize)
+{
+    CHAR16 *ptr = (CHAR16 *)(argv + argc + 1), *prev = NULL;
+    bool_t prev_sep = TRUE;
+
+    for ( ; cmdsize > sizeof(*cmdline) && *cmdline;
+            cmdsize -= sizeof(*cmdline), ++cmdline )
+    {
+        bool_t cur_sep = *cmdline == L' ' || *cmdline == L'\t';
+
+        if ( !prev_sep )
+        {
+            if ( cur_sep )
+                ++ptr;
+            else if ( argv )
+            {
+                *ptr = *cmdline;
+                *++ptr = 0;
+            }
+        }
+        else if ( !cur_sep )
+        {
+            if ( !argv )
+                ++argc;
+            else if ( prev && wstrcmp(prev, L"--") == 0 )
+            {
+                union string rest = { .w = cmdline };
+
+                --argv;
+                place_string(&mbi.cmdline, w2s(&rest));
+                break;
+            }
+            else
+            {
+                *argv++ = prev = ptr;
+                *ptr = *cmdline;
+                *++ptr = 0;
+            }
+        }
+        prev_sep = cur_sep;
+    }
+    if ( argv )
+        *argv = NULL;
+    return argc;
+}
+
+static EFI_FILE_HANDLE __init get_parent_handle(EFI_LOADED_IMAGE *loaded_image,
+                                                CHAR16 **leaf)
+{
+    static EFI_GUID __initdata fs_protocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
+    EFI_FILE_HANDLE dir_handle;
+    EFI_DEVICE_PATH *dp;
+    CHAR16 *pathend, *ptr;
+    EFI_STATUS ret;
+
+    do {
+        EFI_FILE_IO_INTERFACE *fio;
+
+        /* Get the file system interface. */
+        ret = efi_bs->HandleProtocol(loaded_image->DeviceHandle,
+                                     &fs_protocol, (void **)&fio);
+        if ( EFI_ERROR(ret) )
+            blexit(L"Couldn't obtain the File System Protocol Interface");
+        ret = fio->OpenVolume(fio, &dir_handle);
+    } while ( ret == EFI_MEDIA_CHANGED );
+    if ( ret != EFI_SUCCESS )
+        blexit(L"OpenVolume failure");
+
+#define buffer ((CHAR16 *)keyhandler_scratch)
+#define BUFFERSIZE sizeof(keyhandler_scratch)
+    for ( dp = loaded_image->FilePath, *buffer = 0;
+          DevicePathType(dp) != END_DEVICE_PATH_TYPE;
+          dp = (void *)dp + DevicePathNodeLength(dp) )
+    {
+        FILEPATH_DEVICE_PATH *fp;
+
+        if ( DevicePathType(dp) != MEDIA_DEVICE_PATH ||
+             DevicePathSubType(dp) != MEDIA_FILEPATH_DP )
+            blexit(L"Unsupported device path component");
+
+        if ( *buffer )
+        {
+            EFI_FILE_HANDLE new_handle;
+
+            ret = dir_handle->Open(dir_handle, &new_handle, buffer,
+                                   EFI_FILE_MODE_READ, 0);
+            if ( ret != EFI_SUCCESS )
+            {
+                PrintErr(L"Open failed for ");
+                PrintErrMesg(buffer, ret);
+            }
+            dir_handle->Close(dir_handle);
+            dir_handle = new_handle;
+        }
+        fp = (void *)dp;
+        if ( BUFFERSIZE < DevicePathNodeLength(dp) -
+                          sizeof(*dp) + sizeof(*buffer) )
+            blexit(L"Increase BUFFERSIZE");
+        memcpy(buffer, fp->PathName, DevicePathNodeLength(dp) - sizeof(*dp));
+        buffer[(DevicePathNodeLength(dp) - sizeof(*dp)) / sizeof(*buffer)] = 0;
+    }
+    for ( ptr = buffer, pathend = NULL; *ptr; ++ptr )
+        if ( *ptr == L'\\' )
+            pathend = ptr;
+    if ( pathend )
+    {
+        *pathend = 0;
+        *leaf = pathend + 1;
+        if ( *buffer )
+        {
+            EFI_FILE_HANDLE new_handle;
+
+            ret = dir_handle->Open(dir_handle, &new_handle, buffer,
+                                   EFI_FILE_MODE_READ, 0);
+            if ( ret != EFI_SUCCESS ) {
+                PrintErr(L"Open failed for ");
+                PrintErrMesg(buffer, ret);
+            }
+            dir_handle->Close(dir_handle);
+            dir_handle = new_handle;
+        }
+    }
+    else
+        *leaf = buffer;
+#undef BUFFERSIZE
+#undef buffer
+
+    return dir_handle;
+}
+
+static CHAR16 *__init point_tail(CHAR16 *fn)
+{
+    CHAR16 *tail = NULL;
+
+    for ( ; ; ++fn )
+        switch ( *fn )
+        {
+        case 0:
+            return tail;
+        case L'.':
+        case L'-':
+        case L'_':
+            tail = fn;
+            break;
+        }
+}
+
+static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name,
+                               struct file *file)
+{
+    EFI_FILE_HANDLE FileHandle = NULL;
+    UINT64 size;
+    EFI_STATUS ret;
+    CHAR16 *what = NULL;
+
+    if ( !name )
+        PrintErrMesg(L"No filename", EFI_OUT_OF_RESOURCES);
+    ret = dir_handle->Open(dir_handle, &FileHandle, name,
+                           EFI_FILE_MODE_READ, 0);
+    if ( file == &cfg && ret == EFI_NOT_FOUND )
+        return 0;
+    if ( EFI_ERROR(ret) )
+        what = L"Open";
+    else
+        ret = FileHandle->SetPosition(FileHandle, -1);
+    if ( EFI_ERROR(ret) )
+        what = what ?: L"Seek";
+    else
+        ret = FileHandle->GetPosition(FileHandle, &size);
+    if ( EFI_ERROR(ret) )
+        what = what ?: L"Get size";
+    else
+        ret = FileHandle->SetPosition(FileHandle, 0);
+    if ( EFI_ERROR(ret) )
+        what = what ?: L"Seek";
+    else
+    {
+        file->addr = (EFI_PHYSICAL_ADDRESS)1 << (32 + PAGE_SHIFT);
+        ret = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData,
+                                    PFN_UP(size), &file->addr);
+    }
+    if ( EFI_ERROR(ret) )
+    {
+        file->addr = 0;
+        what = what ?: L"Allocation";
+    }
+    else
+    {
+        if ( file != &cfg )
+        {
+            PrintStr(name);
+            PrintStr(L": ");
+            DisplayUint(file->addr, 2 * sizeof(file->addr));
+            PrintStr(L"-");
+            DisplayUint(file->addr + size, 2 * sizeof(file->addr));
+            PrintStr(newline);
+            mb_modules[mbi.mods_count].mod_start = file->addr >> PAGE_SHIFT;
+            mb_modules[mbi.mods_count].mod_end = size;
+            ++mbi.mods_count;
+        }
+
+        file->size = size;
+        ret = FileHandle->Read(FileHandle, &file->size, file->ptr);
+        if ( !EFI_ERROR(ret) && file->size != size )
+            ret = EFI_ABORTED;
+        if ( EFI_ERROR(ret) )
+            what = L"Read";
+    }
+
+    if ( FileHandle )
+        FileHandle->Close(FileHandle);
+
+    if ( what )
+    {
+        PrintErr(what);
+        PrintErr(L" failed for ");
+        PrintErrMesg(name, ret);
+    }
+
+    return 1;
+}
+
+static void __init pre_parse(const struct file *cfg)
+{
+    char *ptr = cfg->ptr, *end = ptr + cfg->size;
+    bool_t start = 1, comment = 0;
+
+    for ( ; ptr < end; ++ptr )
+    {
+        if ( iscntrl(*ptr) )
+        {
+            comment = 0;
+            start = 1;
+            *ptr = 0;
+        }
+        else if ( comment || (start && isspace(*ptr)) )
+            *ptr = 0;
+        else if ( *ptr == '#' || (start && *ptr == ';') )
+        {
+            comment = 1;
+            *ptr = 0;
+        }
+        else
+            start = 0;
+    }
+    if ( cfg->size && end[-1] )
+         PrintStr(L"No newline at end of config file,"
+                   " last line will be ignored.\r\n");
+}
+
+static char *__init get_value(const struct file *cfg, const char *section,
+                              const char *item)
+{
+    char *ptr = cfg->ptr, *end = ptr + cfg->size;
+    size_t slen = section ? strlen(section) : 0, ilen = strlen(item);
+    bool_t match = !slen;
+
+    for ( ; ptr < end; ++ptr )
+    {
+        switch ( *ptr )
+        {
+        case 0:
+            continue;
+        case '[':
+            if ( !slen )
+                break;
+            if ( match )
+                return NULL;
+            match = strncmp(++ptr, section, slen) == 0 && ptr[slen] == ']';
+            break;
+        default:
+            if ( match && strncmp(ptr, item, ilen) == 0 && ptr[ilen] == '=' )
+                return ptr + ilen + 1;
+            break;
+        }
+        ptr += strlen(ptr);
+    }
+    return NULL;
+}
+
+static void __init split_value(char *s)
+{
+    while ( *s && isspace(*s) )
+        ++s;
+    place_string(&mb_modules[mbi.mods_count].string, s);
+    while ( *s && !isspace(*s) )
+        ++s;
+    *s = 0;
+}
+
+static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz)
+{
+   if ( bpp < 0 )
+       return bpp;
+   if ( !mask )
+       return -EINVAL;
+   for ( *pos = 0; !(mask & 1); ++*pos )
+       mask >>= 1;
+   for ( *sz = 0; mask & 1; ++sz)
+       mask >>= 1;
+   if ( mask )
+       return -EINVAL;
+   return max(*pos + *sz, bpp);
+}
+
+#define PE_BASE_RELOC_ABS      0
+#define PE_BASE_RELOC_HIGHLOW  3
+#define PE_BASE_RELOC_DIR64   10
+
+extern const struct pe_base_relocs {
+    u32 rva;
+    u32 size;
+    u16 entries[];
+} __base_relocs_start[], __base_relocs_end[];
+
+static void __init relocate_image(unsigned long delta)
+{
+    const struct pe_base_relocs *base_relocs;
+
+    for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; )
+    {
+        unsigned int i, n;
+
+        n = (base_relocs->size - sizeof(*base_relocs)) /
+            sizeof(*base_relocs->entries);
+        for ( i = 0; i < n; ++i )
+        {
+            unsigned long addr = xen_phys_start + base_relocs->rva +
+                                 (base_relocs->entries[i] & 0xfff);
+
+            switch ( base_relocs->entries[i] >> 12 )
+            {
+            case PE_BASE_RELOC_ABS:
+                break;
+            case PE_BASE_RELOC_HIGHLOW:
+                if ( delta )
+                    *(u32 *)addr += delta;
+                break;
+            case PE_BASE_RELOC_DIR64:
+                if ( delta )
+                    *(u64 *)addr += delta;
+                break;
+            default:
+                blexit(L"Unsupported relocation type\r\n");
+            }
+        }
+        base_relocs = (const void *)(base_relocs->entries + i + (i & 1));
+    }
+}
+
+void EFIAPI __init __attribute__((__noreturn__))
+efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+    static EFI_GUID __initdata loaded_image_guid = LOADED_IMAGE_PROTOCOL;
+    static EFI_GUID __initdata gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+    EFI_LOADED_IMAGE *loaded_image;
+    EFI_STATUS status;
+    unsigned int i, argc;
+    CHAR16 **argv, *file_name, *cfg_file_name = NULL;
+    UINTN cols, rows, depth, size, map_key, info_size, gop_mode = ~0;
+    EFI_HANDLE *handles = NULL;
+    EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL;
+    EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info;
+    EFI_FILE_HANDLE dir_handle;
+    union string section = { NULL }, name;
+    struct e820entry *e;
+    u64 efer;
+    bool_t base_video = 0, trampoline_okay = 0;
+
+    efi_ih = ImageHandle;
+    efi_bs = SystemTable->BootServices;
+    efi_rs = SystemTable->RuntimeServices;
+    efi_ct = SystemTable->ConfigurationTable;
+    efi_num_ct = SystemTable->NumberOfTableEntries;
+    efi_version = SystemTable->Hdr.Revision;
+    efi_fw_vendor = SystemTable->FirmwareVendor;
+    efi_fw_revision = SystemTable->FirmwareRevision;
+
+    StdOut = SystemTable->ConOut;
+    StdErr = SystemTable->StdErr ?: StdOut;
+
+    status = efi_bs->HandleProtocol(ImageHandle, &loaded_image_guid,
+                                    (void **)&loaded_image);
+    if ( status != EFI_SUCCESS )
+        PrintErrMesg(L"No Loaded Image Protocol", status);
+
+    xen_phys_start = (UINTN)loaded_image->ImageBase;
+    if ( (xen_phys_start + loaded_image->ImageSize - 1) >> 32 )
+        blexit(L"Xen must be loaded below 4Gb.\r\n");
+    if ( xen_phys_start & ((1 << L2_PAGETABLE_SHIFT) - 1) )
+        blexit(L"Xen must be loaded at a 2Mb boundary.\r\n");
+    trampoline_xen_phys_start = xen_phys_start;
+
+    /* Get the file system interface. */
+    dir_handle = get_parent_handle(loaded_image, &file_name);
+
+    argc = get_argv(0, NULL, loaded_image->LoadOptions,
+                    loaded_image->LoadOptionsSize);
+    if ( argc > 0 &&
+         efi_bs->AllocatePool(EfiLoaderData,
+                              (argc + 1) * sizeof(*argv) +
+                                  loaded_image->LoadOptionsSize,
+                              (void **)&argv) == EFI_SUCCESS )
+        get_argv(argc, argv, loaded_image->LoadOptions,
+                 loaded_image->LoadOptionsSize);
+    else
+        argc = 0;
+    for ( i = 1; i < argc; ++i )
+    {
+        CHAR16 *ptr = argv[i];
+
+        if ( !ptr )
+            break;
+        if ( *ptr == L'/' || *ptr == L'-' )
+        {
+            if ( wstrcmp(ptr + 1, L"basevideo") == 0 )
+                base_video = 1;
+            else if ( wstrncmp(ptr + 1, L"cfg=", 4) == 0 )
+                cfg_file_name = ptr + 5;
+            else if ( i + 1 < argc && wstrcmp(ptr + 1, L"cfg") == 0 )
+                cfg_file_name = argv[++i];
+            else if ( wstrcmp(ptr + 1, L"help") == 0 ||
+                      (ptr[1] == L'?' && !ptr[2]) )
+            {
+                PrintStr(L"Xen EFI Loader options:\r\n");
+                PrintStr(L"-basevideo   retain current video mode\r\n");
+                PrintStr(L"-cfg=<file>  specify configuration file\r\n");
+                PrintStr(L"-help, -?    display this help\r\n");
+                blexit(NULL);
+            }
+            else
+            {
+                PrintStr(L"WARNING: Unknown command line option '");
+                PrintStr(ptr);
+                PrintStr(L"' ignored\r\n");
+            }
+        }
+        else
+            section.w = ptr;
+    }
+
+    if ( !base_video )
+    {
+        unsigned int best;
+
+        for ( i = 0, size = 0, best = StdOut->Mode->Mode;
+              i < StdOut->Mode->MaxMode; ++i )
+        {
+            if ( StdOut->QueryMode(StdOut, i, &cols, &rows) == EFI_SUCCESS &&
+                 cols * rows > size )
+            {
+                size = cols * rows;
+                best = i;
+            }
+        }
+        if ( best != StdOut->Mode->Mode )
+            StdOut->SetMode(StdOut, best);
+    }
+
+    PrintStr(L"Xen " __stringify(XEN_VERSION) "." __stringify(XEN_SUBVERSION)
+             XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n");
+
+    relocate_image(0);
+
+    if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode,
+                           &cols, &rows) == EFI_SUCCESS )
+    {
+        vga_console_info.video_type = XEN_VGATYPE_TEXT_MODE_3;
+        vga_console_info.u.text_mode_3.columns = cols;
+        vga_console_info.u.text_mode_3.rows = rows;
+        vga_console_info.u.text_mode_3.font_height = 16;
+    }
+
+    size = 0;
+    status = efi_bs->LocateHandle(ByProtocol, &gop_guid, NULL, &size, NULL);
+    if ( status == EFI_BUFFER_TOO_SMALL )
+        status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles);
+    if ( !EFI_ERROR(status) )
+        status = efi_bs->LocateHandle(ByProtocol, &gop_guid, NULL, &size,
+                                      handles);
+    if ( EFI_ERROR(status) )
+        size = 0;
+    for ( i = 0; i < size / sizeof(*handles); ++i )
+    {
+        status = efi_bs->HandleProtocol(handles[i], &gop_guid, (void **)&gop);
+        if ( EFI_ERROR(status) )
+            continue;
+        status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &mode_info);
+        if ( !EFI_ERROR(status) )
+            break;
+    }
+    if ( handles )
+        efi_bs->FreePool(handles);
+    if ( EFI_ERROR(status) )
+        gop = NULL;
+
+    /* Read and parse the config file. */
+    if ( !cfg_file_name )
+    {
+        CHAR16 *tail;
+
+        while ( (tail = point_tail(file_name)) != NULL )
+        {
+            wstrcpy(tail, L".cfg");
+            if ( read_file(dir_handle, file_name, &cfg) )
+                break;
+            *tail = 0;
+        }
+        if ( !tail )
+            blexit(L"No configuration file found\r\n");
+        PrintStr(L"Using configuration file '");
+        PrintStr(file_name);
+        PrintStr(L"'\r\n");
+    }
+    else if ( !read_file(dir_handle, cfg_file_name, &cfg) )
+        blexit(L"Configuration file not found\r\n");
+    pre_parse(&cfg);
+
+    if ( section.w )
+        w2s(&section);
+    else
+        section.s = get_value(&cfg, "global", "default");
+
+    name.s = get_value(&cfg, section.s, "kernel");
+    if ( !name.s )
+        blexit(L"No Dom0 kernel image specified\r\n");
+    split_value(name.s);
+    read_file(dir_handle, s2w(&name), &kernel);
+    efi_bs->FreePool(name.w);
+
+    name.s = get_value(&cfg, section.s, "ramdisk");
+    if ( name.s )
+    {
+        split_value(name.s);
+        read_file(dir_handle, s2w(&name), &ramdisk);
+        efi_bs->FreePool(name.w);
+    }
+
+    name.s = get_value(&cfg, section.s, "xsm");
+    if ( name.s )
+    {
+        split_value(name.s);
+        read_file(dir_handle, s2w(&name), &xsm);
+        efi_bs->FreePool(name.w);
+    }
+
+    name.s = get_value(&cfg, section.s, "options");
+    if ( name.s )
+        place_string(&mbi.cmdline, name.s);
+    /* Insert image name last, as it gets prefixed to the other options. */
+    if ( argc )
+    {
+        name.w = *argv;
+        w2s(&name);
+    }
+    else
+        name.s = "xen";
+    place_string(&mbi.cmdline, name.s);
+
+    cols = rows = depth = 0;
+    if ( !base_video )
+    {
+        name.cs = get_value(&cfg, section.s, "video");
+        if ( !name.cs )
+            name.cs = get_value(&cfg, "global", "video");
+        if ( name.cs && !strncmp(name.cs, "gfx-", 4) )
+        {
+            cols = simple_strtoul(name.cs + 4, &name.cs, 10);
+            if ( *name.cs == 'x' )
+                rows = simple_strtoul(name.cs + 1, &name.cs, 10);
+            if ( *name.cs == 'x' )
+                depth = simple_strtoul(name.cs + 1, &name.cs, 10);
+            if ( *name.cs )
+                cols = rows = depth = 0;
+        }
+    }
+
+    efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
+    cfg.addr = 0;
+
+    dir_handle->Close(dir_handle);
+
+    if ( gop && !base_video )
+    {
+        for ( i = size = 0; i < gop->Mode->MaxMode; ++i )
+        {
+            unsigned int bpp = 0;
+
+            status = gop->QueryMode(gop, i, &info_size, &mode_info);
+            if ( EFI_ERROR(status) )
+                continue;
+            switch ( mode_info->PixelFormat )
+            {
+            case PixelBitMask:
+                bpp = hweight32(mode_info->PixelInformation.RedMask |
+                                mode_info->PixelInformation.GreenMask |
+                                mode_info->PixelInformation.BlueMask);
+                break;
+            case PixelRedGreenBlueReserved8BitPerColor:
+            case PixelBlueGreenRedReserved8BitPerColor:
+                bpp = 24;
+                break;
+            default:
+                continue;
+            }
+            if ( cols == mode_info->HorizontalResolution &&
+                 rows == mode_info->VerticalResolution &&
+                 (!depth || bpp == depth) )
+            {
+                gop_mode = i;
+                break;
+            }
+            if ( !cols && !rows &&
+                 mode_info->HorizontalResolution *
+                 mode_info->VerticalResolution > size )
+            {
+                size = mode_info->HorizontalResolution *
+                       mode_info->VerticalResolution;
+                gop_mode = i;
+            }
+        }
+    }
+
+    if ( mbi.cmdline )
+        mbi.flags |= MBI_CMDLINE;
+    /*
+     * These must not be initialized statically, since the value must
+     * not get relocated when processing base relocations below.
+     */
+    mbi.boot_loader_name = (long)"EFI";
+    mbi.mods_addr = (long)mb_modules;
+
+    place_string(&mbi.mem_upper, NULL);
+
+    /* XXX Collect EDD info. */
+    /* XXX Collect EDID info. */
+
+    if ( cpuid_eax(0x80000000) > 0x80000000 )
+    {
+        cpuid_ext_features = cpuid_edx(0x80000001);
+        boot_cpu_data.x86_capability[1] = cpuid_ext_features;
+    }
+
+    /* Obtain basic table pointers. */
+    for ( i = 0; i < efi_num_ct; ++i )
+    {
+        static EFI_GUID __initdata acpi2_guid = ACPI_20_TABLE_GUID;
+        static EFI_GUID __initdata acpi_guid = ACPI_TABLE_GUID;
+        static EFI_GUID __initdata smbios_guid = SMBIOS_TABLE_GUID;
+
+        if ( match_guid(&acpi2_guid, &efi_ct[i].VendorGuid) )
+	       efi.acpi20 = (long)efi_ct[i].VendorTable;
+        if ( match_guid(&acpi_guid, &efi_ct[i].VendorGuid) )
+	       efi.acpi = (long)efi_ct[i].VendorTable;
+        if ( match_guid(&smbios_guid, &efi_ct[i].VendorGuid) )
+	       efi.smbios = (long)efi_ct[i].VendorTable;
+    }
+
+    if (efi.smbios != EFI_INVALID_TABLE_ADDR)
+        dmi_efi_get_table((void *)(long)efi.smbios);
+
+    /* Allocate space for trampoline (in first Mb). */
+    cfg.addr = BOOT_TRAMPOLINE;
+    cfg.size = trampoline_end - trampoline_start;
+    status = efi_bs->AllocatePages(AllocateAddress, EfiLoaderData,
+                                   PFN_UP(cfg.size), &cfg.addr);
+    if ( EFI_ERROR(status) )
+    {
+        cfg.addr = 0;
+        PrintErr(L"Note: Trampoline area is in use\r\n");
+    }
+
+    /* Initialise L2 identity-map and xen page table entries (16MB). */
+    for ( i = 0; i < 8; ++i )
+    {
+        unsigned int slot = (xen_phys_start >> L2_PAGETABLE_SHIFT) + i;
+        paddr_t addr = slot << L2_PAGETABLE_SHIFT;
+
+        l2_identmap[i] = l2e_from_paddr(i << L2_PAGETABLE_SHIFT,
+                                        PAGE_HYPERVISOR|_PAGE_PSE);
+        l2_identmap[slot] = l2e_from_paddr(addr, PAGE_HYPERVISOR|_PAGE_PSE);
+        l2_xenmap[i] = l2e_from_paddr(addr, PAGE_HYPERVISOR|_PAGE_PSE);
+        slot &= L2_PAGETABLE_ENTRIES - 1;
+        l2_bootmap[slot] = l2e_from_paddr(addr, __PAGE_HYPERVISOR|_PAGE_PSE);
+    }
+    /* Initialise L3 identity-map page directory entries. */
+    for ( i = 0; i < ARRAY_SIZE(l2_identmap) / L2_PAGETABLE_ENTRIES; ++i )
+        l3_identmap[i] = l3e_from_paddr((UINTN)(l2_identmap +
+                                                i * L2_PAGETABLE_ENTRIES),
+                                        __PAGE_HYPERVISOR);
+    /* Initialise L3 xen-map page directory entry. */
+    l3_xenmap[l3_table_offset(XEN_VIRT_START)] =
+        l3e_from_paddr((UINTN)l2_xenmap, __PAGE_HYPERVISOR);
+    /* Initialise L3 boot-map page directory entries. */
+    l3_bootmap[l3_table_offset(xen_phys_start)] =
+        l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR);
+    l3_bootmap[l3_table_offset(xen_phys_start + (8 << L2_PAGETABLE_SHIFT) - 1)] =
+        l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR);
+    /* Hook identity-map, xen-map, and boot-map L3 tables into PML4. */
+    idle_pg_table[0] = l4e_from_paddr((UINTN)l3_bootmap, __PAGE_HYPERVISOR);
+    idle_pg_table[l4_table_offset(DIRECTMAP_VIRT_START)] =
+        l4e_from_paddr((UINTN)l3_identmap, __PAGE_HYPERVISOR);
+    idle_pg_table[l4_table_offset(XEN_VIRT_START)] =
+        l4e_from_paddr((UINTN)l3_xenmap, __PAGE_HYPERVISOR);
+    /* Initialize 4kB mappings of first 2MB of memory. */
+    for ( i = 0; i < L1_PAGETABLE_ENTRIES; ++i )
+    {
+        unsigned int attr = PAGE_HYPERVISOR|MAP_SMALL_PAGES;
+
+        /* VGA hole (0xa0000-0xc0000) should be mapped UC. */
+        if ( i >= 0xa0 && i < 0xc0 )
+            attr |= _PAGE_PCD;
+        l1_identmap[i] = l1e_from_pfn(i, attr);
+    }
+    l2_identmap[0] = l2e_from_paddr((UINTN)l1_identmap, __PAGE_HYPERVISOR);
+
+    if ( gop )
+    {
+        int bpp = 0;
+
+        /* Set graphics mode. */
+        if ( gop_mode < gop->Mode->MaxMode && gop_mode != gop->Mode->Mode )
+            gop->SetMode(gop, gop_mode);
+
+        /* Get graphics and frame buffer info. */
+        status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &mode_info);
+        if ( !EFI_ERROR(status) )
+            switch ( mode_info->PixelFormat )
+            {
+            case PixelRedGreenBlueReserved8BitPerColor:
+                vga_console_info.u.vesa_lfb.red_pos = 0;
+                vga_console_info.u.vesa_lfb.red_size = 8;
+                vga_console_info.u.vesa_lfb.green_pos = 8;
+                vga_console_info.u.vesa_lfb.green_size = 8;
+                vga_console_info.u.vesa_lfb.blue_pos = 16;
+                vga_console_info.u.vesa_lfb.blue_size = 8;
+                vga_console_info.u.vesa_lfb.rsvd_pos = 24;
+                vga_console_info.u.vesa_lfb.rsvd_size = 8;
+                bpp = 32;
+                break;
+            case PixelBlueGreenRedReserved8BitPerColor:
+                vga_console_info.u.vesa_lfb.red_pos = 16;
+                vga_console_info.u.vesa_lfb.red_size = 8;
+                vga_console_info.u.vesa_lfb.green_pos = 8;
+                vga_console_info.u.vesa_lfb.green_size = 8;
+                vga_console_info.u.vesa_lfb.blue_pos = 0;
+                vga_console_info.u.vesa_lfb.blue_size = 8;
+                vga_console_info.u.vesa_lfb.rsvd_pos = 24;
+                vga_console_info.u.vesa_lfb.rsvd_size = 8;
+                bpp = 32;
+                break;
+            case PixelBitMask:
+                bpp = set_color(mode_info->PixelInformation.RedMask, bpp,
+                                &vga_console_info.u.vesa_lfb.red_pos,
+                                &vga_console_info.u.vesa_lfb.red_size);
+                bpp = set_color(mode_info->PixelInformation.GreenMask, bpp,
+                                &vga_console_info.u.vesa_lfb.green_pos,
+                                &vga_console_info.u.vesa_lfb.green_size);
+                bpp = set_color(mode_info->PixelInformation.BlueMask, bpp,
+                                &vga_console_info.u.vesa_lfb.blue_pos,
+                                &vga_console_info.u.vesa_lfb.blue_size);
+                bpp = set_color(mode_info->PixelInformation.ReservedMask, bpp,
+                                &vga_console_info.u.vesa_lfb.rsvd_pos,
+                                &vga_console_info.u.vesa_lfb.rsvd_size);
+                if ( bpp > 0 )
+                    break;
+                /* fall through */
+            default:
+                PrintErr(L"Current graphics mode is unsupported!");
+                status = EFI_UNSUPPORTED;
+                break;
+            }
+        if ( !EFI_ERROR(status) )
+        {
+            vga_console_info.video_type = XEN_VGATYPE_EFI_LFB;
+            vga_console_info.u.vesa_lfb.gbl_caps = 2; /* possibly non-VGA */
+            vga_console_info.u.vesa_lfb.width =
+                mode_info->HorizontalResolution;
+            vga_console_info.u.vesa_lfb.height = mode_info->VerticalResolution;
+            vga_console_info.u.vesa_lfb.bits_per_pixel = bpp;
+            vga_console_info.u.vesa_lfb.bytes_per_line =
+                (mode_info->PixelsPerScanLine * bpp + 7) >> 3;
+            vga_console_info.u.vesa_lfb.lfb_base = gop->Mode->FrameBufferBase;
+            vga_console_info.u.vesa_lfb.lfb_size =
+                (gop->Mode->FrameBufferSize + 0xffff) >> 16;
+        }
+    }
+
+    status = efi_bs->GetMemoryMap(&efi_memmap_size, NULL, &map_key,
+                                  &efi_mdesc_size, &mdesc_ver);
+    mbi.mem_upper -= efi_memmap_size;
+    mbi.mem_upper &= -__alignof__(EFI_MEMORY_DESCRIPTOR);
+    if ( mbi.mem_upper < xen_phys_start )
+        blexit(L"Out of static memory\r\n");
+    efi_memmap = (void *)(long)mbi.mem_upper;
+    status = efi_bs->GetMemoryMap(&efi_memmap_size, efi_memmap, &map_key,
+                                  &efi_mdesc_size, &mdesc_ver);
+    if ( EFI_ERROR(status) )
+        blexit(L"Cannot obtain memory map\r\n");
+
+    /* Populate E820 table and check trampoline area availability. */
+    e = e820map - 1;
+    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+    {
+        EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+        u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+        u32 type;
+
+        switch ( desc->Type )
+        {
+        default:
+            type = E820_RESERVED;
+            break;
+        case EfiConventionalMemory:
+        case EfiLoaderCode:
+        case EfiLoaderData:
+        case EfiBootServicesCode:
+        case EfiBootServicesData:
+            if ( desc->Attribute & EFI_MEMORY_WB )
+                type = E820_RAM;
+            else
+        case EfiUnusableMemory:
+                type = E820_UNUSABLE;
+            break;
+        case EfiACPIReclaimMemory:
+            type = E820_ACPI;
+            break;
+        case EfiACPIMemoryNVS:
+            type = E820_NVS;
+            break;
+        }
+        if ( e820nr && type == e->type &&
+             desc->PhysicalStart == e->addr + e->size )
+            e->size += len;
+        else if ( !len || e820nr >= E820MAX )
+            continue;
+        else
+        {
+            ++e;
+            e->addr = desc->PhysicalStart;
+            e->size = len;
+            e->type = type;
+            ++e820nr;
+        }
+        if ( type == E820_RAM && e->addr <= BOOT_TRAMPOLINE &&
+             e->addr + e->size >= BOOT_TRAMPOLINE + cfg.size )
+            trampoline_okay = 1;
+    }
+
+    if ( !trampoline_okay )
+        blexit(L"Trampoline area unavailable\r\n");
+
+    status = efi_bs->ExitBootServices(ImageHandle, map_key);
+    if ( EFI_ERROR(status) )
+        PrintErrMesg(L"Cannot exit boot services", status);
+
+    /* Adjust pointers into EFI. */
+    efi_ct = (void *)efi_ct + DIRECTMAP_VIRT_START;
+#if 0 /* Only needed when using virtual mode (see efi_init_memory()). */
+    efi_rs = (void *)efi_rs + DIRECTMAP_VIRT_START;
+#endif
+    efi_memmap = (void *)efi_memmap + DIRECTMAP_VIRT_START;
+    efi_fw_vendor = (void *)efi_fw_vendor + DIRECTMAP_VIRT_START;
+
+    relocate_image(__XEN_VIRT_START - xen_phys_start);
+    memcpy((void *)(long)BOOT_TRAMPOLINE, trampoline_start, cfg.size);
+
+    /* Set system registers and transfer control. */
+    asm volatile("pushq $0\n\tpopfq");
+    rdmsrl(MSR_EFER, efer);
+    efer |= EFER_SCE;
+    if ( cpuid_ext_features & (1 << (X86_FEATURE_NX & 0x1f)) )
+        efer |= EFER_NX;
+    wrmsrl(MSR_EFER, efer);
+    write_cr0(X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP |
+              X86_CR0_AM | X86_CR0_PG);
+    asm volatile ( "mov    %[cr4], %%cr4\n\t"
+                   "mov    %[cr3], %%cr3\n\t"
+                   "movabs $__start_xen, %[rip]\n\t"
+                   "lidt   idt_descr(%%rip)\n\t"
+                   "lgdt   gdt_descr(%%rip)\n\t"
+                   "mov    stack_start(%%rip), %%rsp\n\t"
+                   "mov    %[ds], %%ss\n\t"
+                   "mov    %[ds], %%ds\n\t"
+                   "mov    %[ds], %%es\n\t"
+                   "mov    %[ds], %%fs\n\t"
+                   "mov    %[ds], %%gs\n\t"
+                   "movl   %[cs], 8(%%rsp)\n\t"
+                   "mov    %[rip], (%%rsp)\n\t"
+                   "lretq  %[stkoff]-16"
+                   : [rip] "=&r" (efer/* any dead 64-bit variable */)
+                   : [cr3] "r" (idle_pg_table),
+                     [cr4] "r" (mmu_cr4_features),
+                     [cs] "ir" (__HYPERVISOR_CS),
+                     [ds] "r" (__HYPERVISOR_DS),
+                     [stkoff] "i" (STACK_SIZE - sizeof(struct cpu_info)),
+                     "D" (&mbi)
+                   : "memory" );
+    for( ; ; ); /* not reached */
+}
+
+void __init efi_init_memory(void)
+{
+    unsigned int i;
+
+    printk(XENLOG_INFO "EFI memory map:\n");
+    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+    {
+        EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+        u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+        unsigned long smfn, emfn;
+        unsigned int prot = PAGE_HYPERVISOR;
+
+        printk(XENLOG_INFO " %013" PRIx64 "-%013" PRIx64
+                           " type=%u attr=%016" PRIx64 "\n",
+               desc->PhysicalStart, desc->PhysicalStart + len - 1,
+               desc->Type, desc->Attribute);
+
+        if ( !(desc->Attribute & EFI_MEMORY_RUNTIME) )
+            continue;
+
+        smfn = PFN_DOWN(desc->PhysicalStart);
+        emfn = PFN_UP(desc->PhysicalStart + len);
+
+        desc->VirtualStart = 0xBAAADUL << (EFI_PAGE_SHIFT + BITS_PER_LONG - 32);
+
+        if ( desc->Attribute & EFI_MEMORY_WB )
+            /* nothing */;
+        else if ( desc->Attribute & EFI_MEMORY_WT )
+            prot |= _PAGE_PWT | MAP_SMALL_PAGES;
+        else if ( desc->Attribute & EFI_MEMORY_WC )
+            prot |= _PAGE_PAT | MAP_SMALL_PAGES;
+        else if ( desc->Attribute & (EFI_MEMORY_UC | EFI_MEMORY_UCE) )
+            prot |= _PAGE_PWT | _PAGE_PCD | MAP_SMALL_PAGES;
+        else
+        {
+            printk(XENLOG_ERR "Unknown cachability for MFNs %#lx-%#lx\n",
+                   smfn, emfn - 1);
+            continue;
+        }
+
+        if ( desc->Attribute & EFI_MEMORY_WP )
+            prot &= _PAGE_RW;
+        if ( desc->Attribute & EFI_MEMORY_XP )
+            prot |= _PAGE_NX_BIT;
+
+        if ( pfn_to_pdx(emfn - 1) < (DIRECTMAP_SIZE >> PAGE_SHIFT) &&
+             !(smfn & pfn_hole_mask) &&
+             !((smfn ^ (emfn - 1)) & ~pfn_pdx_bottom_mask) )
+        {
+            if ( map_pages_to_xen((unsigned long)mfn_to_virt(smfn),
+                                  smfn, emfn - smfn, prot) == 0 )
+                desc->VirtualStart =
+                    (unsigned long)maddr_to_virt(desc->PhysicalStart);
+            else
+                printk(XENLOG_ERR "Could not map MFNs %#lx-%#lx\n",
+                       smfn, emfn - 1);
+        }
+        else
+        {
+            /* XXX allocate e.g. down from FIXADDR_START */
+            printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n",
+                   smfn, emfn - 1);
+        }
+    }
+
+#if 0 /* Incompatible with kexec. */
+    efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size,
+                                 mdesc_ver, efi_memmap);
+#endif
+}
Index: xen-4.1.4-testing/xen/arch/x86/efi/check.c
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/check.c
@@ -0,0 +1,4 @@
+int __attribute__((__ms_abi__)) test(int i)
+{
+    return i;
+}
Index: xen-4.1.4-testing/xen/arch/x86/efi/compat.c
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/compat.c
@@ -0,0 +1,16 @@
+#include <xen/guest_access.h>
+#include <compat/platform.h>
+
+#define efi_get_info efi_compat_get_info
+#define xenpf_efi_info compat_pf_efi_info
+
+#define COMPAT
+#undef DEFINE_XEN_GUEST_HANDLE
+#define DEFINE_XEN_GUEST_HANDLE DEFINE_COMPAT_HANDLE
+#undef guest_handle_okay
+#define guest_handle_okay compat_handle_okay
+#undef guest_handle_cast
+#define guest_handle_cast compat_handle_cast
+#undef __copy_to_guest_offset
+#define __copy_to_guest_offset __copy_to_compat_offset
+#include "runtime.c"
Index: xen-4.1.4-testing/xen/arch/x86/efi/efi.h
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/efi.h
@@ -0,0 +1,18 @@
+#include <asm/efibind.h>
+#include <efi/efidef.h>
+#include <efi/efierr.h>
+#include <efi/eficon.h>
+#include <efi/efidevp.h>
+#include <efi/efiapi.h>
+#include <xen/efi.h>
+
+extern unsigned int efi_num_ct;
+extern EFI_CONFIGURATION_TABLE *efi_ct;
+
+extern unsigned int efi_version, efi_fw_revision;
+extern const CHAR16 *efi_fw_vendor;
+
+extern EFI_RUNTIME_SERVICES *efi_rs;
+
+extern UINTN efi_memmap_size, efi_mdesc_size;
+extern void *efi_memmap;
Index: xen-4.1.4-testing/xen/arch/x86/efi/mkreloc.c
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/mkreloc.c
@@ -0,0 +1,377 @@
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+struct mz_hdr {
+    uint16_t signature;
+#define MZ_SIGNATURE 0x5a4d
+    uint16_t last_page_size;
+    uint16_t page_count;
+    uint16_t relocation_count;
+    uint16_t header_paras;
+    uint16_t min_paras;
+    uint16_t max_paras;
+    uint16_t entry_ss;
+    uint16_t entry_sp;
+    uint16_t checksum;
+    uint16_t entry_ip;
+    uint16_t entry_cs;
+    uint16_t relocations;
+    uint16_t overlay;
+    uint8_t reserved[32];
+    uint32_t extended_header_base;
+};
+
+struct pe_hdr {
+    uint32_t signature;
+#define PE_SIGNATURE 0x00004550
+    uint16_t cpu;
+    uint16_t section_count;
+    int32_t timestamp;
+    uint32_t symbols_file_offset;
+    uint32_t symbol_count;
+    uint16_t opt_hdr_size;
+    uint16_t flags;
+    struct {
+        uint16_t magic;
+#define PE_MAGIC_EXE32     0x010b
+#define PE_MAGIC_EXE32PLUS 0x020b
+        uint8_t linker_major, linker_minor;
+        uint32_t code_size, data_size, bss_size;
+        uint32_t entry_rva, code_rva, data_rva;
+    } opt_hdr;
+};
+
+#define PE_PAGE_SIZE 0x1000
+
+#define PE_BASE_RELOC_ABS      0
+#define PE_BASE_RELOC_HIGHLOW  3
+#define PE_BASE_RELOC_DIR64   10
+
+struct coff_section {
+    char name[8];
+    uint32_t size;
+    uint32_t rva;
+    uint32_t file_size;
+    uint32_t file_offset;
+    uint32_t relocation_file_offset;
+    uint32_t line_number_file_offset;
+    uint16_t relocation_count;
+    uint16_t line_number_count;
+    uint32_t flags;
+#define COFF_SECTION_BSS         0x00000080
+#define COFF_SECTION_DISCARDABLE 0x02000000
+};
+
+static void usage(const char *cmd, int rc)
+{
+    fprintf(rc ? stderr : stdout,
+            "Usage: %s <image1> <image2>\n",
+            cmd);
+    exit(rc);
+}
+
+static unsigned int load(const char *name, int *handle,
+                         struct coff_section **sections,
+                         uint_fast64_t *image_base,
+                         uint32_t *image_size,
+                         unsigned int *width)
+{
+    int in = open(name, O_RDONLY);
+    struct mz_hdr mz_hdr;
+    struct pe_hdr pe_hdr;
+    uint32_t base;
+
+    if ( in < 0 ||
+         read(in, &mz_hdr, sizeof(mz_hdr)) != sizeof(mz_hdr) )
+    {
+        perror(name);
+        exit(2);
+    }
+    if ( mz_hdr.signature != MZ_SIGNATURE ||
+         mz_hdr.relocations < sizeof(mz_hdr) ||
+         !mz_hdr.extended_header_base )
+    {
+        fprintf(stderr, "%s: Wrong DOS file format\n", name);
+        exit(2);
+    }
+
+    if ( lseek(in, mz_hdr.extended_header_base, SEEK_SET) < 0 ||
+         read(in, &pe_hdr, sizeof(pe_hdr)) != sizeof(pe_hdr) ||
+         read(in, &base, sizeof(base)) != sizeof(base) ||
+         /*
+          * Luckily the image size field lives at the
+          * same offset for both formats.
+          */
+         lseek(in, 24, SEEK_CUR) < 0 ||
+         read(in, image_size, sizeof(*image_size)) != sizeof(*image_size) )
+    {
+        perror(name);
+        exit(3);
+    }
+    switch ( (pe_hdr.signature == PE_SIGNATURE &&
+              pe_hdr.opt_hdr_size > sizeof(pe_hdr.opt_hdr)) *
+             pe_hdr.opt_hdr.magic )
+    {
+    case PE_MAGIC_EXE32:
+        *width = 32;
+        *image_base = base;
+        break;
+    case PE_MAGIC_EXE32PLUS:
+        *width = 64;
+        *image_base = ((uint64_t)base << 32) | pe_hdr.opt_hdr.data_rva;
+        break;
+    default:
+        fprintf(stderr, "%s: Wrong PE file format\n", name);
+        exit(3);
+    }
+
+    *sections = malloc(pe_hdr.section_count * sizeof(**sections));
+    if ( !*sections )
+    {
+        perror(NULL);
+        exit(4);
+    }
+    if ( lseek(in,
+               mz_hdr.extended_header_base + offsetof(struct pe_hdr, opt_hdr) +
+                  pe_hdr.opt_hdr_size,
+               SEEK_SET) < 0 ||
+         read(in, *sections, pe_hdr.section_count * sizeof(**sections)) !=
+             pe_hdr.section_count * sizeof(**sections) )
+    {
+        perror(name);
+        exit(4);
+    }
+
+    *handle = in;
+
+    return pe_hdr.section_count;
+}
+
+static long page_size;
+
+static const void *map_section(const struct coff_section *sec, int in,
+                               const char *name)
+{
+    const char *ptr;
+    unsigned long offs;
+
+    if ( !page_size )
+        page_size = sysconf(_SC_PAGESIZE);
+    offs = sec->file_offset & (page_size - 1);
+
+    ptr = mmap(0, offs + sec->file_size, PROT_READ, MAP_PRIVATE, in,
+               sec->file_offset - offs);
+    if ( ptr == MAP_FAILED )
+    {
+        perror(name);
+        exit(6);
+    }
+
+    return ptr + offs;
+}
+
+static void unmap_section(const void *ptr, const struct coff_section *sec)
+{
+    unsigned long offs = sec->file_offset & (page_size - 1);
+
+    munmap((char *)ptr - offs, offs + sec->file_size);
+}
+
+static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
+                          const struct coff_section *sec,
+                          int_fast64_t diff, unsigned int width,
+                          uint_fast64_t base, uint_fast64_t end)
+{
+    static uint_fast32_t cur_rva, reloc_size;
+    unsigned int disp = 0;
+    uint_fast32_t i;
+
+    if ( !sec )
+    {
+        reloc_size += reloc_size & 2;
+        if ( reloc_size )
+            printf("\t.balign 4\n"
+                   "\t.equ rva_%08" PRIxFAST32 "_relocs, %#08" PRIxFAST32 "\n",
+                   cur_rva, reloc_size);
+        return;
+    }
+
+    while ( !(diff & (((int_fast64_t)1 << ((disp + 1) * CHAR_BIT)) - 1)) )
+        ++disp;
+
+    for ( i = 0; i < sec->file_size; ++i )
+    {
+        uint_fast32_t rva;
+        union {
+            uint32_t u32;
+            uint64_t u64;
+        } val1, val2;
+        int_fast64_t delta;
+        unsigned int reloc = (width == 4 ? PE_BASE_RELOC_HIGHLOW :
+                                           PE_BASE_RELOC_DIR64);
+
+        if ( ptr1[i] == ptr2[i] )
+            continue;
+
+        if ( i < disp || i + width - disp > sec->file_size )
+        {
+            fprintf(stderr,
+                    "Bogus difference at %s:%08" PRIxFAST32 "\n",
+                    sec->name, i);
+            exit(3);
+        }
+
+        memcpy(&val1, ptr1 + i - disp, width);
+        memcpy(&val2, ptr2 + i - disp, width);
+        delta = width == 4 ? val2.u32 - val1.u32 : val2.u64 - val1.u64;
+        if ( delta != diff )
+        {
+            fprintf(stderr,
+                    "Difference at %s:%08" PRIxFAST32 " is %#" PRIxFAST64
+                    " (expected %#" PRIxFAST64 ")\n",
+                    sec->name, i, delta, diff);
+            continue;
+        }
+        if ( width == 8 && (val1.u64 < base || val1.u64 > end) )
+            reloc = PE_BASE_RELOC_HIGHLOW;
+
+        rva = (sec->rva + i - disp) & ~(PE_PAGE_SIZE - 1);
+        if ( rva > cur_rva )
+        {
+            reloc_size += reloc_size & 2;
+            if ( reloc_size )
+                printf("\t.equ rva_%08" PRIxFAST32 "_relocs,"
+                             " %#08" PRIxFAST32 "\n",
+                       cur_rva, reloc_size);
+            printf("\t.balign 4\n"
+                   "\t.long %#08" PRIxFAST32 ","
+                          " rva_%08" PRIxFAST32 "_relocs\n",
+                   rva, rva);
+            cur_rva = rva;
+            reloc_size = 8;
+        }
+        else if ( rva != cur_rva )
+        {
+            fprintf(stderr,
+                    "Cannot handle decreasing RVA (at %s:%08" PRIxFAST32 ")\n",
+                    sec->name, i);
+            exit(3);
+        }
+
+        printf("\t.word (%u << 12) | 0x%03" PRIxFAST32 "\n",
+               reloc, sec->rva + i - disp - rva);
+        reloc_size += 2;
+        i += width - disp - 1;
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int in1, in2;
+    unsigned int i, nsec, width1, width2;
+    uint_fast64_t base1, base2;
+    uint32_t size1, size2;
+    struct coff_section *sec1, *sec2;
+
+    if ( argc == 1 ||
+         !strcmp(argv[1], "-?") ||
+         !strcmp(argv[1], "-h") ||
+         !strcmp(argv[1], "--help") )
+        usage(*argv, argc == 1);
+
+    if ( argc != 3 )
+        usage(*argv, 1);
+
+    nsec = load(argv[1], &in1, &sec1, &base1, &size1, &width1);
+    if ( nsec != load(argv[2], &in2, &sec2, &base2, &size2, &width2) )
+    {
+        fputs("Mismatched section counts\n", stderr);
+        return 5;
+    }
+    if ( width1 != width2 )
+    {
+        fputs("Mismatched image types\n", stderr);
+        return 5;
+    }
+    width1 >>= 3;
+    if ( base1 == base2 )
+    {
+        fputs("Images must have different base addresses\n", stderr);
+        return 5;
+    }
+    if ( size1 != size2 )
+    {
+        fputs("Images must have identical sizes\n", stderr);
+        return 5;
+    }
+
+    puts("\t.section .reloc, \"a\", @progbits\n"
+         "\t.balign 4\n"
+         "\t.globl __base_relocs_start, __base_relocs_end\n"
+         "__base_relocs_start:");
+
+    for ( i = 0; i < nsec; ++i )
+    {
+        const void *ptr1, *ptr2;
+
+        if ( memcmp(sec1[i].name, sec2[i].name, sizeof(sec1[i].name)) ||
+             sec1[i].rva != sec2[i].rva ||
+             sec1[i].size != sec2[i].size ||
+             sec1[i].file_size != sec2[i].file_size ||
+             sec1[i].flags != sec2[i].flags )
+        {
+            fprintf(stderr, "Mismatched section %u parameters\n", i);
+            return 5;
+        }
+
+        if ( !sec1[i].size ||
+             (sec1[i].flags & (COFF_SECTION_DISCARDABLE|COFF_SECTION_BSS)) )
+            continue;
+
+        /*
+         * Don't generate relocations for sections that definitely
+         * aren't used by the boot loader code.
+         */
+        if ( memcmp(sec1[i].name, ".initcal", sizeof(sec1[i].name)) == 0 ||
+             memcmp(sec1[i].name, ".init.se", sizeof(sec1[i].name)) == 0 ||
+             memcmp(sec1[i].name, ".lockpro", sizeof(sec1[i].name)) == 0 )
+            continue;
+
+        if ( !sec1[i].rva )
+        {
+            fprintf(stderr, "Can't handle section %u with zero RVA\n", i);
+            return 3;
+        }
+
+        if ( sec1[i].file_size > sec1[i].size )
+        {
+            sec1[i].file_size = sec1[i].size;
+            sec2[i].file_size = sec2[i].size;
+        }
+        ptr1 = map_section(sec1 + i, in1, argv[1]);
+        ptr2 = map_section(sec2 + i, in2, argv[2]);
+
+        diff_sections(ptr1, ptr2, sec1 + i, base2 - base1, width1,
+                      base1, base1 + size1);
+
+        unmap_section(ptr1, sec1 + i);
+        unmap_section(ptr2, sec2 + i);
+    }
+
+    diff_sections(NULL, NULL, NULL, 0, 0, 0, 0);
+
+    puts("__base_relocs_end:");
+
+    close(in1);
+    close(in2);
+
+    return 0;
+}
Index: xen-4.1.4-testing/xen/arch/x86/efi/relocs-dummy.S
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/relocs-dummy.S
@@ -0,0 +1,13 @@
+#include <xen/config.h>
+
+	.section .reloc, "a", @progbits
+	.balign 4
+	.globl __base_relocs_start, __base_relocs_end
+__base_relocs_start:
+	.long 0
+	.long 8
+__base_relocs_end:
+
+	.globl VIRT_START, ALT_START
+	.equ VIRT_START, XEN_VIRT_START
+	.equ ALT_START, XEN_VIRT_END
Index: xen-4.1.4-testing/xen/arch/x86/efi/runtime.c
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/runtime.c
@@ -0,0 +1,88 @@
+#include "efi.h"
+#include <xen/cache.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+
+DEFINE_XEN_GUEST_HANDLE(CHAR16);
+
+#ifndef COMPAT
+
+# include <public/platform.h>
+
+const bool_t efi_enabled = 1;
+
+unsigned int __read_mostly efi_num_ct;
+EFI_CONFIGURATION_TABLE *__read_mostly efi_ct;
+
+unsigned int __read_mostly efi_version;
+unsigned int __read_mostly efi_fw_revision;
+const CHAR16 *__read_mostly efi_fw_vendor;
+
+EFI_RUNTIME_SERVICES *__read_mostly efi_rs;
+
+UINTN __read_mostly efi_memmap_size;
+UINTN __read_mostly efi_mdesc_size;
+void *__read_mostly efi_memmap;
+
+struct efi __read_mostly efi = {
+	.acpi   = EFI_INVALID_TABLE_ADDR,
+	.acpi20 = EFI_INVALID_TABLE_ADDR,
+	.smbios = EFI_INVALID_TABLE_ADDR,
+};
+
+#endif
+
+int efi_get_info(uint32_t idx, union xenpf_efi_info *info)
+{
+    unsigned int i, n;
+
+    switch ( idx )
+    {
+    case XEN_FW_EFI_VERSION:
+        info->version = efi_version;
+        break;
+    case XEN_FW_EFI_CONFIG_TABLE:
+        info->cfg.addr = __pa(efi_ct);
+        info->cfg.nent = efi_num_ct;
+        break;
+    case XEN_FW_EFI_VENDOR:
+        info->vendor.revision = efi_fw_revision;
+        n = info->vendor.bufsz / sizeof(*efi_fw_vendor);
+        if ( !guest_handle_okay(guest_handle_cast(info->vendor.name,
+                                                  CHAR16), n) )
+            return -EFAULT;
+        for ( i = 0; i < n; ++i )
+        {
+            if ( __copy_to_guest_offset(info->vendor.name, i,
+                                        efi_fw_vendor + i, 1) )
+                return -EFAULT;
+            if ( !efi_fw_vendor[i] )
+                break;
+        }
+        break;
+    case XEN_FW_EFI_MEM_INFO:
+        for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+        {
+            EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+            u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+
+            if ( info->mem.addr >= desc->PhysicalStart &&
+                 info->mem.addr < desc->PhysicalStart + len )
+            {
+                info->mem.type = desc->Type;
+                info->mem.attr = desc->Attribute;
+                if ( info->mem.addr + info->mem.size < info->mem.addr ||
+                     info->mem.addr + info->mem.size >
+                     desc->PhysicalStart + len )
+                    info->mem.size = desc->PhysicalStart + len -
+                                     info->mem.addr;
+                return 0;
+            }
+        }
+        return -ESRCH;
+    default:
+        return -EINVAL;
+    }
+
+    return 0;
+}
Index: xen-4.1.4-testing/xen/arch/x86/efi/stub.c
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/arch/x86/efi/stub.c
@@ -0,0 +1,17 @@
+#include <xen/efi.h>
+#include <xen/errno.h>
+#include <xen/init.h>
+
+#ifndef efi_enabled
+const bool_t efi_enabled = 0;
+#endif
+
+void __init efi_init_memory(void) { }
+
+int efi_get_info(uint32_t idx, union xenpf_efi_info *info)
+{
+    return -ENOSYS;
+}
+
+int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *)
+    __attribute__((__alias__("efi_get_info")));
Index: xen-4.1.4-testing/xen/arch/x86/mm.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/mm.c
+++ xen-4.1.4-testing/xen/arch/x86/mm.c
@@ -101,6 +101,7 @@
 #include <xen/guest_access.h>
 #include <xen/xmalloc.h>
 #include <xen/pfn.h>
+#include <xen/efi.h>
 #include <asm/paging.h>
 #include <asm/shadow.h>
 #include <asm/page.h>
@@ -356,6 +357,8 @@ void __init arch_init_memory(void)
 
     subarch_init_memory();
 
+    efi_init_memory();
+
     mem_sharing_init();
 }
 
Index: xen-4.1.4-testing/xen/arch/x86/platform_hypercall.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/platform_hypercall.c
+++ xen-4.1.4-testing/xen/arch/x86/platform_hypercall.c
@@ -19,6 +19,7 @@
 #include <xen/iocap.h>
 #include <xen/guest_access.h>
 #include <xen/acpi.h>
+#include <xen/efi.h>
 #include <xen/cpu.h>
 #include <asm/current.h>
 #include <public/platform.h>
@@ -294,6 +295,14 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
                                 bootsym(boot_edid_info), 128) )
                 ret = -EFAULT;
             break;
+        case XEN_FW_EFI_INFO:
+            ret = efi_get_info(op->u.firmware_info.index,
+                               &op->u.firmware_info.u.efi_info);
+            if ( ret == 0 &&
+                 copy_field_to_guest(u_xenpf_op, op,
+                                     u.firmware_info.u.efi_info) )
+                ret = -EFAULT;
+            break;
         default:
             ret = -EINVAL;
             break;
Index: xen-4.1.4-testing/xen/arch/x86/setup.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/setup.c
+++ xen-4.1.4-testing/xen/arch/x86/setup.c
@@ -8,6 +8,7 @@
 #include <xen/serial.h>
 #include <xen/softirq.h>
 #include <xen/acpi.h>
+#include <xen/efi.h>
 #include <xen/console.h>
 #include <xen/serial.h>
 #include <xen/trace.h>
@@ -447,6 +448,10 @@ static void __init parse_video_info(void
 {
     struct boot_video_info *bvi = &bootsym(boot_vid_info);
 
+    /* The EFI loader fills vga_console_info directly. */
+    if ( efi_enabled )
+        return;
+
     if ( (bvi->orig_video_isVGA == 1) && (bvi->orig_video_mode == 3) )
     {
         vga_console_info.video_type = XEN_VGATYPE_TEXT_MODE_3;
@@ -618,6 +623,7 @@ void __init __start_xen(unsigned long mb
                vga_console_info.u.text_mode_3.font_height);
         break;
     case XEN_VGATYPE_VESA_LFB:
+    case XEN_VGATYPE_EFI_LFB:
         printk(" VGA is graphics mode %dx%d, %d bpp\n",
                vga_console_info.u.vesa_lfb.width,
                vga_console_info.u.vesa_lfb.height,
@@ -663,7 +669,24 @@ void __init __start_xen(unsigned long mb
     if ( ((unsigned long)cpu0_stack & (STACK_SIZE-1)) != 0 )
         EARLY_FAIL("Misaligned CPU0 stack.\n");
 
-    if ( e820_raw_nr != 0 )
+    if ( efi_enabled )
+    {
+        set_pdx_range(xen_phys_start >> PAGE_SHIFT,
+                      (xen_phys_start + BOOTSTRAP_MAP_BASE) >> PAGE_SHIFT);
+
+        /* Clean up boot loader identity mappings. */
+        destroy_xen_mappings(xen_phys_start,
+                             xen_phys_start + BOOTSTRAP_MAP_BASE);
+
+#ifdef CONFIG_X86_64
+        /* Make boot page tables match non-EFI boot. */
+        l3_bootmap[l3_table_offset(BOOTSTRAP_MAP_BASE)] =
+            l3e_from_paddr(__pa(l2_bootmap), __PAGE_HYPERVISOR);
+#endif
+
+        memmap_type = loader;
+    }
+    else if ( e820_raw_nr != 0 )
     {
         memmap_type = "Xen-e820";
     }
@@ -761,7 +784,7 @@ void __init __start_xen(unsigned long mb
      * we can relocate the dom0 kernel and other multiboot modules. Also, on
      * x86/64, we relocate Xen to higher memory.
      */
-    for ( i = 0; i < mbi->mods_count; i++ )
+    for ( i = 0; !efi_enabled && i < mbi->mods_count; i++ )
     {
         if ( mod[i].mod_start & (PAGE_SIZE - 1) )
             EARLY_FAIL("Bootloader didn't honor module alignment request.\n");
@@ -810,7 +833,6 @@ void __init __start_xen(unsigned long mb
             end = 0;
         if ( end > s )
         {
-            extern l2_pgentry_t l2_xenmap[];
             l4_pgentry_t *pl4e;
             l3_pgentry_t *pl3e;
             l2_pgentry_t *pl2e;
@@ -950,7 +972,8 @@ void __init __start_xen(unsigned long mb
 #else
     if ( !xen_phys_start )
         EARLY_FAIL("Not enough memory to relocate Xen.\n");
-    reserve_e820_ram(&boot_e820, __pa(&_start), __pa(&_end));
+    reserve_e820_ram(&boot_e820, efi_enabled ? mbi->mem_upper : __pa(&_start),
+                     __pa(&_end));
 #endif
 
     /* Late kexec reservation (dynamic start address). */
Index: xen-4.1.4-testing/xen/arch/x86/x86_32/mm.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/x86_32/mm.c
+++ xen-4.1.4-testing/xen/arch/x86/x86_32/mm.c
@@ -34,8 +34,6 @@
 l2_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
     idle_pg_table_l2[4 * L2_PAGETABLE_ENTRIES];
 
-extern l1_pgentry_t l1_identmap[L1_PAGETABLE_ENTRIES];
-
 unsigned int __read_mostly PAGE_HYPERVISOR         = __PAGE_HYPERVISOR;
 unsigned int __read_mostly PAGE_HYPERVISOR_NOCACHE = __PAGE_HYPERVISOR_NOCACHE;
 
Index: xen-4.1.4-testing/xen/arch/x86/x86_64/mm.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/x86_64/mm.c
+++ xen-4.1.4-testing/xen/arch/x86/x86_64/mm.c
@@ -21,6 +21,7 @@
 #include <xen/lib.h>
 #include <xen/init.h>
 #include <xen/mm.h>
+#include <xen/pfn.h>
 #include <xen/sched.h>
 #include <xen/numa.h>
 #include <xen/nodemask.h>
@@ -830,7 +831,8 @@ void __init zap_low_mappings(void)
 
     /* Replace with mapping of the boot trampoline only. */
     map_pages_to_xen(BOOT_TRAMPOLINE, BOOT_TRAMPOLINE >> PAGE_SHIFT,
-                     0x10, __PAGE_HYPERVISOR);
+                     PFN_UP(trampoline_end - trampoline_start),
+                     __PAGE_HYPERVISOR);
 }
 
 void *compat_arg_xlat_virt_base(void)
Index: xen-4.1.4-testing/xen/arch/x86/x86_64/platform_hypercall.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/x86_64/platform_hypercall.c
+++ xen-4.1.4-testing/xen/arch/x86/x86_64/platform_hypercall.c
@@ -11,6 +11,8 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_
 #define xen_platform_op_t   compat_platform_op_t
 #define do_platform_op(x)   compat_platform_op(_##x)
 
+#define efi_get_info        efi_compat_get_info
+
 #define xen_processor_px    compat_processor_px
 #define xen_processor_px_t  compat_processor_px_t
 #define xen_processor_performance    compat_processor_performance
Index: xen-4.1.4-testing/xen/arch/x86/xen.lds.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/xen.lds.S
+++ xen-4.1.4-testing/xen/arch/x86/xen.lds.S
@@ -8,15 +8,34 @@
 #undef ENTRY
 #undef ALIGN
 
+#ifdef EFI
+
+#define FORMAT "pei-x86-64"
+#undef __XEN_VIRT_START
+#define __XEN_VIRT_START __image_base__
+
+ENTRY(efi_start)
+
+#else /* !EFI */
+
+#ifdef __x86_64__
+#define FORMAT "elf64-x86-64"
+#else
+#define FORMAT "elf32-i386"
+#endif
+
+ENTRY(start)
+
+#endif /* EFI */
+
+OUTPUT_FORMAT(FORMAT, FORMAT, FORMAT)
+
 #ifdef __x86_64__
-OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
 OUTPUT_ARCH(i386:x86-64)
 #else
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
 #endif
 
-ENTRY(start)
 PHDRS
 {
   text PT_LOAD ;
@@ -122,12 +141,30 @@ SECTIONS
   } :text
   _end = . ;
 
+#ifdef EFI
+  . = ALIGN(4);
+  .reloc : {
+    *(.reloc)
+  } :text
+  /* Trick the linker into setting the image size to exactly 16Mb. */
+  . = ALIGN(__section_alignment__);
+  .pad : {
+    . = ALIGN(0x1000000);
+  } :text
+#else
+  efi = .;
+#endif
+
   /* Sections to be discarded */
   /DISCARD/ : {
        *(.exit.text)
        *(.exit.data)
        *(.exitcall.exit)
        *(.eh_frame)
+#ifdef EFI
+       *(.comment)
+       *(.comment.*)
+#endif
   }
 
   /* Stabs debugging sections.  */
Index: xen-4.1.4-testing/xen/drivers/acpi/osl.c
===================================================================
--- xen-4.1.4-testing.orig/xen/drivers/acpi/osl.c
+++ xen-4.1.4-testing/xen/drivers/acpi/osl.c
@@ -37,9 +37,7 @@
 #include <acpi/platform/aclinux.h>
 #include <xen/spinlock.h>
 #include <xen/domain_page.h>
-#ifdef __ia64__
-#include <linux/efi.h>
-#endif
+#include <xen/efi.h>
 
 #define _COMPONENT		ACPI_OS_SERVICES
 ACPI_MODULE_NAME("osl")
@@ -82,7 +80,6 @@ void acpi_os_vprintf(const char *fmt, va
 
 acpi_physical_address __init acpi_os_get_root_pointer(void)
 {
-#ifdef __ia64__
 	if (efi_enabled) {
 		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
 			return efi.acpi20;
@@ -93,9 +90,7 @@ acpi_physical_address __init acpi_os_get
 			       "System description tables not found\n");
 			return 0;
 		}
-	} else
-#endif
-	{
+	} else {
 		acpi_physical_address pa = 0;
 
 		acpi_find_root_pointer(&pa);
Index: xen-4.1.4-testing/xen/drivers/video/vga.c
===================================================================
--- xen-4.1.4-testing.orig/xen/drivers/video/vga.c
+++ xen-4.1.4-testing/xen/drivers/video/vga.c
@@ -89,6 +89,7 @@ void __init vga_init(void)
         vga_puts = vga_text_puts;
         break;
     case XEN_VGATYPE_VESA_LFB:
+    case XEN_VGATYPE_EFI_LFB:
         vesa_early_init();
         break;
     default:
@@ -115,6 +116,7 @@ void __init vga_endboot(void)
             memset(video, 0, columns * lines * 2);
         break;
     case XEN_VGATYPE_VESA_LFB:
+    case XEN_VGATYPE_EFI_LFB:
         vesa_endboot(vgacon_keep);
         break;
     default:
Index: xen-4.1.4-testing/xen/include/asm-x86/page.h
===================================================================
--- xen-4.1.4-testing.orig/xen/include/asm-x86/page.h
+++ xen-4.1.4-testing/xen/include/asm-x86/page.h
@@ -301,8 +301,14 @@ extern l2_pgentry_t   idle_pg_table_l2[
 #elif CONFIG_PAGING_LEVELS == 4
 extern l2_pgentry_t  *compat_idle_pg_table_l2;
 extern unsigned int   m2p_compat_vstart;
+extern l2_pgentry_t l2_xenmap[L2_PAGETABLE_ENTRIES],
+    l2_bootmap[L2_PAGETABLE_ENTRIES];
+extern l3_pgentry_t l3_xenmap[L3_PAGETABLE_ENTRIES],
+    l3_identmap[L3_PAGETABLE_ENTRIES],
+    l3_bootmap[L3_PAGETABLE_ENTRIES];
 #endif
 extern l2_pgentry_t l2_identmap[4*L2_PAGETABLE_ENTRIES];
+extern l1_pgentry_t l1_identmap[L1_PAGETABLE_ENTRIES];
 void paging_init(void);
 void setup_idle_pagetable(void);
 #endif /* !defined(__ASSEMBLY__) */
Index: xen-4.1.4-testing/xen/include/public/platform.h
===================================================================
--- xen-4.1.4-testing.orig/xen/include/public/platform.h
+++ xen-4.1.4-testing/xen/include/public/platform.h
@@ -118,6 +118,11 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_platform_q
 #define XEN_FW_DISK_INFO          1 /* from int 13 AH=08/41/48 */
 #define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */
 #define XEN_FW_VBEDDC_INFO        3 /* from int 10 AX=4f15 */
+#define XEN_FW_EFI_INFO           4 /* from EFI */
+#define  XEN_FW_EFI_VERSION        0
+#define  XEN_FW_EFI_CONFIG_TABLE   1
+#define  XEN_FW_EFI_VENDOR         2
+#define  XEN_FW_EFI_MEM_INFO       3
 struct xenpf_firmware_info {
     /* IN variables. */
     uint32_t type;
@@ -148,6 +153,24 @@ struct xenpf_firmware_info {
             /* must refer to 128-byte buffer */
             XEN_GUEST_HANDLE(uint8) edid;
         } vbeddc_info; /* XEN_FW_VBEDDC_INFO */
+        union xenpf_efi_info {
+            uint32_t version;
+            struct {
+                uint64_t addr;                /* EFI_CONFIGURATION_TABLE */
+                uint32_t nent;
+            } cfg;
+            struct {
+                uint32_t revision;
+                uint32_t bufsz;               /* input, in bytes */
+                XEN_GUEST_HANDLE(void) name;  /* UCS-2/UTF-16 string */
+            } vendor;
+            struct {
+                uint64_t addr;
+                uint64_t size;
+                uint64_t attr;
+                uint32_t type;
+            } mem;
+        } efi_info; /* XEN_FW_EFI_INFO */
     } u;
 };
 typedef struct xenpf_firmware_info xenpf_firmware_info_t;
Index: xen-4.1.4-testing/xen/include/public/xen.h
===================================================================
--- xen-4.1.4-testing.orig/xen/include/public/xen.h
+++ xen-4.1.4-testing/xen/include/public/xen.h
@@ -638,6 +638,7 @@ typedef struct dom0_vga_console_info {
     uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */
 #define XEN_VGATYPE_TEXT_MODE_3 0x03
 #define XEN_VGATYPE_VESA_LFB    0x23
+#define XEN_VGATYPE_EFI_LFB     0x70
 
     union {
         struct {
Index: xen-4.1.4-testing/xen/include/xen/compat.h
===================================================================
--- xen-4.1.4-testing.orig/xen/include/xen/compat.h
+++ xen-4.1.4-testing/xen/include/xen/compat.h
@@ -34,7 +34,7 @@
 /* Cast a compat handle to the specified type of handle. */
 #define compat_handle_cast(chnd, type) ({                            \
     type *_x = (__typeof__(**(chnd)._) *)(full_ptr_t)(chnd).c;       \
-    (XEN_GUEST_HANDLE(type)) { _x };                                 \
+    (COMPAT_HANDLE(type)) { (full_ptr_t)_x };                        \
 })
 
 #define guest_from_compat_handle(ghnd, chnd)                         \
Index: xen-4.1.4-testing/xen/include/xen/dmi.h
===================================================================
--- xen-4.1.4-testing.orig/xen/include/xen/dmi.h
+++ xen-4.1.4-testing/xen/include/xen/dmi.h
@@ -36,5 +36,6 @@ extern int dmi_check_system(struct dmi_s
 extern char * dmi_get_system_info(int field);
 extern void dmi_scan_machine(void);
 extern int dmi_get_table(u32 *base, u32 *len);
+extern void dmi_efi_get_table(void *);
 
 #endif	/* __DMI_H__ */
Index: xen-4.1.4-testing/xen/include/xen/efi.h
===================================================================
--- /dev/null
+++ xen-4.1.4-testing/xen/include/xen/efi.h
@@ -0,0 +1,38 @@
+#ifndef __XEN_EFI_H__
+#define __XEN_EFI_H__
+
+#include <xen/types.h>
+
+#if defined(__ia64__)
+# #include <linux/efi.h>
+#else
+
+# if defined(__i386__)
+#  define efi_enabled 0
+# else
+extern const bool_t efi_enabled;
+# endif
+
+#define EFI_INVALID_TABLE_ADDR (~0UL)
+
+/* Add fields here only if they need to be referenced from non-EFI code. */
+struct efi {
+    unsigned long acpi;         /* ACPI table (IA64 ext 0.71) */
+    unsigned long acpi20;       /* ACPI table (ACPI 2.0) */
+    unsigned long smbios;       /* SM BIOS table */
+};
+
+extern struct efi efi;
+
+#endif
+
+union xenpf_efi_info;
+union compat_pf_efi_info;
+
+void efi_init_memory(void);
+#ifndef COMPAT
+int efi_get_info(uint32_t idx, union xenpf_efi_info *);
+#endif
+int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *);
+
+#endif /* __XEN_EFI_H__ */
