This patch series adds EFI boot support for arm64. A PE/COFF header is created in head.S, as there is no toolchain support for PE/COFF on arm64. This also has the advantage that the file is both an "Image" file and a PE/COFF executable - the same binary can be loaded and run either way. The EFI 'stub' code is a shim layer that serves as the loader for the XEN kernel in the EFI environment. The stub loads the dom0 kernel and initrd if required, and adds entries for them as well as for the EFI data structures into the device tree passed to XEN. Once the device tree is constructed, EFI boot services are exited, and the stub transfers control to the normal XEN entry point. The only indication XEN has that it was loaded via the stub is that the device tree contains EFI properties. This is all very similar to the arm/arm64 Linux kernel EFI stubs.
I'm not really that happy with how the x86 build works, in particular the rule I added to arch/x86/Makefile to build boot.init.o to fix parallel builds. Due to the way the EFI build is done - building 2 executables at the same time with different EFI code included in each, the normal common build infrastructure doesn't work.
Changes since v2: * Major refactor to use common EFI entry point and factor out arch specific code, rather than factoring out the common code. * Update entire libfdt to v1.4.0 to provide fdt_create_empty_tree()
Changes since v1: * Added common/efi directory for shared EFI code, and arch/arm/efi for arm-specfic code. Global build hacking of -fshort-wchar removed. arm32, arm64, and x86 with/without EFI enabled toolchain all build. The x86 build previously autodetected whether the EFI version should be built or not based on toolchain support. I couldn't get this working nicely with the common code, so for x86 I have the common code always build, and the EFI autodection works as normal for building the EFI version. * Basic use of the EFI memory map instead of FDT based memory description. More work needed to resolve differences between FDT description of a small number of large memory banks with reserved regions, and EFI's potentially long list of available regions, which can be long. * More refactoring of common EFI code to not directly exit using blexit(), as this broke the pre-linking targets. All shared code returns status, and it is up to the caller to exit and clean up. * Reduced the number of patches. Refactoring of x86 code first, then moving all code to efi-shared.c in one patch. * Fixed formatting/tab issues in new files, added Emacs footer. * Fixed efi_get_memory_map to return NULL map pointer on error in addition to failed status. * Added comments in head.S regarding PE/COFF specification, and 1:1 mapping used by EFI code. * Updated device tree bindings to use new multiboot bindings. Since the stub is always built into XEN, we don't have to support older bindings.
Roy Franz (15): move EFI boot code to common/efi Move x86 specific funtions/variables to arch header create arch functions to get and process EFI memory map. Add architecture functions for pre/post ExitBootServices Add efi_arch_cfg_file() to handle arch specific cfg file fields Add efi_arch_handle_cmdline() for processing commandline Move x86 specific video and disk probing code Add efi_arch_memory() for arch specific memory setup Add arch specific module handling to read_file() Add SMBIOS and runtime services setup arch functions. Add several misc. arch functions for EFI boot code. Add efi_arch_use_config_file() function to control use of config file add arm64 cache flushing code from linux v3.16 Update libfdt to v1.4.0 Add ARM EFI boot support
.gitignore | 2 + xen/arch/arm/arm64/Makefile | 1 + xen/arch/arm/arm64/cache.S | 100 ++ xen/arch/arm/arm64/head.S | 145 ++- xen/arch/arm/xen.lds.S | 1 + xen/arch/x86/Makefile | 15 +- xen/arch/x86/efi/Makefile | 4 +- xen/arch/x86/efi/boot.c | 1723 ----------------------------------- xen/arch/x86/efi/efi.h | 39 - xen/arch/x86/efi/runtime.c | 2 +- xen/common/Makefile | 1 + xen/common/efi/Makefile | 17 + xen/common/efi/boot.c | 823 +++++++++++++++++ xen/common/efi/check.c | 4 + xen/common/efi/dummy.c | 1 + xen/common/efi/efi.h | 39 + xen/common/libfdt/Makefile.libfdt | 4 +- xen/common/libfdt/fdt.c | 30 +- xen/common/libfdt/fdt_empty_tree.c | 84 ++ xen/common/libfdt/fdt_ro.c | 7 +- xen/common/libfdt/fdt_rw.c | 31 +- xen/common/libfdt/fdt_sw.c | 4 +- xen/common/libfdt/fdt_wip.c | 2 +- xen/common/libfdt/version.lds | 6 + xen/include/asm-arm/arm64/efibind.h | 216 +++++ xen/include/asm-arm/efi-boot.h | 602 ++++++++++++ xen/include/asm-arm/efi.h | 29 + xen/include/asm-arm/efibind.h | 2 + xen/include/asm-arm/setup.h | 2 +- xen/include/asm-x86/efi-boot.h | 1064 +++++++++++++++++++++ xen/include/asm-x86/efi.h | 39 + xen/include/xen/libfdt/fdt.h | 93 +- xen/include/xen/libfdt/libfdt.h | 315 ++++++- xen/include/xen/libfdt/libfdt_env.h | 4 + 34 files changed, 3627 insertions(+), 1824 deletions(-) create mode 100644 xen/arch/arm/arm64/cache.S delete mode 100644 xen/arch/x86/efi/boot.c delete mode 100644 xen/arch/x86/efi/efi.h create mode 100644 xen/common/efi/Makefile create mode 100644 xen/common/efi/boot.c create mode 100644 xen/common/efi/check.c create mode 100644 xen/common/efi/dummy.c create mode 100644 xen/common/efi/efi.h create mode 100644 xen/common/libfdt/fdt_empty_tree.c create mode 100644 xen/include/asm-arm/arm64/efibind.h create mode 100644 xen/include/asm-arm/efi-boot.h create mode 100644 xen/include/asm-arm/efi.h create mode 100644 xen/include/asm-arm/efibind.h create mode 100644 xen/include/asm-x86/efi-boot.h create mode 100644 xen/include/asm-x86/efi.h
This moves the boot.c,the file that implements the EFI entry point to efi/common, and builds with both EFI/non-EFI toolchains. No code changes, just file movement and make updates. Note that since both the EFI and non-EFI versions are built at the same time, the EFI boot code cannot be included in the common/build_in.o. In the ARM case, it will always be built in, so the normal common build infrastructure can be used. The EFI runtime code is left alone as this patch series just implements the boot code.
Signed-off-by: Roy Franz roy.franz@linaro.org --- .gitignore | 2 + xen/arch/x86/Makefile | 15 +- xen/arch/x86/efi/Makefile | 4 +- xen/arch/x86/efi/boot.c | 1723 -------------------------------------------- xen/arch/x86/efi/efi.h | 39 - xen/arch/x86/efi/runtime.c | 2 +- xen/common/Makefile | 1 + xen/common/efi/Makefile | 14 + xen/common/efi/boot.c | 1723 ++++++++++++++++++++++++++++++++++++++++++++ xen/common/efi/check.c | 4 + xen/common/efi/dummy.c | 1 + xen/common/efi/efi.h | 39 + xen/include/asm-x86/efi.h | 39 + 13 files changed, 1837 insertions(+), 1769 deletions(-) delete mode 100644 xen/arch/x86/efi/boot.c delete mode 100644 xen/arch/x86/efi/efi.h create mode 100644 xen/common/efi/Makefile create mode 100644 xen/common/efi/boot.c create mode 100644 xen/common/efi/check.c create mode 100644 xen/common/efi/dummy.c create mode 100644 xen/common/efi/efi.h create mode 100644 xen/include/asm-x86/efi.h
diff --git a/.gitignore b/.gitignore index 6d725aa..81ca938 100644 --- a/.gitignore +++ b/.gitignore @@ -254,6 +254,8 @@ xen/arch/x86/efi.lds xen/arch/x86/efi/check.efi xen/arch/x86/efi/disabled xen/arch/x86/efi/mkreloc +xen/common/efi/check.efi +xen/common/efi/disabled xen/ddb/* xen/include/headers.chk xen/include/asm diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index c1e244d..5256bdf 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -75,6 +75,13 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32
ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
+ +# This seems to be required to get parallel builds to work, otherwise prelink-efi.o complains about +# no rule to make boot.init.o +# Not sure what the right fix is +$(BASEDIR)/common/efi/boot.init.o: $(BASEDIR)/common/efi/boot.c + $(MAKE) -f $(BASEDIR)/Rules.mk -C $(BASEDIR)/common/efi/ boot.init.o + ifeq ($(lto),y) # Gather all LTO objects together prelink_lto.o: $(ALL_OBJS) @@ -87,13 +94,13 @@ prelink-efi_lto.o: $(ALL_OBJS) efi/runtime.o efi/compat.o 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 +prelink-efi.o: $(patsubst %/built_in.o,%/built_in_bin.o,$(ALL_OBJS)) prelink-efi_lto.o $(BASEDIR)/common/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 +prelink-efi.o: $(ALL_OBJS) $(BASEDIR)/common/efi/boot.init.o efi/runtime.o efi/compat.o $(guard) $(LD) $(LDFLAGS) -r -o $@ $(filter-out %/efi/built_in.o,$^) endif
@@ -143,8 +150,8 @@ $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbol 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: ; +efi/runtime.o efi/compat.o: $(BASEDIR)/arch/x86/efi/built_in.o +efi/runtime.o efi/compat.o: ;
asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c $(CC) $(filter-out -flto,$(CFLAGS)) -S -o $@ $< diff --git a/xen/arch/x86/efi/Makefile b/xen/arch/x86/efi/Makefile index 1daa7ac..609d05b 100644 --- a/xen/arch/x86/efi/Makefile +++ b/xen/arch/x86/efi/Makefile @@ -7,8 +7,8 @@ create = test -e $(1) || touch -t 199901010000 $(1) efi := $(filter y,$(x86_64)$(shell rm -f disabled)) efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y) .%.d,$(CFLAGS)) -c check.c 2>disabled && echo y)) efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y)) -efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(call create,runtime.o))) +efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,runtime.o)))
-extra-$(efi) += boot.init.o relocs-dummy.o runtime.o compat.o +extra-$(efi) += relocs-dummy.o runtime.o compat.o
stub.o: $(extra-y) diff --git a/xen/arch/x86/efi/boot.c b/xen/arch/x86/efi/boot.c deleted file mode 100644 index 3bdc158..0000000 --- a/xen/arch/x86/efi/boot.c +++ /dev/null @@ -1,1723 +0,0 @@ -#include "efi.h" -#include <efi/efiprot.h> -#include <efi/efipciio.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/mm.h> -#include <xen/multiboot.h> -#include <xen/pci_regs.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/edd.h> -#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ -#include <asm/fixmap.h> -#undef __ASSEMBLY__ -#include <asm/msr.h> -#include <asm/processor.h> - -/* Using SetVirtualAddressMap() is incompatible with kexec: */ -#undef USE_SET_VIRTUAL_ADDRESS_MAP - -#define SHIM_LOCK_PROTOCOL_GUID \ - { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } - -typedef EFI_STATUS -(/* _not_ EFIAPI */ *EFI_SHIM_LOCK_VERIFY) ( - IN VOID *Buffer, - IN UINT32 Size); - -typedef struct { - EFI_SHIM_LOCK_VERIFY Verify; -} EFI_SHIM_LOCK_PROTOCOL; - -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 ucode; -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 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 ( ucode.addr ) - efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size)); - if ( xsm.addr ) - efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size)); - - efi_bs->Exit(efi_ih, EFI_SUCCESS, 0, NULL); - unreachable(); /* 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; - case EFI_SECURITY_VIOLATION: - mesg = L"Security violation"; - break; - case EFI_CRC_ERROR: - mesg = L"CRC error"; - break; - case EFI_COMPROMISED_DATA: - mesg = L"Compromised data"; - 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) ) - PrintErrMesg(L"Couldn't obtain the File System Protocol Interface", - ret); - ret = fio->OpenVolume(fio, &dir_handle); - } while ( ret == EFI_MEDIA_CHANGED ); - if ( ret != EFI_SUCCESS ) - PrintErrMesg(L"OpenVolume failure", ret); - -#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 = min(1UL << (32 + PAGE_SHIFT), - HYPERVISOR_VIRT_END - DIRECTMAP_VIRT_START); - 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 void __init edd_put_string(u8 *dst, size_t n, const char *src) -{ - while ( n-- && *src ) - *dst++ = *src++; - if ( *src ) - PrintErrMesg(L"Internal error populating EDD info", - EFI_BUFFER_TOO_SMALL); - while ( n-- ) - *dst++ = ' '; -} -#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) - -static void __init setup_efi_pci(void) -{ - EFI_STATUS status; - EFI_HANDLE *handles; - static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL; - UINTN i, nr_pci, size = 0; - struct efi_pci_rom *last = NULL; - - status = efi_bs->LocateHandle(ByProtocol, &pci_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, &pci_guid, NULL, &size, - handles); - if ( EFI_ERROR(status) ) - size = 0; - - nr_pci = size / sizeof(*handles); - for ( i = 0; i < nr_pci; ++i ) - { - EFI_PCI_IO *pci = NULL; - u64 attributes; - struct efi_pci_rom *rom, *va; - UINTN segment, bus, device, function; - - status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci); - if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize ) - continue; - - status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0, - &attributes); - if ( EFI_ERROR(status) || - !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) || - EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device, - &function)) ) - continue; - - DisplayUint(segment, 4); - PrintStr(L":"); - DisplayUint(bus, 2); - PrintStr(L":"); - DisplayUint(device, 2); - PrintStr(L"."); - DisplayUint(function, 1); - PrintStr(L": ROM: "); - DisplayUint(pci->RomSize, 0); - PrintStr(L" bytes at "); - DisplayUint((UINTN)pci->RomImage, 0); - PrintStr(newline); - - size = pci->RomSize + sizeof(*rom); - status = efi_bs->AllocatePool(EfiRuntimeServicesData, size, - (void **)&rom); - if ( EFI_ERROR(status) ) - continue; - - rom->next = NULL; - rom->size = pci->RomSize; - - status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, - &rom->vendor); - if ( !EFI_ERROR(status) ) - status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, - &rom->devid); - if ( EFI_ERROR(status) ) - { - efi_bs->FreePool(rom); - continue; - } - - rom->segment = segment; - rom->bus = bus; - rom->devfn = (device << 3) | function; - memcpy(rom->data, pci->RomImage, pci->RomSize); - - va = (void *)rom + DIRECTMAP_VIRT_START; - if ( last ) - last->next = va; - else - efi_pci_roms = va; - last = rom; - } - - efi_bs->FreePool(handles); -} - -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); -} - -extern const intpte_t __page_tables_start[], __page_tables_end[]; -#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ - (intpte_t *)(v) < __page_tables_end) - -#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; - if ( in_page_tables(addr) ) - *(u32 *)addr += xen_phys_start; - } - break; - case PE_BASE_RELOC_DIR64: - if ( delta ) - { - *(u64 *)addr += delta; - if ( in_page_tables(addr) ) - *(intpte_t *)addr += xen_phys_start; - } - break; - default: - blexit(L"Unsupported relocation type"); - } - } - base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); - } -} - -extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; -extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; - -static void __init relocate_trampoline(unsigned long phys) -{ - const s32 *trampoline_ptr; - - trampoline_phys = phys; - /* Apply relocations to trampoline. */ - for ( trampoline_ptr = __trampoline_rel_start; - trampoline_ptr < __trampoline_rel_stop; - ++trampoline_ptr ) - *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; - for ( trampoline_ptr = __trampoline_seg_start; - trampoline_ptr < __trampoline_seg_stop; - ++trampoline_ptr ) - *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; -} - -void EFIAPI __init 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; - static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL; - static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL; - static EFI_GUID __initdata shim_lock_guid = SHIM_LOCK_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_SHIM_LOCK_PROTOCOL *shim_lock; - 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; - - 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."); - if ( xen_phys_start & ((1 << L2_PAGETABLE_SHIFT) - 1) ) - blexit(L"Xen must be loaded at a 2Mb boundary."); - 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."); - 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."); - pre_parse(&cfg); - - if ( section.w ) - w2s(§ion); - else - section.s = get_value(&cfg, "global", "default"); - - for ( ; ; ) - { - name.s = get_value(&cfg, section.s, "kernel"); - if ( name.s ) - break; - name.s = get_value(&cfg, "global", "chain"); - if ( !name.s ) - break; - efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); - cfg.addr = 0; - if ( !read_file(dir_handle, s2w(&name), &cfg) ) - { - PrintStr(L"Chained configuration file '"); - PrintStr(name.w); - efi_bs->FreePool(name.w); - blexit(L"'not found."); - } - pre_parse(&cfg); - efi_bs->FreePool(name.w); - } - if ( !name.s ) - blexit(L"No Dom0 kernel image specified."); - split_value(name.s); - read_file(dir_handle, s2w(&name), &kernel); - efi_bs->FreePool(name.w); - - if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, - (void **)&shim_lock)) && - (status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS ) - PrintErrMesg(L"Dom0 kernel image could not be verified", status); - - 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, "ucode"); - if ( !name.s ) - name.s = get_value(&cfg, "global", "ucode"); - if ( name.s ) - { - microcode_set_module(mbi.mods_count); - split_value(name.s); - read_file(dir_handle, s2w(&name), &ucode); - 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); - - /* Collect EDD info. */ - BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); - BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); - size = 0; - status = efi_bs->LocateHandle(ByProtocol, &bio_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, &bio_guid, NULL, &size, - handles); - if ( EFI_ERROR(status) ) - size = 0; - for ( i = 0; i < size / sizeof(*handles); ++i ) - { - EFI_BLOCK_IO *bio; - EFI_DEV_PATH_PTR devp; - struct edd_info *info = boot_edd_info + boot_edd_info_nr; - struct edd_device_params *params = &info->edd_device_params; - enum { root, acpi, pci, ctrlr } state = root; - - status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio); - if ( EFI_ERROR(status) || - bio->Media->RemovableMedia || - bio->Media->LogicalPartition ) - continue; - if ( boot_edd_info_nr < EDD_INFO_MAX ) - { - info->device = 0x80 + boot_edd_info_nr; /* fake */ - info->version = 0x11; - params->length = offsetof(struct edd_device_params, dpte_ptr); - params->number_of_sectors = bio->Media->LastBlock + 1; - params->bytes_per_sector = bio->Media->BlockSize; - params->dpte_ptr = ~0; - } - ++boot_edd_info_nr; - status = efi_bs->HandleProtocol(handles[i], &devp_guid, - (void **)&devp); - if ( EFI_ERROR(status) ) - continue; - for ( ; !IsDevicePathEnd(devp.DevPath); - devp.DevPath = NextDevicePathNode(devp.DevPath) ) - { - switch ( DevicePathType(devp.DevPath) ) - { - const u8 *p; - - case ACPI_DEVICE_PATH: - if ( state != root || boot_edd_info_nr > EDD_INFO_MAX ) - break; - switch ( DevicePathSubType(devp.DevPath) ) - { - case ACPI_DP: - if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) && - devp.Acpi->HID != EISA_PNP_ID(0xA08) ) - break; - params->interface_path.pci.bus = devp.Acpi->UID; - state = acpi; - break; - case EXPANDED_ACPI_DP: - /* XXX */ - break; - } - break; - case HARDWARE_DEVICE_PATH: - if ( state != acpi || - DevicePathSubType(devp.DevPath) != HW_PCI_DP || - boot_edd_info_nr > EDD_INFO_MAX ) - break; - state = pci; - edd_put_string(params->host_bus_type, "PCI"); - params->interface_path.pci.slot = devp.Pci->Device; - params->interface_path.pci.function = devp.Pci->Function; - break; - case MESSAGING_DEVICE_PATH: - if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX ) - break; - state = ctrlr; - switch ( DevicePathSubType(devp.DevPath) ) - { - case MSG_ATAPI_DP: - edd_put_string(params->interface_type, "ATAPI"); - params->interface_path.pci.channel = - devp.Atapi->PrimarySecondary; - params->device_path.atapi.device = devp.Atapi->SlaveMaster; - params->device_path.atapi.lun = devp.Atapi->Lun; - break; - case MSG_SCSI_DP: - edd_put_string(params->interface_type, "SCSI"); - params->device_path.scsi.id = devp.Scsi->Pun; - params->device_path.scsi.lun = devp.Scsi->Lun; - break; - case MSG_FIBRECHANNEL_DP: - edd_put_string(params->interface_type, "FIBRE"); - params->device_path.fibre.wwid = devp.FibreChannel->WWN; - params->device_path.fibre.lun = devp.FibreChannel->Lun; - break; - case MSG_1394_DP: - edd_put_string(params->interface_type, "1394"); - params->device_path.i1394.eui = devp.F1394->Guid; - break; - case MSG_USB_DP: - case MSG_USB_CLASS_DP: - edd_put_string(params->interface_type, "USB"); - break; - case MSG_I2O_DP: - edd_put_string(params->interface_type, "I2O"); - params->device_path.i2o.identity_tag = devp.I2O->Tid; - break; - default: - continue; - } - info->version = 0x30; - params->length = sizeof(struct edd_device_params); - params->key = 0xbedd; - params->device_path_info_length = - sizeof(struct edd_device_params) - - offsetof(struct edd_device_params, key); - for ( p = (const u8 *)¶ms->key; p < ¶ms->checksum; ++p ) - params->checksum -= *p; - break; - case MEDIA_DEVICE_PATH: - if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP && - devp.HardDrive->MBRType == MBR_TYPE_PCAT && - boot_mbr_signature_nr < EDD_MBR_SIG_MAX ) - { - struct mbr_signature *sig = boot_mbr_signature + - boot_mbr_signature_nr; - - sig->device = 0x80 + boot_edd_info_nr; /* fake */ - memcpy(&sig->signature, devp.HardDrive->Signature, - sizeof(sig->signature)); - ++boot_mbr_signature_nr; - } - break; - } - } - } - if ( handles ) - efi_bs->FreePool(handles); - if ( boot_edd_info_nr > EDD_INFO_MAX ) - boot_edd_info_nr = EDD_INFO_MAX; - - /* 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 mps_guid = MPS_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(&mps_guid, &efi_ct[i].VendorGuid) ) - efi.mps = (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); - - /* Collect PCI ROM contents. */ - setup_efi_pci(); - - /* Get snapshot of variable store parameters. */ - status = (efi_rs->Hdr.Revision >> 16) >= 2 ? - efi_rs->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - &efi_boot_max_var_store_size, - &efi_boot_remain_var_store_size, - &efi_boot_max_var_size) : - EFI_INCOMPATIBLE_VERSION; - if ( EFI_ERROR(status) ) - { - efi_boot_max_var_store_size = 0; - efi_boot_remain_var_store_size = 0; - efi_boot_max_var_size = status; - PrintStr(L"Warning: Could not query variable store: "); - DisplayUint(status, 0); - PrintStr(newline); - } - - /* Allocate space for trampoline (in first Mb). */ - cfg.addr = 0x100000; - cfg.size = trampoline_end - trampoline_start; - status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, - PFN_UP(cfg.size), &cfg.addr); - if ( status == EFI_SUCCESS ) - relocate_trampoline(cfg.addr); - else - { - cfg.addr = 0; - PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); - } - - /* Initialise L2 identity-map and boot-map 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[slot] = 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 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); - - 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!\r\n"); - 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; - } - } - - 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"); - 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) ) - PrintErrMesg(L"Cannot obtain memory map", status); - - /* 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 EfiBootServicesCode: - case EfiBootServicesData: - if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 && - len >= cfg.size && desc->PhysicalStart + len > cfg.addr ) - cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK; - /* fall through */ - case EfiLoaderCode: - case EfiLoaderData: - 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 ( !trampoline_phys ) - { - if ( !cfg.addr ) - blexit(L"No memory for trampoline"); - relocate_trampoline(cfg.addr); - } - - 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; -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - 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 *)trampoline_phys, 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" - "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 */ -} - -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP -static __init void copy_mapping(unsigned long mfn, unsigned long end, - bool_t (*is_valid)(unsigned long smfn, - unsigned long emfn)) -{ - unsigned long next; - - for ( ; mfn < end; mfn = next ) - { - l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)]; - l3_pgentry_t *l3src, *l3dst; - unsigned long va = (unsigned long)mfn_to_virt(mfn); - - next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)); - if ( !is_valid(mfn, min(next, end)) ) - continue; - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) - { - l3dst = alloc_xen_pagetable(); - BUG_ON(!l3dst); - clear_page(l3dst); - efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] = - l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR); - } - else - l3dst = l4e_to_l3e(l4e); - l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]); - l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)]; - } -} - -static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn) -{ - unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1; - - return !(smfn & pfn_hole_mask) && - find_next_bit(pdx_group_valid, sz, - pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz; -} - -static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn) -{ - return 1; -} -#endif - -#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \ - (EFI_PAGE_SHIFT + BITS_PER_LONG - 32)) - -void __init efi_init_memory(void) -{ - unsigned int i; -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP - struct rt_extra { - struct rt_extra *next; - unsigned long smfn, emfn; - unsigned int prot; - } *extra, *extra_head = NULL; -#endif - - 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; - - desc->VirtualStart = INVALID_VIRTUAL_ADDRESS; - - smfn = PFN_DOWN(desc->PhysicalStart); - emfn = PFN_UP(desc->PhysicalStart + len); - - 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 ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END ) - prot &= ~_PAGE_GLOBAL; - 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); - } -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP - else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) && - (extra = xmalloc(struct rt_extra)) != NULL ) - { - extra->smfn = smfn; - extra->emfn = emfn; - extra->prot = prot & ~_PAGE_GLOBAL; - extra->next = extra_head; - extra_head = extra; - desc->VirtualStart = desc->PhysicalStart; - } -#endif - else - { -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - /* XXX allocate e.g. down from FIXADDR_START */ -#endif - printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n", - smfn, emfn - 1); - } - } - -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size, - mdesc_ver, efi_memmap); -#else - /* Set up 1:1 page tables to do runtime calls in "physical" mode. */ - efi_l4_pgtable = alloc_xen_pagetable(); - BUG_ON(!efi_l4_pgtable); - clear_page(efi_l4_pgtable); - - copy_mapping(0, max_page, ram_range_valid); - - /* Insert non-RAM runtime mappings inside the direct map. */ - for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) - { - const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; - - if ( (desc->Attribute & EFI_MEMORY_RUNTIME) && - desc->VirtualStart != INVALID_VIRTUAL_ADDRESS && - desc->VirtualStart != desc->PhysicalStart ) - copy_mapping(PFN_DOWN(desc->PhysicalStart), - PFN_UP(desc->PhysicalStart + - (desc->NumberOfPages << EFI_PAGE_SHIFT)), - rt_range_valid); - } - - /* Insert non-RAM runtime mappings outside of the direct map. */ - while ( (extra = extra_head) != NULL ) - { - unsigned long addr = extra->smfn << PAGE_SHIFT; - l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)]; - l3_pgentry_t *pl3e; - l2_pgentry_t *pl2e; - l1_pgentry_t *l1t; - - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) - { - pl3e = alloc_xen_pagetable(); - BUG_ON(!pl3e); - clear_page(pl3e); - efi_l4_pgtable[l4_table_offset(addr)] = - l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR); - } - else - pl3e = l4e_to_l3e(l4e); - pl3e += l3_table_offset(addr); - if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) - { - pl2e = alloc_xen_pagetable(); - BUG_ON(!pl2e); - clear_page(pl2e); - *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR); - } - else - { - BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE); - pl2e = l3e_to_l2e(*pl3e); - } - pl2e += l2_table_offset(addr); - if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) - { - l1t = alloc_xen_pagetable(); - BUG_ON(!l1t); - clear_page(l1t); - *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR); - } - else - { - BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE); - l1t = l2e_to_l1e(*pl2e); - } - for ( i = l1_table_offset(addr); - i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn; - ++i, ++extra->smfn ) - l1t[i] = l1e_from_pfn(extra->smfn, extra->prot); - - if ( extra->smfn == extra->emfn ) - { - extra_head = extra->next; - xfree(extra); - } - } - - /* Insert Xen mappings. */ - for ( i = l4_table_offset(HYPERVISOR_VIRT_START); - i < l4_table_offset(DIRECTMAP_VIRT_END); ++i ) - efi_l4_pgtable[i] = idle_pg_table[i]; -#endif -} diff --git a/xen/arch/x86/efi/efi.h b/xen/arch/x86/efi/efi.h deleted file mode 100644 index a80d5f1..0000000 --- a/xen/arch/x86/efi/efi.h +++ /dev/null @@ -1,39 +0,0 @@ -#include <asm/efibind.h> -#include <efi/efidef.h> -#include <efi/efierr.h> -#include <efi/eficon.h> -#include <efi/efidevp.h> -#include <efi/eficapsule.h> -#include <efi/efiapi.h> -#include <xen/efi.h> -#include <xen/spinlock.h> -#include <asm/page.h> - -struct efi_pci_rom { - const struct efi_pci_rom *next; - u16 vendor, devid, segment; - u8 bus, devfn; - unsigned long size; - unsigned char data[]; -}; - -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; - -extern l4_pgentry_t *efi_l4_pgtable; - -extern const struct efi_pci_rom *efi_pci_roms; - -extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size, - efi_boot_max_var_size; - -unsigned long efi_rs_enter(void); -void efi_rs_leave(unsigned long); diff --git a/xen/arch/x86/efi/runtime.c b/xen/arch/x86/efi/runtime.c index 166852d..6788a1a 100644 --- a/xen/arch/x86/efi/runtime.c +++ b/xen/arch/x86/efi/runtime.c @@ -1,4 +1,4 @@ -#include "efi.h" +#include <asm/efi.h> #include <xen/cache.h> #include <xen/errno.h> #include <xen/guest_access.h> diff --git a/xen/common/Makefile b/xen/common/Makefile index 3683ae3..e5c7044 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -67,4 +67,5 @@ subdir-$(x86_64) += hvm subdir-$(coverage) += gcov
subdir-y += libelf +subdir-y += efi subdir-$(HAS_DEVICE_TREE) += libfdt diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile new file mode 100644 index 0000000..4313a4e --- /dev/null +++ b/xen/common/efi/Makefile @@ -0,0 +1,14 @@ +CFLAGS += -fshort-wchar + +obj-y += dummy.o + +create = test -e $(1) || touch -t 199901010000 $(1) + +efi := $(filter y,$(x86_64)$(shell rm -f disabled)) +efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y) .%.d,$(CFLAGS)) -c check.c 2>disabled && echo y)) +efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y)) +efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(call create,runtime.o))) + +extra-$(efi) += boot.init.o + +dummy.o: boot.init.o $(extra-y) diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c new file mode 100644 index 0000000..14e2f46 --- /dev/null +++ b/xen/common/efi/boot.c @@ -0,0 +1,1723 @@ +#include <asm/efi.h> +#include <efi/efiprot.h> +#include <efi/efipciio.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/mm.h> +#include <xen/multiboot.h> +#include <xen/pci_regs.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/edd.h> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ +#include <asm/fixmap.h> +#undef __ASSEMBLY__ +#include <asm/msr.h> +#include <asm/processor.h> + +/* Using SetVirtualAddressMap() is incompatible with kexec: */ +#undef USE_SET_VIRTUAL_ADDRESS_MAP + +#define SHIM_LOCK_PROTOCOL_GUID \ + { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } + +typedef EFI_STATUS +(/* _not_ EFIAPI */ *EFI_SHIM_LOCK_VERIFY) ( + IN VOID *Buffer, + IN UINT32 Size); + +typedef struct { + EFI_SHIM_LOCK_VERIFY Verify; +} EFI_SHIM_LOCK_PROTOCOL; + +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 ucode; +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 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 ( ucode.addr ) + efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size)); + if ( xsm.addr ) + efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size)); + + efi_bs->Exit(efi_ih, EFI_SUCCESS, 0, NULL); + unreachable(); /* 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; + case EFI_SECURITY_VIOLATION: + mesg = L"Security violation"; + break; + case EFI_CRC_ERROR: + mesg = L"CRC error"; + break; + case EFI_COMPROMISED_DATA: + mesg = L"Compromised data"; + 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) ) + PrintErrMesg(L"Couldn't obtain the File System Protocol Interface", + ret); + ret = fio->OpenVolume(fio, &dir_handle); + } while ( ret == EFI_MEDIA_CHANGED ); + if ( ret != EFI_SUCCESS ) + PrintErrMesg(L"OpenVolume failure", ret); + +#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 = min(1UL << (32 + PAGE_SHIFT), + HYPERVISOR_VIRT_END - DIRECTMAP_VIRT_START); + 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 void __init edd_put_string(u8 *dst, size_t n, const char *src) +{ + while ( n-- && *src ) + *dst++ = *src++; + if ( *src ) + PrintErrMesg(L"Internal error populating EDD info", + EFI_BUFFER_TOO_SMALL); + while ( n-- ) + *dst++ = ' '; +} +#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) + +static void __init setup_efi_pci(void) +{ + EFI_STATUS status; + EFI_HANDLE *handles; + static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL; + UINTN i, nr_pci, size = 0; + struct efi_pci_rom *last = NULL; + + status = efi_bs->LocateHandle(ByProtocol, &pci_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, &pci_guid, NULL, &size, + handles); + if ( EFI_ERROR(status) ) + size = 0; + + nr_pci = size / sizeof(*handles); + for ( i = 0; i < nr_pci; ++i ) + { + EFI_PCI_IO *pci = NULL; + u64 attributes; + struct efi_pci_rom *rom, *va; + UINTN segment, bus, device, function; + + status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci); + if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize ) + continue; + + status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0, + &attributes); + if ( EFI_ERROR(status) || + !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) || + EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device, + &function)) ) + continue; + + DisplayUint(segment, 4); + PrintStr(L":"); + DisplayUint(bus, 2); + PrintStr(L":"); + DisplayUint(device, 2); + PrintStr(L"."); + DisplayUint(function, 1); + PrintStr(L": ROM: "); + DisplayUint(pci->RomSize, 0); + PrintStr(L" bytes at "); + DisplayUint((UINTN)pci->RomImage, 0); + PrintStr(newline); + + size = pci->RomSize + sizeof(*rom); + status = efi_bs->AllocatePool(EfiRuntimeServicesData, size, + (void **)&rom); + if ( EFI_ERROR(status) ) + continue; + + rom->next = NULL; + rom->size = pci->RomSize; + + status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, + &rom->vendor); + if ( !EFI_ERROR(status) ) + status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, + &rom->devid); + if ( EFI_ERROR(status) ) + { + efi_bs->FreePool(rom); + continue; + } + + rom->segment = segment; + rom->bus = bus; + rom->devfn = (device << 3) | function; + memcpy(rom->data, pci->RomImage, pci->RomSize); + + va = (void *)rom + DIRECTMAP_VIRT_START; + if ( last ) + last->next = va; + else + efi_pci_roms = va; + last = rom; + } + + efi_bs->FreePool(handles); +} + +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); +} + +extern const intpte_t __page_tables_start[], __page_tables_end[]; +#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ + (intpte_t *)(v) < __page_tables_end) + +#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; + if ( in_page_tables(addr) ) + *(u32 *)addr += xen_phys_start; + } + break; + case PE_BASE_RELOC_DIR64: + if ( delta ) + { + *(u64 *)addr += delta; + if ( in_page_tables(addr) ) + *(intpte_t *)addr += xen_phys_start; + } + break; + default: + blexit(L"Unsupported relocation type"); + } + } + base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); + } +} + +extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; +extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; + +static void __init relocate_trampoline(unsigned long phys) +{ + const s32 *trampoline_ptr; + + trampoline_phys = phys; + /* Apply relocations to trampoline. */ + for ( trampoline_ptr = __trampoline_rel_start; + trampoline_ptr < __trampoline_rel_stop; + ++trampoline_ptr ) + *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; + for ( trampoline_ptr = __trampoline_seg_start; + trampoline_ptr < __trampoline_seg_stop; + ++trampoline_ptr ) + *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; +} + +void EFIAPI __init 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; + static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL; + static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL; + static EFI_GUID __initdata shim_lock_guid = SHIM_LOCK_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_SHIM_LOCK_PROTOCOL *shim_lock; + 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; + + 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."); + if ( xen_phys_start & ((1 << L2_PAGETABLE_SHIFT) - 1) ) + blexit(L"Xen must be loaded at a 2Mb boundary."); + 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."); + 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."); + pre_parse(&cfg); + + if ( section.w ) + w2s(§ion); + else + section.s = get_value(&cfg, "global", "default"); + + for ( ; ; ) + { + name.s = get_value(&cfg, section.s, "kernel"); + if ( name.s ) + break; + name.s = get_value(&cfg, "global", "chain"); + if ( !name.s ) + break; + efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); + cfg.addr = 0; + if ( !read_file(dir_handle, s2w(&name), &cfg) ) + { + PrintStr(L"Chained configuration file '"); + PrintStr(name.w); + efi_bs->FreePool(name.w); + blexit(L"'not found."); + } + pre_parse(&cfg); + efi_bs->FreePool(name.w); + } + if ( !name.s ) + blexit(L"No Dom0 kernel image specified."); + split_value(name.s); + read_file(dir_handle, s2w(&name), &kernel); + efi_bs->FreePool(name.w); + + if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, + (void **)&shim_lock)) && + (status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS ) + PrintErrMesg(L"Dom0 kernel image could not be verified", status); + + 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, "ucode"); + if ( !name.s ) + name.s = get_value(&cfg, "global", "ucode"); + if ( name.s ) + { + microcode_set_module(mbi.mods_count); + split_value(name.s); + read_file(dir_handle, s2w(&name), &ucode); + 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); + + /* Collect EDD info. */ + BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); + BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); + size = 0; + status = efi_bs->LocateHandle(ByProtocol, &bio_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, &bio_guid, NULL, &size, + handles); + if ( EFI_ERROR(status) ) + size = 0; + for ( i = 0; i < size / sizeof(*handles); ++i ) + { + EFI_BLOCK_IO *bio; + EFI_DEV_PATH_PTR devp; + struct edd_info *info = boot_edd_info + boot_edd_info_nr; + struct edd_device_params *params = &info->edd_device_params; + enum { root, acpi, pci, ctrlr } state = root; + + status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio); + if ( EFI_ERROR(status) || + bio->Media->RemovableMedia || + bio->Media->LogicalPartition ) + continue; + if ( boot_edd_info_nr < EDD_INFO_MAX ) + { + info->device = 0x80 + boot_edd_info_nr; /* fake */ + info->version = 0x11; + params->length = offsetof(struct edd_device_params, dpte_ptr); + params->number_of_sectors = bio->Media->LastBlock + 1; + params->bytes_per_sector = bio->Media->BlockSize; + params->dpte_ptr = ~0; + } + ++boot_edd_info_nr; + status = efi_bs->HandleProtocol(handles[i], &devp_guid, + (void **)&devp); + if ( EFI_ERROR(status) ) + continue; + for ( ; !IsDevicePathEnd(devp.DevPath); + devp.DevPath = NextDevicePathNode(devp.DevPath) ) + { + switch ( DevicePathType(devp.DevPath) ) + { + const u8 *p; + + case ACPI_DEVICE_PATH: + if ( state != root || boot_edd_info_nr > EDD_INFO_MAX ) + break; + switch ( DevicePathSubType(devp.DevPath) ) + { + case ACPI_DP: + if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) && + devp.Acpi->HID != EISA_PNP_ID(0xA08) ) + break; + params->interface_path.pci.bus = devp.Acpi->UID; + state = acpi; + break; + case EXPANDED_ACPI_DP: + /* XXX */ + break; + } + break; + case HARDWARE_DEVICE_PATH: + if ( state != acpi || + DevicePathSubType(devp.DevPath) != HW_PCI_DP || + boot_edd_info_nr > EDD_INFO_MAX ) + break; + state = pci; + edd_put_string(params->host_bus_type, "PCI"); + params->interface_path.pci.slot = devp.Pci->Device; + params->interface_path.pci.function = devp.Pci->Function; + break; + case MESSAGING_DEVICE_PATH: + if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX ) + break; + state = ctrlr; + switch ( DevicePathSubType(devp.DevPath) ) + { + case MSG_ATAPI_DP: + edd_put_string(params->interface_type, "ATAPI"); + params->interface_path.pci.channel = + devp.Atapi->PrimarySecondary; + params->device_path.atapi.device = devp.Atapi->SlaveMaster; + params->device_path.atapi.lun = devp.Atapi->Lun; + break; + case MSG_SCSI_DP: + edd_put_string(params->interface_type, "SCSI"); + params->device_path.scsi.id = devp.Scsi->Pun; + params->device_path.scsi.lun = devp.Scsi->Lun; + break; + case MSG_FIBRECHANNEL_DP: + edd_put_string(params->interface_type, "FIBRE"); + params->device_path.fibre.wwid = devp.FibreChannel->WWN; + params->device_path.fibre.lun = devp.FibreChannel->Lun; + break; + case MSG_1394_DP: + edd_put_string(params->interface_type, "1394"); + params->device_path.i1394.eui = devp.F1394->Guid; + break; + case MSG_USB_DP: + case MSG_USB_CLASS_DP: + edd_put_string(params->interface_type, "USB"); + break; + case MSG_I2O_DP: + edd_put_string(params->interface_type, "I2O"); + params->device_path.i2o.identity_tag = devp.I2O->Tid; + break; + default: + continue; + } + info->version = 0x30; + params->length = sizeof(struct edd_device_params); + params->key = 0xbedd; + params->device_path_info_length = + sizeof(struct edd_device_params) - + offsetof(struct edd_device_params, key); + for ( p = (const u8 *)¶ms->key; p < ¶ms->checksum; ++p ) + params->checksum -= *p; + break; + case MEDIA_DEVICE_PATH: + if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP && + devp.HardDrive->MBRType == MBR_TYPE_PCAT && + boot_mbr_signature_nr < EDD_MBR_SIG_MAX ) + { + struct mbr_signature *sig = boot_mbr_signature + + boot_mbr_signature_nr; + + sig->device = 0x80 + boot_edd_info_nr; /* fake */ + memcpy(&sig->signature, devp.HardDrive->Signature, + sizeof(sig->signature)); + ++boot_mbr_signature_nr; + } + break; + } + } + } + if ( handles ) + efi_bs->FreePool(handles); + if ( boot_edd_info_nr > EDD_INFO_MAX ) + boot_edd_info_nr = EDD_INFO_MAX; + + /* 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 mps_guid = MPS_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(&mps_guid, &efi_ct[i].VendorGuid) ) + efi.mps = (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); + + /* Collect PCI ROM contents. */ + setup_efi_pci(); + + /* Get snapshot of variable store parameters. */ + status = (efi_rs->Hdr.Revision >> 16) >= 2 ? + efi_rs->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + &efi_boot_max_var_store_size, + &efi_boot_remain_var_store_size, + &efi_boot_max_var_size) : + EFI_INCOMPATIBLE_VERSION; + if ( EFI_ERROR(status) ) + { + efi_boot_max_var_store_size = 0; + efi_boot_remain_var_store_size = 0; + efi_boot_max_var_size = status; + PrintStr(L"Warning: Could not query variable store: "); + DisplayUint(status, 0); + PrintStr(newline); + } + + /* Allocate space for trampoline (in first Mb). */ + cfg.addr = 0x100000; + cfg.size = trampoline_end - trampoline_start; + status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, + PFN_UP(cfg.size), &cfg.addr); + if ( status == EFI_SUCCESS ) + relocate_trampoline(cfg.addr); + else + { + cfg.addr = 0; + PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); + } + + /* Initialise L2 identity-map and boot-map 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[slot] = 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 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); + + 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!\r\n"); + 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; + } + } + + 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"); + 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) ) + PrintErrMesg(L"Cannot obtain memory map", status); + + /* 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 EfiBootServicesCode: + case EfiBootServicesData: + if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 && + len >= cfg.size && desc->PhysicalStart + len > cfg.addr ) + cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK; + /* fall through */ + case EfiLoaderCode: + case EfiLoaderData: + 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 ( !trampoline_phys ) + { + if ( !cfg.addr ) + blexit(L"No memory for trampoline"); + relocate_trampoline(cfg.addr); + } + + 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; +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + 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 *)trampoline_phys, 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" + "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 */ +} + +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP +static __init void copy_mapping(unsigned long mfn, unsigned long end, + bool_t (*is_valid)(unsigned long smfn, + unsigned long emfn)) +{ + unsigned long next; + + for ( ; mfn < end; mfn = next ) + { + l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)]; + l3_pgentry_t *l3src, *l3dst; + unsigned long va = (unsigned long)mfn_to_virt(mfn); + + next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)); + if ( !is_valid(mfn, min(next, end)) ) + continue; + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) + { + l3dst = alloc_xen_pagetable(); + BUG_ON(!l3dst); + clear_page(l3dst); + efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] = + l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR); + } + else + l3dst = l4e_to_l3e(l4e); + l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]); + l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)]; + } +} + +static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn) +{ + unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1; + + return !(smfn & pfn_hole_mask) && + find_next_bit(pdx_group_valid, sz, + pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz; +} + +static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn) +{ + return 1; +} +#endif + +#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \ + (EFI_PAGE_SHIFT + BITS_PER_LONG - 32)) + +void __init efi_init_memory(void) +{ + unsigned int i; +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP + struct rt_extra { + struct rt_extra *next; + unsigned long smfn, emfn; + unsigned int prot; + } *extra, *extra_head = NULL; +#endif + + 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; + + desc->VirtualStart = INVALID_VIRTUAL_ADDRESS; + + smfn = PFN_DOWN(desc->PhysicalStart); + emfn = PFN_UP(desc->PhysicalStart + len); + + 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 ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END ) + prot &= ~_PAGE_GLOBAL; + 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); + } +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP + else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) && + (extra = xmalloc(struct rt_extra)) != NULL ) + { + extra->smfn = smfn; + extra->emfn = emfn; + extra->prot = prot & ~_PAGE_GLOBAL; + extra->next = extra_head; + extra_head = extra; + desc->VirtualStart = desc->PhysicalStart; + } +#endif + else + { +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + /* XXX allocate e.g. down from FIXADDR_START */ +#endif + printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n", + smfn, emfn - 1); + } + } + +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size, + mdesc_ver, efi_memmap); +#else + /* Set up 1:1 page tables to do runtime calls in "physical" mode. */ + efi_l4_pgtable = alloc_xen_pagetable(); + BUG_ON(!efi_l4_pgtable); + clear_page(efi_l4_pgtable); + + copy_mapping(0, max_page, ram_range_valid); + + /* Insert non-RAM runtime mappings inside the direct map. */ + for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) + { + const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; + + if ( (desc->Attribute & EFI_MEMORY_RUNTIME) && + desc->VirtualStart != INVALID_VIRTUAL_ADDRESS && + desc->VirtualStart != desc->PhysicalStart ) + copy_mapping(PFN_DOWN(desc->PhysicalStart), + PFN_UP(desc->PhysicalStart + + (desc->NumberOfPages << EFI_PAGE_SHIFT)), + rt_range_valid); + } + + /* Insert non-RAM runtime mappings outside of the direct map. */ + while ( (extra = extra_head) != NULL ) + { + unsigned long addr = extra->smfn << PAGE_SHIFT; + l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)]; + l3_pgentry_t *pl3e; + l2_pgentry_t *pl2e; + l1_pgentry_t *l1t; + + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) + { + pl3e = alloc_xen_pagetable(); + BUG_ON(!pl3e); + clear_page(pl3e); + efi_l4_pgtable[l4_table_offset(addr)] = + l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR); + } + else + pl3e = l4e_to_l3e(l4e); + pl3e += l3_table_offset(addr); + if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) + { + pl2e = alloc_xen_pagetable(); + BUG_ON(!pl2e); + clear_page(pl2e); + *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR); + } + else + { + BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE); + pl2e = l3e_to_l2e(*pl3e); + } + pl2e += l2_table_offset(addr); + if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) + { + l1t = alloc_xen_pagetable(); + BUG_ON(!l1t); + clear_page(l1t); + *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR); + } + else + { + BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE); + l1t = l2e_to_l1e(*pl2e); + } + for ( i = l1_table_offset(addr); + i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn; + ++i, ++extra->smfn ) + l1t[i] = l1e_from_pfn(extra->smfn, extra->prot); + + if ( extra->smfn == extra->emfn ) + { + extra_head = extra->next; + xfree(extra); + } + } + + /* Insert Xen mappings. */ + for ( i = l4_table_offset(HYPERVISOR_VIRT_START); + i < l4_table_offset(DIRECTMAP_VIRT_END); ++i ) + efi_l4_pgtable[i] = idle_pg_table[i]; +#endif +} diff --git a/xen/common/efi/check.c b/xen/common/efi/check.c new file mode 100644 index 0000000..7fedd5a --- /dev/null +++ b/xen/common/efi/check.c @@ -0,0 +1,4 @@ +int __attribute__((__ms_abi__)) test(int i) +{ + return i; +} diff --git a/xen/common/efi/dummy.c b/xen/common/efi/dummy.c new file mode 100644 index 0000000..5b4047a --- /dev/null +++ b/xen/common/efi/dummy.c @@ -0,0 +1 @@ + int dummy(void){return 1;} diff --git a/xen/common/efi/efi.h b/xen/common/efi/efi.h new file mode 100644 index 0000000..a80d5f1 --- /dev/null +++ b/xen/common/efi/efi.h @@ -0,0 +1,39 @@ +#include <asm/efibind.h> +#include <efi/efidef.h> +#include <efi/efierr.h> +#include <efi/eficon.h> +#include <efi/efidevp.h> +#include <efi/eficapsule.h> +#include <efi/efiapi.h> +#include <xen/efi.h> +#include <xen/spinlock.h> +#include <asm/page.h> + +struct efi_pci_rom { + const struct efi_pci_rom *next; + u16 vendor, devid, segment; + u8 bus, devfn; + unsigned long size; + unsigned char data[]; +}; + +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; + +extern l4_pgentry_t *efi_l4_pgtable; + +extern const struct efi_pci_rom *efi_pci_roms; + +extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size, + efi_boot_max_var_size; + +unsigned long efi_rs_enter(void); +void efi_rs_leave(unsigned long); diff --git a/xen/include/asm-x86/efi.h b/xen/include/asm-x86/efi.h new file mode 100644 index 0000000..a80d5f1 --- /dev/null +++ b/xen/include/asm-x86/efi.h @@ -0,0 +1,39 @@ +#include <asm/efibind.h> +#include <efi/efidef.h> +#include <efi/efierr.h> +#include <efi/eficon.h> +#include <efi/efidevp.h> +#include <efi/eficapsule.h> +#include <efi/efiapi.h> +#include <xen/efi.h> +#include <xen/spinlock.h> +#include <asm/page.h> + +struct efi_pci_rom { + const struct efi_pci_rom *next; + u16 vendor, devid, segment; + u8 bus, devfn; + unsigned long size; + unsigned char data[]; +}; + +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; + +extern l4_pgentry_t *efi_l4_pgtable; + +extern const struct efi_pci_rom *efi_pci_roms; + +extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size, + efi_boot_max_var_size; + +unsigned long efi_rs_enter(void); +void efi_rs_leave(unsigned long);
ink On Sun, 2014-09-07 at 20:53 -0700, Roy Franz wrote:
This moves the boot.c,the file that implements the EFI entry point to efi/common, and builds with both EFI/non-EFI toolchains.
I'm not that familiar with the existing EFI stuff so maybe this is a dump question, but do you mean that it *can* now be built with either EFI or non-EFI, not that it *is* multiply compiled in a given build?
No code changes, just file movement and make updates.
For next time could you please pass -M to git send-email/format-patch so that handles moves more efficiently and shows only the actual changes.
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index c1e244d..5256bdf 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -75,6 +75,13 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32 ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
+# This seems to be required to get parallel builds to work, otherwise prelink-efi.o complains about +# no rule to make boot.init.o
I suppose we must recurse into common and arch at the same time.
+# Not sure what the right fix is
Me neither. This doesn't look right to me though, given that xen/common/efi is also entered via a subdir-y in xen/common/Makefile.
Perhaps Jan has some ideas but I'm wondering if we ought not to recurse into xen/common/efi from here and not from xen/common, or at least to not include extra-$(efi) += boot.init.o in xen/common/efi/Makefile (that would also let the x86 specific checkng code stay here, might it?)
symbols-dummy.o has a similar hack, but notice that it is not build from xen/common/Makefile.
Anyway, I'm flailing, perhaps Jan can suggest the correct fix.
+$(BASEDIR)/common/efi/boot.init.o: $(BASEDIR)/common/efi/boot.c
- $(MAKE) -f $(BASEDIR)/Rules.mk -C $(BASEDIR)/common/efi/ boot.init.o
ifeq ($(lto),y) # Gather all LTO objects together prelink_lto.o: $(ALL_OBJS) @@ -87,13 +94,13 @@ prelink-efi_lto.o: $(ALL_OBJS) efi/runtime.o efi/compat.o 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 +prelink-efi.o: $(patsubst %/built_in.o,%/built_in_bin.o,$(ALL_OBJS)) prelink-efi_lto.o $(BASEDIR)/common/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 +prelink-efi.o: $(ALL_OBJS) $(BASEDIR)/common/efi/boot.init.o efi/runtime.o efi/compat.o $(guard) $(LD) $(LDFLAGS) -r -o $@ $(filter-out %/efi/built_in.o,$^) endif @@ -143,8 +150,8 @@ $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbol 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: ; +efi/runtime.o efi/compat.o: $(BASEDIR)/arch/x86/efi/built_in.o +efi/runtime.o efi/compat.o: ; asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c $(CC) $(filter-out -flto,$(CFLAGS)) -S -o $@ $< diff --git a/xen/arch/x86/efi/Makefile b/xen/arch/x86/efi/Makefile index 1daa7ac..609d05b 100644 --- a/xen/arch/x86/efi/Makefile +++ b/xen/arch/x86/efi/Makefile @@ -7,8 +7,8 @@ create = test -e $(1) || touch -t 199901010000 $(1) efi := $(filter y,$(x86_64)$(shell rm -f disabled)) efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y) .%.d,$(CFLAGS)) -c check.c 2>disabled && echo y)) efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y)) -efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(call create,runtime.o))) +efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,runtime.o))) -extra-$(efi) += boot.init.o relocs-dummy.o runtime.o compat.o +extra-$(efi) += relocs-dummy.o runtime.o compat.o stub.o: $(extra-y)
[...]
diff --git a/xen/common/Makefile b/xen/common/Makefile index 3683ae3..e5c7044 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -67,4 +67,5 @@ subdir-$(x86_64) += hvm subdir-$(coverage) += gcov subdir-y += libelf +subdir-y += efi subdir-$(HAS_DEVICE_TREE) += libfdt diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile new file mode 100644 index 0000000..4313a4e --- /dev/null +++ b/xen/common/efi/Makefile @@ -0,0 +1,14 @@ +CFLAGS += -fshort-wchar
+obj-y += dummy.o
+create = test -e $(1) || touch -t 199901010000 $(1)
+efi := $(filter y,$(x86_64)$(shell rm -f disabled)) +efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y) .%.d,$(CFLAGS)) -c check.c 2>disabled && echo y)) +efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y)) +efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(call create,runtime.o)))
+extra-$(efi) += boot.init.o
+dummy.o: boot.init.o $(extra-y)
On 08.09.14 at 17:23, Ian.Campbell@citrix.com wrote:
ink On Sun, 2014-09-07 at 20:53 -0700, Roy Franz wrote:
--- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -75,6 +75,13 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32 ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
+# This seems to be required to get parallel builds to work, otherwise prelink-efi.o complains about +# no rule to make boot.init.o
I suppose we must recurse into common and arch at the same time.
+# Not sure what the right fix is
Me neither. This doesn't look right to me though, given that xen/common/efi is also entered via a subdir-y in xen/common/Makefile.
Perhaps Jan has some ideas but I'm wondering if we ought not to recurse into xen/common/efi from here and not from xen/common, or at least to not include extra-$(efi) += boot.init.o in xen/common/efi/Makefile (that would also let the x86 specific checkng code stay here, might it?)
symbols-dummy.o has a similar hack, but notice that it is not build from xen/common/Makefile.
Anyway, I'm flailing, perhaps Jan can suggest the correct fix.
So originally the idea was to sym-link the moved file into its current location, limiting the build recursion to what is being done today.
The only seamless alternative I can see would be to move the whole efi/ subtree to common/ (after all, runtime.c will need to be moved at some point too, and other files should then follow for consistency).
Jan
On Mon, Sep 8, 2014 at 8:33 AM, Jan Beulich JBeulich@suse.com wrote:
On 08.09.14 at 17:23, Ian.Campbell@citrix.com wrote:
ink On Sun, 2014-09-07 at 20:53 -0700, Roy Franz wrote:
--- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -75,6 +75,13 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32
ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
+# This seems to be required to get parallel builds to work, otherwise prelink-efi.o complains about +# no rule to make boot.init.o
I suppose we must recurse into common and arch at the same time.
+# Not sure what the right fix is
Me neither. This doesn't look right to me though, given that xen/common/efi is also entered via a subdir-y in xen/common/Makefile.
Perhaps Jan has some ideas but I'm wondering if we ought not to recurse into xen/common/efi from here and not from xen/common, or at least to not include extra-$(efi) += boot.init.o in xen/common/efi/Makefile (that would also let the x86 specific checkng code stay here, might it?)
symbols-dummy.o has a similar hack, but notice that it is not build from xen/common/Makefile.
Anyway, I'm flailing, perhaps Jan can suggest the correct fix.
So originally the idea was to sym-link the moved file into its current location, limiting the build recursion to what is being done today.
I think this will be the cleanest - that will allow ARM to use the standard common build stuff, and x86 to do exactly what it did before. I'll do this in the next version.
The only seamless alternative I can see would be to move the whole efi/ subtree to common/ (after all, runtime.c will need to be moved at some point too, and other files should then follow for consistency).
Jan
Move the global variables and functions that can be moved as-is from the common boot.c file to the x86 implementation header file.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 460 ++--------------------------------------- xen/include/asm-x86/efi-boot.h | 455 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 468 insertions(+), 447 deletions(-) create mode 100644 xen/include/asm-x86/efi-boot.h
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 14e2f46..ca604be 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -18,16 +18,6 @@ #include <xen/string.h> #include <xen/stringify.h> #include <xen/vga.h> -#include <asm/e820.h> -#include <asm/edd.h> -#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ -#include <asm/fixmap.h> -#undef __ASSEMBLY__ -#include <asm/msr.h> -#include <asm/processor.h> - -/* Using SetVirtualAddressMap() is incompatible with kexec: */ -#undef USE_SET_VIRTUAL_ADDRESS_MAP
#define SHIM_LOCK_PROTOCOL_GUID \ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } @@ -41,8 +31,10 @@ typedef struct { EFI_SHIM_LOCK_VERIFY Verify; } EFI_SHIM_LOCK_PROTOCOL;
-extern char start[]; -extern u32 cpuid_ext_features; +static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer); +static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer); +static void __init DisplayUint(UINT64 Val, INTN Width); +static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s);
union string { CHAR16 *w; @@ -69,19 +61,18 @@ static UINT32 __initdata mdesc_ver; static struct file __initdata cfg; static struct file __initdata kernel; static struct file __initdata ramdisk; -static struct file __initdata ucode; 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)
+/* + * Include architecture specific implementation here, which references the + * static globals defined above. + */ +#include <asm/efi-boot.h> + static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer) { if ( Val >= 10 ) @@ -255,32 +246,6 @@ static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode) 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) { @@ -574,104 +539,6 @@ static void __init split_value(char *s) *s = 0; }
-static void __init edd_put_string(u8 *dst, size_t n, const char *src) -{ - while ( n-- && *src ) - *dst++ = *src++; - if ( *src ) - PrintErrMesg(L"Internal error populating EDD info", - EFI_BUFFER_TOO_SMALL); - while ( n-- ) - *dst++ = ' '; -} -#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) - -static void __init setup_efi_pci(void) -{ - EFI_STATUS status; - EFI_HANDLE *handles; - static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL; - UINTN i, nr_pci, size = 0; - struct efi_pci_rom *last = NULL; - - status = efi_bs->LocateHandle(ByProtocol, &pci_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, &pci_guid, NULL, &size, - handles); - if ( EFI_ERROR(status) ) - size = 0; - - nr_pci = size / sizeof(*handles); - for ( i = 0; i < nr_pci; ++i ) - { - EFI_PCI_IO *pci = NULL; - u64 attributes; - struct efi_pci_rom *rom, *va; - UINTN segment, bus, device, function; - - status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci); - if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize ) - continue; - - status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0, - &attributes); - if ( EFI_ERROR(status) || - !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) || - EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device, - &function)) ) - continue; - - DisplayUint(segment, 4); - PrintStr(L":"); - DisplayUint(bus, 2); - PrintStr(L":"); - DisplayUint(device, 2); - PrintStr(L"."); - DisplayUint(function, 1); - PrintStr(L": ROM: "); - DisplayUint(pci->RomSize, 0); - PrintStr(L" bytes at "); - DisplayUint((UINTN)pci->RomImage, 0); - PrintStr(newline); - - size = pci->RomSize + sizeof(*rom); - status = efi_bs->AllocatePool(EfiRuntimeServicesData, size, - (void **)&rom); - if ( EFI_ERROR(status) ) - continue; - - rom->next = NULL; - rom->size = pci->RomSize; - - status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, - &rom->vendor); - if ( !EFI_ERROR(status) ) - status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, - &rom->devid); - if ( EFI_ERROR(status) ) - { - efi_bs->FreePool(rom); - continue; - } - - rom->segment = segment; - rom->bus = bus; - rom->devfn = (device << 3) | function; - memcpy(rom->data, pci->RomImage, pci->RomSize); - - va = (void *)rom + DIRECTMAP_VIRT_START; - if ( last ) - last->next = va; - else - efi_pci_roms = va; - last = rom; - } - - efi_bs->FreePool(handles); -} - static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz) { if ( bpp < 0 ) @@ -687,82 +554,6 @@ static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz) return max(*pos + *sz, bpp); }
-extern const intpte_t __page_tables_start[], __page_tables_end[]; -#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ - (intpte_t *)(v) < __page_tables_end) - -#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; - if ( in_page_tables(addr) ) - *(u32 *)addr += xen_phys_start; - } - break; - case PE_BASE_RELOC_DIR64: - if ( delta ) - { - *(u64 *)addr += delta; - if ( in_page_tables(addr) ) - *(intpte_t *)addr += xen_phys_start; - } - break; - default: - blexit(L"Unsupported relocation type"); - } - } - base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); - } -} - -extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; -extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; - -static void __init relocate_trampoline(unsigned long phys) -{ - const s32 *trampoline_ptr; - - trampoline_phys = phys; - /* Apply relocations to trampoline. */ - for ( trampoline_ptr = __trampoline_rel_start; - trampoline_ptr < __trampoline_rel_stop; - ++trampoline_ptr ) - *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; - for ( trampoline_ptr = __trampoline_seg_start; - trampoline_ptr < __trampoline_seg_stop; - ++trampoline_ptr ) - *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; -} - void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { @@ -879,7 +670,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintStr(L"Xen " __stringify(XEN_VERSION) "." __stringify(XEN_SUBVERSION) XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n");
- relocate_image(0); + efi_arch_relocate_image(0);
if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode, &cols, &rows) == EFI_SUCCESS ) @@ -1258,7 +1049,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) dmi_efi_get_table((void *)(long)efi.smbios);
/* Collect PCI ROM contents. */ - setup_efi_pci(); + efi_arch_pci();
/* Get snapshot of variable store parameters. */ status = (efi_rs->Hdr.Revision >> 16) >= 2 ? @@ -1460,7 +1251,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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); + efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); memcpy((void *)trampoline_phys, trampoline_start, cfg.size);
/* Set system registers and transfer control. */ @@ -1496,228 +1287,3 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) for( ; ; ); /* not reached */ }
-#ifndef USE_SET_VIRTUAL_ADDRESS_MAP -static __init void copy_mapping(unsigned long mfn, unsigned long end, - bool_t (*is_valid)(unsigned long smfn, - unsigned long emfn)) -{ - unsigned long next; - - for ( ; mfn < end; mfn = next ) - { - l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)]; - l3_pgentry_t *l3src, *l3dst; - unsigned long va = (unsigned long)mfn_to_virt(mfn); - - next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)); - if ( !is_valid(mfn, min(next, end)) ) - continue; - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) - { - l3dst = alloc_xen_pagetable(); - BUG_ON(!l3dst); - clear_page(l3dst); - efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] = - l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR); - } - else - l3dst = l4e_to_l3e(l4e); - l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]); - l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)]; - } -} - -static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn) -{ - unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1; - - return !(smfn & pfn_hole_mask) && - find_next_bit(pdx_group_valid, sz, - pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz; -} - -static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn) -{ - return 1; -} -#endif - -#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \ - (EFI_PAGE_SHIFT + BITS_PER_LONG - 32)) - -void __init efi_init_memory(void) -{ - unsigned int i; -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP - struct rt_extra { - struct rt_extra *next; - unsigned long smfn, emfn; - unsigned int prot; - } *extra, *extra_head = NULL; -#endif - - 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; - - desc->VirtualStart = INVALID_VIRTUAL_ADDRESS; - - smfn = PFN_DOWN(desc->PhysicalStart); - emfn = PFN_UP(desc->PhysicalStart + len); - - 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 ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END ) - prot &= ~_PAGE_GLOBAL; - 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); - } -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP - else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) && - (extra = xmalloc(struct rt_extra)) != NULL ) - { - extra->smfn = smfn; - extra->emfn = emfn; - extra->prot = prot & ~_PAGE_GLOBAL; - extra->next = extra_head; - extra_head = extra; - desc->VirtualStart = desc->PhysicalStart; - } -#endif - else - { -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - /* XXX allocate e.g. down from FIXADDR_START */ -#endif - printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n", - smfn, emfn - 1); - } - } - -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size, - mdesc_ver, efi_memmap); -#else - /* Set up 1:1 page tables to do runtime calls in "physical" mode. */ - efi_l4_pgtable = alloc_xen_pagetable(); - BUG_ON(!efi_l4_pgtable); - clear_page(efi_l4_pgtable); - - copy_mapping(0, max_page, ram_range_valid); - - /* Insert non-RAM runtime mappings inside the direct map. */ - for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) - { - const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; - - if ( (desc->Attribute & EFI_MEMORY_RUNTIME) && - desc->VirtualStart != INVALID_VIRTUAL_ADDRESS && - desc->VirtualStart != desc->PhysicalStart ) - copy_mapping(PFN_DOWN(desc->PhysicalStart), - PFN_UP(desc->PhysicalStart + - (desc->NumberOfPages << EFI_PAGE_SHIFT)), - rt_range_valid); - } - - /* Insert non-RAM runtime mappings outside of the direct map. */ - while ( (extra = extra_head) != NULL ) - { - unsigned long addr = extra->smfn << PAGE_SHIFT; - l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)]; - l3_pgentry_t *pl3e; - l2_pgentry_t *pl2e; - l1_pgentry_t *l1t; - - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) - { - pl3e = alloc_xen_pagetable(); - BUG_ON(!pl3e); - clear_page(pl3e); - efi_l4_pgtable[l4_table_offset(addr)] = - l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR); - } - else - pl3e = l4e_to_l3e(l4e); - pl3e += l3_table_offset(addr); - if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) - { - pl2e = alloc_xen_pagetable(); - BUG_ON(!pl2e); - clear_page(pl2e); - *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR); - } - else - { - BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE); - pl2e = l3e_to_l2e(*pl3e); - } - pl2e += l2_table_offset(addr); - if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) - { - l1t = alloc_xen_pagetable(); - BUG_ON(!l1t); - clear_page(l1t); - *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR); - } - else - { - BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE); - l1t = l2e_to_l1e(*pl2e); - } - for ( i = l1_table_offset(addr); - i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn; - ++i, ++extra->smfn ) - l1t[i] = l1e_from_pfn(extra->smfn, extra->prot); - - if ( extra->smfn == extra->emfn ) - { - extra_head = extra->next; - xfree(extra); - } - } - - /* Insert Xen mappings. */ - for ( i = l4_table_offset(HYPERVISOR_VIRT_START); - i < l4_table_offset(DIRECTMAP_VIRT_END); ++i ) - efi_l4_pgtable[i] = idle_pg_table[i]; -#endif -} diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h new file mode 100644 index 0000000..5b91697 --- /dev/null +++ b/xen/include/asm-x86/efi-boot.h @@ -0,0 +1,455 @@ +/* + * Architecture specific implementation for EFI boot code. This file + * is intended to be included by XXX _only_, and therefore can define + * arch specific global variables. + */ +#include <asm/e820.h> +#include <asm/edd.h> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ +#include <asm/fixmap.h> +#undef __ASSEMBLY__ +#include <asm/msr.h> +#include <asm/processor.h> + +static struct file __initdata ucode; +static multiboot_info_t __initdata mbi = { + .flags = MBI_MODULES | MBI_LOADERNAME +}; +static module_t __initdata mb_modules[3]; + +static void noreturn blexit(const CHAR16 *str); +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode); + +/* Using SetVirtualAddressMap() is incompatible with kexec: */ +#undef USE_SET_VIRTUAL_ADDRESS_MAP +extern char start[]; +extern u32 cpuid_ext_features; + +static void __init edd_put_string(u8 *dst, size_t n, const char *src) +{ + while ( n-- && *src ) + *dst++ = *src++; + if ( *src ) + PrintErrMesg(L"Internal error populating EDD info", + EFI_BUFFER_TOO_SMALL); + while ( n-- ) + *dst++ = ' '; +} +#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) + +static void __init efi_arch_pci(void) +{ + EFI_STATUS status; + EFI_HANDLE *handles; + static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL; + UINTN i, nr_pci, size = 0; + struct efi_pci_rom *last = NULL; + + status = efi_bs->LocateHandle(ByProtocol, &pci_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, &pci_guid, NULL, &size, + handles); + if ( EFI_ERROR(status) ) + size = 0; + + nr_pci = size / sizeof(*handles); + for ( i = 0; i < nr_pci; ++i ) + { + EFI_PCI_IO *pci = NULL; + u64 attributes; + struct efi_pci_rom *rom, *va; + UINTN segment, bus, device, function; + + status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci); + if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize ) + continue; + + status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0, + &attributes); + if ( EFI_ERROR(status) || + !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) || + EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device, + &function)) ) + continue; + + DisplayUint(segment, 4); + PrintStr(L":"); + DisplayUint(bus, 2); + PrintStr(L":"); + DisplayUint(device, 2); + PrintStr(L"."); + DisplayUint(function, 1); + PrintStr(L": ROM: "); + DisplayUint(pci->RomSize, 0); + PrintStr(L" bytes at "); + DisplayUint((UINTN)pci->RomImage, 0); + PrintStr(newline); + + size = pci->RomSize + sizeof(*rom); + status = efi_bs->AllocatePool(EfiRuntimeServicesData, size, + (void **)&rom); + if ( EFI_ERROR(status) ) + continue; + + rom->next = NULL; + rom->size = pci->RomSize; + + status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, + &rom->vendor); + if ( !EFI_ERROR(status) ) + status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, + &rom->devid); + if ( EFI_ERROR(status) ) + { + efi_bs->FreePool(rom); + continue; + } + + rom->segment = segment; + rom->bus = bus; + rom->devfn = (device << 3) | function; + memcpy(rom->data, pci->RomImage, pci->RomSize); + + va = (void *)rom + DIRECTMAP_VIRT_START; + if ( last ) + last->next = va; + else + efi_pci_roms = va; + last = rom; + } + + efi_bs->FreePool(handles); +} + + +extern const intpte_t __page_tables_start[], __page_tables_end[]; +#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ + (intpte_t *)(v) < __page_tables_end) + +#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 efi_arch_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; + if ( in_page_tables(addr) ) + *(u32 *)addr += xen_phys_start; + } + break; + case PE_BASE_RELOC_DIR64: + if ( delta ) + { + *(u64 *)addr += delta; + if ( in_page_tables(addr) ) + *(intpte_t *)addr += xen_phys_start; + } + break; + default: + blexit(L"Unsupported relocation type"); + } + } + base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); + } +} + +extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; +extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; + +static void __init relocate_trampoline(unsigned long phys) +{ + const s32 *trampoline_ptr; + + trampoline_phys = phys; + /* Apply relocations to trampoline. */ + for ( trampoline_ptr = __trampoline_rel_start; + trampoline_ptr < __trampoline_rel_stop; + ++trampoline_ptr ) + *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; + for ( trampoline_ptr = __trampoline_seg_start; + trampoline_ptr < __trampoline_seg_stop; + ++trampoline_ptr ) + *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; +} + + +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP +static __init void copy_mapping(unsigned long mfn, unsigned long end, + bool_t (*is_valid)(unsigned long smfn, + unsigned long emfn)) +{ + unsigned long next; + + for ( ; mfn < end; mfn = next ) + { + l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)]; + l3_pgentry_t *l3src, *l3dst; + unsigned long va = (unsigned long)mfn_to_virt(mfn); + + next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)); + if ( !is_valid(mfn, min(next, end)) ) + continue; + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) + { + l3dst = alloc_xen_pagetable(); + BUG_ON(!l3dst); + clear_page(l3dst); + efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] = + l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR); + } + else + l3dst = l4e_to_l3e(l4e); + l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]); + l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)]; + } +} + +static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn) +{ + unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1; + + return !(smfn & pfn_hole_mask) && + find_next_bit(pdx_group_valid, sz, + pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz; +} + +static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn) +{ + return 1; +} +#endif + +#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \ + (EFI_PAGE_SHIFT + BITS_PER_LONG - 32)) + +void __init efi_init_memory(void) +{ + unsigned int i; +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP + struct rt_extra { + struct rt_extra *next; + unsigned long smfn, emfn; + unsigned int prot; + } *extra, *extra_head = NULL; +#endif + + 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; + + desc->VirtualStart = INVALID_VIRTUAL_ADDRESS; + + smfn = PFN_DOWN(desc->PhysicalStart); + emfn = PFN_UP(desc->PhysicalStart + len); + + 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 ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END ) + prot &= ~_PAGE_GLOBAL; + 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); + } +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP + else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) && + (extra = xmalloc(struct rt_extra)) != NULL ) + { + extra->smfn = smfn; + extra->emfn = emfn; + extra->prot = prot & ~_PAGE_GLOBAL; + extra->next = extra_head; + extra_head = extra; + desc->VirtualStart = desc->PhysicalStart; + } +#endif + else + { +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + /* XXX allocate e.g. down from FIXADDR_START */ +#endif + printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n", + smfn, emfn - 1); + } + } + +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size, + mdesc_ver, efi_memmap); +#else + /* Set up 1:1 page tables to do runtime calls in "physical" mode. */ + efi_l4_pgtable = alloc_xen_pagetable(); + BUG_ON(!efi_l4_pgtable); + clear_page(efi_l4_pgtable); + + copy_mapping(0, max_page, ram_range_valid); + + /* Insert non-RAM runtime mappings inside the direct map. */ + for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) + { + const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; + + if ( (desc->Attribute & EFI_MEMORY_RUNTIME) && + desc->VirtualStart != INVALID_VIRTUAL_ADDRESS && + desc->VirtualStart != desc->PhysicalStart ) + copy_mapping(PFN_DOWN(desc->PhysicalStart), + PFN_UP(desc->PhysicalStart + + (desc->NumberOfPages << EFI_PAGE_SHIFT)), + rt_range_valid); + } + + /* Insert non-RAM runtime mappings outside of the direct map. */ + while ( (extra = extra_head) != NULL ) + { + unsigned long addr = extra->smfn << PAGE_SHIFT; + l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)]; + l3_pgentry_t *pl3e; + l2_pgentry_t *pl2e; + l1_pgentry_t *l1t; + + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) + { + pl3e = alloc_xen_pagetable(); + BUG_ON(!pl3e); + clear_page(pl3e); + efi_l4_pgtable[l4_table_offset(addr)] = + l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR); + } + else + pl3e = l4e_to_l3e(l4e); + pl3e += l3_table_offset(addr); + if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) + { + pl2e = alloc_xen_pagetable(); + BUG_ON(!pl2e); + clear_page(pl2e); + *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR); + } + else + { + BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE); + pl2e = l3e_to_l2e(*pl3e); + } + pl2e += l2_table_offset(addr); + if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) + { + l1t = alloc_xen_pagetable(); + BUG_ON(!l1t); + clear_page(l1t); + *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR); + } + else + { + BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE); + l1t = l2e_to_l1e(*pl2e); + } + for ( i = l1_table_offset(addr); + i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn; + ++i, ++extra->smfn ) + l1t[i] = l1e_from_pfn(extra->smfn, extra->prot); + + if ( extra->smfn == extra->emfn ) + { + extra_head = extra->next; + xfree(extra); + } + } + + /* Insert Xen mappings. */ + for ( i = l4_table_offset(HYPERVISOR_VIRT_START); + i < l4_table_offset(DIRECTMAP_VIRT_END); ++i ) + efi_l4_pgtable[i] = idle_pg_table[i]; +#endif +} + +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; +} +
The memory used to store the EFI memory map is allocated in an architecture specific way, and the processing of the memory map itself uses x86 specific data structures. This patch adds architecture specific funtions so each architecture can provide its own implementation.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 75 +++++------------------------------- xen/include/asm-x86/efi-boot.h | 86 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 68 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index ca604be..16ffe35 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -56,8 +56,6 @@ 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; @@ -566,16 +564,18 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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; + UINTN cols, rows, depth, size, info_size, gop_mode = ~0; EFI_HANDLE *handles = NULL; EFI_SHIM_LOCK_PROTOCOL *shim_lock; 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; + UINT32 mmap_desc_ver = 0; + UINTN mmap_size, mmap_desc_size, mmap_key = 0; + void *mmap;
efi_ih = ImageHandle; efi_bs = SystemTable->BootServices; @@ -875,8 +875,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) mbi.boot_loader_name = (long)"EFI"; mbi.mods_addr = (long)mb_modules;
- place_string(&mbi.mem_upper, NULL); - /* Collect EDD info. */ BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); @@ -1171,67 +1169,12 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } }
- 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"); - 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) ) - PrintErrMesg(L"Cannot obtain memory map", status); + efi_arch_get_memory_map(&mmap_size, &mmap, &mmap_key, + &mmap_desc_size, &mmap_desc_ver);
- /* 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; + efi_arch_process_memory_map(SystemTable, mmap, mmap_size, + mmap_desc_size, mmap_desc_ver);
- switch ( desc->Type ) - { - default: - type = E820_RESERVED; - break; - case EfiConventionalMemory: - case EfiBootServicesCode: - case EfiBootServicesData: - if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 && - len >= cfg.size && desc->PhysicalStart + len > cfg.addr ) - cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK; - /* fall through */ - case EfiLoaderCode: - case EfiLoaderData: - 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 ( !trampoline_phys ) { if ( !cfg.addr ) @@ -1239,7 +1182,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) relocate_trampoline(cfg.addr); }
- status = efi_bs->ExitBootServices(ImageHandle, map_key); + status = efi_bs->ExitBootServices(ImageHandle, mmap_key); if ( EFI_ERROR(status) ) PrintErrMesg(L"Cannot exit boot services", status);
diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index 5b91697..179efbb 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -123,7 +123,6 @@ static void __init efi_arch_pci(void) efi_bs->FreePool(handles); }
- extern const intpte_t __page_tables_start[], __page_tables_end[]; #define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ (intpte_t *)(v) < __page_tables_end) @@ -200,7 +199,6 @@ static void __init relocate_trampoline(unsigned long phys) *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; }
- #ifndef USE_SET_VIRTUAL_ADDRESS_MAP static __init void copy_mapping(unsigned long mfn, unsigned long end, bool_t (*is_valid)(unsigned long smfn, @@ -453,3 +451,87 @@ static void __init place_string(u32 *addr, const char *s) *addr = (long)alloc; }
+static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, + void *map, + UINTN map_size, + UINTN desc_size, + UINT32 desc_ver) +{ + struct e820entry *e; + int i; + + /* Set global EFI memory map variables */ + efi_memmap_size = map_size; + efi_mdesc_size = desc_size; + efi_memmap = map; + + /* Populate E820 table and check trampoline area availability. */ + e = e820map - 1; + for ( i = 0; i < map_size; i += desc_size ) + { + EFI_MEMORY_DESCRIPTOR *desc = map + i; + u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT; + u32 type; + + switch ( desc->Type ) + { + default: + type = E820_RESERVED; + break; + case EfiConventionalMemory: + case EfiBootServicesCode: + case EfiBootServicesData: + if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 && + len >= cfg.size && desc->PhysicalStart + len > cfg.addr ) + cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK; + /* fall through */ + case EfiLoaderCode: + case EfiLoaderData: + 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; + } + } + +} +static void __init efi_arch_get_memory_map(UINTN *map_size, + void **map, + UINTN *map_key, UINTN *desc_size, + UINT32 *desc_ver) +{ + EFI_STATUS status; + efi_bs->GetMemoryMap(map_size, NULL, map_key, + desc_size, desc_ver); + place_string(&mbi.mem_upper, NULL); + mbi.mem_upper -= *map_size; + mbi.mem_upper &= -__alignof__(EFI_MEMORY_DESCRIPTOR); + if ( mbi.mem_upper < xen_phys_start ) + blexit(L"Out of static memory"); + *map = (void *)(long)mbi.mem_upper; + status = efi_bs->GetMemoryMap(map_size, *map, map_key, + desc_size, desc_ver); + if ( EFI_ERROR(status) ) + PrintErrMesg(L"Cannot obtain memory map", status); +}
The UEFI ExitBootServices function is invoked to transition the system to the 'runtime' mode of operation, and is done right before transitioning from the EFI loader code into XEN proper. x86 does some arch specific memory management (trampoline) before exit boot services, and the code that transitions from the EFI application state to XEN is architecture specific. This patch adds two functions, one pre and one post ExitBootServices to allow each architecture to to handle these cases in a customized manner.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 50 ++----------------------------------- xen/include/asm-x86/efi-boot.h | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 48 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 16ffe35..ca86beb 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -571,7 +571,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; EFI_FILE_HANDLE dir_handle; union string section = { NULL }, name; - u64 efer; bool_t base_video = 0; UINT32 mmap_desc_ver = 0; UINTN mmap_size, mmap_desc_size, mmap_key = 0; @@ -1175,58 +1174,13 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_arch_process_memory_map(SystemTable, mmap, mmap_size, mmap_desc_size, mmap_desc_ver);
- if ( !trampoline_phys ) - { - if ( !cfg.addr ) - blexit(L"No memory for trampoline"); - relocate_trampoline(cfg.addr); - } + efi_arch_pre_exit_boot();
status = efi_bs->ExitBootServices(ImageHandle, mmap_key); if ( EFI_ERROR(status) ) PrintErrMesg(L"Cannot exit boot services", status);
- /* Adjust pointers into EFI. */ - efi_ct = (void *)efi_ct + DIRECTMAP_VIRT_START; -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - 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; - - efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); - memcpy((void *)trampoline_phys, 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" - "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" ); + efi_arch_post_exit_boot(); for( ; ; ); /* not reached */ }
diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index 179efbb..08ff9a5 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -535,3 +535,59 @@ static void __init efi_arch_get_memory_map(UINTN *map_size, if ( EFI_ERROR(status) ) PrintErrMesg(L"Cannot obtain memory map", status); } +static void __init efi_arch_pre_exit_boot(void) +{ + if ( !trampoline_phys ) + { + if ( !cfg.addr ) + blexit(L"No memory for trampoline"); + relocate_trampoline(cfg.addr); + } +} + +static void __init efi_arch_post_exit_boot(void) +{ + u64 efer; + + /* Adjust pointers into EFI. */ + efi_ct = (void *)efi_ct + DIRECTMAP_VIRT_START; +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + 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; + + efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); + memcpy((void *)trampoline_phys, 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" + "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" ); +}
Different architectures have some different configuration file fields that need to be handled. In particular, x86 has ucode and ARM has device tree files to be loaded. This arch specific function is used to allow each architecture to implement these features in arch specific code.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 30 ++++++++++++++---------------- xen/include/asm-x86/efi-boot.h | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index ca86beb..a33a8f6 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -31,11 +31,6 @@ typedef struct { EFI_SHIM_LOCK_VERIFY Verify; } EFI_SHIM_LOCK_PROTOCOL;
-static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer); -static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer); -static void __init DisplayUint(UINT64 Val, INTN Width); -static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s); - union string { CHAR16 *w; char *s; @@ -50,6 +45,17 @@ struct file { }; };
+static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer); +static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer); +static void __init DisplayUint(UINT64 Val, INTN Width); +static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s); +static char *__init get_value(const struct file *cfg, const char *section, + const char *item); +static void __init split_value(char *s); +static CHAR16 *__init s2w(union string *str); +static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, + struct file *file); + static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih;
@@ -752,6 +758,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } if ( !name.s ) blexit(L"No Dom0 kernel image specified."); + + efi_arch_cfg_file(dir_handle, section.s); + split_value(name.s); read_file(dir_handle, s2w(&name), &kernel); efi_bs->FreePool(name.w); @@ -769,17 +778,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_bs->FreePool(name.w); }
- name.s = get_value(&cfg, section.s, "ucode"); - if ( !name.s ) - name.s = get_value(&cfg, "global", "ucode"); - if ( name.s ) - { - microcode_set_module(mbi.mods_count); - split_value(name.s); - read_file(dir_handle, s2w(&name), &ucode); - efi_bs->FreePool(name.w); - } - name.s = get_value(&cfg, section.s, "xsm"); if ( name.s ) { diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index 08ff9a5..42b087e 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -591,3 +591,18 @@ static void __init efi_arch_post_exit_boot(void) "D" (&mbi) : "memory" ); } + +static void __init efi_arch_cfg_file(EFI_FILE_HANDLE dir_handle, char *section) +{ + union string name; + name.s = get_value(&cfg, section, "ucode"); + if ( !name.s ) + name.s = get_value(&cfg, "global", "ucode"); + if ( name.s ) + { + microcode_set_module(mbi.mods_count); + split_value(name.s); + read_file(dir_handle, s2w(&name), &ucode); + efi_bs->FreePool(name.w); + } +}
Add arch function for processing the XEN commandline and updating internal structures.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 41 +++++++++++------------------------------ xen/include/asm-x86/efi-boot.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 30 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index a33a8f6..fd9d382 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -53,6 +53,7 @@ static char *__init get_value(const struct file *cfg, const char *section, const char *item); static void __init split_value(char *s); static CHAR16 *__init s2w(union string *str); +static char *__init w2s(const union string *str); static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, struct file *file);
@@ -251,7 +252,8 @@ static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode) }
static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv, - CHAR16 *cmdline, UINTN cmdsize) + CHAR16 *cmdline, UINTN cmdsize, + CHAR16 **options) { CHAR16 *ptr = (CHAR16 *)(argv + argc + 1), *prev = NULL; bool_t prev_sep = TRUE; @@ -277,10 +279,8 @@ static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv, ++argc; else if ( prev && wstrcmp(prev, L"--") == 0 ) { - union string rest = { .w = cmdline }; - - --argv; - place_string(&mbi.cmdline, w2s(&rest)); + if ( options ) + *options = cmdline; break; } else @@ -569,7 +569,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; unsigned int i, argc; - CHAR16 **argv, *file_name, *cfg_file_name = NULL; + CHAR16 **argv, *file_name, *cfg_file_name = NULL, *options = NULL; UINTN cols, rows, depth, size, info_size, gop_mode = ~0; EFI_HANDLE *handles = NULL; EFI_SHIM_LOCK_PROTOCOL *shim_lock; @@ -610,14 +610,14 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) dir_handle = get_parent_handle(loaded_image, &file_name);
argc = get_argv(0, NULL, loaded_image->LoadOptions, - loaded_image->LoadOptionsSize); + loaded_image->LoadOptionsSize, &options); 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); + loaded_image->LoadOptionsSize, &options); else argc = 0; for ( i = 1; i < argc; ++i ) @@ -786,19 +786,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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 ) { @@ -817,6 +804,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } }
+ name.s = get_value(&cfg, section.s, "options"); + efi_arch_handle_cmdline(argc ? *argv : NULL, options, name.s); + efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); cfg.addr = 0;
@@ -863,15 +853,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } }
- 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; - /* Collect EDD info. */ BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index 42b087e..dea9be3 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -606,3 +606,36 @@ static void __init efi_arch_cfg_file(EFI_FILE_HANDLE dir_handle, char *section) efi_bs->FreePool(name.w); } } +static void __init efi_arch_handle_cmdline(CHAR16 *image_name, + CHAR16 *cmdline_options, + char *cfgfile_options) +{ + union string name; + + if ( cmdline_options ) + { + name.w = cmdline_options; + w2s(&name); + place_string(&mbi.cmdline, name.s); + } + if ( cfgfile_options ) + place_string(&mbi.cmdline, cfgfile_options); + /* Insert image name last, as it gets prefixed to the other options. */ + if ( image_name ) + { + name.w = image_name; + w2s(&name); + } + else + name.s = "xen"; + place_string(&mbi.cmdline, name.s); + + 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; +}
Move x86 specific video (VGA) and disk (EDD) probing to arch specific file. This code is x86 only, so move it to arch specific code. The efi_arch_edd() and efi_arch_video() will be empty for ARM.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 284 +-------------------------------------- xen/include/asm-x86/efi-boot.h | 298 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+), 281 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index fd9d382..3fe04fd 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -543,34 +543,17 @@ static void __init split_value(char *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); -} - void EFIAPI __init 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; - static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL; - static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL; static EFI_GUID __initdata shim_lock_guid = SHIM_LOCK_PROTOCOL_GUID; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; unsigned int i, argc; CHAR16 **argv, *file_name, *cfg_file_name = NULL, *options = NULL; - UINTN cols, rows, depth, size, info_size, gop_mode = ~0; + UINTN cols, rows, depth, size, info_size; EFI_HANDLE *handles = NULL; EFI_SHIM_LOCK_PROTOCOL *shim_lock; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL; @@ -677,15 +660,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
efi_arch_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 ) @@ -811,189 +785,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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; - } - } - } - - /* Collect EDD info. */ - BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); - BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); - size = 0; - status = efi_bs->LocateHandle(ByProtocol, &bio_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, &bio_guid, NULL, &size, - handles); - if ( EFI_ERROR(status) ) - size = 0; - for ( i = 0; i < size / sizeof(*handles); ++i ) - { - EFI_BLOCK_IO *bio; - EFI_DEV_PATH_PTR devp; - struct edd_info *info = boot_edd_info + boot_edd_info_nr; - struct edd_device_params *params = &info->edd_device_params; - enum { root, acpi, pci, ctrlr } state = root; - - status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio); - if ( EFI_ERROR(status) || - bio->Media->RemovableMedia || - bio->Media->LogicalPartition ) - continue; - if ( boot_edd_info_nr < EDD_INFO_MAX ) - { - info->device = 0x80 + boot_edd_info_nr; /* fake */ - info->version = 0x11; - params->length = offsetof(struct edd_device_params, dpte_ptr); - params->number_of_sectors = bio->Media->LastBlock + 1; - params->bytes_per_sector = bio->Media->BlockSize; - params->dpte_ptr = ~0; - } - ++boot_edd_info_nr; - status = efi_bs->HandleProtocol(handles[i], &devp_guid, - (void **)&devp); - if ( EFI_ERROR(status) ) - continue; - for ( ; !IsDevicePathEnd(devp.DevPath); - devp.DevPath = NextDevicePathNode(devp.DevPath) ) - { - switch ( DevicePathType(devp.DevPath) ) - { - const u8 *p; - - case ACPI_DEVICE_PATH: - if ( state != root || boot_edd_info_nr > EDD_INFO_MAX ) - break; - switch ( DevicePathSubType(devp.DevPath) ) - { - case ACPI_DP: - if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) && - devp.Acpi->HID != EISA_PNP_ID(0xA08) ) - break; - params->interface_path.pci.bus = devp.Acpi->UID; - state = acpi; - break; - case EXPANDED_ACPI_DP: - /* XXX */ - break; - } - break; - case HARDWARE_DEVICE_PATH: - if ( state != acpi || - DevicePathSubType(devp.DevPath) != HW_PCI_DP || - boot_edd_info_nr > EDD_INFO_MAX ) - break; - state = pci; - edd_put_string(params->host_bus_type, "PCI"); - params->interface_path.pci.slot = devp.Pci->Device; - params->interface_path.pci.function = devp.Pci->Function; - break; - case MESSAGING_DEVICE_PATH: - if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX ) - break; - state = ctrlr; - switch ( DevicePathSubType(devp.DevPath) ) - { - case MSG_ATAPI_DP: - edd_put_string(params->interface_type, "ATAPI"); - params->interface_path.pci.channel = - devp.Atapi->PrimarySecondary; - params->device_path.atapi.device = devp.Atapi->SlaveMaster; - params->device_path.atapi.lun = devp.Atapi->Lun; - break; - case MSG_SCSI_DP: - edd_put_string(params->interface_type, "SCSI"); - params->device_path.scsi.id = devp.Scsi->Pun; - params->device_path.scsi.lun = devp.Scsi->Lun; - break; - case MSG_FIBRECHANNEL_DP: - edd_put_string(params->interface_type, "FIBRE"); - params->device_path.fibre.wwid = devp.FibreChannel->WWN; - params->device_path.fibre.lun = devp.FibreChannel->Lun; - break; - case MSG_1394_DP: - edd_put_string(params->interface_type, "1394"); - params->device_path.i1394.eui = devp.F1394->Guid; - break; - case MSG_USB_DP: - case MSG_USB_CLASS_DP: - edd_put_string(params->interface_type, "USB"); - break; - case MSG_I2O_DP: - edd_put_string(params->interface_type, "I2O"); - params->device_path.i2o.identity_tag = devp.I2O->Tid; - break; - default: - continue; - } - info->version = 0x30; - params->length = sizeof(struct edd_device_params); - params->key = 0xbedd; - params->device_path_info_length = - sizeof(struct edd_device_params) - - offsetof(struct edd_device_params, key); - for ( p = (const u8 *)¶ms->key; p < ¶ms->checksum; ++p ) - params->checksum -= *p; - break; - case MEDIA_DEVICE_PATH: - if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP && - devp.HardDrive->MBRType == MBR_TYPE_PCAT && - boot_mbr_signature_nr < EDD_MBR_SIG_MAX ) - { - struct mbr_signature *sig = boot_mbr_signature + - boot_mbr_signature_nr; - - sig->device = 0x80 + boot_edd_info_nr; /* fake */ - memcpy(&sig->signature, devp.HardDrive->Signature, - sizeof(sig->signature)); - ++boot_mbr_signature_nr; - } - break; - } - } - } - if ( handles ) - efi_bs->FreePool(handles); - if ( boot_edd_info_nr > EDD_INFO_MAX ) - boot_edd_info_nr = EDD_INFO_MAX; + efi_arch_edd();
/* XXX Collect EDID info. */
@@ -1075,77 +867,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) l3_bootmap[l3_table_offset(xen_phys_start + (8 << L2_PAGETABLE_SHIFT) - 1)] = l3e_from_paddr((UINTN)l2_bootmap, __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!\r\n"); - 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; - } - } + efi_arch_video(base_video, cols, rows, depth, gop);
efi_arch_get_memory_map(&mmap_size, &mmap, &mmap_key, &mmap_desc_size, &mmap_desc_ver); diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index dea9be3..711ab12 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -639,3 +639,301 @@ static void __init efi_arch_handle_cmdline(CHAR16 *image_name, mbi.boot_loader_name = (long)"EFI"; mbi.mods_addr = (long)mb_modules; } +static void __init efi_arch_edd(void) +{ + static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL; + static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL; + EFI_HANDLE *handles = NULL; + int i; + UINTN size; + EFI_STATUS status; + + /* Collect EDD info. */ + BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); + BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); + size = 0; + status = efi_bs->LocateHandle(ByProtocol, &bio_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, &bio_guid, NULL, &size, + handles); + if ( EFI_ERROR(status) ) + size = 0; + for ( i = 0; i < size / sizeof(*handles); ++i ) + { + EFI_BLOCK_IO *bio; + EFI_DEV_PATH_PTR devp; + struct edd_info *info = boot_edd_info + boot_edd_info_nr; + struct edd_device_params *params = &info->edd_device_params; + enum { root, acpi, pci, ctrlr } state = root; + + status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio); + if ( EFI_ERROR(status) || + bio->Media->RemovableMedia || + bio->Media->LogicalPartition ) + continue; + if ( boot_edd_info_nr < EDD_INFO_MAX ) + { + info->device = 0x80 + boot_edd_info_nr; /* fake */ + info->version = 0x11; + params->length = offsetof(struct edd_device_params, dpte_ptr); + params->number_of_sectors = bio->Media->LastBlock + 1; + params->bytes_per_sector = bio->Media->BlockSize; + params->dpte_ptr = ~0; + } + ++boot_edd_info_nr; + status = efi_bs->HandleProtocol(handles[i], &devp_guid, + (void **)&devp); + if ( EFI_ERROR(status) ) + continue; + for ( ; !IsDevicePathEnd(devp.DevPath); + devp.DevPath = NextDevicePathNode(devp.DevPath) ) + { + switch ( DevicePathType(devp.DevPath) ) + { + const u8 *p; + + case ACPI_DEVICE_PATH: + if ( state != root || boot_edd_info_nr > EDD_INFO_MAX ) + break; + switch ( DevicePathSubType(devp.DevPath) ) + { + case ACPI_DP: + if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) && + devp.Acpi->HID != EISA_PNP_ID(0xA08) ) + break; + params->interface_path.pci.bus = devp.Acpi->UID; + state = acpi; + break; + case EXPANDED_ACPI_DP: + /* XXX */ + break; + } + break; + case HARDWARE_DEVICE_PATH: + if ( state != acpi || + DevicePathSubType(devp.DevPath) != HW_PCI_DP || + boot_edd_info_nr > EDD_INFO_MAX ) + break; + state = pci; + edd_put_string(params->host_bus_type, "PCI"); + params->interface_path.pci.slot = devp.Pci->Device; + params->interface_path.pci.function = devp.Pci->Function; + break; + case MESSAGING_DEVICE_PATH: + if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX ) + break; + state = ctrlr; + switch ( DevicePathSubType(devp.DevPath) ) + { + case MSG_ATAPI_DP: + edd_put_string(params->interface_type, "ATAPI"); + params->interface_path.pci.channel = + devp.Atapi->PrimarySecondary; + params->device_path.atapi.device = devp.Atapi->SlaveMaster; + params->device_path.atapi.lun = devp.Atapi->Lun; + break; + case MSG_SCSI_DP: + edd_put_string(params->interface_type, "SCSI"); + params->device_path.scsi.id = devp.Scsi->Pun; + params->device_path.scsi.lun = devp.Scsi->Lun; + break; + case MSG_FIBRECHANNEL_DP: + edd_put_string(params->interface_type, "FIBRE"); + params->device_path.fibre.wwid = devp.FibreChannel->WWN; + params->device_path.fibre.lun = devp.FibreChannel->Lun; + break; + case MSG_1394_DP: + edd_put_string(params->interface_type, "1394"); + params->device_path.i1394.eui = devp.F1394->Guid; + break; + case MSG_USB_DP: + case MSG_USB_CLASS_DP: + edd_put_string(params->interface_type, "USB"); + break; + case MSG_I2O_DP: + edd_put_string(params->interface_type, "I2O"); + params->device_path.i2o.identity_tag = devp.I2O->Tid; + break; + default: + continue; + } + info->version = 0x30; + params->length = sizeof(struct edd_device_params); + params->key = 0xbedd; + params->device_path_info_length = + sizeof(struct edd_device_params) - + offsetof(struct edd_device_params, key); + for ( p = (const u8 *)¶ms->key; p < ¶ms->checksum; ++p ) + params->checksum -= *p; + break; + case MEDIA_DEVICE_PATH: + if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP && + devp.HardDrive->MBRType == MBR_TYPE_PCAT && + boot_mbr_signature_nr < EDD_MBR_SIG_MAX ) + { + struct mbr_signature *sig = boot_mbr_signature + + boot_mbr_signature_nr; + + sig->device = 0x80 + boot_edd_info_nr; /* fake */ + memcpy(&sig->signature, devp.HardDrive->Signature, + sizeof(sig->signature)); + ++boot_mbr_signature_nr; + } + break; + } + } + } + if ( handles ) + efi_bs->FreePool(handles); + if ( boot_edd_info_nr > EDD_INFO_MAX ) + boot_edd_info_nr = EDD_INFO_MAX; +} + +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); +} + +static void __init efi_arch_video(bool_t base_video, + UINTN cols, UINTN rows, UINTN depth, + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop) +{ + int i; + EFI_STATUS status; + UINTN size, info_size, gop_mode = ~0; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; + + 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 ( 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; + } + + 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!\r\n"); + 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; + } + } +}
This patch adds efi_arch_memory() to allow each architecture a hook to use for do memory setup. x86 uses this for trampoline memory setup and some pagetable setup.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 29 +---------------------------- xen/include/asm-x86/efi-boot.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 28 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 3fe04fd..9ee3b4a 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -838,34 +838,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintStr(newline); }
- /* Allocate space for trampoline (in first Mb). */ - cfg.addr = 0x100000; - cfg.size = trampoline_end - trampoline_start; - status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, - PFN_UP(cfg.size), &cfg.addr); - if ( status == EFI_SUCCESS ) - relocate_trampoline(cfg.addr); - else - { - cfg.addr = 0; - PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); - } - - /* Initialise L2 identity-map and boot-map 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[slot] = 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 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); + efi_arch_memory();
efi_arch_video(base_video, cols, rows, depth, gop);
diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index 711ab12..e1cbdfc 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -937,3 +937,38 @@ static void __init efi_arch_video(bool_t base_video, } } } + +static void __init efi_arch_memory(void) +{ + int i; + EFI_STATUS status; + + /* Allocate space for trampoline (in first Mb). */ + cfg.addr = 0x100000; + cfg.size = trampoline_end - trampoline_start; + status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, + PFN_UP(cfg.size), &cfg.addr); + if ( status == EFI_SUCCESS ) + relocate_trampoline(cfg.addr); + else + { + cfg.addr = 0; + PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); + } + + /* Initialise L2 identity-map and boot-map 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[slot] = 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 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); +}
Each architecture tracks modules differently internally, so add efi_arch_handle_module() routine to enable the common code to invoke the proper handling of modules as the are loaded.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 98 +++++++++++++++++++++++------------------- xen/include/asm-x86/efi-boot.h | 15 +++++-- 2 files changed, 66 insertions(+), 47 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 9ee3b4a..5296d88 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -51,11 +51,10 @@ static void __init DisplayUint(UINT64 Val, INTN Width); static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s); static char *__init get_value(const struct file *cfg, const char *section, const char *item); -static void __init split_value(char *s); static CHAR16 *__init s2w(union string *str); static char *__init w2s(const union string *str); -static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, - struct file *file); +static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, struct file *file, + char *name_options);
static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih; @@ -398,18 +397,39 @@ static CHAR16 *__init point_tail(CHAR16 *fn) break; } } +/* + * Truncate string at first space, and return pointer + * to remainder of string. + */ +static char * __init truncate_string(char *s) +{ + while ( *s && !isspace(*s) ) + ++s; + if ( *s ) + { + *s = 0; + return(s + 1); + } + return(NULL); +}
-static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, - struct file *file) +static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, struct file *file, + char *name_options) { EFI_FILE_HANDLE FileHandle = NULL; UINT64 size; EFI_STATUS ret; CHAR16 *what = NULL; + char *options; + union string name; + + options = truncate_string(name_options);
- if ( !name ) + name.s=name_options; + s2w(&name); + if ( !name.w ) PrintErrMesg(L"No filename", EFI_OUT_OF_RESOURCES); - ret = dir_handle->Open(dir_handle, &FileHandle, name, + ret = dir_handle->Open(dir_handle, &FileHandle, name.w, EFI_FILE_MODE_READ, 0); if ( file == &cfg && ret == EFI_NOT_FOUND ) return 0; @@ -441,20 +461,18 @@ static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, } else { + file->size = size; if ( file != &cfg ) { - PrintStr(name); + PrintStr(name.w); 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; + efi_arch_handle_module(file, name_options, options); }
- file->size = size; ret = FileHandle->Read(FileHandle, &file->size, file->ptr); if ( !EFI_ERROR(ret) && file->size != size ) ret = EFI_ABORTED; @@ -469,7 +487,7 @@ static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, { PrintErr(what); PrintErr(L" failed for "); - PrintErrMesg(name, ret); + PrintErrMesg(name.w, ret); }
return 1; @@ -525,7 +543,13 @@ static char *__init get_value(const struct file *cfg, const char *section, break; default: if ( match && strncmp(ptr, item, ilen) == 0 && ptr[ilen] == '=' ) - return ptr + ilen + 1; + { + ptr += ilen + 1; + /* strip off any leading spaces */ + while ( *ptr && isspace(*ptr) ) + ptr++; + return ptr; + } break; } ptr += strlen(ptr); @@ -533,16 +557,6 @@ static char *__init get_value(const struct file *cfg, const char *section, 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; -} - void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { @@ -552,14 +566,14 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; unsigned int i, argc; - CHAR16 **argv, *file_name, *cfg_file_name = NULL, *options = NULL; + CHAR16 **argv, *options = NULL; UINTN cols, rows, depth, size, info_size; EFI_HANDLE *handles = NULL; EFI_SHIM_LOCK_PROTOCOL *shim_lock; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; EFI_FILE_HANDLE dir_handle; - union string section = { NULL }, name; + union string section = { NULL }, name, file_name, cfg_file_name = {NULL}; bool_t base_video = 0; UINT32 mmap_desc_ver = 0; UINTN mmap_size, mmap_desc_size, mmap_key = 0; @@ -590,7 +604,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) trampoline_xen_phys_start = xen_phys_start;
/* Get the file system interface. */ - dir_handle = get_parent_handle(loaded_image, &file_name); + dir_handle = get_parent_handle(loaded_image, &file_name.w);
argc = get_argv(0, NULL, loaded_image->LoadOptions, loaded_image->LoadOptionsSize, &options); @@ -614,9 +628,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) if ( wstrcmp(ptr + 1, L"basevideo") == 0 ) base_video = 1; else if ( wstrncmp(ptr + 1, L"cfg=", 4) == 0 ) - cfg_file_name = ptr + 5; + cfg_file_name.w = ptr + 5; else if ( i + 1 < argc && wstrcmp(ptr + 1, L"cfg") == 0 ) - cfg_file_name = argv[++i]; + cfg_file_name.w = argv[++i]; else if ( wstrcmp(ptr + 1, L"help") == 0 || (ptr[1] == L'?' && !ptr[2]) ) { @@ -684,24 +698,26 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) gop = NULL;
/* Read and parse the config file. */ - if ( !cfg_file_name ) + if ( !cfg_file_name.w ) { CHAR16 *tail;
- while ( (tail = point_tail(file_name)) != NULL ) + while ( (tail = point_tail(file_name.w)) != NULL ) { wstrcpy(tail, L".cfg"); - if ( read_file(dir_handle, file_name, &cfg) ) + if ( read_file(dir_handle, &cfg, w2s(&file_name)) ) break; *tail = 0; } if ( !tail ) blexit(L"No configuration file found."); PrintStr(L"Using configuration file '"); - PrintStr(file_name); + s2w(&file_name); + PrintStr(file_name.w); PrintStr(L"'\r\n"); + efi_bs->FreePool(file_name.w); } - else if ( !read_file(dir_handle, cfg_file_name, &cfg) ) + else if ( !read_file(dir_handle, &cfg, w2s(&cfg_file_name)) ) blexit(L"Configuration file not found."); pre_parse(&cfg);
@@ -720,7 +736,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) break; efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); cfg.addr = 0; - if ( !read_file(dir_handle, s2w(&name), &cfg) ) + if ( !read_file(dir_handle, &cfg, name.s) ) { PrintStr(L"Chained configuration file '"); PrintStr(name.w); @@ -735,9 +751,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
efi_arch_cfg_file(dir_handle, section.s);
- split_value(name.s); - read_file(dir_handle, s2w(&name), &kernel); - efi_bs->FreePool(name.w); + read_file(dir_handle, &kernel, name.s);
if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, (void **)&shim_lock)) && @@ -747,17 +761,13 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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); + read_file(dir_handle, &ramdisk, name.s); }
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); + read_file(dir_handle, &xsm, name.s); }
cols = rows = depth = 0; diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index e1cbdfc..5684562 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -601,9 +601,7 @@ static void __init efi_arch_cfg_file(EFI_FILE_HANDLE dir_handle, char *section) if ( name.s ) { microcode_set_module(mbi.mods_count); - split_value(name.s); - read_file(dir_handle, s2w(&name), &ucode); - efi_bs->FreePool(name.w); + read_file(dir_handle, &ucode, name.s); } } static void __init efi_arch_handle_cmdline(CHAR16 *image_name, @@ -972,3 +970,14 @@ static void __init efi_arch_memory(void) l3_bootmap[l3_table_offset(xen_phys_start + (8 << L2_PAGETABLE_SHIFT) - 1)] = l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR); } + +static void __init efi_arch_handle_module(struct file *file, char *name, + char *options) +{ + place_string(&mb_modules[mbi.mods_count].string, options); + place_string(&mb_modules[mbi.mods_count].string, ""); + place_string(&mb_modules[mbi.mods_count].string, name); + mb_modules[mbi.mods_count].mod_start = file->addr >> PAGE_SHIFT; + mb_modules[mbi.mods_count].mod_end = file->size; + ++mbi.mods_count; +}
Add architecture specific funtions for setting up SMBIOS and runtime services data structures. These are not fundamentally x86 specific, but ARM currently lacks implementations. These functions may not be needed when ARM SMBIOS and runtime service support is added. Both SMBIOS and EFI runtime service support depend on this EFI boot patch series.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 50 ++++---------------------------------- xen/include/asm-x86/efi-boot.h | 54 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 45 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 5296d88..013597b 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -55,6 +55,8 @@ static CHAR16 *__init s2w(union string *str); static char *__init w2s(const union string *str); static bool_t __init read_file(EFI_FILE_HANDLE dir_handle, struct file *file, char *name_options); +static bool_t __init __maybe_unused match_guid(const EFI_GUID *guid1, + const EFI_GUID *guid2);
static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih; @@ -170,7 +172,7 @@ static char *__init w2s(const union string *str) return str->s; }
-static bool_t __init match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2) +static bool_t __init __maybe_unused match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2) { return guid1->Data1 == guid2->Data1 && guid1->Data2 == guid2->Data2 && @@ -581,12 +583,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
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; @@ -805,49 +801,13 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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 mps_guid = MPS_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(&mps_guid, &efi_ct[i].VendorGuid) ) - efi.mps = (long)efi_ct[i].VendorTable; - if ( match_guid(&smbios_guid, &efi_ct[i].VendorGuid) ) - efi.smbios = (long)efi_ct[i].VendorTable; - } + efi_arch_runtime_setup(SystemTable);
- if (efi.smbios != EFI_INVALID_TABLE_ADDR) - dmi_efi_get_table((void *)(long)efi.smbios); + efi_arch_smbios();
/* Collect PCI ROM contents. */ efi_arch_pci();
- /* Get snapshot of variable store parameters. */ - status = (efi_rs->Hdr.Revision >> 16) >= 2 ? - efi_rs->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - &efi_boot_max_var_store_size, - &efi_boot_remain_var_store_size, - &efi_boot_max_var_size) : - EFI_INCOMPATIBLE_VERSION; - if ( EFI_ERROR(status) ) - { - efi_boot_max_var_store_size = 0; - efi_boot_remain_var_store_size = 0; - efi_boot_max_var_size = status; - PrintStr(L"Warning: Could not query variable store: "); - DisplayUint(status, 0); - PrintStr(newline); - } - efi_arch_memory();
efi_arch_video(base_video, cols, rows, depth, gop); diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index 5684562..f5b7dcd 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -981,3 +981,57 @@ static void __init efi_arch_handle_module(struct file *file, char *name, mb_modules[mbi.mods_count].mod_end = file->size; ++mbi.mods_count; } + +static void __init efi_arch_smbios(void) +{ + if (efi.smbios != EFI_INVALID_TABLE_ADDR) + dmi_efi_get_table((void *)(long)efi.smbios); +} +static void __init efi_arch_runtime_setup(EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS status; + int i; + + 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; + + /* 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 mps_guid = MPS_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(&mps_guid, &efi_ct[i].VendorGuid) ) + efi.mps = (long)efi_ct[i].VendorTable; + if ( match_guid(&smbios_guid, &efi_ct[i].VendorGuid) ) + efi.smbios = (long)efi_ct[i].VendorTable; + } + /* Get snapshot of variable store parameters. */ + status = (efi_rs->Hdr.Revision >> 16) >= 2 ? + efi_rs->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + &efi_boot_max_var_store_size, + &efi_boot_remain_var_store_size, + &efi_boot_max_var_size) : + EFI_INCOMPATIBLE_VERSION; + if ( EFI_ERROR(status) ) + { + efi_boot_max_var_store_size = 0; + efi_boot_remain_var_store_size = 0; + efi_boot_max_var_size = status; + PrintStr(L"Warning: Could not query variable store: "); + DisplayUint(status, 0); + PrintStr(newline); + } +}
Add efi_arch_blexit() for arch specific cleanup on error exit, efi_arch_load_addr_check() to do the arch specific verifications of where the UEFI firmware loaded XEN, and efi_arch_cpu() for probing CPU features.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 18 ++++-------------- xen/include/asm-x86/efi-boot.h | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 013597b..1630dde 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -192,11 +192,11 @@ static void __init noreturn blexit(const CHAR16 *str) efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size)); if ( ramdisk.addr ) efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size)); - if ( ucode.addr ) - efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size)); if ( xsm.addr ) efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size));
+ efi_arch_blexit(); + efi_bs->Exit(efi_ih, EFI_SUCCESS, 0, NULL); unreachable(); /* not reached */ } @@ -592,12 +592,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) 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."); - if ( xen_phys_start & ((1 << L2_PAGETABLE_SHIFT) - 1) ) - blexit(L"Xen must be loaded at a 2Mb boundary."); - trampoline_xen_phys_start = xen_phys_start; + efi_arch_load_addr_check(loaded_image);
/* Get the file system interface. */ dir_handle = get_parent_handle(loaded_image, &file_name.w); @@ -794,12 +789,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_arch_edd();
/* XXX Collect EDID info. */ - - if ( cpuid_eax(0x80000000) > 0x80000000 ) - { - cpuid_ext_features = cpuid_edx(0x80000001); - boot_cpu_data.x86_capability[1] = cpuid_ext_features; - } + efi_arch_cpu();
efi_arch_runtime_setup(SystemTable);
diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index f5b7dcd..d7c6abc 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -982,6 +982,14 @@ static void __init efi_arch_handle_module(struct file *file, char *name, ++mbi.mods_count; }
+static void __init efi_arch_cpu(void) +{ + if ( cpuid_eax(0x80000000) > 0x80000000 ) + { + cpuid_ext_features = cpuid_edx(0x80000001); + boot_cpu_data.x86_capability[1] = cpuid_ext_features; + } +} static void __init efi_arch_smbios(void) { if (efi.smbios != EFI_INVALID_TABLE_ADDR) @@ -1035,3 +1043,18 @@ static void __init efi_arch_runtime_setup(EFI_SYSTEM_TABLE *SystemTable) PrintStr(newline); } } +static void __init efi_arch_blexit(void) +{ + if ( ucode.addr ) + efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size)); +} + +static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image) +{ + xen_phys_start = (UINTN)loaded_image->ImageBase; + if ( (xen_phys_start + loaded_image->ImageSize - 1) >> 32 ) + blexit(L"Xen must be loaded below 4Gb."); + if ( xen_phys_start & ((1 << L2_PAGETABLE_SHIFT) - 1) ) + blexit(L"Xen must be loaded at a 2Mb boundary."); + trampoline_xen_phys_start = xen_phys_start; +}
The x86 EFI build of XEN always uses a configuration file to load modules, but the ARM version can either use a config file to specify the modules, or be loaded by GRUB in which case GRUB loads the modules and adds them to the DTB that is passed to XEN. Add the efi_arch_use_config_file() to indicate if a configuration file is required. For x86, this will always be true. ARM will examine the DTB passed via EFI configuration table (if any), and if it contains module information will use that that not use the configuration file at all.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 169 +++++++++++++++++++++-------------------- xen/include/asm-x86/efi-boot.h | 4 + 2 files changed, 90 insertions(+), 83 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 1630dde..226189d 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -574,8 +574,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_SHIM_LOCK_PROTOCOL *shim_lock; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; - EFI_FILE_HANDLE dir_handle; - union string section = { NULL }, name, file_name, cfg_file_name = {NULL}; + union string section = { NULL }, name = { NULL }, file_name, cfg_file_name = {NULL}; bool_t base_video = 0; UINT32 mmap_desc_ver = 0; UINTN mmap_size, mmap_desc_size, mmap_key = 0; @@ -594,9 +593,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
efi_arch_load_addr_check(loaded_image);
- /* Get the file system interface. */ - dir_handle = get_parent_handle(loaded_image, &file_name.w); - argc = get_argv(0, NULL, loaded_image->LoadOptions, loaded_image->LoadOptionsSize, &options); if ( argc > 0 && @@ -688,104 +684,111 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) if ( EFI_ERROR(status) ) gop = NULL;
- /* Read and parse the config file. */ - if ( !cfg_file_name.w ) + if ( efi_arch_use_config_file(SystemTable) ) { - CHAR16 *tail; + EFI_FILE_HANDLE dir_handle;
- while ( (tail = point_tail(file_name.w)) != NULL ) + /* Get the file system interface. */ + dir_handle = get_parent_handle(loaded_image, &file_name.w); + /* Read and parse the config file. */ + if ( !cfg_file_name.w ) { - wstrcpy(tail, L".cfg"); - if ( read_file(dir_handle, &cfg, w2s(&file_name)) ) - break; - *tail = 0; + CHAR16 *tail; + + while ( (tail = point_tail(file_name.w)) != NULL ) + { + wstrcpy(tail, L".cfg"); + if ( read_file(dir_handle, &cfg, w2s(&file_name)) ) + break; + *tail = 0; + } + if ( !tail ) + blexit(L"No configuration file found."); + PrintStr(L"Using configuration file '"); + s2w(&file_name); + PrintStr(file_name.w); + PrintStr(L"'\r\n"); + efi_bs->FreePool(file_name.w); } - if ( !tail ) - blexit(L"No configuration file found."); - PrintStr(L"Using configuration file '"); - s2w(&file_name); - PrintStr(file_name.w); - PrintStr(L"'\r\n"); - efi_bs->FreePool(file_name.w); - } - else if ( !read_file(dir_handle, &cfg, w2s(&cfg_file_name)) ) - blexit(L"Configuration file not found."); - pre_parse(&cfg); + else if ( !read_file(dir_handle, &cfg, w2s(&cfg_file_name)) ) + blexit(L"Configuration file not found."); + pre_parse(&cfg);
- if ( section.w ) - w2s(§ion); - else - section.s = get_value(&cfg, "global", "default"); + if ( section.w ) + w2s(§ion); + else + section.s = get_value(&cfg, "global", "default");
- for ( ; ; ) - { - name.s = get_value(&cfg, section.s, "kernel"); - if ( name.s ) - break; - name.s = get_value(&cfg, "global", "chain"); - if ( !name.s ) - break; - efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); - cfg.addr = 0; - if ( !read_file(dir_handle, &cfg, name.s) ) + for ( ; ; ) { - PrintStr(L"Chained configuration file '"); - PrintStr(name.w); + name.s = get_value(&cfg, section.s, "kernel"); + if ( name.s ) + break; + name.s = get_value(&cfg, "global", "chain"); + if ( !name.s ) + break; + efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); + cfg.addr = 0; + if ( !read_file(dir_handle, &cfg, name.s) ) + { + PrintStr(L"Chained configuration file '"); + PrintStr(name.w); + efi_bs->FreePool(name.w); + blexit(L"'not found."); + } + pre_parse(&cfg); efi_bs->FreePool(name.w); - blexit(L"'not found."); } - pre_parse(&cfg); - efi_bs->FreePool(name.w); - } - if ( !name.s ) - blexit(L"No Dom0 kernel image specified."); - - efi_arch_cfg_file(dir_handle, section.s); + if ( !name.s ) + blexit(L"No Dom0 kernel image specified.");
- read_file(dir_handle, &kernel, name.s); + efi_arch_cfg_file(dir_handle, section.s);
- if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, - (void **)&shim_lock)) && - (status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS ) + read_file(dir_handle, &kernel, name.s); + if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL, + (void **)&shim_lock)) && + (status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS ) PrintErrMesg(L"Dom0 kernel image could not be verified", status);
- name.s = get_value(&cfg, section.s, "ramdisk"); - if ( name.s ) - { - read_file(dir_handle, &ramdisk, name.s); - } + name.s = get_value(&cfg, section.s, "ramdisk"); + if ( name.s ) + { + read_file(dir_handle, &ramdisk, name.s); + }
- name.s = get_value(&cfg, section.s, "xsm"); - if ( name.s ) - { - read_file(dir_handle, &xsm, name.s); - } + name.s = get_value(&cfg, section.s, "xsm"); + if ( name.s ) + { + read_file(dir_handle, &xsm, 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 = rows = depth = 0; + if ( !base_video ) { - 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; + 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; + } } - } + name.s = get_value(&cfg, section.s, "options");
- name.s = get_value(&cfg, section.s, "options"); - efi_arch_handle_cmdline(argc ? *argv : NULL, options, name.s); + efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); + cfg.addr = 0;
- efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); - cfg.addr = 0; + dir_handle->Close(dir_handle); + + efi_arch_handle_cmdline(argc ? *argv : NULL, options, name.s); + }
- dir_handle->Close(dir_handle); efi_arch_edd();
/* XXX Collect EDID info. */ diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h index d7c6abc..1bd3545 100644 --- a/xen/include/asm-x86/efi-boot.h +++ b/xen/include/asm-x86/efi-boot.h @@ -1058,3 +1058,7 @@ static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image) blexit(L"Xen must be loaded at a 2Mb boundary."); trampoline_xen_phys_start = xen_phys_start; } +static __init bool_t efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable) +{ + return 1; /* x86 always uses a config file */ +}
__flush_dcache_all added from arch/arm64/mm/cache.S, with helper macros from arch/arm64/include/asm/assembler.h, from v3.16. The cache flushing is required when transitioning from EFI code that runs with cache enable to XEN startup code which expects the cache to be disabled.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/arch/arm/arm64/Makefile | 1 + xen/arch/arm/arm64/cache.S | 100 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 xen/arch/arm/arm64/cache.S
diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile index d2d5875..c7243f5 100644 --- a/xen/arch/arm/arm64/Makefile +++ b/xen/arch/arm/arm64/Makefile @@ -7,5 +7,6 @@ obj-y += domain.o obj-y += vfp.o obj-y += smpboot.o obj-y += domctl.o +obj-y += cache.o
obj-$(EARLY_PRINTK) += debug.o diff --git a/xen/arch/arm/arm64/cache.S b/xen/arch/arm/arm64/cache.S new file mode 100644 index 0000000..fb6dff1 --- /dev/null +++ b/xen/arch/arm/arm64/cache.S @@ -0,0 +1,100 @@ +/* + * Cache maintenance + * + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * Copyright (C) 2012 ARM Ltd. + * Copyright (C) 1996-2000 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +/* + * Enable and disable interrupts. + */ + .macro disable_irq + msr daifset, #2 + .endm + + .macro enable_irq + msr daifclr, #2 + .endm + +/* + * Save/disable and restore interrupts. + */ + .macro save_and_disable_irqs, olddaif + mrs \olddaif, daif + disable_irq + .endm + + .macro restore_irqs, olddaif + msr daif, \olddaif + .endm + +/* + * __flush_dcache_all() + * + * Flush the whole D-cache. + * + * Corrupted registers: x0-x7, x9-x11 + */ + ENTRY(__flush_dcache_all) +__flush_dcache_all: + dmb sy // ensure ordering with previous memory accesses + mrs x0, clidr_el1 // read clidr + and x3, x0, #0x7000000 // extract loc from clidr + lsr x3, x3, #23 // left align loc bit field + cbz x3, finished // if loc is 0, then no need to clean + mov x10, #0 // start clean at cache level 0 +loop1: + add x2, x10, x10, lsr #1 // work out 3x current cache level + lsr x1, x0, x2 // extract cache type bits from clidr + and x1, x1, #7 // mask of the bits for current cache only + cmp x1, #2 // see what cache we have at this level + b.lt skip // skip if no cache, or just i-cache + save_and_disable_irqs x9 // make CSSELR and CCSIDR access atomic + msr csselr_el1, x10 // select current cache level in csselr + isb // isb to sych the new cssr&csidr + mrs x1, ccsidr_el1 // read the new ccsidr + restore_irqs x9 + and x2, x1, #7 // extract the length of the cache lines + add x2, x2, #4 // add 4 (line length offset) + mov x4, #0x3ff + and x4, x4, x1, lsr #3 // find maximum number on the way size + clz w5, w4 // find bit position of way size increment + mov x7, #0x7fff + and x7, x7, x1, lsr #13 // extract max number of the index size +loop2: + mov x9, x4 // create working copy of max way size +loop3: + lsl x6, x9, x5 + orr x11, x10, x6 // factor way and cache number into x11 + lsl x6, x7, x2 + orr x11, x11, x6 // factor index number into x11 + dc cisw, x11 // clean & invalidate by set/way + subs x9, x9, #1 // decrement the way + b.ge loop3 + subs x7, x7, #1 // decrement the index + b.ge loop2 +skip: + add x10, x10, #2 // increment cache number + cmp x3, x10 + b.gt loop1 +finished: + mov x10, #0 // swith back to cache level 0 + msr csselr_el1, x10 // select current cache level in csselr + dsb sy + isb + ret +ENDPROC(__flush_dcache_all)
On Sun, 2014-09-07 at 20:53 -0700, Roy Franz wrote:
__flush_dcache_all added from arch/arm64/mm/cache.S, with helper macros from arch/arm64/include/asm/assembler.h, from v3.16. The cache flushing is required when transitioning from EFI code that runs with cache enable to XEN startup code which expects the cache to be disabled.
Signed-off-by: Roy Franz roy.franz@linaro.org
Acked-by: Ian Campbell ian.campbell@citrix.com
- ENTRY(__flush_dcache_all)
This shouldn't be indented. If I come to be applying this version then I'll fix that as I go, but if you repost please fix.
+__flush_dcache_all:
- dmb sy // ensure ordering with previous memory accesses
- mrs x0, clidr_el1 // read clidr
- and x3, x0, #0x7000000 // extract loc from clidr
- lsr x3, x3, #23 // left align loc bit field
- cbz x3, finished // if loc is 0, then no need to clean
- mov x10, #0 // start clean at cache level 0
+loop1:
- add x2, x10, x10, lsr #1 // work out 3x current cache level
- lsr x1, x0, x2 // extract cache type bits from clidr
- and x1, x1, #7 // mask of the bits for current cache only
- cmp x1, #2 // see what cache we have at this level
- b.lt skip // skip if no cache, or just i-cache
- save_and_disable_irqs x9 // make CSSELR and CCSIDR access atomic
- msr csselr_el1, x10 // select current cache level in csselr
- isb // isb to sych the new cssr&csidr
- mrs x1, ccsidr_el1 // read the new ccsidr
- restore_irqs x9
- and x2, x1, #7 // extract the length of the cache lines
- add x2, x2, #4 // add 4 (line length offset)
- mov x4, #0x3ff
- and x4, x4, x1, lsr #3 // find maximum number on the way size
- clz w5, w4 // find bit position of way size increment
- mov x7, #0x7fff
- and x7, x7, x1, lsr #13 // extract max number of the index size
+loop2:
- mov x9, x4 // create working copy of max way size
+loop3:
- lsl x6, x9, x5
- orr x11, x10, x6 // factor way and cache number into x11
- lsl x6, x7, x2
- orr x11, x11, x6 // factor index number into x11
- dc cisw, x11 // clean & invalidate by set/way
- subs x9, x9, #1 // decrement the way
- b.ge loop3
- subs x7, x7, #1 // decrement the index
- b.ge loop2
+skip:
- add x10, x10, #2 // increment cache number
- cmp x3, x10
- b.gt loop1
+finished:
- mov x10, #0 // swith back to cache level 0
- msr csselr_el1, x10 // select current cache level in csselr
- dsb sy
- isb
- ret
+ENDPROC(__flush_dcache_all)
Update libfdt to v1.4.0 of libfdt taken from git://git.jdl.com/software/dtc.git XEN changes to libfdt_env.h carried over from existing libfdt (v1.3.0) This update provides the fdt_create_empty_tree() function used by the ARM EFI boot code.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/libfdt/Makefile.libfdt | 4 +- xen/common/libfdt/fdt.c | 30 +++- xen/common/libfdt/fdt_empty_tree.c | 84 ++++++++++ xen/common/libfdt/fdt_ro.c | 7 +- xen/common/libfdt/fdt_rw.c | 31 +++- xen/common/libfdt/fdt_sw.c | 4 +- xen/common/libfdt/fdt_wip.c | 2 +- xen/common/libfdt/version.lds | 6 + xen/include/xen/libfdt/fdt.h | 93 ++++++++--- xen/include/xen/libfdt/libfdt.h | 315 +++++++++++++++++++++++++++++++++--- xen/include/xen/libfdt/libfdt_env.h | 4 + 11 files changed, 529 insertions(+), 51 deletions(-) create mode 100644 xen/common/libfdt/fdt_empty_tree.c
diff --git a/xen/common/libfdt/Makefile.libfdt b/xen/common/libfdt/Makefile.libfdt index d55a6f8..91126c0 100644 --- a/xen/common/libfdt/Makefile.libfdt +++ b/xen/common/libfdt/Makefile.libfdt @@ -4,7 +4,7 @@ # be easily embeddable into other systems of Makefiles. # LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 -LIBFDT_INCLUDES = fdt.h libfdt.h +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/xen/common/libfdt/fdt.c b/xen/common/libfdt/fdt.c index e56833a..2ce6a44 100644 --- a/xen/common/libfdt/fdt.c +++ b/xen/common/libfdt/fdt.c @@ -92,7 +92,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { - const uint32_t *tagp, *lenp; + const fdt32_t *tagp, *lenp; uint32_t tag; int offset = startoffset; const char *p; @@ -198,6 +198,34 @@ int fdt_next_node(const void *fdt, int offset, int *depth) return offset; }
+int fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +int fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; diff --git a/xen/common/libfdt/fdt_empty_tree.c b/xen/common/libfdt/fdt_empty_tree.c new file mode 100644 index 0000000..f72d13b --- /dev/null +++ b/xen/common/libfdt/fdt_empty_tree.c @@ -0,0 +1,84 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} + diff --git a/xen/common/libfdt/fdt_ro.c b/xen/common/libfdt/fdt_ro.c index 02b6d68..50007f6 100644 --- a/xen/common/libfdt/fdt_ro.c +++ b/xen/common/libfdt/fdt_ro.c @@ -322,7 +322,7 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { - const uint32_t *php; + const fdt32_t *php; int len;
/* FIXME: This is a bit sub-optimal, since we potentially scan @@ -515,8 +515,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) return offset; /* error from fdt_next_node() */ }
-static int _fdt_stringlist_contains(const char *strlist, int listlen, - const char *str) +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) { int len = strlen(str); const char *p; @@ -542,7 +541,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (_fdt_stringlist_contains(prop, len, compatible)) + if (fdt_stringlist_contains(prop, len, compatible)) return 0; else return 1; diff --git a/xen/common/libfdt/fdt_rw.c b/xen/common/libfdt/fdt_rw.c index 994037b..fdba618 100644 --- a/xen/common/libfdt/fdt_rw.c +++ b/xen/common/libfdt/fdt_rw.c @@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, return 0; }
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + int fdt_delprop(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; @@ -312,7 +339,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, int nodelen; int err; uint32_t tag; - uint32_t *endtag; + fdt32_t *endtag;
FDT_RW_CHECK_HEADER(fdt);
@@ -339,7 +366,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); memcpy(nh->name, name, namelen); - endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); *endtag = cpu_to_fdt32(FDT_END_NODE);
return offset; diff --git a/xen/common/libfdt/fdt_sw.c b/xen/common/libfdt/fdt_sw.c index 55ebebf..f422754 100644 --- a/xen/common/libfdt/fdt_sw.c +++ b/xen/common/libfdt/fdt_sw.c @@ -153,7 +153,7 @@ int fdt_begin_node(void *fdt, const char *name)
int fdt_end_node(void *fdt) { - uint32_t *en; + fdt32_t *en;
FDT_SW_CHECK_HEADER(fdt);
@@ -213,7 +213,7 @@ int fdt_property(void *fdt, const char *name, const void *val, int len) int fdt_finish(void *fdt) { char *p = (char *)fdt; - uint32_t *end; + fdt32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; diff --git a/xen/common/libfdt/fdt_wip.c b/xen/common/libfdt/fdt_wip.c index 6025fa1..c5bbb68 100644 --- a/xen/common/libfdt/fdt_wip.c +++ b/xen/common/libfdt/fdt_wip.c @@ -74,7 +74,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
static void _fdt_nop_region(void *start, int len) { - uint32_t *p; + fdt32_t *p;
for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); diff --git a/xen/common/libfdt/version.lds b/xen/common/libfdt/version.lds index 3c3994e..80b322b 100644 --- a/xen/common/libfdt/version.lds +++ b/xen/common/libfdt/version.lds @@ -48,6 +48,12 @@ LIBFDT_1.2 { fdt_strerror; fdt_offset_ptr; fdt_next_tag; + fdt_appendprop; + fdt_create_empty_tree; + fdt_first_property_offset; + fdt_get_property_by_offset; + fdt_getprop_by_offset; + fdt_next_property_offset;
local: *; diff --git a/xen/include/xen/libfdt/fdt.h b/xen/include/xen/libfdt/fdt.h index 48ccfd9..526aedb 100644 --- a/xen/include/xen/libfdt/fdt.h +++ b/xen/include/xen/libfdt/fdt.h @@ -1,48 +1,99 @@ #ifndef _FDT_H #define _FDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */
#ifndef __ASSEMBLY__
struct fdt_header { - uint32_t magic; /* magic word FDT_MAGIC */ - uint32_t totalsize; /* total size of DT block */ - uint32_t off_dt_struct; /* offset to structure */ - uint32_t off_dt_strings; /* offset to strings */ - uint32_t off_mem_rsvmap; /* offset to memory reserve map */ - uint32_t version; /* format version */ - uint32_t last_comp_version; /* last compatible version */ + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */
/* version 2 fields below */ - uint32_t boot_cpuid_phys; /* Which physical CPU id we're + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ - uint32_t size_dt_strings; /* size of the strings block */ + fdt32_t size_dt_strings; /* size of the strings block */
/* version 17 fields below */ - uint32_t size_dt_struct; /* size of the structure block */ + fdt32_t size_dt_struct; /* size of the structure block */ };
struct fdt_reserve_entry { - uint64_t address; - uint64_t size; + fdt64_t address; + fdt64_t size; };
struct fdt_node_header { - uint32_t tag; + fdt32_t tag; char name[0]; };
struct fdt_property { - uint32_t tag; - uint32_t len; - uint32_t nameoff; + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; char data[0]; };
#endif /* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(uint32_t) +#define FDT_TAGSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ #define FDT_END_NODE 0x2 /* End node */ @@ -51,10 +102,10 @@ struct fdt_property { #define FDT_NOP 0x4 /* nop */ #define FDT_END 0x9
-#define FDT_V1_SIZE (7*sizeof(uint32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) #define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
#endif /* _FDT_H */ diff --git a/xen/include/xen/libfdt/libfdt.h b/xen/include/xen/libfdt/libfdt.h index 6086047..37349f1 100644 --- a/xen/include/xen/libfdt/libfdt.h +++ b/xen/include/xen/libfdt/libfdt.h @@ -136,6 +136,28 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
int fdt_next_node(const void *fdt, int offset, int *depth);
+/** + * fdt_first_subnode() - get offset of first direct subnode + * + * @fdt: FDT blob + * @offset: Offset of node to check + * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + */ +int fdt_first_subnode(const void *fdt, int offset); + +/** + * fdt_next_subnode() - get offset of next direct subnode + * + * After first calling fdt_first_subnode(), call this function repeatedly to + * get direct subnodes of a parent node. + * + * @fdt: FDT blob + * @offset: Offset of previous subnode + * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes + */ +int fdt_next_subnode(const void *fdt, int offset); + /**********************************************************************/ /* General functions */ /**********************************************************************/ @@ -582,7 +604,7 @@ const char *fdt_get_alias_namelen(const void *fdt, * value of the property named 'name' in the node /aliases. * * returns: - * a pointer to the expansion of the alias named 'name', of it exists + * a pointer to the expansion of the alias named 'name', if it exists * NULL, if the given alias or the /aliases node does not exist */ const char *fdt_get_alias(const void *fdt, const char *name); @@ -816,6 +838,20 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible);
+/** + * fdt_stringlist_contains - check a string list property for a string + * @strlist: Property containing a list of strings to check + * @listlen: Length of property + * @str: String to search for + * + * This is a utility function provided for convenience. The list contains + * one or more strings, each terminated by \0, as is found in a device tree + * "compatible" property. + * + * @return: 1 if the string is found in the list, 0 not found, or invalid list + */ +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + /**********************************************************************/ /* Write-in-place functions */ /**********************************************************************/ @@ -852,17 +888,17 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len);
/** - * fdt_setprop_inplace_cell - change the value of a single-cell property + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change - * @val: cell (32-bit integer) value to replace the property with + * @val: 32-bit integer value to replace the property with * - * fdt_setprop_inplace_cell() replaces the value of a given property - * with the 32-bit integer cell value in val, converting val to - * big-endian if necessary. This function cannot change the size of a - * property, and so will only work if the property already exists and - * has length 4. + * fdt_setprop_inplace_u32() replaces the value of a given property + * with the 32-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 4. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part @@ -871,7 +907,42 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to replace the property with + * + * fdt_setprop_inplace_u64() replaces the value of a given property + * with the 64-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 8. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -879,11 +950,22 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ +static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * + * This is an alternative name for fdt_setprop_inplace_u32() + */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); }
/** @@ -945,10 +1027,19 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); +static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} +static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_property(fdt, name, &val, sizeof(val)); + return fdt_property_u32(fdt, name, val); } #define fdt_property_string(fdt, name, str) \ fdt_property(fdt, name, str, strlen(str)+1) @@ -959,6 +1050,7 @@ int fdt_finish(void *fdt); /* Read-write functions */ /**********************************************************************/
+int fdt_create_empty_tree(void *buf, int bufsize); int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt);
@@ -1068,14 +1160,14 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len);
/** - * fdt_setprop_cell - set a property to a single cell value + * fdt_setprop_u32 - set a property to a 32-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value for the property (native endian) * - * fdt_setprop_cell() sets the value of the named property in the - * given node to the given cell value (converting to big-endian if + * fdt_setprop_u32() sets the value of the named property in the given + * node to the given 32-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * @@ -1095,11 +1187,57 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ +static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_u64 - set a property to a 64-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value for the property (native endian) + * + * fdt_setprop_u64() sets the value of the named property in the given + * node to the given 64-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, + uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_cell - set a property to a single cell value + * + * This is an alternative name for fdt_setprop_u32() + */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); + return fdt_setprop_u32(fdt, nodeoffset, name, val); }
/** @@ -1134,6 +1272,147 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to append to + * @val: pointer to data to append to the property value + * @len: length of the data to append to the property value + * + * fdt_appendprop() appends the value to the named property in the + * given node, creating the property if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_appendprop_u32 - append a 32-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u32() appends the given 32-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_u64 - append a 64-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u64() appends the given 64-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_cell - append a single cell value to a property + * + * This is an alternative name for fdt_appendprop_u32() + */ +static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_appendprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_appendprop_string - append a string to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value to append to the property + * + * fdt_appendprop_string() appends the given string to the value of + * the named property in the given node, or creates a new property + * with that value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop diff --git a/xen/include/xen/libfdt/libfdt_env.h b/xen/include/xen/libfdt/libfdt_env.h index 2f1b03c..89a794b 100644 --- a/xen/include/xen/libfdt/libfdt_env.h +++ b/xen/include/xen/libfdt/libfdt_env.h @@ -6,6 +6,10 @@ #include <xen/string.h> #include <asm/byteorder.h>
+typedef uint16_t fdt16_t; +typedef uint32_t fdt32_t; +typedef uint64_t fdt64_t; + #define fdt16_to_cpu(x) be16_to_cpu(x) #define cpu_to_fdt16(x) cpu_to_be16(x) #define fdt32_to_cpu(x) be32_to_cpu(x)
On Sun, 2014-09-07 at 20:54 -0700, Roy Franz wrote:
Update libfdt to v1.4.0 of libfdt taken from git://git.jdl.com/software/dtc.git XEN changes to libfdt_env.h carried over from existing libfdt (v1.3.0) This update provides the fdt_create_empty_tree() function used by the ARM EFI boot code.
Signed-off-by: Roy Franz roy.franz@linaro.org
Since this is just an import I'm not actually going to review this, so:
Acked-by: Ian Campbell ian.campbell@citrix.com
I suppose this and the previous patch (cache flush) could safely go in independently from the rest of the series?
Ian.
On Mon, Sep 8, 2014 at 8:54 AM, Ian Campbell Ian.Campbell@citrix.com wrote:
On Sun, 2014-09-07 at 20:54 -0700, Roy Franz wrote:
Update libfdt to v1.4.0 of libfdt taken from git://git.jdl.com/software/dtc.git XEN changes to libfdt_env.h carried over from existing libfdt (v1.3.0) This update provides the fdt_create_empty_tree() function used by the ARM EFI boot code.
Signed-off-by: Roy Franz roy.franz@linaro.org
Since this is just an import I'm not actually going to review this, so:
Acked-by: Ian Campbell ian.campbell@citrix.com
I suppose this and the previous patch (cache flush) could safely go in independently from the rest of the series?
Ian.
Yes, these are independent pieces that could go in separately. I can split them out if that would help, or they could just be applied from this series.
Roy
On Mon, 2014-09-08 at 12:08 -0700, Roy Franz wrote:
On Mon, Sep 8, 2014 at 8:54 AM, Ian Campbell Ian.Campbell@citrix.com wrote:
On Sun, 2014-09-07 at 20:54 -0700, Roy Franz wrote:
Update libfdt to v1.4.0 of libfdt taken from git://git.jdl.com/software/dtc.git XEN changes to libfdt_env.h carried over from existing libfdt (v1.3.0) This update provides the fdt_create_empty_tree() function used by the ARM EFI boot code.
Signed-off-by: Roy Franz roy.franz@linaro.org
Since this is just an import I'm not actually going to review this, so:
Acked-by: Ian Campbell ian.campbell@citrix.com
I suppose this and the previous patch (cache flush) could safely go in independently from the rest of the series?
Ian.
Yes, these are independent pieces that could go in separately. I can split them out if that would help, or they could just be applied from this series.
Thanks, I'll pick them out of this series at some point soon, no need to split them out.
Ian.
This patch adds EFI boot support for ARM based on the previous refactoring of the x86 EFI boot code. All ARM specific code is in the ARM efi-boot.h header file, with the main EFI entry point common/efi/boot.c. The PE/COFF header is open-coded in head.S, which allows us to have a single binary be both an EFI executable and a normal arm64 IMAGE file. There is currently no PE/COFF toolchain support for arm64, so it is not possible to create the PE/COFF header in the same manner as on x86. This also simplifies the build as compared to x86, as we always build the same executable, whereas x86 builds 2. An ARM version of efi-bind.h is added, which is based on the x86_64 version with the x86 specific portions removed. The Makefile in common/efi is different for x86 and ARM, as for ARM we always build in EFI support.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/arch/arm/arm64/head.S | 145 ++++++++- xen/arch/arm/xen.lds.S | 1 + xen/common/efi/Makefile | 5 +- xen/include/asm-arm/arm64/efibind.h | 216 +++++++++++++ xen/include/asm-arm/efi-boot.h | 602 ++++++++++++++++++++++++++++++++++++ xen/include/asm-arm/efi.h | 29 ++ xen/include/asm-arm/efibind.h | 2 + xen/include/asm-arm/setup.h | 2 +- 8 files changed, 997 insertions(+), 5 deletions(-) create mode 100644 xen/include/asm-arm/arm64/efibind.h create mode 100644 xen/include/asm-arm/efi-boot.h create mode 100644 xen/include/asm-arm/efi.h create mode 100644 xen/include/asm-arm/efibind.h
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index 43b5e72..a39aa4e 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -24,6 +24,8 @@ #include <asm/page.h> #include <asm/asm_defns.h> #include <asm/early_printk.h> +#include <efi/efierr.h> +#include <asm/arm64/efibind.h>
#define PT_PT 0xf7f /* nG=1 AF=1 SH=11 AP=01 NS=1 ATTR=111 T=1 P=1 */ #define PT_MEM 0xf7d /* nG=1 AF=1 SH=11 AP=01 NS=1 ATTR=111 T=0 P=1 */ @@ -104,8 +106,14 @@ GLOBAL(start) /* * DO NOT MODIFY. Image header expected by Linux boot-loaders. */ - b real_start /* branch to kernel start, magic */ - .long 0 /* reserved */ +efi_head: + /* + * This add instruction has no meaningful effect except that + * its opcode forms the magic "MZ" signature of a PE/COFF file + * that is required for UEFI applications. + */ + add x13, x18, #0x16 + b real_start /* branch to kernel start */ .quad 0 /* Image load offset from start of RAM */ .quad 0 /* reserved */ .quad 0 /* reserved */ @@ -116,8 +124,113 @@ GLOBAL(start) .byte 0x52 .byte 0x4d .byte 0x64 - .word 0 /* reserved */ + .long pe_header - efi_head /* Offset to the PE header. */
+ /* + * Add the PE/COFF header to the file. The address of this header + * is at offset 0x3c in the file, and is part of Linux "Image" + * header. The arm64 Linux Image format is designed to support + * being both an 'Image' format binary and a PE/COFF binary. + * The PE/COFF format is defined by Microsoft, and is available + * from: http://msdn.microsoft.com/en-us/gg463119.aspx + * Version 8.3 adds support for arm64 and UEFI usage. + */ + + .align 3 +pe_header: + .ascii "PE" + .short 0 +coff_header: + .short 0xaa64 /* AArch64 */ + .short 2 /* nr_sections */ + .long 0 /* TimeDateStamp */ + .long 0 /* PointerToSymbolTable */ + .long 1 /* NumberOfSymbols */ + .short section_table - optional_header /* SizeOfOptionalHeader */ + .short 0x206 /* Characteristics. */ + /* IMAGE_FILE_DEBUG_STRIPPED | */ + /* IMAGE_FILE_EXECUTABLE_IMAGE | */ + /* IMAGE_FILE_LINE_NUMS_STRIPPED */ +optional_header: + .short 0x20b /* PE32+ format */ + .byte 0x02 /* MajorLinkerVersion */ + .byte 0x14 /* MinorLinkerVersion */ + .long _end - real_start /* SizeOfCode */ + .long 0 /* SizeOfInitializedData */ + .long 0 /* SizeOfUninitializedData */ + .long efi_start - efi_head /* AddressOfEntryPoint */ + .long real_start - efi_head /* BaseOfCode */ + +extra_header_fields: + .quad 0 /* ImageBase */ + .long 0x200000 /* SectionAlignment (2MByte) */ + .long 0x8 /* FileAlignment */ + .short 0 /* MajorOperatingSystemVersion */ + .short 0 /* MinorOperatingSystemVersion */ + .short 0 /* MajorImageVersion */ + .short 0 /* MinorImageVersion */ + .short 0 /* MajorSubsystemVersion */ + .short 0 /* MinorSubsystemVersion */ + .long 0 /* Win32VersionValue */ + + .long _end - efi_head /* SizeOfImage */ + + /* Everything before the kernel image is considered part of the header */ + .long real_start - efi_head /* SizeOfHeaders */ + .long 0 /* CheckSum */ + .short 0xa /* Subsystem (EFI application) */ + .short 0 /* DllCharacteristics */ + .quad 0 /* SizeOfStackReserve */ + .quad 0 /* SizeOfStackCommit */ + .quad 0 /* SizeOfHeapReserve */ + .quad 0 /* SizeOfHeapCommit */ + .long 0 /* LoaderFlags */ + .long 0x6 /* NumberOfRvaAndSizes */ + + .quad 0 /* ExportTable */ + .quad 0 /* ImportTable */ + .quad 0 /* ResourceTable */ + .quad 0 /* ExceptionTable */ + .quad 0 /* CertificationTable */ + .quad 0 /* BaseRelocationTable */ + + /* Section table */ +section_table: + + /* + * The EFI application loader requires a relocation section + * because EFI applications must be relocatable. This is a + * dummy section as far as we are concerned. + */ + .ascii ".reloc" + .byte 0 + .byte 0 /* end of 0 padding of section name */ + .long 0 + .long 0 + .long 0 /* SizeOfRawData */ + .long 0 /* PointerToRawData */ + .long 0 /* PointerToRelocations */ + .long 0 /* PointerToLineNumbers */ + .short 0 /* NumberOfRelocations */ + .short 0 /* NumberOfLineNumbers */ + .long 0x42100040 /* Characteristics (section flags) */ + + + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* end of 0 padding of section name */ + .long _end - real_start /* VirtualSize */ + .long real_start - efi_head /* VirtualAddress */ + .long __init_end_efi - real_start /* SizeOfRawData */ + .long real_start - efi_head /* PointerToRawData */ + + .long 0 /* PointerToRelocations (0 for executables) */ + .long 0 /* PointerToLineNumbers (0 for executables) */ + .short 0 /* NumberOfRelocations (0 for executables) */ + .short 0 /* NumberOfLineNumbers (0 for executables) */ + .long 0xe0500020 /* Characteristics (section flags) */ + .align 5 real_start: msr DAIFSet, 0xf /* Disable all interrupts */
@@ -618,6 +731,32 @@ ENTRY(lookup_processor_type) mov x0, #0 ret
+ENTRY(efi_xen_start) + /* + * Turn off cache and MMU as XEN expects. EFI enables them, but also + * mandates a 1:1 (unity) VA->PA mapping, so we can turn off the + * MMU while executing EFI code before entering XEN. + * The EFI loader calls this to start XEN. + */ + mov x20, x0 + bl __flush_dcache_all + ic ialluis + + /* Turn off Dcache and MMU */ + mrs x0, sctlr_el2 + bic x0, x0, #1 << 0 /* clear SCTLR.M */ + bic x0, x0, #1 << 2 /* clear SCTLR.C */ + msr sctlr_el2, x0 + isb + + /* Jump to XEN entry point */ + mov x0, x20 + mov x1, xzr + mov x2, xzr + mov x3, xzr + b real_start +ENDPROC(efi_xen_start) + /* * Local variables: * mode: ASM diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index 079e085..d8b0cfe 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -135,6 +135,7 @@ SECTIONS *(.xsm_initcall.init) __xsm_initcall_end = .; } :text + __init_end_efi = .; . = ALIGN(STACK_SIZE); __init_end = .;
diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile index 4313a4e..fea712e 100644 --- a/xen/common/efi/Makefile +++ b/xen/common/efi/Makefile @@ -1,5 +1,5 @@ CFLAGS += -fshort-wchar - +ifneq ($(XEN_TARGET_ARCH),arm64) obj-y += dummy.o
create = test -e $(1) || touch -t 199901010000 $(1) @@ -12,3 +12,6 @@ efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(c extra-$(efi) += boot.init.o
dummy.o: boot.init.o $(extra-y) +else +obj-y += boot.init.o +endif diff --git a/xen/include/asm-arm/arm64/efibind.h b/xen/include/asm-arm/arm64/efibind.h new file mode 100644 index 0000000..2b0bf40 --- /dev/null +++ b/xen/include/asm-arm/arm64/efibind.h @@ -0,0 +1,216 @@ +/*++ + +Copyright (c) 1998 Intel Corporation + +Module Name: + + efefind.h + +Abstract: + + EFI to compile bindings + + + + +Revision History + +--*/ + +#ifndef __GNUC__ +#pragma pack() +#endif + +#define EFIERR(a) (0x8000000000000000 | a) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | a) + +#define BAD_POINTER 0xFBFBFBFBFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF + +#define EFI_STUB_ERROR MAX_ADDRESS + +#ifndef __ASSEMBLY__ +// +// Basic int types of various widths +// + +#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L ) + + // No ANSI C 1999/2000 stdint.h integer width declarations + + #if defined(__GNUC__) + typedef unsigned long long uint64_t __attribute__((aligned (8))); + typedef long long int64_t __attribute__((aligned (8))); + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #elif defined(UNIX_LP64) + + /* Use LP64 programming model from C_FLAGS for integer width declarations */ + + typedef unsigned long uint64_t; + typedef long int64_t; + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #else + + /* Assume P64 programming model from C_FLAGS for integer width declarations */ + + typedef unsigned long long uint64_t __attribute__((aligned (8))); + typedef long long int64_t __attribute__((aligned (8))); + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #endif +#endif + +// +// Basic EFI types of various widths +// + +#ifndef __WCHAR_TYPE__ +# define __WCHAR_TYPE__ short +#endif + +typedef uint64_t UINT64; +typedef int64_t INT64; + +#ifndef _BASETSD_H_ + typedef uint32_t UINT32; + typedef int32_t INT32; +#endif + +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; +typedef __WCHAR_TYPE__ WCHAR; + +#undef VOID +#define VOID void + + +typedef int64_t INTN; +typedef uint64_t UINTN; + +#define POST_CODE(_Data) + + +#define BREAKPOINT() while (TRUE); // Make it hang on Bios[Dbg]32 + +// +// Pointers must be aligned to these address to function +// + +#define MIN_ALIGNMENT_SIZE 4 + +#define ALIGN_VARIABLE(Value ,Adjustment) \ + (UINTN)Adjustment = 0; \ + if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ + (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ + Value = (UINTN)Value + (UINTN)Adjustment + + +// +// Define macros to build data structure signatures from characters. +// + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +#define EXPORTAPI + + +// +// EFIAPI - prototype calling convention for EFI function pointers +// BOOTSERVICE - prototype for implementation of a boot service interface +// RUNTIMESERVICE - prototype for implementation of a runtime service interface +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service +// RUNTIME_CODE - pragma macro for declaring runtime code +// + +#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options + #define EFIAPI // Substitute expresion to force C calling convention +#endif + +#define BOOTSERVICE +//#define RUNTIMESERVICE(proto,a) alloc_text("rtcode",a); proto a +//#define RUNTIMEFUNCTION(proto,a) alloc_text("rtcode",a); proto a +#define RUNTIMESERVICE +#define RUNTIMEFUNCTION + + +#define RUNTIME_CODE(a) alloc_text("rtcode", a) +#define BEGIN_RUNTIME_DATA() data_seg("rtdata") +#define END_RUNTIME_DATA() data_seg("") + +#define VOLATILE volatile + +#define MEMORY_FENCE() + + +// +// When build similiar to FW, then link everything together as +// one big module. +// + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) \ + UINTN \ + InitializeDriver ( \ + VOID *ImageHandle, \ + VOID *SystemTable \ + ) \ + { \ + return InitFunction(ImageHandle, \ + SystemTable); \ + } \ + \ + EFI_STATUS efi_main( \ + EFI_HANDLE image, \ + EFI_SYSTEM_TABLE *systab \ + ) __attribute__((weak, \ + alias ("InitializeDriver"))); + +#define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, entry) + + +// +// Some compilers don't support the forward reference construct: +// typedef struct XXXXX +// +// The following macro provide a workaround for such cases. +// +#ifdef NO_INTERFACE_DECL +#define INTERFACE_DECL(x) +#else +#ifdef __GNUC__ +#define INTERFACE_DECL(x) struct x +#else +#define INTERFACE_DECL(x) typedef struct x +#endif +#endif + +#endif + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-arm/efi-boot.h b/xen/include/asm-arm/efi-boot.h new file mode 100644 index 0000000..91a637e --- /dev/null +++ b/xen/include/asm-arm/efi-boot.h @@ -0,0 +1,602 @@ +/* + * Architecture specific implementation for EFI boot code. This file + * is intended to be included by XXX _only_, and therefore can define + * arch specific global variables. + */ +#include <xen/libfdt/libfdt.h> +#include <asm/setup.h> + +static void noreturn blexit(const CHAR16 *str); +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode); +void noreturn efi_xen_start(unsigned long fdt_addr); + +#define DEVICE_TREE_GUID \ +{0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}} + +static struct file __initdata dtbfile; +static void __initdata *fdt; +static void __initdata *memmap; + +static int __init setup_chosen_node(void *fdt, int *addr_cells, int *size_cells) +{ + int node; + const struct fdt_property *prop; + int len; + uint32_t val; + + if ( !fdt || !addr_cells || !size_cells ) + return -1; + + /* locate chosen node, which is where we add XEN module info. */ + node = fdt_subnode_offset(fdt, 0, "chosen"); + if ( node < 0 ) + { + node = fdt_add_subnode(fdt, 0, "chosen"); + if ( node < 0 ) + return node; + } + + /* Get or set #address-cells and #size-cells */ + prop = fdt_get_property(fdt, node, "#address-cells", &len); + if ( !prop ) + { + val = cpu_to_fdt32(2); + if ( fdt_setprop(fdt, node, "#address-cells", &val, sizeof(val)) ) + return -1; + *addr_cells = 2; + } + else + *addr_cells = fdt32_to_cpu(*((uint32_t *)prop->data)); + + prop = fdt_get_property(fdt, node, "#size-cells", &len); + if ( !prop ) + { + val = cpu_to_fdt32(2); + if ( fdt_setprop(fdt, node, "#size-cells", &val, sizeof(val)) ) + return -1; + *size_cells = 2; + } + else + *size_cells = fdt32_to_cpu(*((uint32_t *)prop->data)); + + /* + * Make sure ranges is empty if it exists, otherwise create empty ranges + * property. + */ + prop = fdt_get_property(fdt, node, "ranges", &len); + if ( !prop ) + { + val = cpu_to_fdt32(0); + if ( fdt_setprop(fdt, node, "ranges", &val, 0) ) + return -1; + } + else if ( fdt32_to_cpu(prop->len) ) + return -1; /* Non-empty ranges property */ + return node; +} + +/* + * Set a single 'reg' property taking into account the + * configured addr and size cell sizes. + */ +static int __init fdt_set_reg(void *fdt, int node, int addr_cells, + int size_cells, uint64_t addr, uint64_t len) +{ + uint8_t data[16]; /* at most 2 64 bit words */ + void *p = data; + + /* Make sure that the values provided can be represented in + * the reg property. + */ + if ( addr_cells == 1 && (addr >> 32) ) + return -1; + if ( size_cells == 1 && (len >> 32) ) + return -1; + + if ( addr_cells == 1 ) + { + *(uint32_t *)p = cpu_to_fdt32(addr); + p += sizeof(uint32_t); + } + else if ( addr_cells == 2 ) + { + *(uint64_t *)p = cpu_to_fdt64(addr); + p += sizeof(uint64_t); + } + else + return -1; + + if ( size_cells == 1 ) + { + *(uint32_t *)p = cpu_to_fdt32(len); + p += sizeof(uint32_t); + } + else if ( size_cells == 2 ) + { + *(uint64_t *)p = cpu_to_fdt64(len); + p += sizeof(uint64_t); + } + else + return -1; + + return(fdt_setprop(fdt, node, "reg", data, p - (void *)data)); +} + +static void __init *lookup_fdt_config_table(EFI_SYSTEM_TABLE *sys_table) +{ + const EFI_GUID fdt_guid = DEVICE_TREE_GUID; + EFI_CONFIGURATION_TABLE *tables; + void *fdt = NULL; + int i; + + tables = sys_table->ConfigurationTable; + for ( i = 0; i < sys_table->NumberOfTableEntries; i++ ) + { + if ( match_guid(&tables[i].VendorGuid, &fdt_guid) ) + { + fdt = tables[i].VendorTable; + break; + } + } + return fdt; +} +static EFI_STATUS __init efi_get_memory_map(void **map, + UINTN *mmap_size, + UINTN *desc_size, + UINT32 *desc_ver, + UINTN *key_ptr) +{ + EFI_MEMORY_DESCRIPTOR *m = NULL; + EFI_STATUS status; + unsigned long key; + u32 desc_version; + + *map = NULL; + *mmap_size = EFI_PAGE_SIZE; +again: + *mmap_size += EFI_PAGE_SIZE; /* Page size is allocation granularity */ + status = efi_bs->AllocatePool(EfiLoaderData, *mmap_size, (void **)&m); + if ( status != EFI_SUCCESS ) + return status; + + *desc_size = 0; + key = 0; + status = efi_bs->GetMemoryMap(mmap_size, m, &key, desc_size, &desc_version); + if ( status == EFI_BUFFER_TOO_SMALL ) + { + efi_bs->FreePool(m); + goto again; + } + + if ( status != EFI_SUCCESS ) + { + efi_bs->FreePool(m); + return status; + } + + if ( key_ptr && status == EFI_SUCCESS ) + *key_ptr = key; + if ( desc_ver && status == EFI_SUCCESS ) + *desc_ver = desc_version; + + *map = m; + return status; +} +static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map, + UINTN mmap_size, + UINTN desc_size) +{ + int Index; + int i = 0; + + EFI_MEMORY_DESCRIPTOR *desc_ptr = map; + + for ( Index = 0; Index < (mmap_size / desc_size); Index++ ) + { + if ( desc_ptr->Type == EfiConventionalMemory + || desc_ptr->Type == EfiBootServicesCode + || desc_ptr->Type == EfiBootServicesData ) + { + bootinfo.mem.bank[i].start = desc_ptr->PhysicalStart; + bootinfo.mem.bank[i].size = desc_ptr->NumberOfPages * EFI_PAGE_SIZE; + if ( ++i >= NR_MEM_BANKS ) + { + PrintStr(L"Warning: All "); + DisplayUint(NR_MEM_BANKS, -1); + PrintStr(L" bootinfo mem banks exhausted.\r\n"); + break; + } + } + desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size); + } + + bootinfo.mem.nr_banks = i; + return EFI_SUCCESS; + +} + +/* + * Add the FDT nodes for the standard EFI information, which consist + * of the System table address, the address of the final EFI memory map, + * and memory map information. + */ +EFI_STATUS __init fdt_add_uefi_nodes(EFI_SYSTEM_TABLE *sys_table, + void *fdt, + EFI_MEMORY_DESCRIPTOR *memory_map, + UINTN map_size, + UINTN desc_size, + UINT32 desc_ver) +{ + int node; + int status; + u32 fdt_val32; + u64 fdt_val64; + int prev; + /* + * Delete any memory nodes present. The EFI memory map is the only + * memory description provided to XEN. + */ + prev = 0; + for (;;) + { + const char *type; + int len; + + node = fdt_next_node(fdt, prev, NULL); + if ( node < 0 ) + break; + + type = fdt_getprop(fdt, node, "device_type", &len); + if ( type && strncmp(type, "memory", len) == 0 ) + { + fdt_del_node(fdt, node); + continue; + } + + prev = node; + } + + /* Add FDT entries for EFI runtime services in chosen node. */ + node = fdt_subnode_offset(fdt, 0, "chosen"); + if ( node < 0 ) + { + node = fdt_add_subnode(fdt, 0, "chosen"); + if ( node < 0 ) + { + status = node; /* node is error code when negative */ + goto fdt_set_fail; + } + } + + fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table); + status = fdt_setprop(fdt, node, "linux,uefi-system-table", + &fdt_val64, sizeof(fdt_val64)); + if ( status ) + goto fdt_set_fail; + + fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); + status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", + &fdt_val64, sizeof(fdt_val64)); + if ( status ) + goto fdt_set_fail; + + fdt_val32 = cpu_to_fdt32(map_size); + status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", + &fdt_val32, sizeof(fdt_val32)); + if ( status ) + goto fdt_set_fail; + + fdt_val32 = cpu_to_fdt32(desc_size); + status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", + &fdt_val32, sizeof(fdt_val32)); + if ( status ) + goto fdt_set_fail; + + fdt_val32 = cpu_to_fdt32(desc_ver); + status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", + &fdt_val32, sizeof(fdt_val32)); + if ( status ) + goto fdt_set_fail; + + return EFI_SUCCESS; + +fdt_set_fail: + if ( status == -FDT_ERR_NOSPACE ) + return EFI_BUFFER_TOO_SMALL; + + return EFI_LOAD_ERROR; +} + +/* + * Allocates new memory for a larger FDT, and frees existing memory if + * struct file size is non-zero. Updates file struct with new memory + * address/size for later freeing. If fdtfile.ptr is NULL, an empty FDT + * is created. + */ +static void __init *fdt_increase_size(struct file *fdtfile, int add_size) +{ + EFI_STATUS status; + EFI_PHYSICAL_ADDRESS fdt_addr; + int fdt_size; + int pages; + void *new_fdt; + + if ( fdtfile->ptr ) + fdt_size = fdt_totalsize(fdtfile->ptr); + else + fdt_size = 0; + + pages = PFN_UP(fdt_size) + PFN_UP(add_size); + status = efi_bs->AllocatePages(AllocateAnyPages, EfiLoaderData, + pages, &fdt_addr); + + if ( status != EFI_SUCCESS ) + return NULL; + + new_fdt = (void *)fdt_addr; + + if ( fdt_size ) + { + if ( fdt_open_into(dtbfile.ptr, new_fdt, pages * EFI_PAGE_SIZE) ) + return NULL; + } + else + { + /* + * Create an empty FDT if not provided one, which is the expected case + * when booted from the UEFI shell on an ACPI only system. We will use + * the FDT to pass the EFI information to XEN, as well as nodes for + * any modules the stub loads. The ACPI tables are part of the UEFI + * system table that is passed in the FDT. + */ + if ( fdt_create_empty_tree(new_fdt, pages * EFI_PAGE_SIZE) ) + return NULL; + } + + /* + * Now that we have the new FDT allocated and copied, free the + * original and update the struct file so that the error handling + * code will free it. If the original FDT came from a configuration + * table, we don't own that memory and can't free it. + */ + if ( dtbfile.size ) + efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size)); + + /* Update 'file' info for new memory so we clean it up on error exits */ + dtbfile.addr = fdt_addr; + dtbfile.size = pages * EFI_PAGE_SIZE; + return new_fdt; +} + +static void __init efi_arch_pci(void) +{ +} +static void __init efi_arch_relocate_image(unsigned long delta) +{ +} +static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, + void *map, + UINTN map_size, + UINTN desc_size, + UINT32 desc_ver) +{ + EFI_STATUS status; + + status = efi_process_memory_map_bootinfo(map, map_size, desc_size); + if ( EFI_ERROR(status) ) + blexit(L"ERROR processing EFI memory map\r\n"); + + status = fdt_add_uefi_nodes(SystemTable, fdt, map, map_size, desc_size, + desc_ver); + if ( EFI_ERROR(status) ) + PrintErrMesg(L"ERROR updating FDT\r\n", status); +} +static void __init efi_arch_pre_exit_boot(void) +{ +} +static void __init efi_arch_post_exit_boot(void) +{ + efi_xen_start((unsigned long)fdt); +} +static void __init efi_arch_cfg_file(EFI_FILE_HANDLE dir_handle, char *section) +{ + union string name; + name.s = get_value(&cfg, section, "dtb"); + if ( name.s ) + { + if ( !read_file(dir_handle, &dtbfile, name.s)) + blexit(NULL); + } + fdt = fdt_increase_size(&dtbfile, cfg.size + EFI_PAGE_SIZE); + if ( !fdt ) + blexit(L"Unable to create new FDT\r\n"); +} +static void __init efi_arch_get_memory_map(UINTN *map_size, + void **map, + UINTN *map_key, UINTN *desc_size, + UINT32 *desc_ver) +{ + EFI_STATUS status; + + status = efi_get_memory_map(map, map_size, desc_size, desc_ver, map_key); + if ( EFI_ERROR(status) ) + blexit(L"ERROR getting EFI memory map.\r\n"); + memmap = *map; +} +static void __init efi_arch_edd(void) +{ +} +static void __init efi_arch_video(bool_t base_video, + UINTN cols, UINTN rows, UINTN depth, + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop) +{ +} +static void __init efi_arch_memory(void) +{ +} +static void __init efi_arch_handle_cmdline(CHAR16 *image_name, + CHAR16 *cmdline_options, + char *cfgfile_options) +{ + union string name; + char *buf; + EFI_STATUS status; + int prop_len; + int chosen; + + /* locate chosen node, which is where we add XEN module info. */ + chosen = fdt_subnode_offset(fdt, 0, "chosen"); + if ( chosen < 0 ) + blexit(L"ERROR unable to find chosen node\r\n"); + + status = efi_bs->AllocatePool(EfiBootServicesData, EFI_PAGE_SIZE, (void **)&buf); + if ( EFI_ERROR(status) ) + PrintErrMesg(L"ERROR allocating memory.\r\n", status); + + if ( image_name ) + { + name.w = image_name; + w2s(&name); + } + else + name.s = "xen"; + + prop_len = 0; + prop_len += snprintf(buf + prop_len, + EFI_PAGE_SIZE - prop_len, "%s", name.s); + if ( prop_len >= EFI_PAGE_SIZE ) + blexit(L"FDT string overflow"); + + if ( cfgfile_options ) + { + prop_len += snprintf(buf + prop_len, + EFI_PAGE_SIZE - prop_len, " %s", cfgfile_options); + if ( prop_len >= EFI_PAGE_SIZE ) + blexit(L"FDT string overflow"); + } + + if ( cmdline_options ) + { + name.w = cmdline_options; + w2s(&name); + } + else + name.s = NULL; + + if ( name.s ) + { + prop_len += snprintf(buf + prop_len, + EFI_PAGE_SIZE - prop_len, " %s", name.s); + if ( prop_len >= EFI_PAGE_SIZE ) + blexit(L"FDT string overflow"); + } + + if ( fdt_setprop_string(fdt, chosen, "xen,xen-bootargs", buf) < 0 ) + blexit(L"unable to set xen,xen-bootargs property."); + + efi_bs->FreePool(buf); +} +static void __init efi_arch_handle_module(struct file *file, char *name, + char *options) +{ + int node; + int chosen; + int addr_len, size_len; + + if ( file == &dtbfile ) + return; + chosen = setup_chosen_node(fdt, &addr_len, &size_len); + if ( chosen < 0 ) + blexit(L"Unable to setup chosen node\r\n"); + + if ( file == &ramdisk ) + { + char ramdisk_compat[] = "multiboot,ramdisk\0multiboot,module"; + node = fdt_add_subnode(fdt, chosen, "ramdisk"); + if ( node < 0 ) + blexit(L"Error adding ramdisk FDT node."); + if ( fdt_setprop(fdt, node, "compatible", ramdisk_compat, + sizeof(ramdisk_compat)) < 0 ) + blexit(L"unable to set compatible property."); + if ( fdt_set_reg(fdt, node, addr_len, size_len, ramdisk.addr, + ramdisk.size) < 0 ) + blexit(L"unable to set reg property."); + } + else if ( file == &xsm ) + { + char xsm_compat[] = "xen,xsm-policy\0multiboot,module"; + node = fdt_add_subnode(fdt, chosen, "xsm"); + if ( node < 0 ) + blexit(L"Error adding xsm FDT node."); + if ( fdt_setprop(fdt, node, "compatible", xsm_compat, + sizeof(xsm_compat)) < 0 ) + blexit(L"unable to set compatible property."); + if ( fdt_set_reg(fdt, node, addr_len, size_len, xsm.addr, + xsm.size) < 0 ) + blexit(L"unable to set reg property."); + } + else if ( file == &kernel ) + { + char kernel_compat[] = "multiboot,kernel\0multiboot,module"; + node = fdt_add_subnode(fdt, chosen, "kernel"); + if ( node < 0 ) + blexit(L"Error adding dom0 FDT node."); + if ( fdt_setprop(fdt, node, "compatible", kernel_compat, + sizeof(kernel_compat)) < 0 ) + blexit(L"unable to set compatible property."); + if ( options && fdt_setprop_string(fdt, node, "bootargs", options) < 0 ) + blexit(L"unable to set bootargs property."); + if ( fdt_set_reg(fdt, node, addr_len, size_len, kernel.addr, + kernel.size) < 0 ) + blexit(L"unable to set reg property."); + } + else + blexit(L"Unknown module type\r\n"); +} +static void __init efi_arch_cpu(void) +{ +} +static void __init efi_arch_smbios(void) +{ +} +static void __init efi_arch_blexit(void) +{ + if ( dtbfile.addr && dtbfile.size ) + efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size)); + if ( memmap ) + efi_bs->FreePool(memmap); +} +static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image) +{ + if ( (unsigned long)loaded_image->ImageBase & ((1 << 20) - 1) ) + blexit(L"Xen must be loaded at a 2MByte boundary."); +} +static void __init efi_arch_runtime_setup(EFI_SYSTEM_TABLE *SystemTable) +{ +} +static __init bool_t efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable) +{ + /* + * For arm, we may get a device tree from GRUB (or other bootloader) + * that contains modules that have already been loaded into memory. In + * this case, we do not use a configuration file, and rely on the + * bootloader to have loaded all required modules and appropriate + * options. + */ + + fdt = lookup_fdt_config_table(SystemTable); + dtbfile.ptr = fdt; + dtbfile.size = 0; /* Config table memory can't be freed, so set size to 0 */ + if ( !fdt || fdt_node_offset_by_compatible(fdt, 0, "multiboot,module") < 0 ) + { + /* + * We either have no FDT, or one without modules, so we must have a + * XEN EFI configuration file to specify modules. (dom0 required) + */ + return 1; + } + PrintStr(L"Using modules provided by bootloader in FDT\r\n"); + /* We have modules already defined in fdt, just add space. */ + fdt = fdt_increase_size(&dtbfile, EFI_PAGE_SIZE); + return 0; +} diff --git a/xen/include/asm-arm/efi.h b/xen/include/asm-arm/efi.h new file mode 100644 index 0000000..aae4716 --- /dev/null +++ b/xen/include/asm-arm/efi.h @@ -0,0 +1,29 @@ +#include <asm/efibind.h> +#include <efi/efidef.h> +#include <efi/efierr.h> +#include <efi/eficon.h> +#include <efi/efidevp.h> +#include <efi/eficapsule.h> +#include <efi/efiapi.h> +#include <xen/efi.h> +#include <xen/spinlock.h> +#include <asm/page.h> + +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; + +extern const struct efi_pci_rom *efi_pci_roms; + +extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size, + efi_boot_max_var_size; + +unsigned long efi_rs_enter(void); +void efi_rs_leave(unsigned long); diff --git a/xen/include/asm-arm/efibind.h b/xen/include/asm-arm/efibind.h new file mode 100644 index 0000000..09dca7a --- /dev/null +++ b/xen/include/asm-arm/efibind.h @@ -0,0 +1,2 @@ +#include <xen/types.h> +#include <asm/arm64/efibind.h> diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h index 36e5704..40814e6 100644 --- a/xen/include/asm-arm/setup.h +++ b/xen/include/asm-arm/setup.h @@ -3,7 +3,7 @@
#include <public/version.h>
-#define NR_MEM_BANKS 8 +#define NR_MEM_BANKS 32
#define MAX_MODULES 5 /* Current maximum useful modules */
On Sun, 2014-09-07 at 20:54 -0700, Roy Franz wrote:
@@ -618,6 +731,32 @@ ENTRY(lookup_processor_type) mov x0, #0 ret +ENTRY(efi_xen_start)
/*
* Turn off cache and MMU as XEN expects. EFI enables them, but also
It's just "Xen", not "XEN" (throughout).
* mandates a 1:1 (unity) VA->PA mapping, so we can turn off the
* MMU while executing EFI code before entering XEN.
* The EFI loader calls this to start XEN.
*/
Last time there was a handy comment about preserving x0 here. I think it would also (or perhaps instead) be good to have a comment before the entry giving the "prototype" for this function, since it is called from C.
mov x20, x0
bl __flush_dcache_all
ic ialluis
Two too many spaces before iall.
diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile index 4313a4e..fea712e 100644 --- a/xen/common/efi/Makefile +++ b/xen/common/efi/Makefile @@ -1,5 +1,5 @@ CFLAGS += -fshort-wchar
+ifneq ($(XEN_TARGET_ARCH),arm64)
This does still build on arm32, right?
I suppose the discussion on patch #1 will have some knock on effects here.
diff --git a/xen/include/asm-arm/arm64/efibind.h b/xen/include/asm-arm/arm64/efibind.h new file mode 100644 index 0000000..2b0bf40 --- /dev/null +++ b/xen/include/asm-arm/arm64/efibind.h
diff --git a/xen/include/asm-arm/efi-boot.h b/xen/include/asm-arm/efi-boot.h new file mode 100644 index 0000000..91a637e --- /dev/null +++ b/xen/include/asm-arm/efi-boot.h
+static void __init *lookup_fdt_config_table(EFI_SYSTEM_TABLE *sys_table) +{
- const EFI_GUID fdt_guid = DEVICE_TREE_GUID;
- EFI_CONFIGURATION_TABLE *tables;
- void *fdt = NULL;
- int i;
- tables = sys_table->ConfigurationTable;
- for ( i = 0; i < sys_table->NumberOfTableEntries; i++ )
- {
if ( match_guid(&tables[i].VendorGuid, &fdt_guid) )
{
fdt = tables[i].VendorTable;
break;
}
- }
- return fdt;
+} +static EFI_STATUS __init efi_get_memory_map(void **map,
Missing a blank line after the previous function, here and elsewhere. I see you've gone from 2 blanks to 0 since last time ;-)
- fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
(uintptr_t) is arguably more correct than (unsigned long) for this purpose. and again below.
- status = fdt_setprop(fdt, node, "linux,uefi-system-table",
&fdt_val64, sizeof(fdt_val64));
- if ( status )
goto fdt_set_fail;
- fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
- status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
&fdt_val64, sizeof(fdt_val64));
[...]
++static void __init efi_arch_post_exit_boot(void) +{
- efi_xen_start((unsigned long)fdt);
You might as well make the pseudoprototype be a pointer if that is what fdt actually is.
+static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image) +{
- if ( (unsigned long)loaded_image->ImageBase & ((1 << 20) - 1) )
blexit(L"Xen must be loaded at a 2MByte boundary.");
This isn't true any more, Xen only needs to be at a 4K boundary now.
Looking good, all of the above is pretty minor stuff, thanks!
Ian.
On Mon, Sep 8, 2014 at 9:12 AM, Ian Campbell Ian.Campbell@citrix.com wrote:
On Sun, 2014-09-07 at 20:54 -0700, Roy Franz wrote:
@@ -618,6 +731,32 @@ ENTRY(lookup_processor_type) mov x0, #0 ret
+ENTRY(efi_xen_start)
/*
* Turn off cache and MMU as XEN expects. EFI enables them, but also
It's just "Xen", not "XEN" (throughout).
OK.
* mandates a 1:1 (unity) VA->PA mapping, so we can turn off the
* MMU while executing EFI code before entering XEN.
* The EFI loader calls this to start XEN.
*/
Last time there was a handy comment about preserving x0 here. I think it would also (or perhaps instead) be good to have a comment before the entry giving the "prototype" for this function, since it is called from C.
OK, I'll add that.
mov x20, x0
bl __flush_dcache_all
ic ialluis
Two too many spaces before iall.
diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile index 4313a4e..fea712e 100644 --- a/xen/common/efi/Makefile +++ b/xen/common/efi/Makefile @@ -1,5 +1,5 @@ CFLAGS += -fshort-wchar
+ifneq ($(XEN_TARGET_ARCH),arm64)
This does still build on arm32, right?
I suppose the discussion on patch #1 will have some knock on effects here.
Most of the stuff should be common with arm32, although I haven't tried it. The main thing missing for arm32 is the PE/COFF header. I'm not intending to build the EFI stuff for arm32, but it's possible I've borked the build - I forgot to try that on this patchset.
diff --git a/xen/include/asm-arm/arm64/efibind.h b/xen/include/asm-arm/arm64/efibind.h new file mode 100644 index 0000000..2b0bf40 --- /dev/null +++ b/xen/include/asm-arm/arm64/efibind.h
diff --git a/xen/include/asm-arm/efi-boot.h b/xen/include/asm-arm/efi-boot.h new file mode 100644 index 0000000..91a637e --- /dev/null +++ b/xen/include/asm-arm/efi-boot.h
+static void __init *lookup_fdt_config_table(EFI_SYSTEM_TABLE *sys_table) +{
- const EFI_GUID fdt_guid = DEVICE_TREE_GUID;
- EFI_CONFIGURATION_TABLE *tables;
- void *fdt = NULL;
- int i;
- tables = sys_table->ConfigurationTable;
- for ( i = 0; i < sys_table->NumberOfTableEntries; i++ )
- {
if ( match_guid(&tables[i].VendorGuid, &fdt_guid) )
{
fdt = tables[i].VendorTable;
break;
}
- }
- return fdt;
+} +static EFI_STATUS __init efi_get_memory_map(void **map,
Missing a blank line after the previous function, here and elsewhere. I see you've gone from 2 blanks to 0 since last time ;-)
I'll add the proper number of blank lines :)
- fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
(uintptr_t) is arguably more correct than (unsigned long) for this purpose. and again below.
Yup, I'll fix that.
- status = fdt_setprop(fdt, node, "linux,uefi-system-table",
&fdt_val64, sizeof(fdt_val64));
- if ( status )
goto fdt_set_fail;
- fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
- status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
&fdt_val64, sizeof(fdt_val64));
[...]
++static void __init efi_arch_post_exit_boot(void) +{
- efi_xen_start((unsigned long)fdt);
You might as well make the pseudoprototype be a pointer if that is what fdt actually is.
OK. That will save a cast, and the value in the register is the same.
+static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image) +{
- if ( (unsigned long)loaded_image->ImageBase & ((1 << 20) - 1) )
blexit(L"Xen must be loaded at a 2MByte boundary.");
This isn't true any more, Xen only needs to be at a 4K boundary now.
I will update this (along with the alignment requested in the PE/COFF header) and give it a spin.
Looking good, all of the above is pretty minor stuff, thanks!
Ian.
I'm hoping this is in good enough shape for 4.5 - I should be able to address all the feedback received so far quite quickly. Should I wait for more feedback, or prepare an updated patchset addressing the feedback so far?
Thanks, Roy
On Mon, 2014-09-08 at 14:18 -0700, Roy Franz wrote:
I'm hoping this is in good enough shape for 4.5 - I should be able to address all the feedback received so far quite quickly. Should I wait for more feedback, or prepare an updated patchset addressing the feedback so far?
From the ARM side you could respin now, but I skipped over most of the
x86/refactoring bits (i.e. the bulk of the series) since that's more of a Jan thing. Jan -- do you have comments or should Roy wait?
Ian.
On 09.09.14 at 11:24, Ian.Campbell@citrix.com wrote:
On Mon, 2014-09-08 at 14:18 -0700, Roy Franz wrote:
I'm hoping this is in good enough shape for 4.5 - I should be able to address all the feedback received so far quite quickly. Should I wait for more feedback, or prepare an updated patchset addressing the feedback so far?
From the ARM side you could respin now, but I skipped over most of the x86/refactoring bits (i.e. the bulk of the series) since that's more of a Jan thing. Jan -- do you have comments or should Roy wait?
I'm having a hard time estimating when I would get to look at the non-ARM pieces of the series, so I think re-spinning with the one (significant) structural change discussed earlier would be reasonable.
Jan
On Tue, Sep 9, 2014 at 2:53 AM, Jan Beulich JBeulich@suse.com wrote:
On 09.09.14 at 11:24, Ian.Campbell@citrix.com wrote:
On Mon, 2014-09-08 at 14:18 -0700, Roy Franz wrote:
I'm hoping this is in good enough shape for 4.5 - I should be able to address all the feedback received so far quite quickly. Should I wait for more feedback, or prepare an updated patchset addressing the feedback so far?
From the ARM side you could respin now, but I skipped over most of the x86/refactoring bits (i.e. the bulk of the series) since that's more of a Jan thing. Jan -- do you have comments or should Roy wait?
I'm having a hard time estimating when I would get to look at the non-ARM pieces of the series, so I think re-spinning with the one (significant) structural change discussed earlier would be reasonable.
Jan
I'll get an updated series out today.
Thanks, Roy