From: chalianis1@gmail.com
To: s.hauer@pengutronix.de
Cc: barebox@lists.infradead.org, Chali Anis <chalianis1@gmail.com>,
Claude Sonnet 5 <noreply@anthropic.com>
Subject: [PATCH v2 1/1] efi: payload: apply barebox fixups to the devicetree passed to Linux
Date: Tue, 25 Aug 2026 01:43:45 +0200 [thread overview]
Message-ID: <20260824234345.84068-2-chalianis1@gmail.com> (raw)
In-Reply-To: <20260824234345.84068-1-chalianis1@gmail.com>
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 <noreply@anthropic.com>
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
efi/payload/bootm.c | 60 ++++++++++++++++++++++++++++++-------
efi/payload/fdt.c | 34 ++++++++++++++-------
efi/payload/init.c | 69 +++++++++++++++++++++++++++++++++++++++++++
include/efi/payload.h | 10 +++++++
4 files changed, 152 insertions(+), 21 deletions(-)
diff --git a/efi/payload/bootm.c b/efi/payload/bootm.c
index 2f9cc3cbf76b..b9e1d9438e1c 100644
--- a/efi/payload/bootm.c
+++ b/efi/payload/bootm.c
@@ -111,27 +111,61 @@ 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;
+
+ fdt_add_reserve_map(oftree);
+
+ size = efi_size_in_pages(fdt_totalsize(oftree) + 0x3000);
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 +174,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 +190,9 @@ static void efi_unload_fdt(void *fdt)
if (!fdt)
return;
+ size_t size = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
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/efi/payload/init.c b/efi/payload/init.c
index 6d2bd046e4c2..f0ce2a82cefc 100644
--- a/efi/payload/init.c
+++ b/efi/payload/init.c
@@ -203,6 +203,75 @@ static int efi_core_init(void)
}
core_efi_initcall(efi_core_init);
+/**
+ * efi_of_fixup_firmware_nodes() - import firmware-injected nodes onto @root
+ *
+ * A devicetree supplied out-of-band (e.g. embedded in a FIT image) was
+ * flattened at build time, so it can never carry nodes that firmware only
+ * adds to its own devicetree at runtime - most importantly the
+ * /reserved-memory carve-outs TF-A/OP-TEE add to mark their own
+ * secure-world memory off-limits (as child nodes, e.g. tegra-carveouts on
+ * Tegra), and the /firmware node describing the secure monitor call
+ * conduit. /firmware is copied wholesale, replacing whatever @root already
+ * had there. /reserved-memory is merged child by child instead, since
+ * @root may already carry its own reservations alongside firmware's:
+ * each child firmware's tree has is copied into @root's /reserved-memory
+ * (created if necessary), replacing any child of the same name @root
+ * already had.
+ */
+static int efi_of_fixup_firmware_nodes(struct device_node *root, void *unused)
+{
+ struct fdt_header *fw_oftree;
+ struct device_node *fw_root, *fw_firmware, *fw_resmem, *dst_resmem;
+ struct device_node *dst;
+ size_t fw_size;
+
+ fw_oftree = efi_fdt_find(&fw_size);
+ if (IS_ERR(fw_oftree))
+ return 0;
+
+ fw_root = of_unflatten_dtb(fw_oftree, fw_size);
+ if (IS_ERR(fw_root))
+ return 0;
+
+ fw_firmware = of_get_child_by_name(fw_root, "firmware");
+ if (fw_firmware) {
+ dst = of_get_child_by_name(root, "firmware");
+ if (dst)
+ of_delete_node(dst);
+
+ of_copy_node(root, fw_firmware);
+ }
+
+ fw_resmem = of_get_child_by_name(fw_root, "reserved-memory");
+ if (fw_resmem) {
+ dst_resmem = of_get_child_by_name(root, "reserved-memory");
+ if (!dst_resmem) {
+ of_copy_node(root, fw_resmem);
+ } else {
+ struct device_node *child;
+
+ for_each_child_of_node(fw_resmem, child) {
+ dst = of_get_child_by_name(dst_resmem, child->name);
+ if (dst)
+ of_delete_node(dst);
+
+ of_copy_node(dst_resmem, child);
+ }
+ }
+ }
+
+ of_delete_node(fw_root);
+
+ return 0;
+}
+
+static int efi_register_firmware_nodes_fixup(void)
+{
+ return of_register_fixup(efi_of_fixup_firmware_nodes, NULL);
+}
+core_efi_initcall(efi_register_firmware_nodes_fixup);
+
/* Features of the loader, i.e. systemd-boot, barebox (imported from systemd) */
#define EFI_LOADER_FEATURE_CONFIG_TIMEOUT (1LL << 0)
#define EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT (1LL << 1)
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
prev parent reply other threads:[~2026-08-24 23:45 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 23:43 [PATCH v2 0/1] efi: payload: apply barebox fixups to the devicetree passed to Linux chalianis1
2026-08-24 23:43 ` chalianis1 [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260824234345.84068-2-chalianis1@gmail.com \
--to=chalianis1@gmail.com \
--cc=barebox@lists.infradead.org \
--cc=noreply@anthropic.com \
--cc=s.hauer@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.