@@ -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);
@@ -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
*
@@ -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);