mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] efi: payload: apply barebox fixups to the devicetree passed to Linux
@ 2026-08-23 13:18 chalianis1
  0 siblings, 0 replies; only message in thread
From: chalianis1 @ 2026-08-23 13:18 UTC (permalink / raw)
  To: s.hauer; +Cc: barebox, Chali Anis

From: Chali Anis <chalianis1@gmail.com>

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.

Assisted-by: Claude Sonnet 5
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
 efi/payload/bootm.c   | 58 +++++++++++++++++++++++++++++++++++--------
 efi/payload/fdt.c     | 34 +++++++++++++++++--------
 include/efi/payload.h | 10 ++++++++
 3 files changed, 81 insertions(+), 21 deletions(-)

diff --git a/efi/payload/bootm.c b/efi/payload/bootm.c
index 2f9cc3cbf76b..094b2e9c6466 100644
--- a/efi/payload/bootm.c
+++ b/efi/payload/bootm.c
@@ -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)
diff --git a/efi/payload/fdt.c b/efi/payload/fdt.c
index 9cdb32370f22..80e6a1fcec21 100644
--- a/efi/payload/fdt.c
+++ b/efi/payload/fdt.c
@@ -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;
diff --git a/include/efi/payload.h b/include/efi/payload.h
index 381598ba59f2..8dc09dd5acdc 100644
--- a/include/efi/payload.h
+++ b/include/efi/payload.h
@@ -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



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-23 13:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-23 13:18 [PATCH] efi: payload: apply barebox fixups to the devicetree passed to Linux chalianis1

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox