[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V4 15/15] Add ARM EFI boot support
On Tue, 9 Sep 2014, Roy Franz wrote: > 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@xxxxxxxxxx> > --- > config/arm64.mk | 1 + > xen/arch/arm/arm64/head.S | 150 ++++++++- > xen/arch/arm/xen.lds.S | 1 + > xen/common/Makefile | 1 + > xen/common/efi/Makefile | 3 + > xen/include/asm-arm/arm64/efibind.h | 216 +++++++++++++ > xen/include/asm-arm/efi-boot.h | 630 > ++++++++++++++++++++++++++++++++++++ > xen/include/asm-arm/efi.h | 29 ++ > xen/include/asm-arm/efibind.h | 2 + > xen/include/asm-arm/setup.h | 2 +- > 10 files changed, 1031 insertions(+), 4 deletions(-) > create mode 100644 xen/common/efi/Makefile > 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/config/arm64.mk b/config/arm64.mk > index 15b57a4..e6aab0e 100644 > --- a/config/arm64.mk > +++ b/config/arm64.mk > @@ -1,6 +1,7 @@ > CONFIG_ARM := y > CONFIG_ARM_64 := y > CONFIG_ARM_$(XEN_OS) := y > +CONFIG_EFI := y > > CONFIG_XEN_INSTALL_SUFFIX := > > diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S > index 43b5e72..158c102 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 0x1000 /* SectionAlignment (4 > KByte) */ > + .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 */ > > @@ -617,6 +730,37 @@ putn: ret > ENTRY(lookup_processor_type) > mov x0, #0 > ret > +/* > + * Function to transition from EFI loader in C, to Xen entry point. > + * void noreturn efi_xen_start(void *fdt_ptr); > + */ > +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. > + * Preserve x0 (fdf pointer) across call to __flush_dcache_all, > + * restore for entry into 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 */ dsb? > + 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: > 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/Makefile b/xen/common/Makefile > index 3683ae3..e78cb29 100644 > --- a/xen/common/Makefile > +++ b/xen/common/Makefile > @@ -67,4 +67,5 @@ subdir-$(x86_64) += hvm > subdir-$(coverage) += gcov > > subdir-y += libelf > +subdir-$(CONFIG_EFI) += efi > subdir-$(HAS_DEVICE_TREE) += libfdt > diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile > new file mode 100644 > index 0000000..195b2f3 > --- /dev/null > +++ b/xen/common/efi/Makefile > @@ -0,0 +1,3 @@ > +CFLAGS += -fshort-wchar > + > +obj-y += boot.init.o > 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..2db0966 > --- /dev/null > +++ b/xen/include/asm-arm/efi-boot.h > @@ -0,0 +1,630 @@ > +/* > + * 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(void *fdt_ptr); > + > +#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; > + } > + } setup_chosen_node? > + fdt_val64 = cpu_to_fdt64((u64)(uintptr_t)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)(uintptr_t)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); Shouldn't this be PFN_UP(fdt_size+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(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 << 12) - 1) ) > + blexit(L"Xen must be loaded at a 4 KByte 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; > +} > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > 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 Why? At the very least you should write it in the commit message. > #define MAX_MODULES 5 /* Current maximum useful modules */ > > -- > 2.1.0.rc1 > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |