mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Johannes Schneider <johannes.schneider@leica-geosystems.com>
To: barebox@lists.infradead.org
Cc: Marco Felsch <m.felsch@pengutronix.de>,
	Johannes Schneider <johannes.schneider@leica-geosystems.com>
Subject: [PATCH v1 13/14] efi: loader: bootm: install a devicetree for matching UKI devicetrees
Date: Sun,  4 Oct 2026 01:19:46 +0000	[thread overview]
Message-ID: <20261004011958.3255011-14-johannes.schneider@leica-geosystems.com> (raw)
In-Reply-To: <20261004011958.3255011-1-johannes.schneider@leica-geosystems.com>

systemd-stub replaces the devicetree installed as EFI configuration
table with the .dtbauto section of a UKI whose first compatible equals
the installed devicetree's first compatible, or else with a .dtb
section. Without CONFIG_BOOTM_OFTREE_FALLBACK, bootm_get_devicetree()
returns nothing for an image without a devicetree of its own, the stub
would then pick no .dtbauto section, and the kernel starts on an empty
devicetree, silently without a console:

  EFI stub: Generating empty DTB
  EFI stub: Exiting boot services...

Have barebox check if a .dtbauto section in the UKI matches the
machine compatible, and if so install a devicetree consisting of a
root node with only the full machine compatible, vendor prefix
included, to give the stub something valid to compare and pick the
matching .dtbauto section by. barebox then fixes up that section
through EFI_DT_FIXUP_PROTOCOL.

If no section matches, the UKI carries no .dtb and bootm provides no
devicetree either, refuse the UKI before starting it, so that the boot
fails where it can be seen and bootchooser can fall back.

All of the above only if barebox describes hardware by a devicetree,
i.e. with CONFIG_OFTREE, so that the EFI loader keeps building without
the devicetree code.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com>
---
 efi/loader/bootm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/efi/loader/bootm.c b/efi/loader/bootm.c
index fa12caf560..47f7a3d1e2 100644
--- a/efi/loader/bootm.c
+++ b/efi/loader/bootm.c
@@ -38,6 +38,9 @@
 #include <efi/loader/authenticode.h>
 #include <efi/loader/pe.h>
 #include <loadable.h>
+#include <of.h>
+#include <barebox-info.h>
+#include <linux/libfdt.h>
 
 /**
  * copy_fdt() - Copy the device tree to a new location available to EFI
@@ -220,6 +223,86 @@ static int efi_loader_verify(struct image_data *data, void *efi, size_t size)
 	return 0;
 }
 
+static const char *efi_machine_compatible(void)
+{
+	const char *compat = barebox_get_of_machine_compatible();
+
+	/* with vendor prefix, unlike of_get_machine_compatible() */
+	if (!compat)
+		of_property_read_string(of_get_root_node(), "compatible", &compat);
+
+	return compat;
+}
+
+/* The first compatible of the devicetree root, as systemd-stub compares it */
+static bool efi_dtb_first_compatible_is(const void *dtb, size_t len,
+					const char *compat)
+{
+	const char *prop;
+	int plen;
+
+	if (len < sizeof(struct fdt_header) || fdt_check_header(dtb) ||
+	    fdt_totalsize(dtb) > len)
+		return false;
+
+	prop = fdt_getprop(dtb, 0, "compatible", &plen);
+
+	return prop && plen > 0 && strnlen(prop, plen) < plen &&
+	       !strcmp(prop, compat);
+}
+
+static bool efi_uki_has_dtbauto_for(void *efi, size_t size, const char *compat)
+{
+	const void *dtb;
+	size_t len;
+	int index = 0;
+
+	while ((dtb = efi_pe_find_next_section(efi, size, ".dtbauto", &len,
+					       &index)))
+		if (efi_dtb_first_compatible_is(dtb, len, compat))
+			return true;
+
+	return false;
+}
+
+/*
+ * Without a devicetree installed and without a .dtb section, systemd-stub
+ * starts the kernel on no devicetree at all, and it boots without a console
+ */
+static bool efi_uki_lacks_devicetree(void *efi, size_t size, const char *compat)
+{
+	size_t len;
+
+	if (!efi_pe_find_section(efi, size, ".linux", &len) ||
+	    efi_pe_find_section(efi, size, ".dtb", &len))
+		return false;
+
+	if (!efi_pe_find_section(efi, size, ".dtbauto", &len))
+		pr_err("UKI brings no devicetree and none was given\n");
+	else if (compat)
+		pr_err("UKI has no devicetree for \"%s\"\n", compat);
+	else
+		pr_err("no machine compatible to select a UKI devicetree with\n");
+
+	return true;
+}
+
+/* Just enough of a devicetree for systemd-stub to pick a .dtbauto section */
+static void *efi_uki_matching_devicetree(const char *compat)
+{
+	struct device_node *root;
+	void *fdt;
+
+	root = of_new_node(NULL, NULL);
+	of_property_write_string(root, "compatible", compat);
+	fdt = of_flatten_dtb(root);
+	of_delete_node(root);
+
+	pr_info("selecting the UKI devicetree for \"%s\"\n", compat);
+
+	return fdt ?: ERR_PTR(-ENOMEM);
+}
+
 /* The image may sit in a much larger partition: load only the image */
 static const struct resource *efi_load_os(struct image_data *data,
 					  resource_size_t start,
@@ -278,6 +361,8 @@ static int efi_loader_bootm(struct image_data *data)
 	void *fdt;
 	int flags = 0;
 	size_t size, section_size;
+	const char *compat;
+	bool match;
 
 	memory_bank_first_find_space(&start, &end);
 
@@ -295,6 +380,10 @@ static int efi_loader_bootm(struct image_data *data)
 	if (ret)
 		return ret;
 
+	compat = efi_machine_compatible();
+	match = IS_ENABLED(CONFIG_OFTREE) && compat &&
+		efi_uki_has_dtbauto_for((void *)os_res->start, size, compat);
+
 	/* systemd-stub passes the load options on as kernel command line */
 	if (filetype_is_linux_efi_image(data->kernel_type) ||
 	    efi_pe_find_section((void *)os_res->start, size, ".linux",
@@ -322,11 +411,19 @@ static int efi_loader_bootm(struct image_data *data)
 
 	ret = -EINVAL;
 
-	fdt = bootm_get_devicetree(data);
+	if (match)
+		fdt = efi_uki_matching_devicetree(compat);
+	else
+		fdt = bootm_get_devicetree(data);
 	if (IS_ERR(fdt)) {
 		ret = PTR_ERR(fdt);
 		goto out;
 	}
+	if (!fdt && IS_ENABLED(CONFIG_OFTREE) &&
+	    efi_uki_lacks_devicetree((void *)os_res->start, size, compat)) {
+		ret = -ENODEV;
+		goto out;
+	}
 	if (fdt) {
 		/* efi_install_fdt() installs a copy */
 		ret = efi_install_fdt(fdt);
-- 
2.43.0




  parent reply	other threads:[~2026-10-04  1:21 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-04  1:19 [PATCH v1 00/14] efi: loader: boot Authenticode-signed UKIs Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 01/14] mfd: hgs-efi: do not claim the name of the EFI loader's device Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 02/14] efi: loader: file: report EFI_UNSUPPORTED for volumes without a filesystem Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 03/14] efi: loader: bootm: free the devicetree after installing it Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 04/14] efi: loader: provide EFI_DT_FIXUP_PROTOCOL Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 05/14] efi: loader: pe: add helpers for the image size and a named section Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 06/14] efi: loader: bootm: load only the PE image, not the whole file Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 07/14] efi: loader: bootm: pass the kernel command line to UKIs Johannes Schneider
2026-10-05 17:18   ` Ahmad Fatoum
2026-10-04  1:19 ` [PATCH v1 08/14] efi: loader: verify Authenticode signatures against built-in keys Johannes Schneider
2026-10-05  5:33   ` Ahmad Fatoum
2026-10-05  5:45     ` SCHNEIDER Johannes
2026-10-09  0:07       ` SCHNEIDER Johannes
2026-10-04  1:19 ` [PATCH v1 09/14] efi: loader: authenticode: add a fuzz test Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 10/14] efi: loader: authenticate LoadImage() images when signing is forced Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 11/14] efi: loader: file: expose no filesystem when signed images are forced Johannes Schneider
2026-10-04  1:19 ` [PATCH v1 12/14] bootm: efi: boot signed EFI images " Johannes Schneider
2026-10-04  1:19 ` Johannes Schneider [this message]
2026-10-04  1:19 ` [PATCH v1 14/14] efi: loader: bootm: apply overlays carried by a UKI Johannes Schneider

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=20261004011958.3255011-14-johannes.schneider@leica-geosystems.com \
    --to=johannes.schneider@leica-geosystems.com \
    --cc=barebox@lists.infradead.org \
    --cc=m.felsch@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox