aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-01-15 13:54:39 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-01-15 13:54:39 -0500
commit255e6140fa76ec9d0e24f201427e7e9a9573f681 (patch)
tree242eda3c33f43faff66591f1e125169bb9a602bb /drivers/firmware
parentf4d3935e4f4884ba80561db5549394afb8eef8f7 (diff)
parent0100a3e67a9cef64d72cd3a1da86f3ddbee50363 (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: "A number of regression fixes: - Fix a boot hang on machines that have somewhat unusual memory map entries of phys_addr=0x0 num_pages=0, which broke due to a recent commit. This commit got cherry-picked from the v4.11 queue because the bug is affecting real machines. - Fix a boot hang also reported by KASAN, caused by incorrect init ordering introduced by a recent optimization. - Fix a recent robustification fix to allocate_new_fdt_and_exit_boot() that introduced an invalid assumption. Neither bugs were seen in the wild AFAIK" * 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: efi/x86: Prune invalid memory map entries and fix boot regression x86/efi: Don't allocate memmap through memblock after mm_init() efi/libstub/arm*: Pass latest memory map to the kernel
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efi/fake_mem.c3
-rw-r--r--drivers/firmware/efi/libstub/efistub.h8
-rw-r--r--drivers/firmware/efi/libstub/fdt.c87
-rw-r--r--drivers/firmware/efi/memmap.c38
4 files changed, 95 insertions, 41 deletions
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 520a40e5e0e4..6c7d60c239b5 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -71,8 +71,7 @@ void __init efi_fake_memmap(void)
71 } 71 }
72 72
73 /* allocate memory for new EFI memmap */ 73 /* allocate memory for new EFI memmap */
74 new_memmap_phy = memblock_alloc(efi.memmap.desc_size * new_nr_map, 74 new_memmap_phy = efi_memmap_alloc(new_nr_map);
75 PAGE_SIZE);
76 if (!new_memmap_phy) 75 if (!new_memmap_phy)
77 return; 76 return;
78 77
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index b98824e3800a..0e2a96b12cb3 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -39,14 +39,6 @@ efi_status_t efi_file_close(void *handle);
39 39
40unsigned long get_dram_base(efi_system_table_t *sys_table_arg); 40unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
41 41
42efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
43 unsigned long orig_fdt_size,
44 void *fdt, int new_fdt_size, char *cmdline_ptr,
45 u64 initrd_addr, u64 initrd_size,
46 efi_memory_desc_t *memory_map,
47 unsigned long map_size, unsigned long desc_size,
48 u32 desc_ver);
49
50efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, 42efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
51 void *handle, 43 void *handle,
52 unsigned long *new_fdt_addr, 44 unsigned long *new_fdt_addr,
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index a6a93116a8f0..921dfa047202 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -16,13 +16,10 @@
16 16
17#include "efistub.h" 17#include "efistub.h"
18 18
19efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, 19static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
20 unsigned long orig_fdt_size, 20 unsigned long orig_fdt_size,
21 void *fdt, int new_fdt_size, char *cmdline_ptr, 21 void *fdt, int new_fdt_size, char *cmdline_ptr,
22 u64 initrd_addr, u64 initrd_size, 22 u64 initrd_addr, u64 initrd_size)
23 efi_memory_desc_t *memory_map,
24 unsigned long map_size, unsigned long desc_size,
25 u32 desc_ver)
26{ 23{
27 int node, num_rsv; 24 int node, num_rsv;
28 int status; 25 int status;
@@ -101,25 +98,23 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
101 if (status) 98 if (status)
102 goto fdt_set_fail; 99 goto fdt_set_fail;
103 100
104 fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); 101 fdt_val64 = U64_MAX; /* placeholder */
105 status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", 102 status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
106 &fdt_val64, sizeof(fdt_val64)); 103 &fdt_val64, sizeof(fdt_val64));
107 if (status) 104 if (status)
108 goto fdt_set_fail; 105 goto fdt_set_fail;
109 106
110 fdt_val32 = cpu_to_fdt32(map_size); 107 fdt_val32 = U32_MAX; /* placeholder */
111 status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", 108 status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
112 &fdt_val32, sizeof(fdt_val32)); 109 &fdt_val32, sizeof(fdt_val32));
113 if (status) 110 if (status)
114 goto fdt_set_fail; 111 goto fdt_set_fail;
115 112
116 fdt_val32 = cpu_to_fdt32(desc_size);
117 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", 113 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
118 &fdt_val32, sizeof(fdt_val32)); 114 &fdt_val32, sizeof(fdt_val32));
119 if (status) 115 if (status)
120 goto fdt_set_fail; 116 goto fdt_set_fail;
121 117
122 fdt_val32 = cpu_to_fdt32(desc_ver);
123 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", 118 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
124 &fdt_val32, sizeof(fdt_val32)); 119 &fdt_val32, sizeof(fdt_val32));
125 if (status) 120 if (status)
@@ -148,6 +143,43 @@ fdt_set_fail:
148 return EFI_LOAD_ERROR; 143 return EFI_LOAD_ERROR;
149} 144}
150 145
146static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
147{
148 int node = fdt_path_offset(fdt, "/chosen");
149 u64 fdt_val64;
150 u32 fdt_val32;
151 int err;
152
153 if (node < 0)
154 return EFI_LOAD_ERROR;
155
156 fdt_val64 = cpu_to_fdt64((unsigned long)*map->map);
157 err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-start",
158 &fdt_val64, sizeof(fdt_val64));
159 if (err)
160 return EFI_LOAD_ERROR;
161
162 fdt_val32 = cpu_to_fdt32(*map->map_size);
163 err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-size",
164 &fdt_val32, sizeof(fdt_val32));
165 if (err)
166 return EFI_LOAD_ERROR;
167
168 fdt_val32 = cpu_to_fdt32(*map->desc_size);
169 err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-size",
170 &fdt_val32, sizeof(fdt_val32));
171 if (err)
172 return EFI_LOAD_ERROR;
173
174 fdt_val32 = cpu_to_fdt32(*map->desc_ver);
175 err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-ver",
176 &fdt_val32, sizeof(fdt_val32));
177 if (err)
178 return EFI_LOAD_ERROR;
179
180 return EFI_SUCCESS;
181}
182
151#ifndef EFI_FDT_ALIGN 183#ifndef EFI_FDT_ALIGN
152#define EFI_FDT_ALIGN EFI_PAGE_SIZE 184#define EFI_FDT_ALIGN EFI_PAGE_SIZE
153#endif 185#endif
@@ -243,20 +275,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
243 goto fail; 275 goto fail;
244 } 276 }
245 277
246 /*
247 * Now that we have done our final memory allocation (and free)
248 * we can get the memory map key needed for
249 * exit_boot_services().
250 */
251 status = efi_get_memory_map(sys_table, &map);
252 if (status != EFI_SUCCESS)
253 goto fail_free_new_fdt;
254
255 status = update_fdt(sys_table, 278 status = update_fdt(sys_table,
256 (void *)fdt_addr, fdt_size, 279 (void *)fdt_addr, fdt_size,
257 (void *)*new_fdt_addr, new_fdt_size, 280 (void *)*new_fdt_addr, new_fdt_size,
258 cmdline_ptr, initrd_addr, initrd_size, 281 cmdline_ptr, initrd_addr, initrd_size);
259 memory_map, map_size, desc_size, desc_ver);
260 282
261 /* Succeeding the first time is the expected case. */ 283 /* Succeeding the first time is the expected case. */
262 if (status == EFI_SUCCESS) 284 if (status == EFI_SUCCESS)
@@ -266,20 +288,16 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
266 /* 288 /*
267 * We need to allocate more space for the new 289 * We need to allocate more space for the new
268 * device tree, so free existing buffer that is 290 * device tree, so free existing buffer that is
269 * too small. Also free memory map, as we will need 291 * too small.
270 * to get new one that reflects the free/alloc we do
271 * on the device tree buffer.
272 */ 292 */
273 efi_free(sys_table, new_fdt_size, *new_fdt_addr); 293 efi_free(sys_table, new_fdt_size, *new_fdt_addr);
274 sys_table->boottime->free_pool(memory_map);
275 new_fdt_size += EFI_PAGE_SIZE; 294 new_fdt_size += EFI_PAGE_SIZE;
276 } else { 295 } else {
277 pr_efi_err(sys_table, "Unable to construct new device tree.\n"); 296 pr_efi_err(sys_table, "Unable to construct new device tree.\n");
278 goto fail_free_mmap; 297 goto fail_free_new_fdt;
279 } 298 }
280 } 299 }
281 300
282 sys_table->boottime->free_pool(memory_map);
283 priv.runtime_map = runtime_map; 301 priv.runtime_map = runtime_map;
284 priv.runtime_entry_count = &runtime_entry_count; 302 priv.runtime_entry_count = &runtime_entry_count;
285 status = efi_exit_boot_services(sys_table, handle, &map, &priv, 303 status = efi_exit_boot_services(sys_table, handle, &map, &priv,
@@ -288,6 +306,16 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
288 if (status == EFI_SUCCESS) { 306 if (status == EFI_SUCCESS) {
289 efi_set_virtual_address_map_t *svam; 307 efi_set_virtual_address_map_t *svam;
290 308
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
291 /* Install the new virtual address map */ 319 /* Install the new virtual address map */
292 svam = sys_table->runtime->set_virtual_address_map; 320 svam = sys_table->runtime->set_virtual_address_map;
293 status = svam(runtime_entry_count * desc_size, desc_size, 321 status = svam(runtime_entry_count * desc_size, desc_size,
@@ -319,9 +347,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
319 347
320 pr_efi_err(sys_table, "Exit boot services failed.\n"); 348 pr_efi_err(sys_table, "Exit boot services failed.\n");
321 349
322fail_free_mmap:
323 sys_table->boottime->free_pool(memory_map);
324
325fail_free_new_fdt: 350fail_free_new_fdt:
326 efi_free(sys_table, new_fdt_size, *new_fdt_addr); 351 efi_free(sys_table, new_fdt_size, *new_fdt_addr);
327 352
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
index f03ddecd232b..78686443cb37 100644
--- a/drivers/firmware/efi/memmap.c
+++ b/drivers/firmware/efi/memmap.c
@@ -9,6 +9,44 @@
9#include <linux/efi.h> 9#include <linux/efi.h>
10#include <linux/io.h> 10#include <linux/io.h>
11#include <asm/early_ioremap.h> 11#include <asm/early_ioremap.h>
12#include <linux/memblock.h>
13#include <linux/slab.h>
14
15static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
16{
17 return memblock_alloc(size, 0);
18}
19
20static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
21{
22 unsigned int order = get_order(size);
23 struct page *p = alloc_pages(GFP_KERNEL, order);
24
25 if (!p)
26 return 0;
27
28 return PFN_PHYS(page_to_pfn(p));
29}
30
31/**
32 * efi_memmap_alloc - Allocate memory for the EFI memory map
33 * @num_entries: Number of entries in the allocated map.
34 *
35 * Depending on whether mm_init() has already been invoked or not,
36 * either memblock or "normal" page allocation is used.
37 *
38 * Returns the physical address of the allocated memory map on
39 * success, zero on failure.
40 */
41phys_addr_t __init efi_memmap_alloc(unsigned int num_entries)
42{
43 unsigned long size = num_entries * efi.memmap.desc_size;
44
45 if (slab_is_available())
46 return __efi_memmap_alloc_late(size);
47
48 return __efi_memmap_alloc_early(size);
49}
12 50
13/** 51/**
14 * __efi_memmap_init - Common code for mapping the EFI memory map 52 * __efi_memmap_init - Common code for mapping the EFI memory map