A UKI has no place for the overlays a FIT image carries next to its devicetrees, and systemd-stub knows nothing about overlays. Carry them in a ".bbdtbo" PE section, covered by the image's Authenticode signature: a devicetree whose child nodes each hold one overlay in a "data" property, named like the overlay file.
Unpack them to /tmp/efi-overlays and point global.of.overlay.path there while the payload runs, so EFI_DT_FIXUP_PROTOCOL applies them to the devicetree systemd-stub installs, filtered by global.of.overlay.filter and pattern like overlays from a FIT image. Without such a section the path is empty for that time, as it may point at the boot partition, which now holds the UKI. The previous value is restored when the payload returns. Refuse a UKI whose overlay section cannot be unpacked, which would otherwise boot without the hardware its overlays describe. Only with CONFIG_OFTREE, which EFI_DT_FIXUP_PROTOCOL depends on. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Johannes Schneider <[email protected]> --- efi/loader/bootm.c | 86 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/efi/loader/bootm.c b/efi/loader/bootm.c index 47f7a3d1e2..71c61935b1 100644 --- a/efi/loader/bootm.c +++ b/efi/loader/bootm.c @@ -37,6 +37,7 @@ #include <efi/devicepath.h> #include <efi/loader/authenticode.h> #include <efi/loader/pe.h> +#include <globalvar.h> #include <loadable.h> #include <of.h> #include <barebox-info.h> @@ -223,6 +224,62 @@ static int efi_loader_verify(struct image_data *data, void *efi, size_t size) return 0; } +#define EFI_UKI_OVERLAY_SECTION ".bbdtbo" +#define EFI_UKI_OVERLAY_DIR "/tmp/efi-overlays" + +/* + * The overlay section is a devicetree whose child nodes each hold one overlay + * in a "data" property, named like the overlay file + */ +static int efi_uki_unpack_overlays(void *efi, size_t size) +{ + struct device_node *root, *np; + const void *blob, *ovl; + char *path; + size_t len; + int ovl_len, n = 0, ret = 0; + + blob = efi_pe_find_section(efi, size, EFI_UKI_OVERLAY_SECTION, &len); + if (!blob) + return 0; + + root = of_unflatten_dtb(blob, len); + if (IS_ERR(root)) + return PTR_ERR(root); + + unlink_recursive(EFI_UKI_OVERLAY_DIR, NULL); + ret = make_directory(EFI_UKI_OVERLAY_DIR); + if (ret) + goto out; + + for_each_child_of_node(root, np) { + ovl = of_get_property(np, "data", &ovl_len); + if (!ovl) + continue; + + path = basprintf(EFI_UKI_OVERLAY_DIR "/%s", np->name); + ret = write_file(path, ovl, ovl_len); + free(path); + if (ret) + goto out; + n++; + } + + pr_info("unpacked %d overlay(s) to %s\n", n, EFI_UKI_OVERLAY_DIR); + ret = n; +out: + of_delete_node(root); + return ret; +} + +static bool efi_image_brings_devicetree(void *efi, size_t size) +{ + size_t len; + + return efi_pe_find_section(efi, size, ".dtbauto", &len) || + efi_pe_find_section(efi, size, ".dtb", &len); +} + static const char *efi_machine_compatible(void) { const char *compat = barebox_get_of_machine_compatible(); @@ -361,8 +418,9 @@ static int efi_loader_bootm(struct image_data *data) void *fdt; int flags = 0; size_t size, section_size; + char *overlay_path = NULL; const char *compat; - bool match; + bool match, uki; memory_bank_first_find_space(&start, &end); @@ -384,6 +442,11 @@ static int efi_loader_bootm(struct image_data *data) match = IS_ENABLED(CONFIG_OFTREE) && compat && efi_uki_has_dtbauto_for((void *)os_res->start, size, compat); + uki = IS_ENABLED(CONFIG_OFTREE) && + efi_image_brings_devicetree((void *)os_res->start, size); + if (uki) + overlay_path = xstrdup(getenv("global.of.overlay.path") ?: ""); + /* 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", @@ -432,6 +495,18 @@ static int efi_loader_bootm(struct image_data *data) goto out; } + if (uki) { + int n = efi_uki_unpack_overlays((void *)os_res->start, size); + + if (n < 0) { + pr_err("cannot unpack the UKI overlays: %pe\n", ERR_PTR(n)); + ret = n; + goto out; + } + + globalvar_set("of.overlay.path", n ? EFI_UKI_OVERLAY_DIR : ""); + } + efiret = efi_install_initrd(data, os_res->end + 1); if(efiret != EFI_SUCCESS) goto out; @@ -502,9 +577,18 @@ static int efi_loader_bootm(struct image_data *data) /* Control is returned to us, disable EFI watchdog */ efi_set_watchdog(0); + if (overlay_path) { + globalvar_set("of.overlay.path", overlay_path); + free(overlay_path); + } + return -efi_errno(efiret); out: + if (overlay_path) { + globalvar_set("of.overlay.path", overlay_path); + free(overlay_path); + } efi_initrd_unregister(); efi_install_configuration_table(&efi_fdt_guid, NULL); efi_free_pool(file_path); -- 2.43.0
