diff options
author | Roy Franz | 2015-09-23 20:17:54 -0700 |
---|---|---|
committer | ard | 2015-12-14 10:38:21 +0100 |
commit | 81a0bc39ea1960bbf8ece6a895d7cfd2d9efa28a (patch) | |
tree | 58f4c5c73cc4292b242dce2e0018511f9e18e39e /drivers/firmware | |
parent | da58fb6571bf40e5b2287d6aa3bbca04965f5677 (diff) |
ARM: add UEFI stub support
This patch adds EFI stub support for the ARM Linux kernel.
The EFI stub operates similarly to the x86 and arm64 stubs: it is a
shim between the EFI firmware and the normal zImage entry point, and
sets up the environment that the zImage is expecting. This includes
optionally loading the initrd and device tree from the system partition
based on the kernel command line.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Tested-by: Ryan Harkin <ryan.harkin@linaro.org>
Reviewed-by: Matt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efi/libstub/Makefile | 9 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm32-stub.c | 85 |
3 files changed, 97 insertions, 1 deletions
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 3c0467d3688c..8cf9ccbf42d5 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -34,6 +34,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ $(patsubst %.c,lib-%.o,$(arm-deps)) +lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) @@ -67,3 +68,11 @@ quiet_cmd_stubcopy = STUBCPY $@ $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \ && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ rm -f $@; /bin/false); else /bin/false; fi + +# +# ARM discards the .data section because it disallows r/w data in the +# decompressor. So move our .data to .data.efistub, which is preserved +# explicitly by the decompressor linker script. +# +STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub +STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 950c87f5d279..3397902e4040 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -303,8 +303,10 @@ fail: * The value chosen is the largest non-zero power of 2 suitable for this purpose * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can * be mapped efficiently. + * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split, + * map everything below 1 GB. */ -#define EFI_RT_VIRTUAL_BASE 0x40000000 +#define EFI_RT_VIRTUAL_BASE SZ_512M static int cmp_mem_desc(const void *l, const void *r) { diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c new file mode 100644 index 000000000000..495ebd657e38 --- /dev/null +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2013 Linaro Ltd; <roy.franz@linaro.org> + * + * 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. + * + */ +#include <linux/efi.h> +#include <asm/efi.h> + +efi_status_t handle_kernel_image(efi_system_table_t *sys_table, + unsigned long *image_addr, + unsigned long *image_size, + unsigned long *reserve_addr, + unsigned long *reserve_size, + unsigned long dram_base, + efi_loaded_image_t *image) +{ + unsigned long nr_pages; + efi_status_t status; + /* Use alloc_addr to tranlsate between types */ + efi_physical_addr_t alloc_addr; + + /* + * Verify that the DRAM base address is compatible with the ARM + * boot protocol, which determines the base of DRAM by masking + * off the low 27 bits of the address at which the zImage is + * loaded. These assumptions are made by the decompressor, + * before any memory map is available. + */ + dram_base = round_up(dram_base, SZ_128M); + + /* + * Reserve memory for the uncompressed kernel image. This is + * all that prevents any future allocations from conflicting + * with the kernel. Since we can't tell from the compressed + * image how much DRAM the kernel actually uses (due to BSS + * size uncertainty) we allocate the maximum possible size. + * Do this very early, as prints can cause memory allocations + * that may conflict with this. + */ + alloc_addr = dram_base; + *reserve_size = MAX_UNCOMP_KERNEL_SIZE; + nr_pages = round_up(*reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + status = sys_table->boottime->allocate_pages(EFI_ALLOCATE_ADDRESS, + EFI_LOADER_DATA, + nr_pages, &alloc_addr); + if (status != EFI_SUCCESS) { + *reserve_size = 0; + pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n"); + return status; + } + *reserve_addr = alloc_addr; + + /* + * Relocate the zImage, so that it appears in the lowest 128 MB + * memory window. + */ + *image_size = image->image_size; + status = efi_relocate_kernel(sys_table, image_addr, *image_size, + *image_size, + dram_base + MAX_UNCOMP_KERNEL_SIZE, 0); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to relocate kernel.\n"); + efi_free(sys_table, *reserve_size, *reserve_addr); + *reserve_size = 0; + return status; + } + + /* + * Check to see if we were able to allocate memory low enough + * in memory. The kernel determines the base of DRAM from the + * address at which the zImage is loaded. + */ + if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) { + pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n"); + efi_free(sys_table, *reserve_size, *reserve_addr); + *reserve_size = 0; + efi_free(sys_table, *image_size, *image_addr); + *image_size = 0; + return EFI_LOAD_ERROR; + } + return EFI_SUCCESS; +} |