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 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 | ||
| 40 | unsigned long get_dram_base(efi_system_table_t *sys_table_arg); | 40 | unsigned long get_dram_base(efi_system_table_t *sys_table_arg); |
| 41 | 41 | ||
| 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 | |||
| 50 | efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, | 42 | efi_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 | ||
| 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 | ||
