Merge branch '2022-12-31-cmd-source-support-specifying-config-name' into next

To quote the author:
This series adds support for using configs with the source command.

And to paraphrase the rest, see the patch commit messages for more
details.
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
index 007f713..cb13a14 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -154,7 +154,7 @@
 			do_bootz(cmdtp, 0, 4, bootm_argv);
 	}
 	if (data->script)
-		image_source_script(data->script, "script@stm32prog");
+		image_source_script(data->script, NULL, NULL);
 
 	if (reset) {
 		puts("Reset...\n");
diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c
index d1c3f94..6c84721 100644
--- a/boot/bootmeth_script.c
+++ b/boot/bootmeth_script.c
@@ -101,7 +101,7 @@
 	log_debug("mmc_bootdev: %s\n", env_get("mmc_bootdev"));
 
 	addr = map_to_sysmem(bflow->buf);
-	ret = image_source_script(addr, NULL);
+	ret = image_source_script(addr, NULL, NULL);
 	if (ret)
 		return log_msg_ret("boot", ret);
 
diff --git a/cmd/source.c b/cmd/source.c
index 698d9f8..94da5d8 100644
--- a/cmd/source.c
+++ b/cmd/source.c
@@ -42,7 +42,7 @@
 }
 #endif
 
-int image_source_script(ulong addr, const char *fit_uname)
+int image_source_script(ulong addr, const char *fit_uname, const char *confname)
 {
 	ulong		len;
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
@@ -112,32 +112,58 @@
 			return 1;
 		}
 
-		if (!fit_uname)
-			fit_uname = get_default_image(fit_hdr);
-
 		if (!fit_uname) {
-			puts("No FIT subimage unit name\n");
-			return 1;
-		}
+			/* If confname is empty, use the default */
+			if (confname && *confname)
+				noffset = fit_conf_get_node(fit_hdr, confname);
+			else
+				noffset = fit_conf_get_node(fit_hdr, NULL);
+			if (noffset < 0) {
+				if (!confname)
+					goto fallback;
+				printf("Could not find config %s\n", confname);
+				return 1;
+			}
 
-		/* get script component image node offset */
-		noffset = fit_image_get_node (fit_hdr, fit_uname);
-		if (noffset < 0) {
-			printf ("Can't find '%s' FIT subimage\n", fit_uname);
-			return 1;
+			if (verify && fit_config_verify(fit_hdr, noffset))
+				return 1;
+
+			noffset = fit_conf_get_prop_node(fit_hdr, noffset,
+							 FIT_SCRIPT_PROP,
+							 IH_PHASE_NONE);
+			if (noffset < 0) {
+				if (!confname)
+					goto fallback;
+				printf("Could not find script in %s\n", confname);
+				return 1;
+			}
+		} else {
+fallback:
+			if (!fit_uname || !*fit_uname)
+				fit_uname = get_default_image(fit_hdr);
+			if (!fit_uname) {
+				puts("No FIT subimage unit name\n");
+				return 1;
+			}
+
+			/* get script component image node offset */
+			noffset = fit_image_get_node(fit_hdr, fit_uname);
+			if (noffset < 0) {
+				printf("Can't find '%s' FIT subimage\n",
+				       fit_uname);
+				return 1;
+			}
 		}
 
 		if (!fit_image_check_type (fit_hdr, noffset, IH_TYPE_SCRIPT)) {
-			puts ("Not a image image\n");
+			puts("Not a script image\n");
 			return 1;
 		}
 
 		/* verify integrity */
-		if (verify) {
-			if (!fit_image_verify(fit_hdr, noffset)) {
-				puts ("Bad Data Hash\n");
-				return 1;
-			}
+		if (verify && !fit_image_verify(fit_hdr, noffset)) {
+			puts("Bad Data Hash\n");
+			return 1;
 		}
 
 		/* get script subimage data address and length */
@@ -166,7 +192,7 @@
 {
 	ulong addr;
 	int rcode;
-	const char *fit_uname = NULL;
+	const char *fit_uname = NULL, *confname = NULL;
 
 	/* Find script image */
 	if (argc < 2) {
@@ -177,6 +203,9 @@
 				      &fit_uname)) {
 		debug("*  source: subimage '%s' from FIT image at 0x%08lx\n",
 		      fit_uname, addr);
+	} else if (fit_parse_conf(argv[1], image_load_addr, &addr, &confname)) {
+		debug("*  source: config '%s' from FIT image at 0x%08lx\n",
+		      confname, addr);
 #endif
 	} else {
 		addr = hextoul(argv[1], NULL);
@@ -184,21 +213,22 @@
 	}
 
 	printf ("## Executing script at %08lx\n", addr);
-	rcode = image_source_script(addr, fit_uname);
+	rcode = image_source_script(addr, fit_uname, confname);
 	return rcode;
 }
 
 #ifdef CONFIG_SYS_LONGHELP
 static char source_help_text[] =
-	"[addr]\n"
-	"\t- run script starting at addr\n"
-	"\t- A valid image header must be present"
 #if defined(CONFIG_FIT)
-	"\n"
-	"For FIT format uImage addr must include subimage\n"
-	"unit name in the form of addr:<subimg_uname>"
+	"[<addr>][:[<image>]|#[<config>]]\n"
+	"\t- Run script starting at addr\n"
+	"\t- A FIT config name or subimage name may be specified with : or #\n"
+	"\t  (like bootm). If the image or config name is omitted, the\n"
+	"\t  default is used.";
+#else
+	"[<addr>]\n"
+	"\t- Run script starting at addr";
 #endif
-	"";
 #endif
 
 U_BOOT_CMD(
diff --git a/doc/uImage.FIT/source_file_format.txt b/doc/uImage.FIT/source_file_format.txt
index 4640e38..269e1fa 100644
--- a/doc/uImage.FIT/source_file_format.txt
+++ b/doc/uImage.FIT/source_file_format.txt
@@ -247,6 +247,7 @@
   |- kernel = "kernel sub-node unit name"
   |- fdt = "fdt sub-node unit-name" [, "fdt overlay sub-node unit-name", ...]
   |- loadables = "loadables sub-node unit-name"
+  |- script = "
   |- compatible = "vendor,board-style device tree compatible string"
 
 
@@ -268,6 +269,8 @@
     of strings. U-Boot will load each binary at its given start-address and
     may optionally invoke additional post-processing steps on this binary based
     on its component image node type.
+  - script : The image to use when loading a U-Boot script (for use with the
+    source command).
   - compatible : The root compatible string of the U-Boot device tree that
     this configuration shall automatically match when CONFIG_FIT_BEST_MATCH is
     enabled. If this property is not provided, the compatible string will be
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index af4b167..5ae5b62 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -868,7 +868,7 @@
 			jump_to_image_no_args(&spl_image);
 #else
 			/* In U-Boot, allow jumps to scripts */
-			image_source_script(sdp_func->jmp_address, "script@1");
+			image_source_script(sdp_func->jmp_address, NULL, NULL);
 #endif
 		}
 
diff --git a/include/image.h b/include/image.h
index b6a8098..bed75ce 100644
--- a/include/image.h
+++ b/include/image.h
@@ -711,15 +711,23 @@
 
 /**
  * image_source_script() - Execute a script
+ * @addr: Address of script
+ * @fit_uname: FIT subimage name
+ * @confname: FIT config name. The subimage is chosen based on FIT_SCRIPT_PROP.
  *
  * Executes a U-Boot script at a particular address in memory. The script should
  * have a header (FIT or legacy) with the script type (IH_TYPE_SCRIPT).
  *
- * @addr: Address of script
- * @fit_uname: FIT subimage name
+ * If @fit_uname is the empty string, then the default image is used. If
+ * @confname is the empty string, the default config is used. If @confname and
+ * @fit_uname are both non-%NULL, then @confname is ignored. If @confname and
+ * @fit_uname are both %NULL, then first the default config is tried, and then
+ * the default image.
+ *
  * Return: result code (enum command_ret_t)
  */
-int image_source_script(ulong addr, const char *fit_uname);
+int image_source_script(ulong addr, const char *fit_uname,
+			const char *confname);
 
 /**
  * fit_get_node_from_config() - Look up an image a FIT by type
@@ -1032,6 +1040,7 @@
 #define FIT_FPGA_PROP		"fpga"
 #define FIT_FIRMWARE_PROP	"firmware"
 #define FIT_STANDALONE_PROP	"standalone"
+#define FIT_SCRIPT_PROP		"script"
 #define FIT_PHASE_PROP		"phase"
 
 #define FIT_MAX_HASH_LEN	HASH_MAX_DIGEST_SIZE
@@ -1259,7 +1268,14 @@
 			       size_t size);
 
 int fit_image_verify(const void *fit, int noffset);
+#if CONFIG_IS_ENABLED(FIT_SIGNATURE)
 int fit_config_verify(const void *fit, int conf_noffset);
+#else
+static inline int fit_config_verify(const void *fit, int conf_noffset)
+{
+	return 0;
+}
+#endif
 int fit_all_image_verify(const void *fit);
 int fit_config_decrypt(const void *fit, int conf_noffset);
 int fit_image_check_os(const void *fit, int noffset, uint8_t os);
diff --git a/test/py/tests/source.its b/test/py/tests/source.its
new file mode 100644
index 0000000..3c62f77
--- /dev/null
+++ b/test/py/tests/source.its
@@ -0,0 +1,43 @@
+/dts-v1/;
+
+/ {
+    description = "FIT image to test the source command";
+    #address-cells = <1>;
+
+    images {
+        default = "script-1";
+
+        script-1 {
+            data = "echo 1";
+            type = "script";
+            arch = "sandbox";
+            compression = "none";
+        };
+
+        script-2 {
+            data = "echo 2";
+            type = "script";
+            arch = "sandbox";
+            compression = "none";
+        };
+
+        not-a-script {
+            data = "echo 3";
+            type = "kernel";
+            arch = "sandbox";
+            compression = "none";
+        };
+    };
+
+    configurations {
+        default = "conf-2";
+
+        conf-1 {
+            script = "script-1";
+        };
+
+        conf-2 {
+            script = "script-2";
+        };
+    };
+};
diff --git a/test/py/tests/test_source.py b/test/py/tests/test_source.py
new file mode 100644
index 0000000..bbc311d
--- /dev/null
+++ b/test/py/tests/test_source.py
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
+
+import os
+import pytest
+import u_boot_utils as util
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('cmd_source')
+@pytest.mark.buildconfigspec('fit')
+def test_source(u_boot_console):
+    # Compile our test script image
+    cons = u_boot_console
+    mkimage = os.path.join(cons.config.build_dir, 'tools/mkimage')
+    its = os.path.join(cons.config.source_dir, 'test/py/tests/source.its')
+    fit = os.path.join(cons.config.build_dir, 'source.itb')
+    util.run_and_log(cons, (mkimage, '-f', its, fit))
+    cons.run_command(f'host load hostfs - $loadaddr {fit}')
+
+    assert '2' in cons.run_command('source')
+    assert '1' in cons.run_command('source :')
+    assert '1' in cons.run_command('source :script-1')
+    assert '2' in cons.run_command('source :script-2')
+    assert 'Fail' in cons.run_command('source :not-a-script || echo Fail')
+    assert '2' in cons.run_command('source \\#')
+    assert '1' in cons.run_command('source \\#conf-1')
+    assert '2' in cons.run_command('source \\#conf-2')
+
+    cons.run_command('fdt addr $loadaddr')
+    cons.run_command('fdt rm /configurations default')
+    assert '1' in cons.run_command('source')
+    assert 'Fail' in cons.run_command('source \\# || echo Fail')
+
+    cons.run_command('fdt rm /images default')
+    assert 'Fail' in cons.run_command('source || echo Fail')
+    assert 'Fail' in cons.run_command('source \\# || echo Fail')