diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-02 04:20:03 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-02 04:20:03 +0300 |
commit | 3711c94fd6593318146348c940d81040acf9e877 (patch) | |
tree | 46119e721e66184e4e73c3e59307047677dfc7cc /drivers | |
parent | 174ddfd5dfbfc2d91a45332f809977050ac3fdc5 (diff) | |
parent | 197decefdb79d6f1350ba0316ce26ba737372d0c (diff) | |
download | linux-3711c94fd6593318146348c940d81040acf9e877.tar.xz |
Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI updates from Ingo Molnar:
"The main changes in this cycle were:
- move BGRT handling to drivers/acpi so it can be shared between x86
and ARM
- bring the EFI stub's initrd and FDT allocation logic in line with
the latest changes to the arm64 boot protocol
- improvements and fixes to the EFI stub's command line parsing
routines
- randomize the virtual mapping of the UEFI runtime services on
ARM/arm64
- ... and other misc enhancements, cleanups and fixes"
* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
efi/libstub/arm: Don't use TASK_SIZE when randomizing the RT space
ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region
efi/libstub/arm/arm64: Disable debug prints on 'quiet' cmdline arg
efi/libstub: Unify command line param parsing
efi/libstub: Fix harmless command line parsing bug
efi/arm32-stub: Allow boot-time allocations in the vmlinux region
x86/efi: Clean up a minor mistake in comment
efi/pstore: Return error code (if any) from efi_pstore_write()
efi/bgrt: Enable ACPI BGRT handling on arm64
x86/efi/bgrt: Move efi-bgrt handling out of arch/x86
efi/arm-stub: Round up FDT allocation to mapping size
efi/arm-stub: Correct FDT and initrd allocation rules for arm64
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/Kconfig | 2 | ||||
-rw-r--r-- | drivers/acpi/bgrt.c | 6 | ||||
-rw-r--r-- | drivers/firmware/efi/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-bgrt.c | 84 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 6 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 87 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm32-stub.c | 150 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm64-stub.c | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 32 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 9 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 57 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/secureboot.c | 2 |
12 files changed, 337 insertions, 103 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index de3b8fce5164..18f3036fcb82 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -440,7 +440,7 @@ config ACPI_CUSTOM_METHOD config ACPI_BGRT bool "Boottime Graphics Resource Table support" - depends on EFI && X86 + depends on EFI && (X86 || ARM64) help This driver adds support for exposing the ACPI Boottime Graphics Resource Table, which allows the operating system to obtain diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index ca28aa572aa9..df1c629205e7 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -81,6 +81,12 @@ static struct attribute_group bgrt_attribute_group = { .bin_attrs = bgrt_bin_attributes, }; +int __init acpi_parse_bgrt(struct acpi_table_header *table) +{ + efi_bgrt_init(table); + return 0; +} + static int __init bgrt_init(void) { int ret; diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index ad67342313ed..0329d319d89a 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -9,6 +9,7 @@ # KASAN_SANITIZE_runtime-wrappers.o := n +obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o obj-$(CONFIG_EFI) += capsule.o memmap.o obj-$(CONFIG_EFI_VARS) += efivars.o diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c new file mode 100644 index 000000000000..04ca8764f0c0 --- /dev/null +++ b/drivers/firmware/efi/efi-bgrt.c @@ -0,0 +1,84 @@ +/* + * Copyright 2012 Intel Corporation + * Author: Josh Triplett <josh@joshtriplett.org> + * + * Based on the bgrt driver: + * Copyright 2012 Red Hat, Inc <mjg@redhat.com> + * Author: Matthew Garrett + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/efi.h> +#include <linux/efi-bgrt.h> + +struct acpi_table_bgrt bgrt_tab; +size_t __initdata bgrt_image_size; + +struct bmp_header { + u16 id; + u32 size; +} __packed; + +void __init efi_bgrt_init(struct acpi_table_header *table) +{ + void *image; + struct bmp_header bmp_header; + struct acpi_table_bgrt *bgrt = &bgrt_tab; + + if (acpi_disabled) + return; + + if (table->length < sizeof(bgrt_tab)) { + pr_notice("Ignoring BGRT: invalid length %u (expected %zu)\n", + table->length, sizeof(bgrt_tab)); + return; + } + *bgrt = *(struct acpi_table_bgrt *)table; + if (bgrt->version != 1) { + pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n", + bgrt->version); + goto out; + } + if (bgrt->status & 0xfe) { + pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n", + bgrt->status); + goto out; + } + if (bgrt->image_type != 0) { + pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n", + bgrt->image_type); + goto out; + } + if (!bgrt->image_address) { + pr_notice("Ignoring BGRT: null image address\n"); + goto out; + } + + image = early_memremap(bgrt->image_address, sizeof(bmp_header)); + if (!image) { + pr_notice("Ignoring BGRT: failed to map image header memory\n"); + goto out; + } + + memcpy(&bmp_header, image, sizeof(bmp_header)); + early_memunmap(image, sizeof(bmp_header)); + if (bmp_header.id != 0x4d42) { + pr_notice("Ignoring BGRT: Incorrect BMP magic number 0x%x (expected 0x4d42)\n", + bmp_header.id); + goto out; + } + bgrt_image_size = bmp_header.size; + efi_mem_reserve(bgrt->image_address, bgrt_image_size); + + return; +out: + memset(bgrt, 0, sizeof(bgrt_tab)); +} diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index f402ba2eed46..6b5acefce6b3 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -274,9 +274,9 @@ static int efi_pstore_write(enum pstore_type_id type, for (i = 0; i < DUMP_NAME_LEN; i++) efi_name[i] = name[i]; - efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, - !pstore_cannot_block_path(reason), - size, psi->buf); + ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, + !pstore_cannot_block_path(reason), + size, psi->buf); if (reason == KMSG_DUMP_OOPS) efivar_run_worker(); diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index d4056c6be1ec..8181ac179d14 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -18,7 +18,27 @@ #include "efistub.h" -bool __nokaslr; +/* + * This is the base address at which to start allocating virtual memory ranges + * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use + * any allocation we choose, and eliminate the risk of a conflict after kexec. + * 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. (512 MB is a reasonable upper bound for the + * entire footprint of the UEFI runtime services memory regions) + */ +#define EFI_RT_VIRTUAL_BASE SZ_512M +#define EFI_RT_VIRTUAL_SIZE SZ_512M + +#ifdef CONFIG_ARM64 +# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_64 +#else +# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE +#endif + +static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) @@ -118,8 +138,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) goto fail; - pr_efi(sys_table, "Booting Linux Kernel...\n"); - status = check_platform_features(sys_table); if (status != EFI_SUCCESS) goto fail; @@ -153,17 +171,15 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail; } - /* check whether 'nokaslr' was passed on the command line */ - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - static const u8 default_cmdline[] = CONFIG_CMDLINE; - const u8 *str, *cmdline = cmdline_ptr; + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + cmdline_size == 0) + efi_parse_options(CONFIG_CMDLINE); - if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) - cmdline = default_cmdline; - str = strstr(cmdline, "nokaslr"); - if (str == cmdline || (str > cmdline && *(str - 1) == ' ')) - __nokaslr = true; - } + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) + efi_parse_options(cmdline_ptr); + + pr_efi(sys_table, "Booting Linux Kernel...\n"); si = setup_graphics(sys_table); @@ -176,10 +192,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail_free_cmdline; } - status = efi_parse_options(cmdline_ptr); - if (status != EFI_SUCCESS) - pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); - secure_boot = efi_get_secureboot(sys_table); /* @@ -213,8 +225,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (!fdt_addr) pr_efi(sys_table, "Generating empty DTB\n"); - status = handle_cmdline_files(sys_table, image, cmdline_ptr, - "initrd=", dram_base + SZ_512M, + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=", + efi_get_max_initrd_addr(dram_base, + *image_addr), (unsigned long *)&initrd_addr, (unsigned long *)&initrd_size); if (status != EFI_SUCCESS) @@ -222,9 +235,29 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, efi_random_get_seed(sys_table); + if (!nokaslr()) { + /* + * Randomize the base of the UEFI runtime services region. + * Preserve the 2 MB alignment of the region by taking a + * shift of 21 bit positions into account when scaling + * the headroom value using a 32-bit random value. + */ + static const u64 headroom = EFI_RT_VIRTUAL_LIMIT - + EFI_RT_VIRTUAL_BASE - + EFI_RT_VIRTUAL_SIZE; + u32 rnd; + + status = efi_get_random_bytes(sys_table, sizeof(rnd), + (u8 *)&rnd); + if (status == EFI_SUCCESS) { + virtmap_base = EFI_RT_VIRTUAL_BASE + + (((headroom >> 21) * rnd) >> (32 - 21)); + } + } + new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(sys_table, handle, - &new_fdt_addr, dram_base + MAX_FDT_OFFSET, + &new_fdt_addr, efi_get_max_fdt_addr(dram_base), initrd_addr, initrd_size, cmdline_ptr, fdt_addr, fdt_size); @@ -251,18 +284,6 @@ fail: return EFI_ERROR; } -/* - * This is the base address at which to start allocating virtual memory ranges - * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use - * any allocation we choose, and eliminate the risk of a conflict after kexec. - * 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 SZ_512M - static int cmp_mem_desc(const void *l, const void *r) { const efi_memory_desc_t *left = l, *right = r; @@ -312,7 +333,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, efi_memory_desc_t *runtime_map, int *count) { - u64 efi_virt_base = EFI_RT_VIRTUAL_BASE; + u64 efi_virt_base = virtmap_base; efi_memory_desc_t *in, *prev = NULL, *out = runtime_map; int l; diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index e1f0b28e1dcb..becbda445913 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -9,6 +9,8 @@ #include <linux/efi.h> #include <asm/efi.h> +#include "efistub.h" + efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) { int block; @@ -63,6 +65,132 @@ void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si) efi_call_early(free_pool, si); } +static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg, + unsigned long dram_base, + unsigned long *reserve_addr, + unsigned long *reserve_size) +{ + efi_physical_addr_t alloc_addr; + efi_memory_desc_t *memory_map; + unsigned long nr_pages, map_size, desc_size, buff_size; + efi_status_t status; + unsigned long l; + + struct efi_boot_memmap map = { + .map = &memory_map, + .map_size = &map_size, + .desc_size = &desc_size, + .desc_ver = NULL, + .key_ptr = NULL, + .buff_size = &buff_size, + }; + + /* + * 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 + MAX_UNCOMP_KERNEL_SIZE; + nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE; + status = efi_call_early(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS, + EFI_BOOT_SERVICES_DATA, nr_pages, &alloc_addr); + if (status == EFI_SUCCESS) { + if (alloc_addr == dram_base) { + *reserve_addr = alloc_addr; + *reserve_size = MAX_UNCOMP_KERNEL_SIZE; + return EFI_SUCCESS; + } + /* + * If we end up here, the allocation succeeded but starts below + * dram_base. This can only occur if the real base of DRAM is + * not a multiple of 128 MB, in which case dram_base will have + * been rounded up. Since this implies that a part of the region + * was already occupied, we need to fall through to the code + * below to ensure that the existing allocations don't conflict. + * For this reason, we use EFI_BOOT_SERVICES_DATA above and not + * EFI_LOADER_DATA, which we wouldn't able to distinguish from + * allocations that we want to disallow. + */ + } + + /* + * If the allocation above failed, we may still be able to proceed: + * if the only allocations in the region are of types that will be + * released to the OS after ExitBootServices(), the decompressor can + * safely overwrite them. + */ + status = efi_get_memory_map(sys_table_arg, &map); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, + "reserve_kernel_base(): Unable to retrieve memory map.\n"); + return status; + } + + for (l = 0; l < map_size; l += desc_size) { + efi_memory_desc_t *desc; + u64 start, end; + + desc = (void *)memory_map + l; + start = desc->phys_addr; + end = start + desc->num_pages * EFI_PAGE_SIZE; + + /* Skip if entry does not intersect with region */ + if (start >= dram_base + MAX_UNCOMP_KERNEL_SIZE || + end <= dram_base) + continue; + + switch (desc->type) { + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + /* Ignore types that are released to the OS anyway */ + continue; + + case EFI_CONVENTIONAL_MEMORY: + /* + * Reserve the intersection between this entry and the + * region. + */ + start = max(start, (u64)dram_base); + end = min(end, (u64)dram_base + MAX_UNCOMP_KERNEL_SIZE); + + status = efi_call_early(allocate_pages, + EFI_ALLOCATE_ADDRESS, + EFI_LOADER_DATA, + (end - start) / EFI_PAGE_SIZE, + &start); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, + "reserve_kernel_base(): alloc failed.\n"); + goto out; + } + break; + + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + /* + * These regions may be released and reallocated for + * another purpose (including EFI_RUNTIME_SERVICE_DATA) + * at any time during the execution of the OS loader, + * so we cannot consider them as safe. + */ + default: + /* + * Treat any other allocation in the region as unsafe */ + status = EFI_OUT_OF_RESOURCES; + goto out; + } + } + + status = EFI_SUCCESS; +out: + efi_call_early(free_pool, memory_map); + return status; +} + efi_status_t handle_kernel_image(efi_system_table_t *sys_table, unsigned long *image_addr, unsigned long *image_size, @@ -71,10 +199,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, 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 @@ -85,27 +210,12 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, */ 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); + status = reserve_kernel_base(sys_table, dram_base, reserve_addr, + reserve_size); 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 diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index eae693eb3e91..b4c2589d7c91 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -16,8 +16,6 @@ #include "efistub.h" -extern bool __nokaslr; - efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) { u64 tg; @@ -52,7 +50,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, u64 phys_seed = 0; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - if (!__nokaslr) { + if (!nokaslr()) { status = efi_get_random_bytes(sys_table_arg, sizeof(phys_seed), (u8 *)&phys_seed); diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 919822b7773d..b0184360efc6 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,6 +32,18 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; +static int __section(.data) __nokaslr; +static int __section(.data) __quiet; + +int __pure nokaslr(void) +{ + return __nokaslr; +} +int __pure is_quiet(void) +{ + return __quiet; +} + #define EFI_MMAP_NR_SLACK_SLOTS 8 struct file_info { @@ -409,17 +421,17 @@ static efi_status_t efi_file_close(void *handle) * environments, first in the early boot environment of the EFI boot * stub, and subsequently during the kernel boot. */ -efi_status_t efi_parse_options(char *cmdline) +efi_status_t efi_parse_options(char const *cmdline) { char *str; - /* - * Currently, the only efi= option we look for is 'nochunk', which - * is intended to work around known issues on certain x86 UEFI - * versions. So ignore for now on other architectures. - */ - if (!IS_ENABLED(CONFIG_X86)) - return EFI_SUCCESS; + str = strstr(cmdline, "nokaslr"); + if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) + __nokaslr = 1; + + str = strstr(cmdline, "quiet"); + if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) + __quiet = 1; /* * If no EFI parameters were specified on the cmdline we've got @@ -436,14 +448,14 @@ efi_status_t efi_parse_options(char *cmdline) * Remember, because efi= is also used by the kernel we need to * skip over arguments we don't understand. */ - while (*str) { + while (*str && *str != ' ') { if (!strncmp(str, "nochunk", 7)) { str += strlen("nochunk"); __chunk_size = -1UL; } /* Group words together, delimited by "," */ - while (*str && *str != ',') + while (*str && *str != ' ' && *str != ',') str++; if (*str == ',') diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 71c4d0e3c4ed..83f268c05007 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -24,6 +24,15 @@ #define EFI_ALLOC_ALIGN EFI_PAGE_SIZE #endif +extern int __pure nokaslr(void); +extern int __pure is_quiet(void); + +#define pr_efi(sys_table, msg) do { \ + if (!is_quiet()) efi_printk(sys_table, "EFI stub: "msg); \ +} while (0) + +#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) + void efi_char16_printk(efi_system_table_t *, efi_char16_t *); efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 260c4b4b492e..41f457be64e8 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -206,6 +206,10 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, return update_fdt_memmap(p->new_fdt_addr, map); } +#ifndef MAX_FDT_SIZE +#define MAX_FDT_SIZE SZ_2M +#endif + /* * Allocate memory for a new FDT, then add EFI, commandline, and * initrd related fields to the FDT. This routine increases the @@ -233,7 +237,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, u32 desc_ver; unsigned long mmap_key; efi_memory_desc_t *memory_map, *runtime_map; - unsigned long new_fdt_size; efi_status_t status; int runtime_entry_count = 0; struct efi_boot_memmap map; @@ -262,41 +265,29 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, "Exiting boot services and installing virtual address map...\n"); map.map = &memory_map; + status = efi_high_alloc(sys_table, MAX_FDT_SIZE, EFI_FDT_ALIGN, + new_fdt_addr, max_addr); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, + "Unable to allocate memory for new device tree.\n"); + goto fail; + } + /* - * Estimate size of new FDT, and allocate memory for it. We - * will allocate a bigger buffer if this ends up being too - * small, so a rough guess is OK here. + * Now that we have done our final memory allocation (and free) + * we can get the memory map key needed for exit_boot_services(). */ - new_fdt_size = fdt_size + EFI_PAGE_SIZE; - while (1) { - status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN, - new_fdt_addr, max_addr); - if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n"); - goto fail; - } - - status = update_fdt(sys_table, - (void *)fdt_addr, fdt_size, - (void *)*new_fdt_addr, new_fdt_size, - cmdline_ptr, initrd_addr, initrd_size); + status = efi_get_memory_map(sys_table, &map); + if (status != EFI_SUCCESS) + goto fail_free_new_fdt; - /* Succeeding the first time is the expected case. */ - if (status == EFI_SUCCESS) - break; + status = update_fdt(sys_table, (void *)fdt_addr, fdt_size, + (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr, + initrd_addr, initrd_size); - if (status == EFI_BUFFER_TOO_SMALL) { - /* - * We need to allocate more space for the new - * device tree, so free existing buffer that is - * too small. - */ - efi_free(sys_table, new_fdt_size, *new_fdt_addr); - new_fdt_size += EFI_PAGE_SIZE; - } else { - pr_efi_err(sys_table, "Unable to construct new device tree.\n"); - goto fail_free_new_fdt; - } + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Unable to construct new device tree.\n"); + goto fail_free_new_fdt; } priv.runtime_map = runtime_map; @@ -340,7 +331,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, pr_efi_err(sys_table, "Exit boot services failed.\n"); fail_free_new_fdt: - efi_free(sys_table, new_fdt_size, *new_fdt_addr); + efi_free(sys_table, MAX_FDT_SIZE, *new_fdt_addr); fail: sys_table->boottime->free_pool(runtime_map); diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index 5da36e56b36a..8c34d50a4d80 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -12,6 +12,8 @@ #include <linux/efi.h> #include <asm/efi.h> +#include "efistub.h" + /* BIOS variables */ static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID; static const efi_char16_t const efi_SecureBoot_name[] = { |