diff options
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 8 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 87 |
2 files changed, 56 insertions, 39 deletions
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index ee49cd23ee63..fac67992bede 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h | |||
@@ -30,14 +30,6 @@ efi_status_t efi_file_close(void *handle); | |||
30 | 30 | ||
31 | unsigned long get_dram_base(efi_system_table_t *sys_table_arg); | 31 | unsigned long get_dram_base(efi_system_table_t *sys_table_arg); |
32 | 32 | ||
33 | efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, | ||
34 | unsigned long orig_fdt_size, | ||
35 | void *fdt, int new_fdt_size, char *cmdline_ptr, | ||
36 | u64 initrd_addr, u64 initrd_size, | ||
37 | efi_memory_desc_t *memory_map, | ||
38 | unsigned long map_size, unsigned long desc_size, | ||
39 | u32 desc_ver); | ||
40 | |||
41 | efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, | 33 | efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, |
42 | void *handle, | 34 | void *handle, |
43 | unsigned long *new_fdt_addr, | 35 | 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 | ||
19 | efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, | 19 | static 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 | ||
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 | |||
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 | ||
322 | fail_free_mmap: | ||
323 | sys_table->boottime->free_pool(memory_map); | ||
324 | |||
325 | fail_free_new_fdt: | 350 | fail_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 | ||