[v5,14/17] cmd: add "efidebug capsule" command

Message ID 20200803054355.17356-15-takahiro.akashi@linaro.org
State Superseded
Headers show
Series
  • efi_loader: add capsule update support
Related show

Commit Message

AKASHI Takahiro Aug. 3, 2020, 5:43 a.m.
"efidebug capsule" is more or less a debugging utility.
  efidebug capsule update: invoke UpdateCapsule against data on memory
  efidebug capsule show: show a capsule header
  efidebug capsule result: dump a capsule result variable

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

---
 cmd/efidebug.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 235 insertions(+)

-- 
2.27.0

Patch

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 58018f700cd4..29054d09daba 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -18,6 +18,228 @@ 
 #include <linux/ctype.h>
 
 #define BS systab.boottime
+#define RT systab.runtime
+
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
+/**
+ * do_efi_capsule_update() - process a capsule update
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "capsule update" sub-command.
+ * process a capsule update.
+ *
+ *     efidebug capsule update [-v] <capsule address>
+ */
+static int do_efi_capsule_update(struct cmd_tbl *cmdtp, int flag,
+				 int argc, char * const argv[])
+{
+	struct efi_capsule_header *capsule;
+	int verbose = 0;
+	char *endp;
+	efi_status_t ret;
+
+	if (argc != 2 && argc != 3)
+		return CMD_RET_USAGE;
+
+	if (argc == 3) {
+		if (strcmp(argv[1], "-v"))
+			return CMD_RET_USAGE;
+
+		verbose = 1;
+		argc--;
+		argv++;
+	}
+
+	capsule = (typeof(capsule))simple_strtoul(argv[1], &endp, 16);
+	if (endp == argv[1]) {
+		printf("Invalid address: %s", argv[1]);
+		return CMD_RET_FAILURE;
+	}
+
+	if (verbose) {
+		printf("Capsule guid: %pUl\n", &capsule->capsule_guid);
+		printf("Capsule flags: 0x%x\n", capsule->flags);
+		printf("Capsule header size: 0x%x\n", capsule->header_size);
+		printf("Capsule image size: 0x%x\n",
+		       capsule->capsule_image_size);
+	}
+
+	ret = EFI_CALL(RT->update_capsule(&capsule, 1, (u64)NULL));
+	if (ret) {
+		printf("Cannot handle a capsule at %p", capsule);
+		return CMD_RET_FAILURE;
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+/**
+ * do_efi_capsule_show() - show capsule information
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "capsule show" sub-command.
+ * show capsule information.
+ *
+ *     efidebug capsule show <capsule address>
+ */
+static int do_efi_capsule_show(struct cmd_tbl *cmdtp, int flag,
+			       int argc, char * const argv[])
+{
+	struct efi_capsule_header *capsule;
+	char *endp;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	capsule = (typeof(capsule))simple_strtoul(argv[1], &endp, 16);
+	if (endp == argv[1]) {
+		printf("Invalid address: %s", argv[1]);
+		return CMD_RET_FAILURE;
+	}
+
+	printf("Capsule guid: %pUl\n", &capsule->capsule_guid);
+	printf("Capsule flags: 0x%x\n", capsule->flags);
+	printf("Capsule header size: 0x%x\n", capsule->header_size);
+	printf("Capsule image size: 0x%x\n",
+	       capsule->capsule_image_size);
+
+	return CMD_RET_SUCCESS;
+}
+
+/**
+ * do_efi_capsule_res() - show a capsule update result
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "capsule result" sub-command.
+ * show a capsule update result.
+ * If result number is not specified, CapsuleLast will be shown.
+ *
+ *     efidebug capsule result [<capsule result number>]
+ */
+static int do_efi_capsule_res(struct cmd_tbl *cmdtp, int flag,
+			      int argc, char * const argv[])
+{
+	int capsule_id;
+	char *endp;
+	char var_name[12];
+	u16 var_name16[12], *p;
+	efi_guid_t guid;
+	struct efi_capsule_result_variable_header *result = NULL;
+	efi_uintn_t size;
+	efi_status_t ret;
+
+	if (argc != 1 && argc != 2)
+		return CMD_RET_USAGE;
+
+	guid = efi_guid_capsule_report;
+	if (argc == 1) {
+		size = sizeof(var_name16);
+		ret = EFI_CALL(RT->get_variable(L"CapsuleLast", &guid, NULL,
+						&size, var_name16));
+		if (ret != EFI_SUCCESS) {
+			if (ret == EFI_NOT_FOUND)
+				printf("CapsuleLast doesn't exist\n");
+			else
+				printf("Failed to get CapsuleLast\n");
+
+			return CMD_RET_FAILURE;
+		}
+		printf("CapsuleLast is %ls\n", var_name16);
+	} else {
+		argc--;
+		argv++;
+
+		capsule_id = simple_strtoul(argv[0], &endp, 16);
+		if (capsule_id < 0 || capsule_id > 0xffff)
+			return CMD_RET_USAGE;
+
+		sprintf(var_name, "Capsule%04X", capsule_id);
+		p = var_name16;
+		utf8_utf16_strncpy(&p, var_name, 9);
+	}
+
+	size = 0;
+	ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		result = malloc(size);
+		ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
+						result));
+		if (ret != EFI_SUCCESS) {
+			free(result);
+			printf("Failed to get %ls\n", var_name16);
+
+			return CMD_RET_FAILURE;
+		}
+	}
+
+	printf("Result total size: 0x%x\n", result->variable_total_size);
+	printf("Capsule guid: %pUl\n", &result->capsule_guid);
+	printf("Time processed: %04d-%02d-%02d %02d:%02d:%02d\n",
+	       result->capsule_processed.year, result->capsule_processed.month,
+	       result->capsule_processed.day, result->capsule_processed.hour,
+	       result->capsule_processed.minute,
+	       result->capsule_processed.second);
+	printf("Capsule status: 0x%lx\n", result->capsule_status);
+
+	free(result);
+
+	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,
+			 "", ""),
+	U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show,
+			 "", ""),
+	U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
+			 "", ""),
+};
+
+/**
+ * do_efi_capsule() - manage UEFI capsules
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success,
+ *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "capsule" sub-command.
+ */
+static int do_efi_capsule(struct cmd_tbl *cmdtp, int flag,
+			  int argc, char * const argv[])
+{
+	struct cmd_tbl *cp;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	argc--; argv++;
+
+	cp = find_cmd_tbl(argv[0], cmd_efidebug_capsule_sub,
+			  ARRAY_SIZE(cmd_efidebug_capsule_sub));
+	if (!cp)
+		return CMD_RET_USAGE;
+
+	return cp->cmd(cmdtp, flag, argc, argv);
+}
+#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
 
 /**
  * efi_get_device_handle_info() - get information of UEFI device
@@ -1230,6 +1452,10 @@  static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag,
 
 static struct cmd_tbl cmd_efidebug_sub[] = {
 	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
+	U_BOOT_CMD_MKENT(capsule, CONFIG_SYS_MAXARGS, 1, do_efi_capsule,
+			 "", ""),
+#endif
 	U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
 			 "", ""),
 	U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
@@ -1304,6 +1530,15 @@  static char efidebug_help_text[] =
 	"efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
 	"  - set/show UEFI boot order\n"
 	"\n"
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
+	"efidebug capsule update [-v] <capsule address>\n"
+	"  - process a capsule\n"
+	"efidebug capsule show <capsule address>\n"
+	"  - show capsule information\n"
+	"efidebug capsule result [<capsule result var>]\n"
+	"  - show a capsule update result\n"
+	"\n"
+#endif
 	"efidebug devices\n"
 	"  - show UEFI devices\n"
 	"efidebug drivers\n"