aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/libstub/fdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/efi/libstub/fdt.c')
-rw-r--r--drivers/firmware/efi/libstub/fdt.c87
1 files changed, 56 insertions, 31 deletions
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