From: Simon Glass <simon.glass@canonical.com> Extract the FDT address fallback logic from label_boot() into a new exported function pxe_get_fdt_fallback(). This determines the FDT address when a label doesn't specify an FDT file: 1. First tries fdt_addr environment variable 2. Falls back to fdtcontroladdr (unless kernel is FIT format) Add a test that verifies the fallback priority and behaviour. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/pxe_utils.c | 55 +++++++++++++++++++++++++++------------------ include/pxe_utils.h | 14 ++++++++++++ test/boot/pxe.c | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 22 deletions(-) diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index fbe4a111453..9034c3d86e7 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -396,6 +396,37 @@ skip_overlay: } #endif +const char *pxe_get_fdt_fallback(struct pxe_label *label, ulong kern_addr) +{ + const char *conf_fdt_str = NULL; + void *buf; + + /* + * Fallback to fdt_addr env var if label doesn't specify FDT + * and it's not ATAG mode (fdt="-") + */ + if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || + !label->fdt || strcmp("-", label->fdt)) { + conf_fdt_str = env_get("fdt_addr"); + if (conf_fdt_str) + return conf_fdt_str; + } + + /* + * Fallback to fdtcontroladdr if not a FIT image and not ATAG mode + */ + buf = map_sysmem(kern_addr, 0); + if (genimg_get_format(buf) != IMAGE_FORMAT_FIT) { + if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || + !label->fdt || strcmp("-", label->fdt)) { + conf_fdt_str = env_get("fdtcontroladdr"); + } + } + unmap_sysmem(buf); + + return conf_fdt_str; +} + /* * label_process_fdt() - Process FDT for the label * @@ -789,28 +820,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) if (ret) return ret; - if (!conf_fdt_str) { - if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || - strcmp("-", label->fdt)) { - conf_fdt_str = env_get("fdt_addr"); - log_debug("using fdt_addr '%s'\n", conf_fdt_str); - } - } - - if (!conf_fdt_str) { - void *buf; - - buf = map_sysmem(kern_addr, 0); - if (genimg_get_format(buf) != IMAGE_FORMAT_FIT) { - if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) || - strcmp("-", label->fdt)) { - conf_fdt_str = env_get("fdtcontroladdr"); - log_debug("using fdtcontroladdr '%s'\n", - conf_fdt_str); - } - } - unmap_sysmem(buf); - } + if (!conf_fdt_str) + conf_fdt_str = pxe_get_fdt_fallback(label, kern_addr); if (conf_fdt_str) conf_fdt = hextoul(conf_fdt_str, NULL); log_debug("conf_fdt %lx\n", conf_fdt); diff --git a/include/pxe_utils.h b/include/pxe_utils.h index 7ecb5788d0b..9629f051a91 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -306,6 +306,20 @@ int pxe_process(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt); */ int pxe_get_file_size(ulong *sizep); +/** + * pxe_get_fdt_fallback() - Get the FDT address using fallback logic + * + * When a label doesn't specify an FDT file (via 'fdt' or 'fdtdir'), this + * function determines the FDT address using fallback environment variables: + * 1. fdt_addr - if set, use this address + * 2. fdtcontroladdr - if set and kernel is not FIT format + * + * @label: Label being processed + * @kern_addr: Address where kernel is loaded + * Return: FDT address string from environment, or NULL if no fallback available + */ +const char *pxe_get_fdt_fallback(struct pxe_label *label, ulong kern_addr); + /** * pxe_get() - Get the PXE file from the server * diff --git a/test/boot/pxe.c b/test/boot/pxe.c index fec2361c27f..505628ab92d 100644 --- a/test/boot/pxe.c +++ b/test/boot/pxe.c @@ -660,3 +660,52 @@ static int pxe_test_ipappend_norun(struct unit_test_state *uts) PXE_TEST_ARGS(pxe_test_ipappend_norun, UTF_CONSOLE | UTF_MANUAL | UTF_ETH_BOOTDEV, { "fs_image", UT_ARG_STR }, { "cfg_path", UT_ARG_STR }); + +/** + * Test pxe_get_fdt_fallback() function + * + * This tests the FDT address fallback logic when a label doesn't specify + * an FDT file via 'fdt' or 'fdtdir' keywords. + */ +static int pxe_test_fdt_fallback(struct unit_test_state *uts) +{ + const char *orig_fdt_addr, *orig_fdtcontroladdr; + ulong kern_addr = 0x1000000; + struct pxe_label label; + void *kern_buf; + + /* Create a dummy kernel buffer (not FIT format) */ + kern_buf = map_sysmem(kern_addr, 64); + memset(kern_buf, '\0', 64); + unmap_sysmem(kern_buf); + + memset(&label, '\0', sizeof(label)); + + /* Save and clear env vars (fdtcontroladdr is set by U-Boot) */ + orig_fdt_addr = env_get("fdt_addr"); + orig_fdtcontroladdr = env_get("fdtcontroladdr"); + ut_assertok(env_set("fdt_addr", NULL)); + ut_assertok(env_set("fdtcontroladdr", NULL)); + + /* Test 1: No fallback env vars set - should return NULL */ + ut_assertnull(pxe_get_fdt_fallback(&label, kern_addr)); + + /* Test 2: fdt_addr set - should return fdt_addr */ + ut_assertok(env_set_hex("fdt_addr", 0x2000000)); + ut_asserteq_str("2000000", pxe_get_fdt_fallback(&label, kern_addr)); + + /* Test 3: Both set - fdt_addr takes priority */ + ut_assertok(env_set_hex("fdtcontroladdr", 0x3000000)); + ut_asserteq_str("2000000", pxe_get_fdt_fallback(&label, kern_addr)); + + /* Test 4: Only fdtcontroladdr set - should return fdtcontroladdr */ + ut_assertok(env_set("fdt_addr", NULL)); + ut_asserteq_str("3000000", pxe_get_fdt_fallback(&label, kern_addr)); + + /* Restore env vars */ + ut_assertok(env_set("fdt_addr", orig_fdt_addr)); + ut_assertok(env_set("fdtcontroladdr", orig_fdtcontroladdr)); + + return 0; +} +PXE_TEST(pxe_test_fdt_fallback, 0); -- 2.43.0