diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index e557cac22e..f330302871 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -1,6 +1,7 @@ subdir-$(arm32) += arm32 subdir-$(arm64) += arm64 subdir-y += platforms +subdir-$(arm64) += efi obj-$(EARLY_PRINTK) += early_printk.o obj-y += cpu.o diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index d22af1c9bb..7650abe083 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -24,6 +24,8 @@ #include #include #include +#include +#include #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 */ @@ -621,6 +734,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 */ + 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/efi/Makefile b/xen/arch/arm/efi/Makefile new file mode 100644 index 0000000000..729e53e619 --- /dev/null +++ b/xen/arch/arm/efi/Makefile @@ -0,0 +1,3 @@ +CFLAGS += -fshort-wchar + +obj-y += boot.init.o runtime.o diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h new file mode 100644 index 0000000000..61cb13ad21 --- /dev/null +++ b/xen/arch/arm/efi/efi-boot.h @@ -0,0 +1,575 @@ +/* + * Architecture specific implementation for EFI boot code. This file + * is intended to be included by common/efi/boot.c _only_, and + * therefore can define arch specific global variables. + */ +#include +#include +#include + +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) +{ + __be32 val[4]; /* At most 2 64 bit values to be stored */ + __be32 *cellp; + + /* + * Make sure that the values provided can be represented in + * the reg property, and sizes are valid. + */ + if ( addr_cells < 1 || addr_cells > 2 || size_cells < 1 || size_cells > 2 ) + return -1; + if ( addr_cells == 1 && (addr >> 32) ) + return -1; + if ( size_cells == 1 && (len >> 32) ) + return -1; + + cellp = (__be32 *)val; + dt_set_cell(&cellp, addr_cells, addr); + dt_set_cell(&cellp, size_cells, len); + + return(fdt_setprop(fdt, node, "reg", val, sizeof(*cellp) * (cellp - val))); +} + +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_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; + int num_rsv; + + /* + * 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; + } + + /* + * Delete all memory reserve map entries. When booting via UEFI, + * kernel will use the UEFI memory map to find reserved regions. + */ + num_rsv = fdt_num_mem_rsv(fdt); + while ( num_rsv-- > 0 ) + fdt_del_mem_rsv(fdt, num_rsv); + + /* 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)(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 + 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_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"EFI memory map processing failed"); + + status = fdt_add_uefi_nodes(SystemTable, fdt, map, map_size, desc_size, + desc_ver); + if ( EFI_ERROR(status) ) + PrintErrMesg(L"Updating FDT failed\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_early(EFI_FILE_HANDLE dir_handle, char *section) +{ + union string name; + + /* + * The DTB must be processed before any other entries in the configuration + * file, as the DTB is updated as modules are loaded. + */ + name.s = get_value(&cfg, section, "dtb"); + if ( name.s ) + { + split_string(name.s); + read_file(dir_handle, s2w(&name), &dtbfile, NULL); + blexit(NULL); + efi_bs->FreePool(name.w); + } + fdt = fdt_increase_size(&dtbfile, cfg.size + EFI_PAGE_SIZE); + if ( !fdt ) + blexit(L"Unable to create new FDT"); +} + +static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *section) +{ +} + +static void *__init efi_arch_allocate_mmap_buffer(UINTN map_size) +{ + void *ptr; + EFI_STATUS status; + + status = efi_bs->AllocatePool(EfiLoaderData, map_size + EFI_PAGE_SIZE, &ptr); + if ( status != EFI_SUCCESS ) + return NULL; + return ptr; +} + +static void __init efi_arch_edd(void) +{ +} + +static void __init efi_arch_memory_setup(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"Unable to find chosen node"); + + status = efi_bs->AllocatePool(EfiBootServicesData, EFI_PAGE_SIZE, (void **)&buf); + if ( EFI_ERROR(status) ) + PrintErrMesg(L"Unable to allocate string buffer\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, const CHAR16 *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"); + + if ( file == &ramdisk ) + { + char ramdisk_compat[] = "multiboot,ramdisk\0multiboot,module"; + node = fdt_add_subnode(fdt, chosen, "ramdisk"); + if ( node < 0 ) + blexit(L"Unable to add 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"Unable to add 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"Unable to add 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"); +} + +static void __init efi_arch_cpu(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 bool_t __init 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; +} + +static void __init efi_arch_console_init(UINTN cols, UINTN rows) +{ +} + +static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, + UINTN info_size, + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info) +{ +} +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/efi/runtime.h b/xen/arch/arm/efi/runtime.h new file mode 100644 index 0000000000..25afcebed1 --- /dev/null +++ b/xen/arch/arm/efi/runtime.h @@ -0,0 +1 @@ +/* Placeholder for ARM-specific runtime include/declarations */ diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index 079e0851c7..d8b0cfe4dd 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/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index b44746f509..4348cfe4c5 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -3,6 +3,7 @@ * is intended to be included by common/efi/boot.c _only_, and * therefore can define arch specific global variables. */ +#include #include #include #include diff --git a/xen/arch/x86/efi/runtime.h b/xen/arch/x86/efi/runtime.h new file mode 100644 index 0000000000..0eb2fb93fe --- /dev/null +++ b/xen/arch/x86/efi/runtime.h @@ -0,0 +1,5 @@ +#include + +#ifndef COMPAT +l4_pgentry_t *__read_mostly efi_l4_pgtable; +#endif diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 3d3d76b3be..f272171a63 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -17,10 +18,16 @@ #endif #include #include -#include +#ifdef CONFIG_X86 +/* + * Keep this arch-specific modified include in the common file, as moving + * it to the arch specific include file would obscure that special care is + * taken to include it with __ASSEMBLY__ defined. + */ #define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ #include #undef __ASSEMBLY__ +#endif /* Using SetVirtualAddressMap() is incompatible with kexec: */ #undef USE_SET_VIRTUAL_ADDRESS_MAP @@ -66,6 +73,7 @@ static bool_t read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, struct file *file, char *options); static size_t wstrlen(const CHAR16 * s); static int set_color(u32 mask, int bpp, u8 *pos, u8 *sz); +static bool_t match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2); static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih; @@ -121,7 +129,7 @@ static void __init DisplayUint(UINT64 Val, INTN Width) PrintStr(PrintString); } -static size_t __init wstrlen(const CHAR16 *s) +static size_t __init __maybe_unused wstrlen(const CHAR16 *s) { const CHAR16 *sc; @@ -661,7 +669,7 @@ static void __init setup_efi_pci(void) efi_bs->FreePool(handles); } -static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz) +static int __init __maybe_unused set_color(u32 mask, int bpp, u8 *pos, u8 *sz) { if ( bpp < 0 ) return bpp; @@ -986,8 +994,10 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi.smbios = (long)efi_ct[i].VendorTable; } +#ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ if (efi.smbios != EFI_INVALID_TABLE_ADDR) dmi_efi_get_table((void *)(long)efi.smbios); +#endif /* Collect PCI ROM contents. */ setup_efi_pci(); @@ -1058,6 +1068,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) for( ; ; ); /* not reached */ } +#ifndef CONFIG_ARM /* TODO - runtime service support */ #ifndef USE_SET_VIRTUAL_ADDRESS_MAP static __init void copy_mapping(unsigned long mfn, unsigned long end, bool_t (*is_valid)(unsigned long smfn, @@ -1283,3 +1294,4 @@ void __init efi_init_memory(void) efi_l4_pgtable[i] = idle_pg_table[i]; #endif } +#endif diff --git a/xen/common/efi/efi.h b/xen/common/efi/efi.h index a80d5f1abb..bee3b77bf2 100644 --- a/xen/common/efi/efi.h +++ b/xen/common/efi/efi.h @@ -28,7 +28,9 @@ extern EFI_RUNTIME_SERVICES *efi_rs; extern UINTN efi_memmap_size, efi_mdesc_size; extern void *efi_memmap; +#ifdef CONFIG_X86 extern l4_pgentry_t *efi_l4_pgtable; +#endif extern const struct efi_pci_rom *efi_pci_roms; diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c index 166852decc..1c43d109fc 100644 --- a/xen/common/efi/runtime.c +++ b/xen/common/efi/runtime.c @@ -1,20 +1,24 @@ #include "efi.h" +#include "runtime.h" #include #include #include #include #include -#include DEFINE_XEN_GUEST_HANDLE(CHAR16); #ifndef COMPAT +#ifdef CONFIG_ARM /* Disabled until runtime services implemented */ +const bool_t efi_enabled = 0; +#else # include # include # include const bool_t efi_enabled = 1; +#endif unsigned int __read_mostly efi_num_ct; EFI_CONFIGURATION_TABLE *__read_mostly efi_ct; @@ -24,7 +28,9 @@ unsigned int __read_mostly efi_fw_revision; const CHAR16 *__read_mostly efi_fw_vendor; EFI_RUNTIME_SERVICES *__read_mostly efi_rs; +#ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ static DEFINE_SPINLOCK(efi_rs_lock); +#endif UINTN __read_mostly efi_memmap_size; UINTN __read_mostly efi_mdesc_size; @@ -41,10 +47,9 @@ struct efi __read_mostly efi = { .smbios = EFI_INVALID_TABLE_ADDR, }; -l4_pgentry_t *__read_mostly efi_l4_pgtable; - const struct efi_pci_rom *__read_mostly efi_pci_roms; +#ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ unsigned long efi_rs_enter(void) { static const u16 fcw = FCW_DEFAULT; @@ -134,8 +139,10 @@ void efi_reset_system(bool_t warm) printk(XENLOG_WARNING "EFI: could not reset system (%#lx)\n", status); } +#endif /* CONFIG_ARM */ #endif +#ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ int efi_get_info(uint32_t idx, union xenpf_efi_info *info) { unsigned int i, n; @@ -545,3 +552,4 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) return rc; } +#endif diff --git a/xen/include/asm-arm/arm64/efibind.h b/xen/include/asm-arm/arm64/efibind.h new file mode 100644 index 0000000000..2b0bf40bf2 --- /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/efibind.h b/xen/include/asm-arm/efibind.h new file mode 100644 index 0000000000..09dca7a8c9 --- /dev/null +++ b/xen/include/asm-arm/efibind.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h index 36e57041c1..ba5a67d4df 100644 --- a/xen/include/asm-arm/setup.h +++ b/xen/include/asm-arm/setup.h @@ -3,7 +3,7 @@ #include -#define NR_MEM_BANKS 8 +#define NR_MEM_BANKS 64 #define MAX_MODULES 5 /* Current maximum useful modules */