* [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