Merge tag 'efi-2022-10-rc5' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2022-10-rc5

Documentation:

* man-page for tftpput

UEFI:

* fix driver binding protocol for block IO devices
* don't delete invalid handles
* add a unit test for the EFI Conformance Profile Table

Other:

* correct short text for tftpboot
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 8ea064b..0e0be94 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1719,7 +1719,7 @@
 	bool "tftpboot"
 	default y
 	help
-	  tftpboot - boot image via network using TFTP protocol
+	  tftpboot - load file via network using TFTP protocol
 
 config CMD_TFTPPUT
 	bool "tftp put"
diff --git a/cmd/net.c b/cmd/net.c
index 3619c84..46f8c87 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -46,7 +46,7 @@
 
 U_BOOT_CMD(
 	tftpboot,	3,	1,	do_tftpb,
-	"boot image via network using TFTP protocol",
+	"load file via network using TFTP protocol",
 	"[loadAddress] [[hostIPaddr:]bootfilename]"
 );
 #endif
@@ -189,30 +189,49 @@
 #endif
 }
 
-static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
-			  char *const argv[])
+/**
+ * parse_addr_size() - parse address and size arguments for tftpput
+ *
+ * @argv:	command line arguments
+ * Return:	0 on success
+ */
+static int parse_addr_size(char * const argv[])
 {
-	char *s;
-	char *end;
-	int   rcode = 0;
-	int   size;
-	ulong addr;
-
-	net_boot_file_name_explicit = false;
+	if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
+	    strict_strtoul(argv[2], 16, &image_save_size) < 0) {
+		printf("Invalid address/size\n");
+		return CMD_RET_USAGE;
+	}
+	return 0;
+}
 
-	/* pre-set image_load_addr */
-	s = env_get("loadaddr");
-	if (s != NULL)
-		image_load_addr = hextoul(s, NULL);
+/**
+ * parse_args() - parse command line arguments
+ *
+ * @proto:	command prototype
+ * @argc:	number of arguments
+ * @argv:	command line arguments
+ * Return:	0 on success
+ */
+static int parse_args(enum proto_t proto, int argc, char *const argv[])
+{
+	ulong addr;
+	char *end;
 
 	switch (argc) {
 	case 1:
+		if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT)
+			return 1;
+
 		/* refresh bootfile name from env */
 		copy_filename(net_boot_file_name, env_get("bootfile"),
 			      sizeof(net_boot_file_name));
 		break;
 
-	case 2:	/*
+	case 2:
+		if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT)
+			return 1;
+		/*
 		 * Only one arg - accept two forms:
 		 * Just load address, or just boot file name. The latter
 		 * form must be written in a format which can not be
@@ -232,29 +251,52 @@
 		break;
 
 	case 3:
-		image_load_addr = hextoul(argv[1], NULL);
-		net_boot_file_name_explicit = true;
-		copy_filename(net_boot_file_name, argv[2],
-			      sizeof(net_boot_file_name));
-
+		if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT) {
+			if (parse_addr_size(argv))
+				return 1;
+		} else {
+			image_load_addr = hextoul(argv[1], NULL);
+			net_boot_file_name_explicit = true;
+			copy_filename(net_boot_file_name, argv[2],
+				      sizeof(net_boot_file_name));
+		}
 		break;
 
 #ifdef CONFIG_CMD_TFTPPUT
 	case 4:
-		if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
-		    strict_strtoul(argv[2], 16, &image_save_size) < 0) {
-			printf("Invalid address/size\n");
-			return CMD_RET_USAGE;
-		}
+		if (parse_addr_size(argv))
+			return 1;
 		net_boot_file_name_explicit = true;
 		copy_filename(net_boot_file_name, argv[3],
 			      sizeof(net_boot_file_name));
 		break;
 #endif
 	default:
+		return 1;
+	}
+	return 0;
+}
+
+static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
+			  char *const argv[])
+{
+	char *s;
+	int   rcode = 0;
+	int   size;
+
+	net_boot_file_name_explicit = false;
+	*net_boot_file_name = '\0';
+
+	/* pre-set image_load_addr */
+	s = env_get("loadaddr");
+	if (s != NULL)
+		image_load_addr = hextoul(s, NULL);
+
+	if (parse_args(proto, argc, argv)) {
 		bootstage_error(BOOTSTAGE_ID_NET_START);
 		return CMD_RET_USAGE;
 	}
+
 	bootstage_mark(BOOTSTAGE_ID_NET_START);
 
 	size = net_loop(proto);
diff --git a/doc/usage/cmd/tftpput.rst b/doc/usage/cmd/tftpput.rst
new file mode 100644
index 0000000..52ba7b1
--- /dev/null
+++ b/doc/usage/cmd/tftpput.rst
@@ -0,0 +1,87 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+tftpput command
+===============
+
+Synopsis
+--------
+
+::
+
+    tftpput address size [[hostIPaddr:]filename]
+
+Description
+-----------
+
+The tftpput command is used to transfer a file to a TFTP server.
+
+By default the destination port is 69 and the source port is pseudo-random.
+If CONFIG_TFTP_PORT=y, the environment variable *tftpsrcp* can be used to set
+the source port and the environment variable *tftpdstp* can be used to set
+the destination port.
+
+address
+    memory address where the data starts
+
+size
+    number of bytes to be transferred
+
+hostIPaddr
+    IP address of the TFTP server, defaults to the value of environment
+    variable *serverip*
+
+filename
+    path of the file to be written. If not provided, the client's IP address is
+    used to construct a default file name, e.g. C0.A8.00.28.img for IP address
+    192.168.0.40.
+
+Example
+-------
+
+In the example the following steps are executed:
+
+* setup client network address
+* load a file from the SD-card
+* send the file via TFTP to a server
+
+::
+
+    => setenv autoload no
+    => dhcp
+    BOOTP broadcast 1
+    DHCP client bound to address 192.168.1.40 (7 ms)
+    => load mmc 0:1 $loadaddr test.txt
+    260096 bytes read in 13 ms (19.1 MiB/s)
+    => tftpput $loadaddr $filesize 192.168.1.3:upload/test.txt
+    Using ethernet@1c30000 device
+    TFTP to server 192.168.1.3; our IP address is 192.168.1.40
+    Filename 'upload/test.txt'.
+    Save address: 0x42000000
+    Save size:    0x3f800
+    Saving: #################
+         4.4 MiB/s
+    done
+    Bytes transferred = 260096 (3f800 hex)
+    =>
+
+Configuration
+-------------
+
+The command is only available if CONFIG_CMD_TFTPPUT=y.
+
+CONFIG_TFTP_BLOCKSIZE defines the size of the TFTP blocks sent. It defaults
+to 1468 matching an ethernet MTU of 1500.
+
+If CONFIG_TFTP_PORT=y, the environment variables *tftpsrcp* and *tftpdstp* can
+be used to set the source and the destination ports.
+
+CONFIG_TFTP_WINDOWSIZE can be used to set the TFTP window size of transmits
+after which an ACK response is required. The window size defaults to 1.
+
+If CONFIG_TFTP_TSIZE=y, the progress bar is limited to 50 '#' characters.
+Otherwise an '#' is written per UDP package which may decrease performance.
+
+Return value
+------------
+
+The return value $? is 0 (true) on success and 1 (false) otherwise.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 28f9683..f1beeec 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -63,6 +63,7 @@
    cmd/scp03
    cmd/setexpr
    cmd/size
+   cmd/tftpput
    cmd/true
    cmd/ums
    cmd/wdt
diff --git a/include/efi_selftest.h b/include/efi_selftest.h
index 5340cef..e900cb8 100644
--- a/include/efi_selftest.h
+++ b/include/efi_selftest.h
@@ -18,6 +18,9 @@
 #define EFI_ST_FAILURE 1
 #define EFI_ST_SUCCESS_STR u"SUCCESS"
 
+extern const struct efi_system_table *st_systable;
+extern const struct efi_boot_services *st_boottime;
+
 /**
  * efi_st_printf() - print a message
  *
@@ -131,6 +134,14 @@
 int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2);
 
 /**
+ * efi_st_get_config_table() - get configuration table
+ *
+ * @guid:	GUID of the configuration table
+ * Return:	pointer to configuration table or NULL
+ */
+void *efi_st_get_config_table(const efi_guid_t *guid);
+
+/**
  * efi_st_get_key() - reads an Unicode character from the input device
  *
  * Return:	Unicode character
diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c
index b01ce89..74dd003 100644
--- a/lib/efi_driver/efi_uclass.c
+++ b/lib/efi_driver/efi_uclass.c
@@ -71,6 +71,15 @@
 	EFI_ENTRY("%p, %p, %ls", this, controller_handle,
 		  efi_dp_str(remaining_device_path));
 
+	/*
+	 * U-Boot internal devices install protocols interfaces without calling
+	 * ConnectController(). Hence we should not bind an extra driver.
+	 */
+	if (controller_handle->dev) {
+		ret = EFI_UNSUPPORTED;
+		goto out;
+	}
+
 	ret = EFI_CALL(systab.boottime->open_protocol(
 			controller_handle, bp->ops->protocol,
 			&interface, this->driver_binding_handle,
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 4da64b5..6f73336 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -619,9 +619,14 @@
  */
 void efi_delete_handle(efi_handle_t handle)
 {
-	if (!handle)
+	efi_status_t ret;
+
+	ret = efi_remove_all_protocols(handle);
+	if (ret == EFI_INVALID_PARAMETER) {
+		log_err("Can't remove invalid handle %p\n", handle);
 		return;
-	efi_remove_all_protocols(handle);
+	}
+
 	list_del(&handle->link);
 	free(handle);
 }
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 33536c9..daac6c3 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -49,6 +49,7 @@
 efi_selftest_variables_runtime.o \
 efi_selftest_watchdog.o
 
+obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o
 obj-$(CONFIG_NET) += efi_selftest_snp.o
 
 obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c
index 8e427b9..191da7f 100644
--- a/lib/efi_selftest/efi_selftest.c
+++ b/lib/efi_selftest/efi_selftest.c
@@ -14,8 +14,8 @@
 #define EFI_ST_EXECUTE	2
 #define EFI_ST_TEARDOWN	4
 
-static const struct efi_system_table *systable;
-static const struct efi_boot_services *boottime;
+const struct efi_system_table *st_systable;
+const struct efi_boot_services *st_boottime;
 static const struct efi_runtime_services *runtime;
 static efi_handle_t handle;
 static u16 reset_message[] = u"Selftest completed";
@@ -41,7 +41,7 @@
 	/* Do not detach devices in ExitBootServices. We need the console. */
 	efi_st_keep_devices = true;
 
-	ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
+	ret = st_boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
 				       &desc_version);
 	if (ret != EFI_BUFFER_TOO_SMALL) {
 		efi_st_error(
@@ -50,19 +50,19 @@
 	}
 	/* Allocate extra space for newly allocated memory */
 	map_size += sizeof(struct efi_mem_desc);
-	ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
+	ret = st_boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
 				      (void **)&memory_map);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
 		return;
 	}
-	ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
+	ret = st_boottime->get_memory_map(&map_size, memory_map, &map_key,
 				       &desc_size, &desc_version);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
 		return;
 	}
-	ret = boottime->exit_boot_services(handle, map_key);
+	ret = st_boottime->exit_boot_services(handle, map_key);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("ExitBootServices did not return EFI_SUCCESS\n");
 		return;
@@ -84,7 +84,7 @@
 	if (!test->setup)
 		return EFI_ST_SUCCESS;
 	efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
-	ret = test->setup(handle, systable);
+	ret = test->setup(handle, st_systable);
 	if (ret != EFI_ST_SUCCESS) {
 		efi_st_error("Setting up '%s' failed\n", test->name);
 		++*failures;
@@ -240,8 +240,8 @@
  * All tests use a driver model and are run in three phases:
  * setup, execute, teardown.
  *
- * A test may be setup and executed at boottime,
- * it may be setup at boottime and executed at runtime,
+ * A test may be setup and executed at st_boottime,
+ * it may be setup at st_boottime and executed at runtime,
  * or it may be setup and executed at runtime.
  *
  * After executing all tests the system is reset.
@@ -257,14 +257,14 @@
 	struct efi_loaded_image *loaded_image;
 	efi_status_t ret;
 
-	systable = systab;
-	boottime = systable->boottime;
-	runtime = systable->runtime;
+	st_systable = systab;
+	st_boottime = st_systable->boottime;
+	runtime = st_systable->runtime;
 	handle = image_handle;
-	con_out = systable->con_out;
-	con_in = systable->con_in;
+	con_out = st_systable->con_out;
+	con_in = st_systable->con_in;
 
-	ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image,
+	ret = st_boottime->handle_protocol(image_handle, &efi_guid_loaded_image,
 					(void **)&loaded_image);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Cannot open loaded image protocol\n");
@@ -280,9 +280,9 @@
 			list_all_tests();
 			/*
 			 * TODO:
-			 * Once the Exit boottime service is correctly
+			 * Once the Exit st_boottime service is correctly
 			 * implemented we should call
-			 *   boottime->exit(image_handle, EFI_SUCCESS, 0, NULL);
+			 *   st_boottime->exit(image_handle, EFI_SUCCESS, 0, NULL);
 			 * here, cf.
 			 * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html
 			 */
@@ -300,7 +300,7 @@
 					     efi_unit_test));
 
 	/* Allocate buffer for setup results */
-	ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) *
+	ret = st_boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) *
 				      ll_entry_count(struct efi_unit_test,
 						     efi_unit_test),
 				      (void **)&setup_status);
@@ -309,7 +309,7 @@
 		return ret;
 	}
 
-	/* Execute boottime tests */
+	/* Execute st_boottime tests */
 	efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 			EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
 			&failures);
diff --git a/lib/efi_selftest/efi_selftest_ecpt.c b/lib/efi_selftest/efi_selftest_ecpt.c
new file mode 100644
index 0000000..e8cc135
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_ecpt.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_fdt
+ *
+ * Copyright (c) 2022 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Check the EFI_CONFORMANCE_PROFILE_TABLE
+ */
+
+#include <efi_selftest.h>
+
+static const efi_guid_t guid_ecpt = EFI_CONFORMANCE_PROFILES_TABLE_GUID;
+static const efi_guid_t guid_ebbr_2_0 = EFI_CONFORMANCE_PROFILE_EBBR_2_0_GUID;
+
+/*
+ * ecpt_find_guid() - find GUID in EFI Conformance Profile Table
+ *
+ * @ecpt:	EFI Conformance Profile Table
+ * @guid:	GUID to find
+ * Return:	EFI_ST_SUCCESS for success
+ */
+static int ecpt_find_guid(struct efi_conformance_profiles_table *ecpt,
+			  const efi_guid_t *guid) {
+	int i;
+
+	for (i = 0; i < ecpt->number_of_profiles; ++i) {
+		if (!memcmp(&ecpt->conformance_profiles[i], guid, 16))
+			return EFI_ST_SUCCESS;
+	}
+	efi_st_error("GUID %pU not found\n", guid);
+	return EFI_ST_FAILURE;
+}
+
+/*
+ * Execute unit test.
+ *
+ * Return:	EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+	struct efi_conformance_profiles_table *ecpt;
+	int expected_entries = 0;
+
+	ecpt = efi_st_get_config_table(&guid_ecpt);
+
+	if (!ecpt) {
+		efi_st_error("Missing EFI Conformance Profile Table\n");
+		return EFI_ST_FAILURE;
+	}
+
+	if (ecpt->version != EFI_CONFORMANCE_PROFILES_TABLE_VERSION) {
+		efi_st_error("Wrong table version\n");
+		return EFI_ST_FAILURE;
+	}
+
+	if (CONFIG_IS_ENABLED(EFI_EBBR_2_0_CONFORMANCE)) {
+		++expected_entries;
+		if (ecpt_find_guid(ecpt, &guid_ebbr_2_0))
+			return EFI_ST_FAILURE;
+	}
+
+	if (ecpt->number_of_profiles != expected_entries) {
+		efi_st_error("Expected %d entries, found %d\n",
+			     expected_entries, ecpt->number_of_profiles);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+
+EFI_UNIT_TEST(ecpt) = {
+	.name = "conformance profile table",
+	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+	.execute = execute,
+};
diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c
index 114ac58..aa3b13a 100644
--- a/lib/efi_selftest/efi_selftest_fdt.c
+++ b/lib/efi_selftest/efi_selftest_fdt.c
@@ -144,23 +144,6 @@
 	return NULL;
 }
 
-/**
- * efi_st_get_config_table() - get configuration table
- *
- * @guid:	GUID of the configuration table
- * Return:	pointer to configuration table or NULL
- */
-static void *efi_st_get_config_table(const efi_guid_t *guid)
-{
-	size_t i;
-
-	for (i = 0; i < systab.nr_tables; i++) {
-		if (!guidcmp(guid, &systemtab->tables[i].guid))
-			return systemtab->tables[i].table;
-	}
-	return NULL;
-}
-
 /*
  * Setup unit test.
  *
diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c
index dba02d6..7e03e0c 100644
--- a/lib/efi_selftest/efi_selftest_util.c
+++ b/lib/efi_selftest/efi_selftest_util.c
@@ -110,3 +110,14 @@
 	}
 	return 0;
 }
+
+void *efi_st_get_config_table(const efi_guid_t *guid)
+{
+	size_t i;
+
+	for (i = 0; i < st_systable->nr_tables; i++) {
+		if (!guidcmp(guid, &st_systable->tables[i].guid))
+			return st_systable->tables[i].table;
+	}
+	return NULL;
+}