diff options
| author | Matt Fleming <matt@codeblueprint.co.uk> | 2016-02-29 16:22:52 -0500 |
|---|---|---|
| committer | Matt Fleming <matt@codeblueprint.co.uk> | 2016-09-09 11:08:34 -0400 |
| commit | 816e76129ed5fadd28e526c43397c79775194b5c (patch) | |
| tree | de3ec000aa5bb1fdbc6d652fbd4db9da0e82ebda /drivers/firmware | |
| parent | c45f4da33a297f85435f8dccb26a24852ea01bb9 (diff) | |
efi: Allow drivers to reserve boot services forever
Today, it is not possible for drivers to reserve EFI boot services for
access after efi_free_boot_services() has been called on x86. For
ARM/arm64 it can be done simply by calling memblock_reserve().
Having this ability for all three architectures is desirable for a
couple of reasons,
1) It saves drivers copying data out of those regions
2) kexec reboot can now make use of things like ESRT
Instead of using the standard memblock_reserve() which is insufficient
to reserve the region on x86 (see efi_reserve_boot_services()), a new
API is introduced in this patch; efi_mem_reserve().
efi.memmap now always represents which EFI memory regions are
available. On x86 the EFI boot services regions that have not been
reserved via efi_mem_reserve() will be removed from efi.memmap during
efi_free_boot_services().
This has implications for kexec, since it is not possible for a newly
kexec'd kernel to access the same boot services regions that the
initial boot kernel had access to unless they are reserved by every
kexec kernel in the chain.
Tested-by: Dave Young <dyoung@redhat.com> [kexec/kdump]
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> [arm]
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Diffstat (limited to 'drivers/firmware')
| -rw-r--r-- | drivers/firmware/efi/efi.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index d4886fd50c16..dfe07316cae5 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/acpi.h> | 28 | #include <linux/acpi.h> |
| 29 | #include <linux/ucs2_string.h> | 29 | #include <linux/ucs2_string.h> |
| 30 | #include <linux/memblock.h> | ||
| 30 | 31 | ||
| 31 | #include <asm/early_ioremap.h> | 32 | #include <asm/early_ioremap.h> |
| 32 | 33 | ||
| @@ -396,6 +397,35 @@ u64 __init efi_mem_desc_end(efi_memory_desc_t *md) | |||
| 396 | return end; | 397 | return end; |
| 397 | } | 398 | } |
| 398 | 399 | ||
| 400 | void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {} | ||
| 401 | |||
| 402 | /** | ||
| 403 | * efi_mem_reserve - Reserve an EFI memory region | ||
| 404 | * @addr: Physical address to reserve | ||
| 405 | * @size: Size of reservation | ||
| 406 | * | ||
| 407 | * Mark a region as reserved from general kernel allocation and | ||
| 408 | * prevent it being released by efi_free_boot_services(). | ||
| 409 | * | ||
| 410 | * This function should be called drivers once they've parsed EFI | ||
| 411 | * configuration tables to figure out where their data lives, e.g. | ||
| 412 | * efi_esrt_init(). | ||
| 413 | */ | ||
| 414 | void __init efi_mem_reserve(phys_addr_t addr, u64 size) | ||
| 415 | { | ||
| 416 | if (!memblock_is_region_reserved(addr, size)) | ||
| 417 | memblock_reserve(addr, size); | ||
| 418 | |||
| 419 | /* | ||
| 420 | * Some architectures (x86) reserve all boot services ranges | ||
| 421 | * until efi_free_boot_services() because of buggy firmware | ||
| 422 | * implementations. This means the above memblock_reserve() is | ||
| 423 | * superfluous on x86 and instead what it needs to do is | ||
| 424 | * ensure the @start, @size is not freed. | ||
| 425 | */ | ||
| 426 | efi_arch_mem_reserve(addr, size); | ||
| 427 | } | ||
| 428 | |||
| 399 | static __initdata efi_config_table_type_t common_tables[] = { | 429 | static __initdata efi_config_table_type_t common_tables[] = { |
| 400 | {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, | 430 | {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, |
| 401 | {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, | 431 | {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, |
