82e844b703
x86-EFI-discard-comment.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=131
2504 lines
78 KiB
Diff
2504 lines
78 KiB
Diff
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>
|
|
|
|
--- a/xen/Makefile
|
|
+++ b/xen/Makefile
|
|
@@ -11,6 +11,8 @@ export XEN_DOMAIN ?= $(shell ([ -x /bin/
|
|
|
|
export BASEDIR := $(CURDIR)
|
|
|
|
+EFI_MOUNTPOINT ?= /boot/efi
|
|
+
|
|
.PHONY: default
|
|
default: build
|
|
|
|
@@ -32,6 +34,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:
|
|
--- a/xen/arch/x86/Makefile
|
|
+++ b/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
|
|
--- 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
|
|
|
|
--- 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
|
|
--- 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
|
|
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 (*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];
|
|
|
|
/*
|
|
@@ -468,8 +530,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");
|
|
--- /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.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
|
|
--- /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(§ion);
|
|
+ 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
|
|
+}
|
|
--- /dev/null
|
|
+++ b/xen/arch/x86/efi/check.c
|
|
@@ -0,0 +1,4 @@
|
|
+int __attribute__((__ms_abi__)) test(int i)
|
|
+{
|
|
+ return i;
|
|
+}
|
|
--- /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"
|
|
--- /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;
|
|
--- /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;
|
|
+}
|
|
--- /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
|
|
--- /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;
|
|
+}
|
|
--- /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")));
|
|
--- a/xen/arch/x86/mm.c
|
|
+++ b/xen/arch/x86/mm.c
|
|
@@ -100,6 +100,7 @@
|
|
#include <xen/iocap.h>
|
|
#include <xen/guest_access.h>
|
|
#include <xen/pfn.h>
|
|
+#include <xen/efi.h>
|
|
#include <asm/paging.h>
|
|
#include <asm/shadow.h>
|
|
#include <asm/page.h>
|
|
@@ -353,6 +354,8 @@ void __init arch_init_memory(void)
|
|
|
|
subarch_init_memory();
|
|
|
|
+ efi_init_memory();
|
|
+
|
|
mem_sharing_init();
|
|
}
|
|
|
|
--- 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 <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;
|
|
--- 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>
|
|
@@ -448,6 +449,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;
|
|
@@ -619,6 +624,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,
|
|
@@ -664,7 +670,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";
|
|
}
|
|
@@ -762,7 +785,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");
|
|
@@ -811,7 +834,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;
|
|
@@ -951,7 +973,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). */
|
|
--- a/xen/arch/x86/x86_32/mm.c
|
|
+++ b/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;
|
|
|
|
--- a/xen/arch/x86/x86_64/mm.c
|
|
+++ b/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>
|
|
@@ -828,7 +829,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)
|
|
--- 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_
|
|
#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
|
|
--- 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. */
|
|
--- a/xen/drivers/acpi/osl.c
|
|
+++ b/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);
|
|
--- a/xen/drivers/video/vga.c
|
|
+++ b/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:
|
|
--- a/xen/include/asm-x86/page.h
|
|
+++ b/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__) */
|
|
--- a/xen/include/public/platform.h
|
|
+++ b/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;
|
|
--- 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 {
|
|
--- 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) \
|
|
--- a/xen/include/xen/dmi.h
|
|
+++ b/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__ */
|
|
--- /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__ */
|