From: Simon Glass <simon.glass@canonical.com> Introduce struct pxe_fdtoverlay to hold both the path and loaded address for each overlay. Update label_boot_fdtoverlay() to: 1. First pass: load all overlay files and store their addresses 2. Resize the main FDT once to make room for all overlays 3. Second pass: apply all loaded overlays This ensures all overlays are loaded before any are applied, which may be useful when overlays depend on each other or when the FDT resize could affect memory layout. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/pxe_parse.c | 19 ++++++++++--------- boot/pxe_utils.c | 37 +++++++++++++++++++++---------------- include/pxe_utils.h | 13 ++++++++++++- test/boot/pxe.c | 4 ++-- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/boot/pxe_parse.c b/boot/pxe_parse.c index b115fb413a2..6d148756b0d 100644 --- a/boot/pxe_parse.c +++ b/boot/pxe_parse.c @@ -106,14 +106,14 @@ static struct pxe_label *label_create(void) if (!label) return NULL; memset(label, 0, sizeof(struct pxe_label)); - alist_init_struct(&label->fdtoverlays, char *); + alist_init_struct(&label->fdtoverlays, struct pxe_fdtoverlay); return label; } void label_destroy(struct pxe_label *label) { - char **overlayp; + struct pxe_fdtoverlay *overlay; free(label->name); free(label->kernel_label); @@ -123,8 +123,8 @@ void label_destroy(struct pxe_label *label) free(label->initrd); free(label->fdt); free(label->fdtdir); - alist_for_each(overlayp, &label->fdtoverlays) - free(*overlayp); + alist_for_each(overlay, &label->fdtoverlays) + free(overlay->path); alist_uninit(&label->fdtoverlays); free(label->say); free(label); @@ -323,7 +323,7 @@ static int parse_fdtoverlays(char **c, struct alist *overlays) return err; while (*val) { - char *path; + struct pxe_fdtoverlay item; char *end; /* Skip leading spaces */ @@ -336,15 +336,16 @@ static int parse_fdtoverlays(char **c, struct alist *overlays) /* Find end of this path */ end = strchr(val, ' '); if (end) { - path = strndup(val, end - val); + item.path = strndup(val, end - val); val = end; } else { - path = strdup(val); + item.path = strdup(val); val += strlen(val); } + item.addr = 0; - if (!path || !alist_add(overlays, path)) { - free(path); + if (!item.path || !alist_add(overlays, item)) { + free(item.path); return -ENOMEM; } } diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index a50fa4bc333..8d565d971fc 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -306,9 +306,9 @@ static void label_boot_kaslrseed(struct pxe_context *ctx) static void label_boot_fdtoverlay(struct pxe_context *ctx, struct pxe_label *label) { + struct pxe_fdtoverlay *overlay; struct fdt_header *blob; ulong fdtoverlay_addr; - char **overlayp; bool use_lmb; char *envaddr; int err; @@ -331,38 +331,43 @@ static void label_boot_fdtoverlay(struct pxe_context *ctx, use_lmb = true; } - /* Apply each overlay file in order */ - alist_for_each(overlayp, &label->fdtoverlays) { - const char *overlayfile = *overlayp; + /* First pass: load all overlay files */ + alist_for_each(overlay, &label->fdtoverlays) { ulong addr = fdtoverlay_addr; ulong size; - /* Load overlay file */ - err = get_relfile(ctx, overlayfile, &addr, SZ_4K, + err = get_relfile(ctx, overlay->path, &addr, SZ_4K, (enum bootflow_img_t)IH_TYPE_FLATDT, &size); if (err < 0) { - printf("Failed loading overlay %s\n", overlayfile); + printf("Failed loading overlay %s\n", overlay->path); continue; } + overlay->addr = addr; - /* Resize main fdt */ - fdt_shrink_to_minimum(ctx->fdt, 8192); + /* Move to next address if using fixed addresses */ + if (!use_lmb) + fdtoverlay_addr = addr + size; + } + + /* Resize main fdt to make room for overlays */ + fdt_shrink_to_minimum(ctx->fdt, 8192); - blob = map_sysmem(addr, 0); + /* Second pass: apply all loaded overlays */ + alist_for_each(overlay, &label->fdtoverlays) { + if (!overlay->addr) + continue; + + blob = map_sysmem(overlay->addr, 0); err = fdt_check_header(blob); if (err) { - printf("Invalid overlay %s, skipping\n", overlayfile); + printf("Invalid overlay %s, skipping\n", overlay->path); continue; } err = fdt_overlay_apply_verbose(ctx->fdt, blob); if (err) printf("Failed to apply overlay %s, skipping\n", - overlayfile); - - /* Move to next address if using fixed addresses */ - if (!use_lmb) - fdtoverlay_addr = addr + size; + overlay->path); } } diff --git a/include/pxe_utils.h b/include/pxe_utils.h index 52a520e4823..d2062c03997 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -24,6 +24,17 @@ * take a 'include file getter' function. */ +/** + * struct pxe_fdtoverlay - info about an FDT overlay + * + * @path: Path to the overlay file + * @addr: Address where the overlay was loaded (0 if not yet loaded) + */ +struct pxe_fdtoverlay { + char *path; + ulong addr; +}; + /** * struct pxe_label - describes a single label in a pxe file * @@ -39,7 +50,7 @@ * @initrd: path to the initrd to use for this label. * @fdt: path to FDT to use * @fdtdir: path to FDT directory to use - * @fdtoverlays: list of paths of FDT overlays to apply (alist of char *) + * @fdtoverlays: list of FDT overlays to apply (alist of struct pxe_fdtoverlay) * @say: message to print when this label is selected for booting * @ipappend: flags for appending IP address (0x1) and MAC address (0x3) * @attempted: 0 if we haven't tried to boot this label, 1 if we have diff --git a/test/boot/pxe.c b/test/boot/pxe.c index 47cfa4042f5..df5c106caab 100644 --- a/test/boot/pxe.c +++ b/test/boot/pxe.c @@ -192,9 +192,9 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) ut_assertnull(label->fdtdir); ut_asserteq(2, label->fdtoverlays.count); ut_asserteq_str("/dtb/overlay1.dtbo", - *alist_get(&label->fdtoverlays, 0, char *)); + alist_get(&label->fdtoverlays, 0, struct pxe_fdtoverlay)->path); ut_asserteq_str("/dtb/overlay2.dtbo", - *alist_get(&label->fdtoverlays, 1, char *)); + alist_get(&label->fdtoverlays, 1, struct pxe_fdtoverlay)->path); ut_asserteq_str("Booting default Linux kernel", label->say); ut_asserteq(0, label->ipappend); ut_asserteq(0, label->attempted); -- 2.43.0