aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/Makefile9
-rw-r--r--xen/Rules.mk2
-rw-r--r--xen/arch/x86/Makefile65
-rw-r--r--xen/arch/x86/boot/trampoline.S1
-rw-r--r--xen/arch/x86/boot/x86_64.S2
-rw-r--r--xen/arch/x86/dmi_scan.c66
-rw-r--r--xen/arch/x86/efi/Makefile17
-rw-r--r--xen/arch/x86/efi/boot.c1221
-rw-r--r--xen/arch/x86/efi/check.c4
-rw-r--r--xen/arch/x86/efi/compat.c16
-rw-r--r--xen/arch/x86/efi/efi.h18
-rw-r--r--xen/arch/x86/efi/mkreloc.c377
-rw-r--r--xen/arch/x86/efi/relocs-dummy.S13
-rw-r--r--xen/arch/x86/efi/runtime.c88
-rw-r--r--xen/arch/x86/efi/stub.c17
-rw-r--r--xen/arch/x86/mm.c3
-rw-r--r--xen/arch/x86/platform_hypercall.c9
-rw-r--r--xen/arch/x86/setup.c30
-rw-r--r--xen/arch/x86/x86_64/mm.c3
-rw-r--r--xen/arch/x86/x86_64/platform_hypercall.c2
-rw-r--r--xen/arch/x86/xen.lds.S42
-rw-r--r--xen/drivers/acpi/osl.c9
-rw-r--r--xen/drivers/video/vga.c2
-rw-r--r--xen/include/asm-x86/page.h6
-rw-r--r--xen/include/public/platform.h23
-rw-r--r--xen/include/public/xen.h1
-rw-r--r--xen/include/xen/compat.h2
-rw-r--r--xen/include/xen/dmi.h1
-rw-r--r--xen/include/xen/efi.h38
29 files changed, 2064 insertions, 23 deletions
diff --git a/xen/Makefile b/xen/Makefile
index 19ada7ef54..ad52e7998e 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -12,6 +12,8 @@ export XEN_DOMAIN ?= $(shell ([ -x /bin/dnsdomainname ] && /bin/dnsdomainname) |
export BASEDIR := $(CURDIR)
export XEN_ROOT := $(BASEDIR)/..
+EFI_MOUNTPOINT ?= /boot/efi
+
.PHONY: default
default: build
@@ -33,6 +35,13 @@ _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 -a -n "$(EFI_MOUNTPOINT)" ]; then \
+ if [ -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 not done (EFI_VENDOR not set)' >&2; \
+ fi; \
+ fi
.PHONY: _debug
_debug:
diff --git a/xen/Rules.mk b/xen/Rules.mk
index fedda9181b..59c7dd7577 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -158,7 +158,7 @@ _clean_%/: FORCE
SPECIAL_DATA_SECTIONS := rodata $(foreach n,1 2 4 8,rodata.str1.$(n)) \
$(foreach r,rel rel.ro,data.$(r) data.$(r).local)
-$(filter %.init.o,$(obj-y) $(obj-bin-y)): %.init.o: %.o Makefile
+$(filter %.init.o,$(obj-y) $(obj-bin-y) $(extra-y)): %.init.o: %.o Makefile
$(OBJDUMP) -h $< | sed -n '/[0-9]/{s,00*,0,g;p}' | while read idx name sz rest; do \
case "$$name" in \
.text|.text.*|.data|.data.*|.bss) \
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 8691cd3248..466ecee5b8 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -62,28 +62,43 @@ 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_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
ifeq ($(lto),y)
# Gather all LTO objects together
prelink_lto.o: $(ALL_OBJS)
$(LD_LTO) -r -o $@ $^
+prelink-efi_lto.o: $(ALL_OBJS) efi/runtime.o efi/compat.o
+ $(guard) $(LD_LTO) -r -o $@ $(filter-out %/efi/built_in.o,$^)
+
# Link it with all the binary objects
prelink.o: $(patsubst %/built_in.o,%/built_in_bin.o,$(ALL_OBJS)) prelink_lto.o
$(LD) $(LDFLAGS) -r -o $@ $^
+
+prelink-efi.o: $(patsubst %/built_in.o,%/built_in_bin.o,$(ALL_OBJS)) prelink-efi_lto.o efi/boot.init.o
+ $(guard) $(LD) $(LDFLAGS) -r -o $@ $^
else
prelink.o: $(ALL_OBJS)
$(LD) $(LDFLAGS) -r -o $@ $^
+
+prelink-efi.o: $(ALL_OBJS) efi/boot.init.o efi/runtime.o efi/compat.o
+ $(guard) $(LD) $(LDFLAGS) -r -o $@ $(filter-out %/efi/built_in.o,$^)
endif
-$(TARGET)-syms: prelink.o xen.lds
- $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/common/symbols-dummy.o
+$(BASEDIR)/common/symbols-dummy.o:
+ $(MAKE) -f $(BASEDIR)/Rules.mk -C $(BASEDIR)/common symbols-dummy.o
+
+$(TARGET)-syms: prelink.o xen.lds $(BASEDIR)/common/symbols-dummy.o
$(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
$(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0
$(NM) -n $(@D)/.$(@F).0 | $(BASEDIR)/tools/symbols >$(@D)/.$(@F).0.S
@@ -96,6 +111,39 @@ $(TARGET)-syms: prelink.o 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: prelink-efi.o 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 $< 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 $< \
+ $(@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 $< \
+ $(@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.init.o efi/runtime.o efi/compat.o: $(BASEDIR)/arch/x86/efi/built_in.o
+efi/boot.init.o efi/runtime.o efi/compat.o: ;
+
asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c
$(CC) $(filter-out -flto,$(CFLAGS)) -S -o $@ $<
@@ -104,11 +152,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
diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S
index ad15f5c4e8..e5b4dbef45 100644
--- a/xen/arch/x86/boot/trampoline.S
+++ b/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
diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S
index edf7891610..3c0958bcf2 100644
--- a/xen/arch/x86/boot/x86_64.S
+++ b/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
diff --git a/xen/arch/x86/dmi_scan.c b/xen/arch/x86/dmi_scan.c
index f73a9a4c52..75b3507ac9 100644
--- a/xen/arch/x86/dmi_scan.c
+++ b/xen/arch/x86/dmi_scan.c
@@ -9,6 +9,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <xen/dmi.h>
+#include <xen/efi.h>
#define bt_ioremap(b,l) ((void *)__acpi_map_table(b,l))
#define bt_iounmap(b,l) ((void)0)
@@ -122,11 +123,39 @@ static inline bool_t __init dmi_checksum(const void __iomem *buf,
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);
@@ -178,6 +207,39 @@ static int __init dmi_iterate(void (*decode)(struct dmi_header *))
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 *__initdata dmi_ident[DMI_STRING_MAX];
/*
@@ -418,8 +480,8 @@ static void __init dmi_decode(struct dmi_header *dm)
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");
diff --git a/xen/arch/x86/efi/Makefile b/xen/arch/x86/efi/Makefile
new file mode 100644
index 0000000000..6e3f94c208
--- /dev/null
+++ b/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) -c -Werror 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.init.o); $(call create,runtime.o)))
+
+extra-$(efi) += boot.init.o relocs-dummy.o runtime.o compat.o
+
+stub.o: $(extra-y)
+
+clean::
+ rm -f disabled *.efi
diff --git a/xen/arch/x86/efi/boot.c b/xen/arch/x86/efi/boot.c
new file mode 100644
index 0000000000..50ea3c8ee3
--- /dev/null
+++ b/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
+}
diff --git a/xen/arch/x86/efi/check.c b/xen/arch/x86/efi/check.c
new file mode 100644
index 0000000000..7fedd5a610
--- /dev/null
+++ b/xen/arch/x86/efi/check.c
@@ -0,0 +1,4 @@
+int __attribute__((__ms_abi__)) test(int i)
+{
+ return i;
+}
diff --git a/xen/arch/x86/efi/compat.c b/xen/arch/x86/efi/compat.c
new file mode 100644
index 0000000000..4277f51f9f
--- /dev/null
+++ b/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"
diff --git a/xen/arch/x86/efi/efi.h b/xen/arch/x86/efi/efi.h
new file mode 100644
index 0000000000..e7673ee910
--- /dev/null
+++ b/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;
diff --git a/xen/arch/x86/efi/mkreloc.c b/xen/arch/x86/efi/mkreloc.c
new file mode 100644
index 0000000000..6e52a2e647
--- /dev/null
+++ b/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;
+}
diff --git a/xen/arch/x86/efi/relocs-dummy.S b/xen/arch/x86/efi/relocs-dummy.S
new file mode 100644
index 0000000000..36c30063d2
--- /dev/null
+++ b/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
diff --git a/xen/arch/x86/efi/runtime.c b/xen/arch/x86/efi/runtime.c
new file mode 100644
index 0000000000..5b98d0c9df
--- /dev/null
+++ b/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;
+}
diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c
new file mode 100644
index 0000000000..12289938d1
--- /dev/null
+++ b/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")));
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 3cc337d8a9..a3ca63f549 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -101,6 +101,7 @@
#include <xen/guest_access.h>
#include <xen/pfn.h>
#include <xen/xmalloc.h>
+#include <xen/efi.h>
#include <xen/grant_table.h>
#include <asm/paging.h>
#include <asm/shadow.h>
@@ -382,6 +383,8 @@ void __init arch_init_memory(void)
subarch_init_memory();
+ efi_init_memory();
+
mem_sharing_init();
}
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index 4475a5c1a5..aede176cbd 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/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 <xen/pmstat.h>
#include <xen/irq.h>
@@ -290,6 +291,14 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
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;
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 7a338d6d01..a7d132a250 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -7,6 +7,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>
@@ -444,6 +445,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;
@@ -615,6 +620,7 @@ void __init __start_xen(unsigned long mbi_p)
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,
@@ -660,7 +666,24 @@ void __init __start_xen(unsigned long mbi_p)
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";
}
@@ -758,7 +781,7 @@ void __init __start_xen(unsigned long mbi_p)
* 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");
@@ -946,7 +969,8 @@ void __init __start_xen(unsigned long mbi_p)
#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). */
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
index 933b68f17b..9ff343b97e 100644
--- a/xen/arch/x86/x86_64/mm.c
+++ b/xen/arch/x86/x86_64/mm.c
@@ -830,7 +830,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)
diff --git a/xen/arch/x86/x86_64/platform_hypercall.c b/xen/arch/x86/x86_64/platform_hypercall.c
index 2c9048c237..f20fb99dc6 100644
--- a/xen/arch/x86/x86_64/platform_hypercall.c
+++ b/xen/arch/x86/x86_64/platform_hypercall.c
@@ -11,6 +11,8 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_op_t);
#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
diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S
index 16e710c3fd..7679202d50 100644
--- a/xen/arch/x86/xen.lds.S
+++ b/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,29 @@ 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)
+#endif
}
/* Stabs debugging sections. */
diff --git a/xen/drivers/acpi/osl.c b/xen/drivers/acpi/osl.c
index acee045512..dd96a1a20e 100644
--- a/xen/drivers/acpi/osl.c
+++ b/xen/drivers/acpi/osl.c
@@ -36,9 +36,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")
@@ -66,7 +64,6 @@ void __init acpi_os_vprintf(const char *fmt, va_list args)
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;
@@ -77,9 +74,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
"System description tables not found\n");
return 0;
}
- } else
-#endif
- {
+ } else {
acpi_physical_address pa = 0;
acpi_find_root_pointer(&pa);
diff --git a/xen/drivers/video/vga.c b/xen/drivers/video/vga.c
index fea3e23cb4..7696946c73 100644
--- a/xen/drivers/video/vga.c
+++ b/xen/drivers/video/vga.c
@@ -87,6 +87,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:
@@ -113,6 +114,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:
diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
index 68af2a77a0..3327705983 100644
--- a/xen/include/asm-x86/page.h
+++ b/xen/include/asm-x86/page.h
@@ -301,10 +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];
-extern l2_pgentry_t l2_xenmap[];
void paging_init(void);
void setup_idle_pagetable(void);
#endif /* !defined(__ASSEMBLY__) */
diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h
index d03ec24e7e..deb2f57bb3 100644
--- a/xen/include/public/platform.h
+++ b/xen/include/public/platform.h
@@ -118,6 +118,11 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t);
#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;
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 93c3fe3837..02b8fe0ec5 100644
--- a/xen/include/public/xen.h
+++ b/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 {
diff --git a/xen/include/xen/compat.h b/xen/include/xen/compat.h
index 0b8c2c9416..de87aac336 100644
--- a/xen/include/xen/compat.h
+++ b/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) \
diff --git a/xen/include/xen/dmi.h b/xen/include/xen/dmi.h
index 65cf2ad4e3..e9c92b32c3 100644
--- a/xen/include/xen/dmi.h
+++ b/xen/include/xen/dmi.h
@@ -35,6 +35,7 @@ struct dmi_system_id {
extern int dmi_check_system(struct dmi_system_id *list);
extern void dmi_scan_machine(void);
extern int dmi_get_table(u32 *base, u32 *len);
+extern void dmi_efi_get_table(void *);
extern void dmi_end_boot(void);
#endif /* __DMI_H__ */
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
new file mode 100644
index 0000000000..d32d4f2bc1
--- /dev/null
+++ b/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__ */