There is no easy way to see which firmware images a capsule can actually
target on a given board. On platforms that build their fw_images[] table
at runtime this is worse, since the set of images vary per board.

Add "efidebug capsule images", which walks the installed Firmware
Management Protocol handles and prints the image descriptors each one
reports, along with the image index, name and type GUID. This is the
same information capsule matching looks at, so it doubles as a quick way
to check the GUIDs in a capsule line up with what the board expects
before attempting an update.

Signed-off-by: Balaji Selvanathan <[email protected]>
---
 cmd/efidebug.c                                     | 102 +++++++++++++++++++++
 .../test_efi_capsule/test_capsule_firmware_raw.py  |  22 +++++
 2 files changed, 124 insertions(+)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index e55de04c699..a9e445d03fa 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -294,6 +294,104 @@ static int do_efi_capsule_res(struct cmd_tbl *cmdtp, int 
flag,
        return CMD_RET_SUCCESS;
 }
 
+/**
+ * do_efi_capsule_images() - list firmware images updatable by capsule
+ *
+ * @cmdtp:     Command table
+ * @flag:      Command flag
+ * @argc:      Number of arguments
+ * @argv:      Argument array
+ * Return:     CMD_RET_SUCCESS on success, CMD_RET_FAILURE on failure
+ *
+ * Implement efidebug "capsule images" sub-command.
+ * Walk every Firmware Management Protocol instance and print the image
+ * descriptors it reports, i.e. the firmware images a capsule can target
+ * on this board along with their name, index and type GUID.
+ *
+ *     efidebug capsule images
+ */
+static int do_efi_capsule_images(struct cmd_tbl *cmdtp, int flag,
+                                int argc, char * const argv[])
+{
+       struct efi_firmware_management_protocol *fmp;
+       struct efi_firmware_image_descriptor *image_info, *desc;
+       efi_uintn_t info_size, descriptor_size, no_handles;
+       u32 descriptor_version, package_version;
+       u16 *package_version_name;
+       u8 descriptor_count;
+       efi_handle_t *handles;
+       efi_status_t ret;
+       int i, j;
+
+       if (argc != 1)
+               return CMD_RET_USAGE;
+
+       ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
+                                               
&efi_guid_firmware_management_protocol,
+                                               NULL, &no_handles, &handles));
+       if (ret != EFI_SUCCESS || no_handles == 0) {
+               printf("No firmware images found\n");
+               return CMD_RET_SUCCESS;
+       }
+
+       printf("Image Index    Firmware Name         Image Type GUID\n");
+       printf("===========    ===================== 
====================================\n");
+
+       for (i = 0; i < no_handles; i++) {
+               struct efi_handler *handler;
+
+               ret = efi_search_protocol(handles[i],
+                                         
&efi_guid_firmware_management_protocol,
+                                         &handler);
+               if (ret != EFI_SUCCESS)
+                       continue;
+               fmp = handler->protocol_interface;
+
+               info_size = 0;
+               image_info = NULL;
+               descriptor_version = 0;
+               descriptor_count = 0;
+               descriptor_size = 0;
+               package_version = 0;
+               package_version_name = NULL;
+               ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, image_info,
+                                                  &descriptor_version,
+                                                  &descriptor_count,
+                                                  &descriptor_size,
+                                                  &package_version,
+                                                  &package_version_name));
+               if (ret != EFI_BUFFER_TOO_SMALL)
+                       continue;
+
+               image_info = malloc(info_size);
+               if (!image_info)
+                       continue;
+
+               ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, image_info,
+                                                  &descriptor_version,
+                                                  &descriptor_count,
+                                                  &descriptor_size,
+                                                  &package_version,
+                                                  &package_version_name));
+               if (ret == EFI_SUCCESS &&
+                   descriptor_version == 
EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
+                       for (j = 0, desc = image_info; j < descriptor_count;
+                            j++, desc = (void *)desc + descriptor_size)
+                               printf("%11d    %-21ls %pUl\n",
+                                      desc->image_index,
+                                      desc->image_id_name ? 
desc->image_id_name : u"",
+                                      &desc->image_type_id);
+               }
+
+               efi_free_pool(package_version_name);
+               free(image_info);
+       }
+
+       efi_free_pool(handles);
+
+       return CMD_RET_SUCCESS;
+}
+
 static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
        U_BOOT_CMD_MKENT(update, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_update,
                         "", ""),
@@ -309,6 +407,8 @@ static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
 #endif
        U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
                         "", ""),
+       U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_images,
+                        "", ""),
 };
 
 /**
@@ -1618,6 +1718,8 @@ U_BOOT_LONGHELP(efidebug,
        "  - show capsule information\n"
        "efidebug capsule result [<capsule result var>]\n"
        "  - show a capsule update result\n"
+       "efidebug capsule images\n"
+       "  - list firmware images updatable by capsule\n"
 #ifdef CONFIG_EFI_ESRT
        "efidebug capsule esrt\n"
        "  - print the ESRT\n"
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py 
b/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py
index b8cb483b380..e6246a83ff0 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py
@@ -238,3 +238,25 @@ class TestEfiCapsuleFirmwareRaw:
             check_file_removed(ubman, disk_img, capsule_files)
 
             verify_content(ubman, '100000', 'u-boot:Old')
+
+    def test_efi_capsule_fw6(
+            self, u_boot_config, ubman, efi_capsule_data):
+        """ Test Case 6
+        List the firmware images updatable by capsule with
+        'efidebug capsule images' and check the images sandbox exposes
+        for raw capsule updates
+        """
+        ubman.restart_uboot()
+
+        output = ubman.run_command('efidebug capsule images')
+
+        # ensure that SANDBOX-UBOOT and SANDBOX-UBOOT-ENV are both listed,
+        # along with the image index each one is exposed at.
+        assert '1' in output and 'SANDBOX-UBOOT' in output
+        assert '2' in output and 'SANDBOX-UBOOT-ENV' in output
+
+        # ensure that SANDBOX_UBOOT_IMAGE_GUID is reported.
+        assert '985F2937-7C2E-5E9A-8A5E-8E063312964B' in output
+
+        # ensure that SANDBOX_UBOOT_ENV_IMAGE_GUID is reported.
+        assert '9E339473-C2EB-530A-A69B-0CD6BBBED40E' in output

-- 
2.34.1

Reply via email to