diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-02 16:20:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-02 16:20:23 -0500 |
commit | c67b42f3a3f03e68bf915f32c8f7be0b726fec1a (patch) | |
tree | 9abf8c8a276cd5e8119e5c50f53afc220648008e | |
parent | 027eb72cbcf81561867a764074964e2ce9828398 (diff) | |
parent | c8f325a59cfc718d13a50fbc746ed9b415c25e92 (diff) |
Merge branch 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI fixes from Ingo Molnar:
"Two EFI boot fixes, one for arm64 and one for x86 systems with certain
firmware versions"
* 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
efi/fdt: Avoid FDT manipulation after ExitBootServices()
x86/efi: Always map the first physical page into the EFI pagetables
-rw-r--r-- | arch/x86/platform/efi/efi_64.c | 16 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 14 |
2 files changed, 19 insertions, 11 deletions
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 319148bd4b05..2f25a363068c 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
@@ -269,6 +269,22 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | |||
269 | efi_scratch.use_pgd = true; | 269 | efi_scratch.use_pgd = true; |
270 | 270 | ||
271 | /* | 271 | /* |
272 | * Certain firmware versions are way too sentimential and still believe | ||
273 | * they are exclusive and unquestionable owners of the first physical page, | ||
274 | * even though they explicitly mark it as EFI_CONVENTIONAL_MEMORY | ||
275 | * (but then write-access it later during SetVirtualAddressMap()). | ||
276 | * | ||
277 | * Create a 1:1 mapping for this page, to avoid triple faults during early | ||
278 | * boot with such firmware. We are free to hand this page to the BIOS, | ||
279 | * as trim_bios_range() will reserve the first page and isolate it away | ||
280 | * from memory allocators anyway. | ||
281 | */ | ||
282 | if (kernel_map_pages_in_pgd(pgd, 0x0, 0x0, 1, _PAGE_RW)) { | ||
283 | pr_err("Failed to create 1:1 mapping for the first page!\n"); | ||
284 | return 1; | ||
285 | } | ||
286 | |||
287 | /* | ||
272 | * When making calls to the firmware everything needs to be 1:1 | 288 | * When making calls to the firmware everything needs to be 1:1 |
273 | * mapped and addressable with 32-bit pointers. Map the kernel | 289 | * mapped and addressable with 32-bit pointers. Map the kernel |
274 | * text and allocate a new stack because we can't rely on the | 290 | * text and allocate a new stack because we can't rely on the |
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) | |||
187 | struct exit_boot_struct { | 187 | struct 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 | ||
192 | static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, | 193 | static 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, |