efi: payload: apply barebox fixups to the devicetree passed to Linux
PATCH 1/1 efi: payload: apply barebox fixups to the devicetree passed to Linux
From: Chali Anis <[email protected]>
efi_load_fdt() never ran barebox's fixup/overlay pipeline on the devicetree it handed to the kernel. When bootm.oftree was set, the raw file bytes were extracted straight into EFI pages and installed as-is via loadable_extract_into_buf_full(); of_unflatten_dtb(), of_fix_tree() and of_flatten_dtb() were never called. When bootm.oftree was unset, the function just returned early, so there was no path at all for adopting (and fixing up) a devicetree already exposed by firmware. Either way, none of barebox's usual fixups -- memory nodes, bootargs, state, overlays, and everything else hung off of_register_fixup() -- ever reached the tree Linux booted with.
Fix this for both sources: add efi_fdt_find() to locate the FDT firmware exposes via its EFI configuration table, and have efi_load_fdt() fall back to it when no bootm.oftree is set. Whichever tree is in play, unflatten it into data->of_root_node, run it through the standard bootm_set_pending_oftree_overlays()/of_fix_tree() sequence, reflatten it, and install the fixed-up result as the UEFI configuration table -- matching what every other barebox boot path already guarantees.
While here, size the FDT allocation/free from the actual flattened tree instead of a fixed 2 MiB buffer, and reuse efi_fdt_find() in the existing efi_fdt_probe() initcall so both callers share one EFI-configuration-table lookup instead of duplicating it.
--- efi/payload/bootm.c | 58 +++++++++++++++++++++++++++++++++++-------- efi/payload/fdt.c | 34 +++++++++++++++++-------- include/efi/payload.h | 10 ++++++++ 3 files changed, 81 insertions(+), 21 deletions(-)
efi/payload/bootm.c +47 -11
@@ -111,27 +111,59 @@ static int efi_load_ramdisk(struct image_data *data,static int efi_load_fdt (struct image_data *data,void **fdt) {efi_physical_addr_t mem; +struct fdt_header *oftree; +bool is_loadable = true;efi_status_t efiret; +size_t size;void *vmem; -size_t bufsize =DIV_ROUND_UP (SZ_2M ,EFI_PAGE_SIZE ); -ssize_t ret; +int ret; + +if (!data->oftree) { +/* +* No devicetree requested; fall back to the one provided by +* firmware (if any) so barebox's fixups still get applied to it. +*/ + oftree =efi_fdt_find (&size); + is_loadable = false; + }else { + oftree =loadable_extract (data->oftree, &size) ?:ERR_PTR (-ENODATA ); +if (IS_ERR (oftree)) +pr_warn ("Failed to extract oftree\n" ); + } -if (!data->oftree) +if (IS_ERR (oftree))return 0 ; + data->of_root_node =of_unflatten_dtb (oftree, size); +if (IS_ERR (data->of_root_node)) { + data->of_root_node =NULL ; +pr_err ("unable to unflatten devicetree\n" ); +return -EINVAL ; + } + +if (is_loadable) +free (oftree); + +bootm_set_pending_oftree_overlays (data->oftree); +of_fix_tree (data->of_root_node); +bootm_clear_pending_oftree_overlays (); + + oftree =of_flatten_dtb (data->of_root_node); +if (!oftree) +return -EINVAL ; + + size =DIV_ROUND_UP (fdt_totalsize (oftree),EFI_PAGE_SIZE ); efiret =BS ->allocate_pages (EFI_ALLOCATE_ANY_PAGES ,EFI_ACPI_RECLAIM_MEMORY , - bufsize, &mem); + size, &mem);if (EFI_ERROR (efiret)) {pr_err ("Failed to allocate pages for FDT: %s\n" ,efi_strerror (efiret)); -return -efi_errno (efiret); + ret = -efi_errno (efiret); + goto free_oftree; } vmem =efi_phys_to_virt (mem); - ret =loadable_extract_into_buf_full (data->oftree, vmem, - bufsize *EFI_PAGE_SIZE ); -if (ret <0 ) - goto free_efi_mem; +memcpy (vmem, oftree,fdt_totalsize (oftree)); efiret =BS ->install_configuration_table (&efi_fdt_guid, vmem);if (EFI_ERROR (efiret)) {
@@ -140,11 +172,14 @@ static int efi_load_fdt(struct image_data *data, void **fdt) goto free_efi_mem; } +free (oftree); *fdt = vmem;return 0 ; free_efi_mem: -BS ->free_pages (mem, bufsize); +BS ->free_pages (mem, size); +free_oftree: +free (oftree);return ret; }
@@ -153,8 +188,9 @@ static void efi_unload_fdt(void *fdt)if (!fdt)return ; +size_t size =DIV_ROUND_UP (fdt_totalsize (fdt),EFI_PAGE_SIZE );BS ->install_configuration_table (&efi_fdt_guid,NULL ); -BS ->free_pages (efi_virt_to_phys (fdt),DIV_ROUND_UP (SZ_2M ,EFI_PAGE_SIZE )); +BS ->free_pages (efi_virt_to_phys (fdt), size); }static int do_bootm_efi_stub (struct image_data *data)
efi/payload/fdt.c +24 -10
@@ -9,14 +9,14 @@#include <efi/payload/init.h> #include <efi/guid.h> -static int efi_fdt_probe (void ) +void *efi_fdt_find (size_t *size) {struct efi_config_table *ect; + *size =0 ;for_each_efi_config_table (ect) {struct fdt_header *oftree; -u32 magic, size; -int ret; +u32 magic;if (efi_guidcmp (ect->guid,EFI_DEVICE_TREE_GUID ))continue ;
@@ -26,17 +26,31 @@ static int efi_fdt_probe(void)if (magic !=FDT_MAGIC ) {pr_err ("table has invalid magic 0x%08x\n" , magic); -return -EILSEQ ; +return ERR_PTR (-EILSEQ ); } - size =be32_to_cpu (oftree->totalsize); - ret =write_file ("/efi.dtb" , oftree, size); -if (ret) { -pr_err ("error saving /efi.dtb: %pe\n" ,ERR_PTR (ret)); -return ret; - } + *size =fdt_totalsize (oftree); +return oftree; + } + +pr_warn ("No FDT found in EFI configuration tables\n" ); +return ERR_PTR (-ENODATA ); +} +static int efi_fdt_probe (void ) +{ +struct fdt_header *oftree; +size_t size; +int ret; + + oftree =efi_fdt_find (&size); +if (IS_ERR (oftree) || !size)return 0 ; + + ret =write_file ("/efi.dtb" , oftree, size); +if (ret) { +pr_err ("error saving /efi.dtb: %pe\n" ,ERR_PTR (ret)); +return ret; }return 0 ;
include/efi/payload.h +10 -0
@@ -34,4 +34,14 @@ __attribute__((noreturn)) void efi_main(efi_handle_t, struct efi_system_table *) t - efi_sys_table->tables < efi_sys_table->nr_tables; \ t++) +#if IS_ENABLED (CONFIG_OFTREE ) +void *efi_fdt_find (size_t *size); +#else +static inline void *efi_fdt_find (size_t *size) +{ + *size =0 ; +return NULL ; +} +#endif +#endif