Merge tag 'efi-2022-10-rc5' of https://source.denx.de/u-boot/custodians/u-boot-efi
authorTom Rini <trini@konsulko.com>
Fri, 9 Sep 2022 18:10:51 +0000 (14:10 -0400)
committerTom Rini <trini@konsulko.com>
Fri, 9 Sep 2022 19:07:05 +0000 (15:07 -0400)
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

12 files changed:
cmd/Kconfig
cmd/net.c
doc/usage/cmd/tftpput.rst [new file with mode: 0644]
doc/usage/index.rst
include/efi_selftest.h
lib/efi_driver/efi_uclass.c
lib/efi_loader/efi_boottime.c
lib/efi_selftest/Makefile
lib/efi_selftest/efi_selftest.c
lib/efi_selftest/efi_selftest_ecpt.c [new file with mode: 0644]
lib/efi_selftest/efi_selftest_fdt.c
lib/efi_selftest/efi_selftest_util.c

index 8ea064b..0e0be94 100644 (file)
@@ -1719,7 +1719,7 @@ config CMD_TFTPBOOT
        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"
index 3619c84..46f8c87 100644 (file)
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -46,7 +46,7 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 
 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 @@ static void netboot_update_env(void)
 #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 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
                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 (file)
index 0000000..52ba7b1
--- /dev/null
@@ -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.
index 28f9683..f1beeec 100644 (file)
@@ -63,6 +63,7 @@ Shell commands
    cmd/scp03
    cmd/setexpr
    cmd/size
+   cmd/tftpput
    cmd/true
    cmd/ums
    cmd/wdt
index 5340cef..e900cb8 100644 (file)
@@ -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 @@ u16 *efi_st_translate_code(u16 code);
 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
index b01ce89..74dd003 100644 (file)
@@ -71,6 +71,15 @@ static efi_status_t EFIAPI efi_uc_supported(
        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,
index 4da64b5..6f73336 100644 (file)
@@ -619,9 +619,14 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
  */
 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);
 }
index 33536c9..daac6c3 100644 (file)
@@ -49,6 +49,7 @@ efi_selftest_variables.o \
 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
index 8e427b9..191da7f 100644 (file)
@@ -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 @@ void efi_st_exit_boot_services(void)
        /* 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 @@ void efi_st_exit_boot_services(void)
        }
        /* 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 @@ static int setup(struct efi_unit_test *test, unsigned int *failures)
        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 @@ void efi_st_do_tests(const u16 *testname, unsigned int phase,
  * 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 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
        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 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
                        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_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
                                             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 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
                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 (file)
index 0000000..e8cc135
--- /dev/null
@@ -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,
+};
index 114ac58..aa3b13a 100644 (file)
@@ -144,23 +144,6 @@ static char *get_property(const u16 *property, const u16 *node)
        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.
  *
index dba02d6..7e03e0c 100644 (file)
@@ -110,3 +110,14 @@ int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2)
        }
        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;
+}