cmd: add "efidebug capsule" command

"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>
This commit is contained in:
AKASHI Takahiro 2020-11-17 09:28:01 +09:00 committed by Heinrich Schuchardt
parent bb7e71d33c
commit 7f35cedfd9

View File

@ -19,6 +19,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
@ -1241,6 +1463,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,
@ -1315,6 +1541,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"