aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-02-01 12:45:02 -0500
committerIngo Molnar <mingo@kernel.org>2017-02-01 15:17:49 -0500
commitc8f325a59cfc718d13a50fbc746ed9b415c25e92 (patch)
treed53fbdac9d0781e39a13b2ac6b2bd258cf3b4140
parentbf29bddf0417a4783da3b24e8c9e017ac649326f (diff)
efi/fdt: Avoid FDT manipulation after ExitBootServices()
Some AArch64 UEFI implementations disable the MMU in ExitBootServices(), after which unaligned accesses to RAM are no longer supported. Commit: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") fixed an issue in the memory map handling of the stub FDT code, but inadvertently created an issue with such firmware, by moving some of the FDT manipulation to after the invocation of ExitBootServices(). Given that the stub's libfdt implementation uses the ordinary, accelerated string functions, which rely on hardware handling of unaligned accesses, manipulating the FDT with the MMU off may result in alignment faults. So fix the situation by moving the update_fdt_memmap() call into the callback function invoked by efi_exit_boot_services() right before it calls the ExitBootServices() UEFI service (which is arguably a better place for it anyway) Note that disabling the MMU in ExitBootServices() is not compliant with the UEFI spec, and carries great risk due to the fact that switching from cached to uncached memory accesses halfway through compiler generated code (i.e., involving a stack) can never be done in a way that is architecturally safe. Fixes: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Tested-by: Riku Voipio <riku.voipio@linaro.org> Cc: <stable@vger.kernel.org> Cc: mark.rutland@arm.com Cc: linux-efi@vger.kernel.org Cc: matt@codeblueprint.co.uk Cc: leif.lindholm@linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1485971102-23330-2-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--drivers/firmware/efi/libstub/fdt.c14
1 files changed, 3 insertions, 11 deletions
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 921dfa047202..260c4b4b492e 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -187,6 +187,7 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
187struct exit_boot_struct { 187struct exit_boot_struct {
188 efi_memory_desc_t *runtime_map; 188 efi_memory_desc_t *runtime_map;
189 int *runtime_entry_count; 189 int *runtime_entry_count;
190 void *new_fdt_addr;
190}; 191};
191 192
192static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, 193static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
@@ -202,7 +203,7 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
202 efi_get_virtmap(*map->map, *map->map_size, *map->desc_size, 203 efi_get_virtmap(*map->map, *map->map_size, *map->desc_size,
203 p->runtime_map, p->runtime_entry_count); 204 p->runtime_map, p->runtime_entry_count);
204 205
205 return EFI_SUCCESS; 206 return update_fdt_memmap(p->new_fdt_addr, map);
206} 207}
207 208
208/* 209/*
@@ -300,22 +301,13 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
300 301
301 priv.runtime_map = runtime_map; 302 priv.runtime_map = runtime_map;
302 priv.runtime_entry_count = &runtime_entry_count; 303 priv.runtime_entry_count = &runtime_entry_count;
304 priv.new_fdt_addr = (void *)*new_fdt_addr;
303 status = efi_exit_boot_services(sys_table, handle, &map, &priv, 305 status = efi_exit_boot_services(sys_table, handle, &map, &priv,
304 exit_boot_func); 306 exit_boot_func);
305 307
306 if (status == EFI_SUCCESS) { 308 if (status == EFI_SUCCESS) {
307 efi_set_virtual_address_map_t *svam; 309 efi_set_virtual_address_map_t *svam;
308 310
309 status = update_fdt_memmap((void *)*new_fdt_addr, &map);
310 if (status != EFI_SUCCESS) {
311 /*
312 * The kernel won't get far without the memory map, but
313 * may still be able to print something meaningful so
314 * return success here.
315 */
316 return EFI_SUCCESS;
317 }
318
319 /* Install the new virtual address map */ 311 /* Install the new virtual address map */
320 svam = sys_table->runtime->set_virtual_address_map; 312 svam = sys_table->runtime->set_virtual_address_map;
321 status = svam(runtime_entry_count * desc_size, desc_size, 313 status = svam(runtime_entry_count * desc_size, desc_size,