[PATCH 2/4] bootmeth: efi: source the devicetree from a firmware partition

Carlo Caione ccaione at baylibre.com
Mon Jul 6 17:06:43 CEST 2026


When a firmware-owned devicetree source is configured (EBBR / Arm
SystemReady IR), assemble the devicetree from the FIT manifest on
the firmware partition instead of reading a DTB from the EFI System
Partition, and hand it to the EFI application through the normal
bflow->fdt_addr path (efi_install_fdt()).

Signed-off-by: Carlo Caione <ccaione at baylibre.com>
---
 boot/bootmeth_efi.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c
index e187dc39912..ae3f1c9b91e 100644
--- a/boot/bootmeth_efi.c
+++ b/boot/bootmeth_efi.c
@@ -17,6 +17,7 @@
 #include <efi_loader.h>
 #include <env.h>
 #include <extension_board.h>
+#include <firmware_fdt.h>
 #include <fs.h>
 #include <malloc.h>
 #include <mapmem.h>
@@ -73,6 +74,61 @@ static int efiload_read_file(struct bootflow *bflow, ulong addr)
 	return 0;
 }
 
+/**
+ * distro_efi_firmware_fdt() - try to stage the firmware-owned devicetree
+ *
+ * Prefer a firmware-owned devicetree if one is configured: assemble it
+ * from the FIT manifest on the firmware partition, stage it at 'fdt_addr_r'
+ * and fill the bootflow, so it reaches the EFI app through the normal
+ * bflow->fdt_addr path (efi_install_fdt()).
+ *
+ * The semantics are fail closed: only -ENOENT (no firmware-FDT source
+ * configured) lets the caller fall back to its normal devicetree source, so
+ * a missing or broken firmware devicetree is never silently replaced.
+ *
+ * @bflow: bootflow to update
+ * Return: 0 if the firmware devicetree was staged (the bootflow devicetree
+ * fields are set), -ENOENT if no source is configured, other -ve error if a
+ * configured source failed to assemble (the bootflow must fail)
+ */
+static int distro_efi_firmware_fdt(struct bootflow *bflow)
+{
+	struct firmware_fdt fw;
+	ulong fdt_addr;
+	int ret;
+
+	if (!CONFIG_IS_ENABLED(BOOTSTD_FIRMWARE_FDT))
+		return -ENOENT;
+
+	ret = firmware_fdt_load(&fw);
+	if (ret) {
+		if (ret != -ENOENT)
+			log_err("Failed to assemble the firmware devicetree (err %d)\n",
+				ret);
+		return ret;
+	}
+
+	/* stage it at fdt_addr_r, like any other devicetree */
+	fdt_addr = env_get_hex("fdt_addr_r", 0);
+	if (!fdt_addr || fw.size > SZ_4M) {
+		firmware_fdt_free(&fw);
+		return log_msg_ret("fwa", -EINVAL);
+	}
+
+	memcpy(map_sysmem(fdt_addr, fw.size), fw.fdt, fw.size);
+
+	bflow->fdt_fname = strdup(fw.name);
+	bflow->fdt_size = fw.size;
+	bflow->fdt_addr = fdt_addr;
+	firmware_fdt_free(&fw);
+	if (!bflow->fdt_fname)
+		return log_msg_ret("fwn", -ENOMEM);
+
+	log_debug("Using firmware-owned devicetree\n");
+
+	return 0;
+}
+
 static int distro_efi_check(struct udevice *dev, struct bootflow_iter *iter)
 {
 	/* This only works on block and network devices */
@@ -130,6 +186,18 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
 
 	fdt_addr = env_get_hex("fdt_addr_r", 0);
 
+	/*
+	 * A staged firmware-owned devicetree is complete and authoritative,
+	 * so return without considering any other devicetree source. The
+	 * extension overlays below are deliberately not applied on top:
+	 * such combinations belong in the manifest as configurations.
+	 */
+	ret = distro_efi_firmware_fdt(bflow);
+	if (!ret)
+		return 0;
+	if (ret != -ENOENT)
+		return log_msg_ret("fwf", ret);
+
 	/* try the various available names */
 	ret = -ENOENT;
 	*fname = '\0';
@@ -268,6 +336,19 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow)
 	if (!bflow->fname)
 		return log_msg_ret("fi0", -ENOMEM);
 
+	/*
+	 * A configured firmware-owned devicetree outranks the network-provided
+	 * one (and the prior-stage / built-in devicetree below): a DHCP/TFTP
+	 * server must not be able to replace it.
+	 */
+	ret = distro_efi_firmware_fdt(bflow);
+	if (!ret) {
+		bflow->state = BOOTFLOWST_READY;
+		return 0;
+	}
+	if (ret != -ENOENT)
+		return log_msg_ret("fwf", ret);
+
 	/* read the DT file also */
 	ret = efi_get_distro_fdt_name(fname, sizeof(fname), 0);
 	if (ret == -EALREADY) {

-- 
2.55.0



More information about the U-Boot mailing list