| From 2bab693a608bdf614b9fcd44083c5100f34b9f77 Mon Sep 17 00:00:00 2001 |
| From: Marc Zyngier <maz@kernel.org> |
| Date: Tue, 13 Jul 2021 19:43:26 +0100 |
| Subject: firmware/efi: Tell memblock about EFI iomem reservations |
| |
| From: Marc Zyngier <maz@kernel.org> |
| |
| commit 2bab693a608bdf614b9fcd44083c5100f34b9f77 upstream. |
| |
| kexec_load_file() relies on the memblock infrastructure to avoid |
| stamping over regions of memory that are essential to the survival |
| of the system. |
| |
| However, nobody seems to agree how to flag these regions as reserved, |
| and (for example) EFI only publishes its reservations in /proc/iomem |
| for the benefit of the traditional, userspace based kexec tool. |
| |
| On arm64 platforms with GICv3, this can result in the payload being |
| placed at the location of the LPI tables. Shock, horror! |
| |
| Let's augment the EFI reservation code with a memblock_reserve() call, |
| protecting our dear tables from the secondary kernel invasion. |
| |
| Reported-by: Moritz Fischer <mdf@kernel.org> |
| Tested-by: Moritz Fischer <mdf@kernel.org> |
| Signed-off-by: Marc Zyngier <maz@kernel.org> |
| Cc: stable@vger.kernel.org |
| Cc: Ard Biesheuvel <ardb@kernel.org> |
| Cc: James Morse <james.morse@arm.com> |
| Cc: Catalin Marinas <catalin.marinas@arm.com> |
| Cc: Will Deacon <will@kernel.org> |
| Signed-off-by: Ard Biesheuvel <ardb@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/firmware/efi/efi.c | 13 ++++++++++++- |
| 1 file changed, 12 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/firmware/efi/efi.c |
| +++ b/drivers/firmware/efi/efi.c |
| @@ -896,6 +896,7 @@ static int __init efi_memreserve_map_roo |
| static int efi_mem_reserve_iomem(phys_addr_t addr, u64 size) |
| { |
| struct resource *res, *parent; |
| + int ret; |
| |
| res = kzalloc(sizeof(struct resource), GFP_ATOMIC); |
| if (!res) |
| @@ -908,7 +909,17 @@ static int efi_mem_reserve_iomem(phys_ad |
| |
| /* we expect a conflict with a 'System RAM' region */ |
| parent = request_resource_conflict(&iomem_resource, res); |
| - return parent ? request_resource(parent, res) : 0; |
| + ret = parent ? request_resource(parent, res) : 0; |
| + |
| + /* |
| + * Given that efi_mem_reserve_iomem() can be called at any |
| + * time, only call memblock_reserve() if the architecture |
| + * keeps the infrastructure around. |
| + */ |
| + if (IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK) && !ret) |
| + memblock_reserve(addr, size); |
| + |
| + return ret; |
| } |
| |
| int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) |