Skip to content

Commit abfb7b6

Browse files
Ard BiesheuvelIngo Molnar
Ard Biesheuvel
authored and
Ingo Molnar
committed
efi/libstub/arm*: Pass latest memory map to the kernel
As reported by James Morse, the current libstub code involving the annotated memory map only works somewhat correctly by accident, due to the fact that a pool allocation happens to be reused immediately, retaining its former contents on most implementations of the UEFI boot services. Instead of juggling memory maps, which makes the code more complex than it needs to be, simply put placeholder values into the FDT for the memory map parameters, and only write the actual values after ExitBootServices() has been called. Reported-by: James Morse <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Cc: <[email protected]> Cc: Jeffrey Hugo <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Matt Fleming <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: [email protected] Fixes: ed9cc15 ("efi/libstub: Use efi_exit_boot_services() in FDT") Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 2d706e7 commit abfb7b6

File tree

2 files changed

+56
-39
lines changed

2 files changed

+56
-39
lines changed

drivers/firmware/efi/libstub/efistub.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ efi_status_t efi_file_close(void *handle);
3939

4040
unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
4141

42-
efi_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-
5042
efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
5143
void *handle,
5244
unsigned long *new_fdt_addr,

drivers/firmware/efi/libstub/fdt.c

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,10 @@
1616

1717
#include "efistub.h"
1818

19-
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
20-
unsigned long orig_fdt_size,
21-
void *fdt, int new_fdt_size, char *cmdline_ptr,
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)
19+
static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
20+
unsigned long orig_fdt_size,
21+
void *fdt, int new_fdt_size, char *cmdline_ptr,
22+
u64 initrd_addr, u64 initrd_size)
2623
{
2724
int node, num_rsv;
2825
int status;
@@ -101,25 +98,23 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
10198
if (status)
10299
goto fdt_set_fail;
103100

104-
fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
101+
fdt_val64 = U64_MAX; /* placeholder */
105102
status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
106103
&fdt_val64, sizeof(fdt_val64));
107104
if (status)
108105
goto fdt_set_fail;
109106

110-
fdt_val32 = cpu_to_fdt32(map_size);
107+
fdt_val32 = U32_MAX; /* placeholder */
111108
status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
112109
&fdt_val32, sizeof(fdt_val32));
113110
if (status)
114111
goto fdt_set_fail;
115112

116-
fdt_val32 = cpu_to_fdt32(desc_size);
117113
status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
118114
&fdt_val32, sizeof(fdt_val32));
119115
if (status)
120116
goto fdt_set_fail;
121117

122-
fdt_val32 = cpu_to_fdt32(desc_ver);
123118
status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
124119
&fdt_val32, sizeof(fdt_val32));
125120
if (status)
@@ -148,6 +143,43 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
148143
return EFI_LOAD_ERROR;
149144
}
150145

146+
static 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+
151183
#ifndef EFI_FDT_ALIGN
152184
#define EFI_FDT_ALIGN EFI_PAGE_SIZE
153185
#endif
@@ -243,20 +275,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
243275
goto fail;
244276
}
245277

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-
255278
status = update_fdt(sys_table,
256279
(void *)fdt_addr, fdt_size,
257280
(void *)*new_fdt_addr, new_fdt_size,
258-
cmdline_ptr, initrd_addr, initrd_size,
259-
memory_map, map_size, desc_size, desc_ver);
281+
cmdline_ptr, initrd_addr, initrd_size);
260282

261283
/* Succeeding the first time is the expected case. */
262284
if (status == EFI_SUCCESS)
@@ -266,20 +288,16 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
266288
/*
267289
* We need to allocate more space for the new
268290
* device tree, so free existing buffer that is
269-
* too small. Also free memory map, as we will need
270-
* to get new one that reflects the free/alloc we do
271-
* on the device tree buffer.
291+
* too small.
272292
*/
273293
efi_free(sys_table, new_fdt_size, *new_fdt_addr);
274-
sys_table->boottime->free_pool(memory_map);
275294
new_fdt_size += EFI_PAGE_SIZE;
276295
} else {
277296
pr_efi_err(sys_table, "Unable to construct new device tree.\n");
278-
goto fail_free_mmap;
297+
goto fail_free_new_fdt;
279298
}
280299
}
281300

282-
sys_table->boottime->free_pool(memory_map);
283301
priv.runtime_map = runtime_map;
284302
priv.runtime_entry_count = &runtime_entry_count;
285303
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,
288306
if (status == EFI_SUCCESS) {
289307
efi_set_virtual_address_map_t *svam;
290308

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+
291319
/* Install the new virtual address map */
292320
svam = sys_table->runtime->set_virtual_address_map;
293321
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,
319347

320348
pr_efi_err(sys_table, "Exit boot services failed.\n");
321349

322-
fail_free_mmap:
323-
sys_table->boottime->free_pool(memory_map);
324-
325350
fail_free_new_fdt:
326351
efi_free(sys_table, new_fdt_size, *new_fdt_addr);
327352

0 commit comments

Comments
 (0)