[U-Boot] [PATCH v5 0/7] cmd: add efidebug for efi environment

This patch set is a collection of patches to enhance efi user interfaces /commands. It will help improve user experience on efi boot and make it more usable *without* edk2's shell utility.
Let's see how it works: => efidebug boot add 1 SHELL mmc 0:1 /Shell.efi "" => efidebug boot add 2 HELLO mmc 0:1 /hello.efi "" => efidebug boot dump Boot0001: attributes: A-- (0x00000001) label: SHELL file_path: /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/HD(1,MBR,0x086246ba,0x800,0x40000)/\Shell.efi data: Boot0002: attributes: A-- (0x00000001) label: HELLO file_path: /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/HD(1,MBR,0x086246ba,0x800,0x40000)/\hello.efi data:
=> efidebug boot order 1 2 => efidebug boot order 1: Boot0001: SHELL 2: Boot0002: HELLO
=> run -e Boot0002 (or bootefi bootmgr - 2) ; '-' means no dtb specified WARNING: booting without device tree Booting: HELLO ## Starting EFI application at 000000007db8b040 ... Hello, world! ## Application terminated, r = 0
=> env set -e PlatformLang en ; important! (or you can do "efidebug setvar PlatformLang en") => env print -e Boot0001: {boot,run}(blob) 00000000: 01 00 00 00 68 00 53 00 ....h.S. 00000010: 48 00 45 00 4c 00 4c 00 H.E.L.L. 00000020: 00 00 01 04 14 00 b9 73 .......s 00000030: 1d e6 84 a3 cc 4a ae ab .....J.. 00000040: 82 e8 28 f3 62 8b 03 1a ..(.b... 00000050: 05 00 00 03 1a 05 00 00 ........ 00000060: 04 01 2a 00 01 00 00 00 ..*..... 00000070: 00 08 00 00 00 00 00 00 ........ 00000080: 00 00 04 00 00 00 00 00 ........ 00000090: ba 46 62 08 00 00 00 00 .Fb..... 000000a0: 00 00 00 00 00 00 00 00 ........ 000000b0: 01 01 04 04 1c 00 5c 00 ....... 000000c0: 5c 00 53 00 68 00 65 00 .S.h.e. 000000d0: 6c 00 6c 00 2e 00 65 00 l.l...e. 000000e0: 66 00 69 00 00 00 7f ff f.i.... 000000f0: 04 00 00 ... Boot0002: {boot,run}(blob) 00000000: 01 00 00 00 68 00 48 00 ....h.H. 00000010: 45 00 4c 00 4c 00 4f 00 E.L.L.O. 00000020: 00 00 01 04 14 00 b9 73 .......s 00000030: 1d e6 84 a3 cc 4a ae ab .....J.. 00000040: 82 e8 28 f3 62 8b 03 1a ..(.b... 00000050: 05 00 00 03 1a 05 00 00 ........ 00000060: 04 01 2a 00 01 00 00 00 ..*..... 00000070: 00 08 00 00 00 00 00 00 ........ 00000080: 00 00 04 00 00 00 00 00 ........ 00000090: ba 46 62 08 00 00 00 00 .Fb..... 000000a0: 00 00 00 00 00 00 00 00 ........ 000000b0: 01 01 04 04 1c 00 5c 00 ....... 000000c0: 5c 00 68 00 65 00 6c 00 .h.e.l. 000000d0: 6c 00 6f 00 2e 00 65 00 l.o...e. 000000e0: 66 00 69 00 00 00 7f ff f.i.... 000000f0: 04 00 00 ... BootOrder: {boot,run}(blob) 00000000: 01 00 02 00 .... OsIndicationsSupported: {ro,boot}(blob) 00000000: 00 00 00 00 00 00 00 00 ........ PlatformLang: {boot,run}(blob) 00000000: 65 6e en
=> run -e Boot0001 or bootefi bootmgr
(UEFI shell ...)
"setvar" command now supports efi shell-like syntax:
=> env set -e foo =S"akashi" =0x012345 =Habcdef => env print -e foo foo: {boot,run}(blob) 00000000: 61 6b 61 73 68 69 45 23 akashiE# 00000010: 01 00 ab cd ef .....
Other useful sub commands are: => efidebug devices ; print uefi devices => efidebug drivers ; print uefi drivers => efidebug dh ; print uefi handles => efidebug images ; print loaded images => efidebug memmap ; dump uefi memory map
Enjoy! -Takahiro Akashi
Changes in v5 (Jan 21, 2019) * rename the command name from efitool to efidebug again * add it to MAINTAINERS * follow a standard way of adding sub commands * allow "env -e" syntax without enabling CONFIG_CMD_EFIDEBUG (merging v4's patch#8 into patch#1) * change "_"-prefixed function names * change some internal variables' names * not print an efi driver's name at "efidebug drivers", yet showing a device path * change protocol name strings from char to u16 at "efidebug dh" * add a helper function to print efi memory attributes at "efidebug memmap"
Changes in v4 (Jan 15, 2019) * rename the command name from efishell to efitool * use efi_uintn_t for "size" if appropriate * correct a help text for "boot add" sub-command * "boot" sub-command always takes a hexadecimal number * use systab.boottime directly instead of a local variable, bs * fix a bug in "setvar" sub-command * fix a bug in "devices" and "dh" sub-command * fix a bug in "memmap" sub-command * add "boot next" sub-command to set BootNext variable * "drivers" sub-command prints more useful info, including a driver's name which originates from a corresponding u-boot efi driver * "dh" sub-commands prints more useful info, including a list of protocols which are bound to a given handle
Changes in v3 (Dec 18, 2018) * split v2 into two separate patch series * add CONFIG_CMD_EFISHELL to enable/disable efishell command * add missing free() at several places in efishell command
Changes in v2 (Nov 5, 2018) * modify efi_dp_from_name() for use in efishell * rename efi_marshal_load_option() to efi_serialize_load_option(), taking a "struct efi_load_option" as an argument * improve a format in dumping uefi variables * enhance a setvar syntax as efi's shell does * change a syntax from "bootefi bootmgr -2" to "bootefi bootmgr - 2" * add -e option to run command * add -e option to env command * add more sub-commands
AKASHI Takahiro (7): cmd: add efidebug command cmd: efidebug: add devices command cmd: efidebug: add drivers command cmd: efidebug: add dh command cmd: efidebug: add images command cmd: efidebug: add memmap command cmd: env: add "-e" option for handling UEFI variables
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 1155 +++++++++++++++++++++++++++++++++++++++++++++ cmd/nvedit.c | 59 ++- include/command.h | 6 + 6 files changed, 1231 insertions(+), 1 deletion(-) create mode 100644 cmd/efidebug.c

Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces: * efidebug boot add: add BootXXXX variable * efidebug boot rm: remove BootXXXX variable * efidebug boot dump: display all BootXXXX variables * efidebug boot next: set BootNext variable * efidebug boot order: set/display a boot order (BootOrder) * efidebug setvar: set an UEFI variable (with limited functionality) * efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c
FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it.
+config CMD_EFIDEBUG + bool "efidebug - display/customize UEFI environment" + depends on EFI_LOADER + default n + help + Enable the 'efidebug' command which provides a subset of UEFI + shell utility with simplified functionality. It will be useful + particularly for managing boot parameters as well as examining + various EFI status for debugging. + config CMD_LED bool "led" default y if LED diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UEFI Shell-like command + * + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + */ + +#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h> + +static void dump_var_data(char *data, unsigned long len) +{ + char *start, *end, *p; + unsigned long pos, count; + char hex[3], line[9]; + int i; + + end = data + len; + for (start = data, pos = 0; start < end; start += count, pos += count) { + count = end - start; + if (count > 16) + count = 16; + + /* count should be multiple of two */ + printf("%08lx: ", pos); + + /* in hex format */ + p = start; + for (i = 0; i < count / 2; p += 2, i++) + printf(" %c%c", *p, *(p + 1)); + for (; i < 8; i++) + printf(" "); + + /* in character format */ + p = start; + hex[2] = '\0'; + for (i = 0; i < count / 2; i++) { + hex[0] = *p++; + hex[1] = *p++; + line[i] = (char)simple_strtoul(hex, 0, 16); + if (line[i] < 0x20 || line[i] > 0x7f) + line[i] = '.'; + } + line[i] = '\0'; + printf(" %s\n", line); + } +} + +/* + * From efi_variable.c, + * + * Mapping between UEFI variables and u-boot variables: + * + * efi_$guid_$varname = {attributes}(type)value + */ +static int do_efi_dump_var(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char regex[256]; + char * const regexlist[] = {regex}; + char *res = NULL, *start, *end; + int len; + + if (argc > 2) + return CMD_RET_USAGE; + + if (argc == 2) + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_%s", argv[1]); + else + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*"); + debug("%s:%d grep uefi var %s\n", __func__, __LINE__, regex); + + len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, + &res, 0, 1, regexlist); + + if (len < 0) + return CMD_RET_FAILURE; + + if (len > 0) { + end = res; + while (true) { + /* variable name */ + start = strchr(end, '_'); + if (!start) + break; + start = strchr(++start, '_'); + if (!start) + break; + end = strchr(++start, '='); + if (!end) + break; + printf("%.*s:", (int)(end - start), start); + end++; + + /* value */ + start = end; + end = strstr(start, "(blob)"); + if (!end) { + putc('\n'); + break; + } + end += 6; + printf(" %.*s\n", (int)(end - start), start); + + start = end; + end = strchr(start, '\n'); + if (!end) + break; + dump_var_data(start, end - start); + } + free(res); + + if (len < 2 && argc == 2) + printf("%s: not found\n", argv[1]); + } + + return CMD_RET_SUCCESS; +} + +int do_efi_dump_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_status_t r; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return do_efi_dump_var(cmdtp, flag, argc, argv); +} + +static int append_value(char **bufp, unsigned long *sizep, char *data) +{ + char *tmp_buf = NULL, *new_buf = NULL, *value; + unsigned long len = 0; + + if (!strncmp(data, "=0x", 2)) { /* hexadecimal number */ + union { + u8 u8; + u16 u16; + u32 u32; + u64 u64; + } tmp_data; + unsigned long hex_value; + void *hex_ptr; + + data += 3; + len = strlen(data); + if ((len & 0x1)) /* not multiple of two */ + return -1; + + len /= 2; + if (len > 8) + return -1; + else if (len > 4) + len = 8; + else if (len > 2) + len = 4; + + /* convert hex hexadecimal number */ + if (strict_strtoul(data, 16, &hex_value) < 0) + return -1; + + tmp_buf = malloc(len); + if (!tmp_buf) + return -1; + + if (len == 1) { + tmp_data.u8 = hex_value; + hex_ptr = &tmp_data.u8; + } else if (len == 2) { + tmp_data.u16 = hex_value; + hex_ptr = &tmp_data.u16; + } else if (len == 4) { + tmp_data.u32 = hex_value; + hex_ptr = &tmp_data.u32; + } else { + tmp_data.u64 = hex_value; + hex_ptr = &tmp_data.u64; + } + memcpy(tmp_buf, hex_ptr, len); + value = tmp_buf; + + } else if (!strncmp(data, "=H", 2)) { /* hexadecimal-byte array */ + data += 2; + len = strlen(data); + if (len & 0x1) /* not multiple of two */ + return -1; + + len /= 2; + tmp_buf = malloc(len); + if (!tmp_buf) + return -1; + + if (hex2bin((u8 *)tmp_buf, data, len) < 0) + return -1; + + value = tmp_buf; + } else { /* string */ + if (!strncmp(data, "="", 2) || !strncmp(data, "=S"", 3)) { + if (data[1] == '"') + data += 2; + else + data += 3; + value = data; + len = strlen(data) - 1; + if (data[len] != '"') + return -1; + } else { + value = data; + len = strlen(data); + } + } + + new_buf = realloc(*bufp, *sizep + len); + if (!new_buf) + goto out; + + memcpy(new_buf + *sizep, value, len); + *bufp = new_buf; + *sizep += len; + +out: + free(tmp_buf); + + return 0; +} + +static int do_efi_set_var(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char *var_name, *value = NULL; + efi_uintn_t size = 0; + u16 *var_name16 = NULL, *p; + efi_guid_t guid; + efi_status_t ret; + + if (argc == 1) + return CMD_RET_SUCCESS; + + var_name = argv[1]; + if (argc == 2) { + /* remove */ + value = NULL; + size = 0; + } else { /* set */ + argc -= 2; + argv += 2; + + for ( ; argc > 0; argc--, argv++) + if (append_value(&value, &size, argv[0]) < 0) { + ret = CMD_RET_FAILURE; + goto out; + } + } + + var_name16 = malloc((strlen(var_name) + 1) * 2); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, strlen(var_name) + 1); + + guid = efi_global_variable_guid; + ret = efi_set_variable(var_name16, &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, value); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(value); + free(var_name16); + + return ret; +} + +int do_efi_set_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_status_t r; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return do_efi_set_var(cmdtp, flag, argc, argv); +} + +#ifdef CONFIG_CMD_EFIDEBUG +static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + int id; + char *endp; + char var_name[9]; + u16 var_name16[9], *p; + efi_guid_t guid; + size_t label_len, label_len16; + u16 *label; + struct efi_device_path *device_path = NULL, *file_path = NULL; + struct efi_load_option lo; + void *data = NULL; + efi_uintn_t size; + int ret; + + if (argc < 6 || argc > 7) + return CMD_RET_USAGE; + + id = (int)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || id > 0xffff) + return CMD_RET_FAILURE; + + sprintf(var_name, "Boot%04X", id); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, 9); + + guid = efi_global_variable_guid; + + /* attributes */ + lo.attributes = 0x1; /* always ACTIVE */ + + /* label */ + label_len = strlen(argv[2]); + label_len16 = utf8_utf16_strnlen(argv[2], label_len); + label = malloc((label_len16 + 1) * sizeof(u16)); + if (!label) + return CMD_RET_FAILURE; + lo.label = label; /* label will be changed below */ + utf8_utf16_strncpy(&label, argv[2], label_len); + + /* file path */ + ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path, + &file_path); + if (ret != EFI_SUCCESS) { + ret = CMD_RET_FAILURE; + goto out; + } + lo.file_path = file_path; + lo.file_path_length = efi_dp_size(file_path) + + sizeof(struct efi_device_path); /* for END */ + + /* optional data */ + lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]); + + size = efi_serialize_load_option(&lo, (u8 **)&data); + if (!size) { + ret = CMD_RET_FAILURE; + goto out; + } + + ret = efi_set_variable(var_name16, &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, data); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(data); + efi_free_pool(device_path); + efi_free_pool(file_path); + free(lo.label); + + return ret; +} + +static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_guid_t guid; + int id, i; + char *endp; + char var_name[9]; + u16 var_name16[9]; + efi_status_t ret; + + if (argc == 1) + return CMD_RET_USAGE; + + guid = efi_global_variable_guid; + for (i = 1; i < argc; i++, argv++) { + id = (int)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || id > 0xffff) + return CMD_RET_FAILURE; + + sprintf(var_name, "Boot%04X", id); + utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9); + + ret = efi_set_variable(var_name16, &guid, 0, 0, NULL); + if (ret) { + printf("cannot remove Boot%04X", id); + return CMD_RET_FAILURE; + } + } + + return CMD_RET_SUCCESS; +} + +static void show_efi_boot_opt_data(int id, void *data) +{ + struct efi_load_option lo; + char *label, *p; + size_t label_len16, label_len; + u16 *dp_str; + + efi_deserialize_load_option(&lo, data); + + label_len16 = u16_strlen(lo.label); + label_len = utf16_utf8_strnlen(lo.label, label_len16); + label = malloc(label_len + 1); + if (!label) + return; + p = label; + utf16_utf8_strncpy(&p, lo.label, label_len16); + + printf("Boot%04X:\n", id); + printf("\tattributes: %c%c%c (0x%08x)\n", + /* ACTIVE */ + lo.attributes & 0x1 ? 'A' : '-', + /* FORCE RECONNECT */ + lo.attributes & 0x2 ? 'R' : '-', + /* HIDDEN */ + lo.attributes & 0x8 ? 'H' : '-', + lo.attributes); + printf("\tlabel: %s\n", label); + + dp_str = efi_dp_str(lo.file_path); + printf("\tfile_path: %ls\n", dp_str); + efi_free_pool(dp_str); + + printf("\tdata: %s\n", lo.optional_data); + + free(label); +} + +static void show_efi_boot_opt(int id) +{ + char var_name[9]; + u16 var_name16[9], *p; + efi_guid_t guid; + void *data = NULL; + efi_uintn_t size; + int ret; + + sprintf(var_name, "Boot%04X", id); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, 9); + guid = efi_global_variable_guid; + + size = 0; + ret = efi_get_variable(var_name16, &guid, NULL, &size, NULL); + if (ret == (int)EFI_BUFFER_TOO_SMALL) { + data = malloc(size); + ret = efi_get_variable(var_name16, &guid, NULL, &size, data); + } + if (ret == EFI_SUCCESS) + show_efi_boot_opt_data(id, data); + else if (ret == EFI_NOT_FOUND) + printf("Boot%04X: not found\n", id); + + free(data); +} + +static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char regex[256]; + char * const regexlist[] = {regex}; + char *variables = NULL, *boot, *value; + int len; + int id; + + if (argc > 1) + return CMD_RET_USAGE; + + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+"); + + len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, + &variables, 0, 1, regexlist); + + if (!len) + return CMD_RET_SUCCESS; + + if (len < 0) + return CMD_RET_FAILURE; + + boot = variables; + while (*boot) { + value = strstr(boot, "Boot") + 4; + id = (int)simple_strtoul(value, NULL, 16); + show_efi_boot_opt(id); + boot = strchr(boot, '\n'); + if (!*boot) + break; + boot++; + } + free(variables); + + return CMD_RET_SUCCESS; +} + +static int show_efi_boot_order(void) +{ + efi_guid_t guid; + u16 *bootorder = NULL; + efi_uintn_t size; + int num, i; + char var_name[9]; + u16 var_name16[9], *p16; + void *data; + struct efi_load_option lo; + char *label, *p; + size_t label_len16, label_len; + efi_status_t ret; + + guid = efi_global_variable_guid; + size = 0; + ret = efi_get_variable(L"BootOrder", &guid, NULL, &size, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + bootorder = malloc(size); + ret = efi_get_variable(L"BootOrder", &guid, NULL, &size, + bootorder); + } + if (ret == EFI_NOT_FOUND) { + printf("BootOrder not defined\n"); + ret = CMD_RET_SUCCESS; + goto out; + } else if (ret != EFI_SUCCESS) { + ret = CMD_RET_FAILURE; + goto out; + } + + num = size / sizeof(u16); + for (i = 0; i < num; i++) { + sprintf(var_name, "Boot%04X", bootorder[i]); + p16 = var_name16; + utf8_utf16_strncpy(&p16, var_name, 9); + + size = 0; + ret = efi_get_variable(var_name16, &guid, NULL, &size, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + printf("%2d: Boot%04X: (not defined)\n", + i + 1, bootorder[i]); + continue; + } + + data = malloc(size); + if (!data) { + ret = CMD_RET_FAILURE; + goto out; + } + ret = efi_get_variable(var_name16, &guid, NULL, &size, data); + if (ret != EFI_SUCCESS) { + free(data); + ret = CMD_RET_FAILURE; + goto out; + } + + efi_deserialize_load_option(&lo, data); + + label_len16 = u16_strlen(lo.label); + label_len = utf16_utf8_strnlen(lo.label, label_len16); + label = malloc(label_len + 1); + if (!label) { + free(data); + ret = CMD_RET_FAILURE; + goto out; + } + p = label; + utf16_utf8_strncpy(&p, lo.label, label_len16); + printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label); + free(label); + + free(data); + } +out: + free(bootorder); + + return ret; +} + +static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u16 bootnext; + efi_uintn_t size; + char *endp; + efi_guid_t guid; + efi_status_t ret; + + if (argc != 2) + return CMD_RET_USAGE; + + bootnext = (u16)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || bootnext > 0xffff) { + printf("invalid value: %s\n", argv[1]); + ret = CMD_RET_FAILURE; + goto out; + } + + guid = efi_global_variable_guid; + size = sizeof(u16); + ret = efi_set_variable(L"BootNext", &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, &bootnext); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + return ret; +} + +static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u16 *bootorder = NULL; + efi_uintn_t size; + int id, i; + char *endp; + efi_guid_t guid; + efi_status_t ret; + + if (argc == 1) + return show_efi_boot_order(); + + argc--; + argv++; + + size = argc * sizeof(u16); + bootorder = malloc(size); + if (!bootorder) + return CMD_RET_FAILURE; + + for (i = 0; i < argc; i++) { + id = (int)simple_strtoul(argv[i], &endp, 16); + if (*endp != '\0' || id > 0xffff) { + printf("invalid value: %s\n", argv[i]); + ret = CMD_RET_FAILURE; + goto out; + } + + bootorder[i] = (u16)id; + } + + guid = efi_global_variable_guid; + ret = efi_set_variable(L"BootOrder", &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, bootorder); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(bootorder); + + return ret; +} + +static cmd_tbl_t cmd_efidebug_boot_sub[] = { + U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""), + U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""), + U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""), + U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""), + U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order, + "", ""), +}; + +static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub, + ARRAY_SIZE(cmd_efidebug_boot_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +static cmd_tbl_t cmd_efidebug_sub[] = { + U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), + U_BOOT_CMD_MKENT(dumpvar, CONFIG_SYS_MAXARGS, 1, do_efi_dump_var, + "", ""), + U_BOOT_CMD_MKENT(setvar, CONFIG_SYS_MAXARGS, 1, do_efi_set_var, "", ""), +}; + +/* Interpreter command to configure UEFI environment */ +static int do_efidebug(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + efi_status_t r; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + /* Initialize UEFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + cp = find_cmd_tbl(argv[0], cmd_efidebug_sub, + ARRAY_SIZE(cmd_efidebug_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +#ifdef CONFIG_SYS_LONGHELP +static char efidebug_help_text[] = + " - UEFI Shell-like interface to configure UEFI environment\n" + "\n" + "efidebug boot add <bootid> <label> <interface> <device>[:<part>] <file path> [<load options>]\n" + " - set UEFI BootXXXX variable\n" + " <load options> will be passed to UEFI application\n" + "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n" + " - delete UEFI BootXXXX variables\n" + "efidebug boot dump\n" + " - show all UEFI BootXXXX variables\n" + "efidebug boot next <bootid>\n" + " - set UEFI BootNext variable\n" + "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n" + " - set/show UEFI boot order\n" + "\n" + "efidebug dumpvar [<name>]\n" + " - show UEFI variable's value\n" + "efidebug setvar <name> [<value>]\n" + " - set/delete uefi variable's value\n" + " <value> may be "="..."", "=0x...", "=H...", (set) or "=" (delete)\n"; +#endif + +U_BOOT_CMD( + efidebug, 10, 0, do_efidebug, + "Configure UEFI environment", + efidebug_help_text +); +#endif /* CONFIG_CMD_EFIDEBUG */ diff --git a/include/command.h b/include/command.h index feddef300ccc..7210d1769a63 100644 --- a/include/command.h +++ b/include/command.h @@ -51,6 +51,12 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #if defined(CONFIG_CMD_BOOTEFI) extern int do_bootefi_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #endif +#if defined(CONFIG_EFI_LOADER) +int do_efi_dump_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]); +int do_efi_set_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]); +#endif
/* common/command.c */ int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int

On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces:
- efidebug boot add: add BootXXXX variable
- efidebug boot rm: remove BootXXXX variable
- efidebug boot dump: display all BootXXXX variables
- efidebug boot next: set BootNext variable
- efidebug boot order: set/display a boot order (BootOrder)
- efidebug setvar: set an UEFI variable (with limited functionality)
- efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c
FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it.
+config CMD_EFIDEBUG
- bool "efidebug - display/customize UEFI environment"
- depends on EFI_LOADER
- default n
- help
Enable the 'efidebug' command which provides a subset of UEFI
shell utility with simplified functionality. It will be useful
particularly for managing boot parameters as well as examining
various EFI status for debugging.
- config CMD_LED bool "led" default y if LED
diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- UEFI Shell-like command
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h>
+static void dump_var_data(char *data, unsigned long len) +{
- char *start, *end, *p;
- unsigned long pos, count;
- char hex[3], line[9];
- int i;
- end = data + len;
- for (start = data, pos = 0; start < end; start += count, pos += count) {
count = end - start;
if (count > 16)
count = 16;
/* count should be multiple of two */
printf("%08lx: ", pos);
/* in hex format */
p = start;
for (i = 0; i < count / 2; p += 2, i++)
printf(" %c%c", *p, *(p + 1));
for (; i < 8; i++)
printf(" ");
/* in character format */
p = start;
hex[2] = '\0';
for (i = 0; i < count / 2; i++) {
hex[0] = *p++;
hex[1] = *p++;
line[i] = (char)simple_strtoul(hex, 0, 16);
if (line[i] < 0x20 || line[i] > 0x7f)
line[i] = '.';
}
line[i] = '\0';
printf(" %s\n", line);
- }
+}
Is this print_hex_dump() reimplemented?
Alex

Alex,
On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces:
- efidebug boot add: add BootXXXX variable
- efidebug boot rm: remove BootXXXX variable
- efidebug boot dump: display all BootXXXX variables
- efidebug boot next: set BootNext variable
- efidebug boot order: set/display a boot order (BootOrder)
- efidebug setvar: set an UEFI variable (with limited functionality)
- efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG
- bool "efidebug - display/customize UEFI environment"
- depends on EFI_LOADER
- default n
- help
Enable the 'efidebug' command which provides a subset of UEFI
shell utility with simplified functionality. It will be useful
particularly for managing boot parameters as well as examining
various EFI status for debugging.
config CMD_LED bool "led" default y if LED diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- UEFI Shell-like command
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h>
+static void dump_var_data(char *data, unsigned long len) +{
- char *start, *end, *p;
- unsigned long pos, count;
- char hex[3], line[9];
- int i;
- end = data + len;
- for (start = data, pos = 0; start < end; start += count, pos += count) {
count = end - start;
if (count > 16)
count = 16;
/* count should be multiple of two */
printf("%08lx: ", pos);
/* in hex format */
p = start;
for (i = 0; i < count / 2; p += 2, i++)
printf(" %c%c", *p, *(p + 1));
for (; i < 8; i++)
printf(" ");
/* in character format */
p = start;
hex[2] = '\0';
for (i = 0; i < count / 2; i++) {
hex[0] = *p++;
hex[1] = *p++;
line[i] = (char)simple_strtoul(hex, 0, 16);
if (line[i] < 0x20 || line[i] > 0x7f)
line[i] = '.';
}
line[i] = '\0';
printf(" %s\n", line);
- }
+}
Is this print_hex_dump() reimplemented?
Actually, no. A UEFI variable on u-boot is encoded as ascii representation of binary data. That means, for example,
=> env set -e PlatformLang en => env print -e PlatformLang: {boot,run}(blob) 00000000: 65 6e en => env print ... efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e ...
the value of "PlatformLang" as a u-boot variable here is "656e", not "en." So if we want to use print_hex_dump(), we first have to convert that string to a binary. But then print_hex_dump() converts the binary to a string. It's just rediculuous, isn't it?
You might think that the value in this case should be {boot, run}(utf8)en ^^^^ It's possible, but it depends on a variable and currently my do_set_efi_var() doesn't support it anyway.
Thanks, -Takahiro Akashi
Alex

On 22.01.19 02:02, AKASHI Takahiro wrote:
Alex,
On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces:
- efidebug boot add: add BootXXXX variable
- efidebug boot rm: remove BootXXXX variable
- efidebug boot dump: display all BootXXXX variables
- efidebug boot next: set BootNext variable
- efidebug boot order: set/display a boot order (BootOrder)
- efidebug setvar: set an UEFI variable (with limited functionality)
- efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG
- bool "efidebug - display/customize UEFI environment"
- depends on EFI_LOADER
- default n
- help
Enable the 'efidebug' command which provides a subset of UEFI
shell utility with simplified functionality. It will be useful
particularly for managing boot parameters as well as examining
various EFI status for debugging.
config CMD_LED bool "led" default y if LED diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- UEFI Shell-like command
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h>
+static void dump_var_data(char *data, unsigned long len) +{
- char *start, *end, *p;
- unsigned long pos, count;
- char hex[3], line[9];
- int i;
- end = data + len;
- for (start = data, pos = 0; start < end; start += count, pos += count) {
count = end - start;
if (count > 16)
count = 16;
/* count should be multiple of two */
printf("%08lx: ", pos);
/* in hex format */
p = start;
for (i = 0; i < count / 2; p += 2, i++)
printf(" %c%c", *p, *(p + 1));
for (; i < 8; i++)
printf(" ");
/* in character format */
p = start;
hex[2] = '\0';
for (i = 0; i < count / 2; i++) {
hex[0] = *p++;
hex[1] = *p++;
line[i] = (char)simple_strtoul(hex, 0, 16);
if (line[i] < 0x20 || line[i] > 0x7f)
line[i] = '.';
}
line[i] = '\0';
printf(" %s\n", line);
- }
+}
Is this print_hex_dump() reimplemented?
Actually, no. A UEFI variable on u-boot is encoded as ascii representation of binary data. That means, for example,
=> env set -e PlatformLang en => env print -e PlatformLang: {boot,run}(blob) 00000000: 65 6e en => env print ... efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e ...
the value of "PlatformLang" as a u-boot variable here is "656e", not "en." So if we want to use print_hex_dump(), we first have to convert that string to a binary. But then print_hex_dump() converts the binary to a string. It's just rediculuous, isn't it?
I actually think I would prefer that. This way we consolidate everything through a single API which means we then know that the results are always the same. If we implement parsing multiple times, there's a good chance we'll have a bug in one of them which gives us different results which then again makes debugging harder rather than easier.
You might think that the value in this case should be {boot, run}(utf8)en ^^^^ It's possible, but it depends on a variable and currently my do_set_efi_var() doesn't support it anyway.
One more reason to use only a single path to funnel things through :).
So yes, can you maybe reuse RTS->get_variable() here? Same question on writing variables I suppose.
Alex

On Tue, Jan 22, 2019 at 10:18:58AM +0100, Alexander Graf wrote:
On 22.01.19 02:02, AKASHI Takahiro wrote:
Alex,
On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces:
- efidebug boot add: add BootXXXX variable
- efidebug boot rm: remove BootXXXX variable
- efidebug boot dump: display all BootXXXX variables
- efidebug boot next: set BootNext variable
- efidebug boot order: set/display a boot order (BootOrder)
- efidebug setvar: set an UEFI variable (with limited functionality)
- efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG
- bool "efidebug - display/customize UEFI environment"
- depends on EFI_LOADER
- default n
- help
Enable the 'efidebug' command which provides a subset of UEFI
shell utility with simplified functionality. It will be useful
particularly for managing boot parameters as well as examining
various EFI status for debugging.
config CMD_LED bool "led" default y if LED diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- UEFI Shell-like command
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h>
+static void dump_var_data(char *data, unsigned long len) +{
- char *start, *end, *p;
- unsigned long pos, count;
- char hex[3], line[9];
- int i;
- end = data + len;
- for (start = data, pos = 0; start < end; start += count, pos += count) {
count = end - start;
if (count > 16)
count = 16;
/* count should be multiple of two */
printf("%08lx: ", pos);
/* in hex format */
p = start;
for (i = 0; i < count / 2; p += 2, i++)
printf(" %c%c", *p, *(p + 1));
for (; i < 8; i++)
printf(" ");
/* in character format */
p = start;
hex[2] = '\0';
for (i = 0; i < count / 2; i++) {
hex[0] = *p++;
hex[1] = *p++;
line[i] = (char)simple_strtoul(hex, 0, 16);
if (line[i] < 0x20 || line[i] > 0x7f)
line[i] = '.';
}
line[i] = '\0';
printf(" %s\n", line);
- }
+}
Is this print_hex_dump() reimplemented?
Actually, no. A UEFI variable on u-boot is encoded as ascii representation of binary data. That means, for example,
=> env set -e PlatformLang en => env print -e PlatformLang: {boot,run}(blob) 00000000: 65 6e en => env print ... efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e ...
the value of "PlatformLang" as a u-boot variable here is "656e", not "en." So if we want to use print_hex_dump(), we first have to convert that string to a binary. But then print_hex_dump() converts the binary to a string. It's just rediculuous, isn't it?
I actually think I would prefer that. This way we consolidate everything through a single API which means we then know that the results are always the same. If we implement parsing multiple times, there's a good chance we'll have a bug in one of them which gives us different results which then again makes debugging harder rather than easier.
Agree, but please note we have to add an apparently weird dependency of CONFIG_HEXDUMP to EFI_LOADER as do_efi_dump_var_ext() needs to be compiled in whether CMD_EFIDEBUG is enabled or not.
You might think that the value in this case should be {boot, run}(utf8)en ^^^^ It's possible, but it depends on a variable and currently my do_set_efi_var() doesn't support it anyway.
One more reason to use only a single path to funnel things through :).
So yes, can you maybe reuse RTS->get_variable() here? Same question on writing variables I suppose.
Well, we need GetNextVariableName API if we want to use GetVariable (for listing). I have held off merging my another patch for this. Is it time to do it?
-Takahiro Akashi
Alex

On 01/23/2019 05:47 AM, AKASHI Takahiro wrote:
On Tue, Jan 22, 2019 at 10:18:58AM +0100, Alexander Graf wrote:
On 22.01.19 02:02, AKASHI Takahiro wrote:
Alex,
On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces:
- efidebug boot add: add BootXXXX variable
- efidebug boot rm: remove BootXXXX variable
- efidebug boot dump: display all BootXXXX variables
- efidebug boot next: set BootNext variable
- efidebug boot order: set/display a boot order (BootOrder)
- efidebug setvar: set an UEFI variable (with limited functionality)
- efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG
- bool "efidebug - display/customize UEFI environment"
- depends on EFI_LOADER
- default n
- help
Enable the 'efidebug' command which provides a subset of UEFI
shell utility with simplified functionality. It will be useful
particularly for managing boot parameters as well as examining
various EFI status for debugging.
- config CMD_LED bool "led" default y if LED
diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- UEFI Shell-like command
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h>
+static void dump_var_data(char *data, unsigned long len) +{
- char *start, *end, *p;
- unsigned long pos, count;
- char hex[3], line[9];
- int i;
- end = data + len;
- for (start = data, pos = 0; start < end; start += count, pos += count) {
count = end - start;
if (count > 16)
count = 16;
/* count should be multiple of two */
printf("%08lx: ", pos);
/* in hex format */
p = start;
for (i = 0; i < count / 2; p += 2, i++)
printf(" %c%c", *p, *(p + 1));
for (; i < 8; i++)
printf(" ");
/* in character format */
p = start;
hex[2] = '\0';
for (i = 0; i < count / 2; i++) {
hex[0] = *p++;
hex[1] = *p++;
line[i] = (char)simple_strtoul(hex, 0, 16);
if (line[i] < 0x20 || line[i] > 0x7f)
line[i] = '.';
}
line[i] = '\0';
printf(" %s\n", line);
- }
+}
Is this print_hex_dump() reimplemented?
Actually, no. A UEFI variable on u-boot is encoded as ascii representation of binary data. That means, for example,
=> env set -e PlatformLang en => env print -e PlatformLang: {boot,run}(blob) 00000000: 65 6e en => env print ... efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e ...
the value of "PlatformLang" as a u-boot variable here is "656e", not "en." So if we want to use print_hex_dump(), we first have to convert that string to a binary. But then print_hex_dump() converts the binary to a string. It's just rediculuous, isn't it?
I actually think I would prefer that. This way we consolidate everything through a single API which means we then know that the results are always the same. If we implement parsing multiple times, there's a good chance we'll have a bug in one of them which gives us different results which then again makes debugging harder rather than easier.
Agree, but please note we have to add an apparently weird dependency of CONFIG_HEXDUMP to EFI_LOADER as do_efi_dump_var_ext() needs to be compiled in whether CMD_EFIDEBUG is enabled or not.
You can just not print hex dumps of variables if CONFIG_HEXDUMP is not set?
You might think that the value in this case should be {boot, run}(utf8)en ^^^^ It's possible, but it depends on a variable and currently my do_set_efi_var() doesn't support it anyway.
One more reason to use only a single path to funnel things through :).
So yes, can you maybe reuse RTS->get_variable() here? Same question on writing variables I suppose.
Well, we need GetNextVariableName API if we want to use GetVariable (for listing). I have held off merging my another patch for this. Is it time to do it?
I thought that was in the tree now?
Alex

On Wed, Jan 23, 2019 at 10:52:38AM +0100, Alexander Graf wrote:
On 01/23/2019 05:47 AM, AKASHI Takahiro wrote:
On Tue, Jan 22, 2019 at 10:18:58AM +0100, Alexander Graf wrote:
On 22.01.19 02:02, AKASHI Takahiro wrote:
Alex,
On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format.
The new command, efidebug, helps address these issues and give us more friendly interfaces:
- efidebug boot add: add BootXXXX variable
- efidebug boot rm: remove BootXXXX variable
- efidebug boot dump: display all BootXXXX variables
- efidebug boot next: set BootNext variable
- efidebug boot order: set/display a boot order (BootOrder)
- efidebug setvar: set an UEFI variable (with limited functionality)
- efidebug dumpvar: display all UEFI variables
Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG
- bool "efidebug - display/customize UEFI environment"
- depends on EFI_LOADER
- default n
- help
Enable the 'efidebug' command which provides a subset of UEFI
shell utility with simplified functionality. It will be useful
particularly for managing boot parameters as well as examining
various EFI status for debugging.
config CMD_LED bool "led" default y if LED diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- UEFI Shell-like command
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h>
+static void dump_var_data(char *data, unsigned long len) +{
- char *start, *end, *p;
- unsigned long pos, count;
- char hex[3], line[9];
- int i;
- end = data + len;
- for (start = data, pos = 0; start < end; start += count, pos += count) {
count = end - start;
if (count > 16)
count = 16;
/* count should be multiple of two */
printf("%08lx: ", pos);
/* in hex format */
p = start;
for (i = 0; i < count / 2; p += 2, i++)
printf(" %c%c", *p, *(p + 1));
for (; i < 8; i++)
printf(" ");
/* in character format */
p = start;
hex[2] = '\0';
for (i = 0; i < count / 2; i++) {
hex[0] = *p++;
hex[1] = *p++;
line[i] = (char)simple_strtoul(hex, 0, 16);
if (line[i] < 0x20 || line[i] > 0x7f)
line[i] = '.';
}
line[i] = '\0';
printf(" %s\n", line);
- }
+}
Is this print_hex_dump() reimplemented?
Actually, no. A UEFI variable on u-boot is encoded as ascii representation of binary data. That means, for example,
=> env set -e PlatformLang en => env print -e PlatformLang: {boot,run}(blob) 00000000: 65 6e en => env print ... efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e ...
the value of "PlatformLang" as a u-boot variable here is "656e", not "en." So if we want to use print_hex_dump(), we first have to convert that string to a binary. But then print_hex_dump() converts the binary to a string. It's just rediculuous, isn't it?
I actually think I would prefer that. This way we consolidate everything through a single API which means we then know that the results are always the same. If we implement parsing multiple times, there's a good chance we'll have a bug in one of them which gives us different results which then again makes debugging harder rather than easier.
Agree, but please note we have to add an apparently weird dependency of CONFIG_HEXDUMP to EFI_LOADER as do_efi_dump_var_ext() needs to be compiled in whether CMD_EFIDEBUG is enabled or not.
You can just not print hex dumps of variables if CONFIG_HEXDUMP is not set?
Yes, print_hex_dump() just prints nothing if !CONFIG_HEXDUMP. Adding "imply HEXDUMP" would be enough.
You might think that the value in this case should be {boot, run}(utf8)en ^^^^ It's possible, but it depends on a variable and currently my do_set_efi_var() doesn't support it anyway.
One more reason to use only a single path to funnel things through :).
So yes, can you maybe reuse RTS->get_variable() here? Same question on writing variables I suppose.
Well, we need GetNextVariableName API if we want to use GetVariable (for listing). I have held off merging my another patch for this. Is it time to do it?
I thought that was in the tree now?
Not GetNextVariableName patch itself, but a patch of modifying do_efi_dump_var() using GetNextVariableName.
-Takahiro Akashi
Alex

"devices" command prints all the uefi variables on the system.
=> efi devices Scanning disk ahci_scsi.id0lun0... Scanning disk ahci_scsi.id1lun0... Found 4 disks D e v Device Path ================ ==================== 7ef3bfa0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) 7ef3cca0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(0,0) 7ef3d070 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0) 7ef3d1b0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)/HD(1,MBR,0x086246ba,0x800,0x40000) 7ef3d3e0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)/HD(2,MBR,0x086246ba,0x40800,0x3f800)
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/efidebug.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index c54fb6cfa101..0c7b51364753 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -18,6 +18,8 @@ #include <linux/ctype.h> #include <asm/global_data.h>
+#define BS systab.boottime + static void dump_var_data(char *data, unsigned long len) { char *start, *end, *p; @@ -301,6 +303,97 @@ int do_efi_set_var_ext(cmd_tbl_t *cmdtp, int flag, }
#ifdef CONFIG_CMD_EFIDEBUG +static int efi_get_handles_by_proto(efi_guid_t *guid, efi_handle_t **handlesp, + int *num) +{ + efi_handle_t *handles = NULL; + efi_uintn_t size = 0; + efi_status_t ret; + + if (guid) { + ret = BS->locate_handle(BY_PROTOCOL, guid, NULL, &size, + handles); + if (ret == EFI_BUFFER_TOO_SMALL) { + handles = calloc(1, size); + if (!handles) + return -1; + + ret = BS->locate_handle(BY_PROTOCOL, guid, NULL, &size, + handles); + } + if (ret != EFI_SUCCESS) { + free(handles); + return -1; + } + } else { + ret = BS->locate_handle(ALL_HANDLES, NULL, NULL, &size, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + handles = calloc(1, size); + if (!handles) + return -1; + + ret = BS->locate_handle(ALL_HANDLES, NULL, NULL, &size, + handles); + } + if (ret != EFI_SUCCESS) { + free(handles); + return -1; + } + } + + *handlesp = handles; + *num = size / sizeof(efi_handle_t); + + return 0; +} + +static int efi_get_device_handle_info(efi_handle_t handle, u16 **dev_path_text) +{ + struct efi_device_path *dp; + efi_status_t ret; + + ret = BS->open_protocol(handle, &efi_guid_device_path, + (void **)&dp, NULL /* FIXME */, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret == EFI_SUCCESS) { + *dev_path_text = efi_dp_str(dp); + return 0; + } else { + return -1; + } +} + +static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_handle_t *handles; + u16 *dev_path_text; + int num, i; + + handles = NULL; + num = 0; + if (efi_get_handles_by_proto(NULL, &handles, &num)) + return CMD_RET_FAILURE; + + if (!num) + return CMD_RET_SUCCESS; + + printf("D\n"); + printf("e\n"); + printf("v Device Path\n"); + printf("================ ====================\n"); + for (i = 0; i < num; i++) { + if (!efi_get_device_handle_info(handles[i], &dev_path_text)) { + printf("%16p %ls\n", handles[i], dev_path_text); + efi_free_pool(dev_path_text); + } + } + + free(handles); + + return CMD_RET_SUCCESS; +} + static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -694,6 +787,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = { U_BOOT_CMD_MKENT(dumpvar, CONFIG_SYS_MAXARGS, 1, do_efi_dump_var, "", ""), U_BOOT_CMD_MKENT(setvar, CONFIG_SYS_MAXARGS, 1, do_efi_set_var, "", ""), + U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices, + "", ""), };
/* Interpreter command to configure UEFI environment */ @@ -744,7 +839,9 @@ static char efidebug_help_text[] = " - show UEFI variable's value\n" "efidebug setvar <name> [<value>]\n" " - set/delete uefi variable's value\n" - " <value> may be "="..."", "=0x...", "=H...", (set) or "=" (delete)\n"; + " <value> may be "="..."", "=0x...", "=H...", (set) or "=" (delete)\n" + "efidebug devices\n" + " - show uefi devices\n"; #endif
U_BOOT_CMD(

On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"devices" command prints all the uefi variables on the system.
=> efi devices Scanning disk ahci_scsi.id0lun0... Scanning disk ahci_scsi.id1lun0... Found 4 disks D e v Device Path
Why the weird formatting of "Dev"?
Alex

Alex,
On Mon, Jan 21, 2019 at 02:34:43PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"devices" command prints all the uefi variables on the system.
=> efi devices Scanning disk ahci_scsi.id0lun0... Scanning disk ahci_scsi.id1lun0... Found 4 disks D e v Device Path
Why the weird formatting of "Dev"?
Good question :) The format mimics a EDK2's shell. The purpose is that we will be able to add some *narrow* data fields later without spilling out a line length.
But I admit that we don't have to do so because we have an enough width, 16 digits, for ID (or address of efi object in this case).
=== From EDK2 UEFI Shell output === Shell> drivers T D D Y C I e P F A V VERSION E G G #D #C DRIVER NAME IMAGE NAME == ======== = = = == == =================================== ========== 6E 0000000A D - - 1 - Platform Console Management Driver ConPlatformDxe ... Shell> devices T D Y C I P F A CTRL E G G #P #D #C Device Name ==== = = = == == === ========================================================= 15 R - - 0 1 1 VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(38400,8,N,1) ...
Thanks, -Takahiro Akashi
Alex

On 22.01.19 02:38, AKASHI Takahiro wrote:
Alex,
On Mon, Jan 21, 2019 at 02:34:43PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"devices" command prints all the uefi variables on the system.
=> efi devices Scanning disk ahci_scsi.id0lun0... Scanning disk ahci_scsi.id1lun0... Found 4 disks D e v Device Path
Why the weird formatting of "Dev"?
Good question :) The format mimics a EDK2's shell. The purpose is that we will be able to add some *narrow* data fields later without spilling out a line length.
But I admit that we don't have to do so because we have an enough width, 16 digits, for ID (or address of efi object in this case).
=== From EDK2 UEFI Shell output === Shell> drivers T D D Y C I e P F A V VERSION E G G #D #C DRIVER NAME IMAGE NAME == ======== = = = == == =================================== ========== 6E 0000000A D - - 1 - Platform Console Management Driver ConPlatformDxe
Ah, yes, in this output it makes sense. We don't have the table header size problem though, so let's please not pull that ugly header in :).
Alex

On Tue, Jan 22, 2019 at 10:19:35AM +0100, Alexander Graf wrote:
On 22.01.19 02:38, AKASHI Takahiro wrote:
Alex,
On Mon, Jan 21, 2019 at 02:34:43PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"devices" command prints all the uefi variables on the system.
=> efi devices Scanning disk ahci_scsi.id0lun0... Scanning disk ahci_scsi.id1lun0... Found 4 disks D e v Device Path
Why the weird formatting of "Dev"?
Good question :) The format mimics a EDK2's shell. The purpose is that we will be able to add some *narrow* data fields later without spilling out a line length.
But I admit that we don't have to do so because we have an enough width, 16 digits, for ID (or address of efi object in this case).
=== From EDK2 UEFI Shell output === Shell> drivers T D D Y C I e P F A V VERSION E G G #D #C DRIVER NAME IMAGE NAME == ======== = = = == == =================================== ========== 6E 0000000A D - - 1 - Platform Console Management Driver ConPlatformDxe
Ah, yes, in this output it makes sense. We don't have the table header size problem though, so let's please not pull that ugly header in :).
Okay. I will also modify the code so that this field (address of efi_handle_t) can be 32-bit or 64-bit wide.
-Takahiro Akashi
Alex

"drivers" command prints all the uefi drivers on the system.
=> efi drivers D r v Driver Name Image Path ================ ==================== ========== 7ef31d30 <NULL> <built-in>
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/efidebug.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 0c7b51364753..739b7880459d 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -8,6 +8,7 @@ #include <charset.h> #include <common.h> #include <command.h> +#include <efi_driver.h> #include <efi_loader.h> #include <environment.h> #include <errno.h> @@ -16,6 +17,7 @@ #include <malloc.h> #include <search.h> #include <linux/ctype.h> +#include <linux/kernel.h> #include <asm/global_data.h>
#define BS systab.boottime @@ -394,6 +396,80 @@ static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; }
+static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name, + u16 **image_path) +{ + struct efi_handler *handler; + struct efi_loaded_image *image; + efi_status_t ret; + + /* + * driver name + * TODO: support EFI_COMPONENT_NAME2_PROTOCOL + */ + *driver_name = NULL; + + /* image name */ + ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler); + if (ret != EFI_SUCCESS) { + *image_path = NULL; + return 0; + } + + image = handler->protocol_interface; + *image_path = efi_dp_str(image->file_path); + + return 0; +} + +static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_handle_t *handles = NULL, *handle; + efi_uintn_t size = 0; + u16 *driver_name, *image_path_text; + efi_status_t ret; + int i; + + ret = BS->locate_handle(BY_PROTOCOL, &efi_guid_driver_binding_protocol, + NULL, &size, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + handles = calloc(1, size); + if (!handles) + return CMD_RET_FAILURE; + + ret = BS->locate_handle(BY_PROTOCOL, + &efi_guid_driver_binding_protocol, + NULL, &size, handles); + } + if (ret != EFI_SUCCESS) { + free(handles); + return CMD_RET_FAILURE; + } + + printf("D\n"); + printf("r\n"); + printf("v Driver Name Image Path\n"); + printf("================ ==================== ==========\n"); + handle = handles; + for (i = 0; i < size / sizeof(*handle); i++) { + if (!efi_get_driver_handle_info(*handle, &driver_name, + &image_path_text)) { + if (image_path_text) + printf("%16p %-20ls %ls\n", + *handle, driver_name, image_path_text); + else + printf("%16p %-20ls <built-in>\n", + *handle, driver_name); + efi_free_pool(driver_name); + efi_free_pool(image_path_text); + } + handle++; + } + + return CMD_RET_SUCCESS; +} + static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -789,6 +865,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = { U_BOOT_CMD_MKENT(setvar, CONFIG_SYS_MAXARGS, 1, do_efi_set_var, "", ""), 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, + "", ""), };
/* Interpreter command to configure UEFI environment */ @@ -841,7 +919,9 @@ static char efidebug_help_text[] = " - set/delete uefi variable's value\n" " <value> may be "="..."", "=0x...", "=H...", (set) or "=" (delete)\n" "efidebug devices\n" - " - show uefi devices\n"; + " - show uefi devices\n" + "efidebug drivers\n" + " - show uefi drivers\n"; #endif
U_BOOT_CMD(

"dh" command prints all the uefi handles used in the system.
=> efi dh 7ef3bfa0: Device Path, Device Path To Text, Device Path Utilities, Unicode Collation 2 7ef31d30: Driver Binding 7ef31da0: Simple Text Output 7ef31e10: Simple Text Input, Simple Text Input Ex 7ef3cca0: Block IO, Device Path 7ef3d070: Block IO, Device Path 7ef3d1b0: Block IO, Device Path, Simple File System 7ef3d3e0: Block IO, Device Path, Simple File System
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/efidebug.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 739b7880459d..34794398c0c2 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -470,6 +470,120 @@ static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; }
+static const struct { + const char *text; + const efi_guid_t guid; +} guid_list[] = { + { + "Device Path", + DEVICE_PATH_GUID, + }, + { + "Device Path To Text", + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, + }, + { + "Device Path Utilities", + EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID, + }, + { + "Unicode Collation 2", + EFI_UNICODE_COLLATION_PROTOCOL2_GUID, + }, + { + "Driver Binding", + EFI_DRIVER_BINDING_PROTOCOL_GUID, + }, + { + "Simple Text Input", + EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, + }, + { + "Simple Text Input Ex", + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, + }, + { + "Simple Text Output", + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, + }, + { + "Block IO", + BLOCK_IO_GUID, + }, + { + "Simple File System", + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, + }, + { + "Loaded Image", + LOADED_IMAGE_PROTOCOL_GUID, + }, + { + "GOP", + EFI_GOP_GUID, + }, +}; + +static const char *get_guid_text(const efi_guid_t *guid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(guid_list); i++) + if (!guidcmp(&guid_list[i].guid, guid)) + break; + + if (i != ARRAY_SIZE(guid_list)) + return guid_list[i].text; + else + return NULL; +} + +static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_handle_t *handles; + efi_guid_t **guid; + efi_uintn_t count; + const char *guid_text; + int num, i, j; + efi_status_t ret; + + handles = NULL; + num = 0; + if (efi_get_handles_by_proto(NULL, &handles, &num)) + return CMD_RET_FAILURE; + + if (!num) + return CMD_RET_SUCCESS; + + for (i = 0; i < num; i++) { + printf("%16p:", handles[i]); + ret = BS->protocols_per_handle(handles[i], &guid, &count); + if (ret || !count) { + putc('\n'); + continue; + } + + for (j = 0; j < count; j++) { + if (j) + printf(", "); + else + putc(' '); + + guid_text = get_guid_text(guid[j]); + if (guid_text) + puts(guid_text); + else + printf("%pUl", guid[j]); + } + putc('\n'); + } + + free(handles); + + return CMD_RET_SUCCESS; +} + static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -867,6 +981,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers, "", ""), + U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles, + "", ""), };
/* Interpreter command to configure UEFI environment */ @@ -921,7 +1037,9 @@ static char efidebug_help_text[] = "efidebug devices\n" " - show uefi devices\n" "efidebug drivers\n" - " - show uefi drivers\n"; + " - show uefi drivers\n" + "efidebug dh\n" + " - show uefi handles\n"; #endif
U_BOOT_CMD(

"images" command prints loaded images-related information.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/efidebug.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 34794398c0c2..906e6b2d0295 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -584,6 +584,14 @@ static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; }
+static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_print_image_infos(NULL); + + return CMD_RET_SUCCESS; +} + static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -983,6 +991,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles, "", ""), + U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images, + "", ""), };
/* Interpreter command to configure UEFI environment */ @@ -1039,7 +1049,9 @@ static char efidebug_help_text[] = "efidebug drivers\n" " - show uefi drivers\n" "efidebug dh\n" - " - show uefi handles\n"; + " - show uefi handles\n" + "efidebug images\n" + " - show loaded images\n"; #endif
U_BOOT_CMD(

"memmap" command prints uefi-specific memory map information. => efi memmap Type Start End Attributes ================ ================ ================ ========== CONVENTIONAL 0000000040000000-000000007de27000 WB RUNTIME DATA 000000007de27000-000000007de28000 WB|RT RESERVED 000000007de28000-000000007de2a000 WB RUNTIME DATA 000000007de2a000-000000007de2b000 WB|RT RESERVED 000000007de2b000-000000007de2c000 WB RUNTIME DATA 000000007de2c000-000000007de2d000 WB|RT LOADER DATA 000000007de2d000-000000007ff37000 WB RUNTIME CODE 000000007ff37000-000000007ff38000 WB|RT LOADER DATA 000000007ff38000-0000000080000000 WB
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/efidebug.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 906e6b2d0295..bd6b095562e7 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -592,6 +592,95 @@ static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; }
+static const char * const efi_mem_type_string[] = { + [EFI_RESERVED_MEMORY_TYPE] = "RESERVED", + [EFI_LOADER_CODE] = "LOADER CODE", + [EFI_LOADER_DATA] = "LOADER DATA", + [EFI_BOOT_SERVICES_CODE] = "BOOT CODE", + [EFI_BOOT_SERVICES_DATA] = "BOOT DATA", + [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE", + [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA", + [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL", + [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM", + [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM", + [EFI_ACPI_MEMORY_NVS] = "ACPI NVS", + [EFI_MMAP_IO] = "IO", + [EFI_MMAP_IO_PORT] = "IO PORT", + [EFI_PAL_CODE] = "PAL", +}; + +static const struct efi_mem_attrs { + const u64 bit; + const char *text; +} efi_mem_attrs[] = { + {EFI_MEMORY_UC, "UC"}, + {EFI_MEMORY_UC, "UC"}, + {EFI_MEMORY_WC, "WC"}, + {EFI_MEMORY_WT, "WT"}, + {EFI_MEMORY_WB, "WB"}, + {EFI_MEMORY_UCE, "UCE"}, + {EFI_MEMORY_WP, "WP"}, + {EFI_MEMORY_RP, "RP"}, + {EFI_MEMORY_XP, "WP"}, + {EFI_MEMORY_NV, "NV"}, + {EFI_MEMORY_MORE_RELIABLE, "REL"}, + {EFI_MEMORY_RO, "RO"}, + {EFI_MEMORY_RUNTIME, "RT"}, +}; + +static void print_memory_attributes(u64 attributes) +{ + int sep, i; + + for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++) + if (attributes & efi_mem_attrs[i].bit) { + if (sep) { + putc('|'); + } else { + putc(' '); + sep = 1; + } + puts(efi_mem_attrs[i].text); + } +} + +static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + struct efi_mem_desc *memmap = NULL, *map; + efi_uintn_t map_size = 0; + int i; + efi_status_t ret; + + ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + memmap = malloc(map_size); + if (!memmap) + return CMD_RET_FAILURE; + ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL); + } + if (ret != EFI_SUCCESS) { + free(memmap); + return CMD_RET_FAILURE; + } + + printf("Type Start End Attributes\n"); + printf("================ ================ ================ ==========\n"); + for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) { + printf("%-16s %016llx-%016llx", + efi_mem_type_string[map->type], + map->physical_start, + map->physical_start + map->num_pages * EFI_PAGE_SIZE); + + print_memory_attributes(map->attribute); + putc('\n'); + } + + free(memmap); + + return CMD_RET_SUCCESS; +} + static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -993,6 +1082,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images, "", ""), + U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap, + "", ""), };
/* Interpreter command to configure UEFI environment */ @@ -1051,7 +1142,9 @@ static char efidebug_help_text[] = "efidebug dh\n" " - show uefi handles\n" "efidebug images\n" - " - show loaded images\n"; + " - show loaded images\n" + "efidebug memmap\n" + " - show uefi memory map\n"; #endif
U_BOOT_CMD(

On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"memmap" command prints uefi-specific memory map information. => efi memmap Type Start End Attributes ================ ================ ================ ========== CONVENTIONAL 0000000040000000-000000007de27000 WB RUNTIME DATA 000000007de27000-000000007de28000 WB|RT RESERVED 000000007de28000-000000007de2a000 WB RUNTIME DATA 000000007de2a000-000000007de2b000 WB|RT RESERVED 000000007de2b000-000000007de2c000 WB RUNTIME DATA 000000007de2c000-000000007de2d000 WB|RT LOADER DATA 000000007de2d000-000000007ff37000 WB RUNTIME CODE 000000007ff37000-000000007ff38000 WB|RT LOADER DATA 000000007ff38000-0000000080000000 WB
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
cmd/efidebug.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 906e6b2d0295..bd6b095562e7 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -592,6 +592,95 @@ static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; }
+static const char * const efi_mem_type_string[] = {
- [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
- [EFI_LOADER_CODE] = "LOADER CODE",
- [EFI_LOADER_DATA] = "LOADER DATA",
- [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
- [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
- [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
- [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
- [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
- [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
- [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
- [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
- [EFI_MMAP_IO] = "IO",
- [EFI_MMAP_IO_PORT] = "IO PORT",
- [EFI_PAL_CODE] = "PAL",
+};
+static const struct efi_mem_attrs {
- const u64 bit;
- const char *text;
+} efi_mem_attrs[] = {
- {EFI_MEMORY_UC, "UC"},
- {EFI_MEMORY_UC, "UC"},
- {EFI_MEMORY_WC, "WC"},
- {EFI_MEMORY_WT, "WT"},
- {EFI_MEMORY_WB, "WB"},
- {EFI_MEMORY_UCE, "UCE"},
- {EFI_MEMORY_WP, "WP"},
- {EFI_MEMORY_RP, "RP"},
- {EFI_MEMORY_XP, "WP"},
- {EFI_MEMORY_NV, "NV"},
- {EFI_MEMORY_MORE_RELIABLE, "REL"},
- {EFI_MEMORY_RO, "RO"},
- {EFI_MEMORY_RUNTIME, "RT"},
+};
+static void print_memory_attributes(u64 attributes) +{
- int sep, i;
- for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
if (attributes & efi_mem_attrs[i].bit) {
if (sep) {
putc('|');
} else {
putc(' ');
sep = 1;
}
puts(efi_mem_attrs[i].text);
}
+}
+static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
+{
- struct efi_mem_desc *memmap = NULL, *map;
- efi_uintn_t map_size = 0;
- int i;
- efi_status_t ret;
- ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
- if (ret == EFI_BUFFER_TOO_SMALL) {
memmap = malloc(map_size);
if (!memmap)
return CMD_RET_FAILURE;
ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
- }
- if (ret != EFI_SUCCESS) {
free(memmap);
return CMD_RET_FAILURE;
- }
- printf("Type Start End Attributes\n");
- printf("================ ================ ================ ==========\n");
- for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
printf("%-16s %016llx-%016llx",
efi_mem_type_string[map->type],
Please check that map->type is within bounds (<= PAL; better yet < ARRAY_SIZE(efi_mem_type_string)).
Alex

On Mon, Jan 21, 2019 at 02:39:07PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"memmap" command prints uefi-specific memory map information. => efi memmap Type Start End Attributes ================ ================ ================ ========== CONVENTIONAL 0000000040000000-000000007de27000 WB RUNTIME DATA 000000007de27000-000000007de28000 WB|RT RESERVED 000000007de28000-000000007de2a000 WB RUNTIME DATA 000000007de2a000-000000007de2b000 WB|RT RESERVED 000000007de2b000-000000007de2c000 WB RUNTIME DATA 000000007de2c000-000000007de2d000 WB|RT LOADER DATA 000000007de2d000-000000007ff37000 WB RUNTIME CODE 000000007ff37000-000000007ff38000 WB|RT LOADER DATA 000000007ff38000-0000000080000000 WB
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
cmd/efidebug.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 906e6b2d0295..bd6b095562e7 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -592,6 +592,95 @@ static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; } +static const char * const efi_mem_type_string[] = {
- [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
- [EFI_LOADER_CODE] = "LOADER CODE",
- [EFI_LOADER_DATA] = "LOADER DATA",
- [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
- [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
- [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
- [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
- [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
- [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
- [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
- [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
- [EFI_MMAP_IO] = "IO",
- [EFI_MMAP_IO_PORT] = "IO PORT",
- [EFI_PAL_CODE] = "PAL",
+};
+static const struct efi_mem_attrs {
- const u64 bit;
- const char *text;
+} efi_mem_attrs[] = {
- {EFI_MEMORY_UC, "UC"},
- {EFI_MEMORY_UC, "UC"},
- {EFI_MEMORY_WC, "WC"},
- {EFI_MEMORY_WT, "WT"},
- {EFI_MEMORY_WB, "WB"},
- {EFI_MEMORY_UCE, "UCE"},
- {EFI_MEMORY_WP, "WP"},
- {EFI_MEMORY_RP, "RP"},
- {EFI_MEMORY_XP, "WP"},
- {EFI_MEMORY_NV, "NV"},
- {EFI_MEMORY_MORE_RELIABLE, "REL"},
- {EFI_MEMORY_RO, "RO"},
- {EFI_MEMORY_RUNTIME, "RT"},
+};
+static void print_memory_attributes(u64 attributes) +{
- int sep, i;
- for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
if (attributes & efi_mem_attrs[i].bit) {
if (sep) {
putc('|');
} else {
putc(' ');
sep = 1;
}
puts(efi_mem_attrs[i].text);
}
+}
+static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
+{
- struct efi_mem_desc *memmap = NULL, *map;
- efi_uintn_t map_size = 0;
- int i;
- efi_status_t ret;
- ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
- if (ret == EFI_BUFFER_TOO_SMALL) {
memmap = malloc(map_size);
if (!memmap)
return CMD_RET_FAILURE;
ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
- }
- if (ret != EFI_SUCCESS) {
free(memmap);
return CMD_RET_FAILURE;
- }
- printf("Type Start End Attributes\n");
- printf("================ ================ ================ ==========\n");
- for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
printf("%-16s %016llx-%016llx",
efi_mem_type_string[map->type],
Please check that map->type is within bounds (<= PAL; better yet < ARRAY_SIZE(efi_mem_type_string)).
OK.
-Takahiro Akashi
Alex

"env [print|set] -e" allows for handling uefi variables without knowing details about mapping to corresponding u-boot variables.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/nvedit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/cmd/nvedit.c b/cmd/nvedit.c index ce746bbf1b3e..1b971d7233bc 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -27,6 +27,8 @@ #include <cli.h> #include <command.h> #include <console.h> +#include <efi.h> +#include <efi_loader.h> #include <environment.h> #include <search.h> #include <errno.h> @@ -119,6 +121,25 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, int rcode = 0; int env_flag = H_HIDE_DOT;
+#if defined(CONFIG_EFI_LOADER) + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') { + efi_status_t r; + + argc--; + argv++; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot set up EFI drivers, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return do_efi_dump_var_ext(cmdtp, flag, argc, argv); + } +#endif + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { argc--; argv++; @@ -216,6 +237,26 @@ static int _do_env_set(int flag, int argc, char * const argv[], int env_flag) ENTRY e, *ep;
debug("Initial value for argc=%d\n", argc); + +#if defined(CONFIG_EFI_LOADER) + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') { + efi_status_t r; + + argc--; + argv++; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot set up EFI drivers, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return do_efi_set_var_ext(NULL, flag, argc, argv); + } +#endif + while (argc > 1 && **(argv + 1) == '-') { char *arg = *++argv;
@@ -1262,15 +1303,23 @@ static char env_help_text[] = #if defined(CONFIG_CMD_IMPORTENV) "env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import environment\n" #endif +#if defined(CONFIG_EFI_LOADER) + "env print [-a | -e [name] | name ...] - print environment\n" +#else "env print [-a | name ...] - print environment\n" +#endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) "env save - save environment\n" #endif +#if defined(CONFIG_EFI_LOADER) + "env set [-e | -f] name [arg ...]\n"; +#else "env set [-f] name [arg ...]\n"; #endif +#endif
U_BOOT_CMD( env, CONFIG_SYS_MAXARGS, 1, do_env, @@ -1295,6 +1344,10 @@ U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", "[-a]\n - print [all] values of all environment variables\n" +#if defined(CONFIG_EFI_LOADER) + "printenv -e [<name>]\n" + " - print UEFI variable 'name' or all the variables\n" +#endif "printenv name ...\n" " - print value of environment variable 'name'", var_complete @@ -1322,7 +1375,11 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables", - "[-f] name value ...\n" +#if defined(CONFIG_EFI_LOADER) + "-e <name> [<value>]\n" + " - set UEFI variable 'name' to 'value' ...'\n" +#endif + "setenv [-f] name value ...\n" " - [forcibly] set environment variable 'name' to 'value ...'\n" "setenv [-f] name\n" " - [forcibly] delete environment variable 'name'",

On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"env [print|set] -e" allows for handling uefi variables without knowing details about mapping to corresponding u-boot variables.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
cmd/nvedit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/cmd/nvedit.c b/cmd/nvedit.c index ce746bbf1b3e..1b971d7233bc 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -27,6 +27,8 @@ #include <cli.h> #include <command.h> #include <console.h> +#include <efi.h> +#include <efi_loader.h> #include <environment.h> #include <search.h> #include <errno.h> @@ -119,6 +121,25 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, int rcode = 0; int env_flag = H_HIDE_DOT;
+#if defined(CONFIG_EFI_LOADER)
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
efi_status_t r;
argc--;
argv++;
/* Initialize EFI drivers */
r = efi_init_obj_list();
if (r != EFI_SUCCESS) {
printf("Error: Cannot set up EFI drivers, r = %lu\n",
r & ~EFI_ERROR_MASK);
return CMD_RET_FAILURE;
}
No need for efi_init_obj_list() here, as it's already done by do_efi_dump_var_ext(), no?
return do_efi_dump_var_ext(cmdtp, flag, argc, argv);
- }
+#endif
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { argc--; argv++;
@@ -216,6 +237,26 @@ static int _do_env_set(int flag, int argc, char * const argv[], int env_flag) ENTRY e, *ep;
debug("Initial value for argc=%d\n", argc);
+#if defined(CONFIG_EFI_LOADER)
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
efi_status_t r;
argc--;
argv++;
/* Initialize EFI drivers */
r = efi_init_obj_list();
if (r != EFI_SUCCESS) {
printf("Error: Cannot set up EFI drivers, r = %lu\n",
r & ~EFI_ERROR_MASK);
return CMD_RET_FAILURE;
}
Same here.
Alex
return do_efi_set_var_ext(NULL, flag, argc, argv);
- }
+#endif
- while (argc > 1 && **(argv + 1) == '-') { char *arg = *++argv;
@@ -1262,15 +1303,23 @@ static char env_help_text[] = #if defined(CONFIG_CMD_IMPORTENV) "env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import environment\n" #endif +#if defined(CONFIG_EFI_LOADER)
- "env print [-a | -e [name] | name ...] - print environment\n"
+#else "env print [-a | name ...] - print environment\n" +#endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) "env save - save environment\n" #endif +#if defined(CONFIG_EFI_LOADER)
- "env set [-e | -f] name [arg ...]\n";
+#else "env set [-f] name [arg ...]\n"; #endif +#endif
U_BOOT_CMD( env, CONFIG_SYS_MAXARGS, 1, do_env, @@ -1295,6 +1344,10 @@ U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", "[-a]\n - print [all] values of all environment variables\n" +#if defined(CONFIG_EFI_LOADER)
- "printenv -e [<name>]\n"
- " - print UEFI variable 'name' or all the variables\n"
+#endif "printenv name ...\n" " - print value of environment variable 'name'", var_complete @@ -1322,7 +1375,11 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables",
- "[-f] name value ...\n"
+#if defined(CONFIG_EFI_LOADER)
- "-e <name> [<value>]\n"
- " - set UEFI variable 'name' to 'value' ...'\n"
+#endif
- "setenv [-f] name value ...\n" " - [forcibly] set environment variable 'name' to 'value ...'\n" "setenv [-f] name\n" " - [forcibly] delete environment variable 'name'",

On Mon, Jan 21, 2019 at 02:41:07PM +0100, Alexander Graf wrote:
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote:
"env [print|set] -e" allows for handling uefi variables without knowing details about mapping to corresponding u-boot variables.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
cmd/nvedit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/cmd/nvedit.c b/cmd/nvedit.c index ce746bbf1b3e..1b971d7233bc 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -27,6 +27,8 @@ #include <cli.h> #include <command.h> #include <console.h> +#include <efi.h> +#include <efi_loader.h> #include <environment.h> #include <search.h> #include <errno.h> @@ -119,6 +121,25 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, int rcode = 0; int env_flag = H_HIDE_DOT; +#if defined(CONFIG_EFI_LOADER)
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
efi_status_t r;
argc--;
argv++;
/* Initialize EFI drivers */
r = efi_init_obj_list();
if (r != EFI_SUCCESS) {
printf("Error: Cannot set up EFI drivers, r = %lu\n",
r & ~EFI_ERROR_MASK);
return CMD_RET_FAILURE;
}
No need for efi_init_obj_list() here, as it's already done by do_efi_dump_var_ext(), no?
Ah, right. (That's why do_efi_dump_var_ext() was introduced.)
Thanks, -Takahiro Akashi
return do_efi_dump_var_ext(cmdtp, flag, argc, argv);
- }
+#endif
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { argc--; argv++;
@@ -216,6 +237,26 @@ static int _do_env_set(int flag, int argc, char * const argv[], int env_flag) ENTRY e, *ep; debug("Initial value for argc=%d\n", argc);
+#if defined(CONFIG_EFI_LOADER)
- if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
efi_status_t r;
argc--;
argv++;
/* Initialize EFI drivers */
r = efi_init_obj_list();
if (r != EFI_SUCCESS) {
printf("Error: Cannot set up EFI drivers, r = %lu\n",
r & ~EFI_ERROR_MASK);
return CMD_RET_FAILURE;
}
Same here.
Alex
return do_efi_set_var_ext(NULL, flag, argc, argv);
- }
+#endif
- while (argc > 1 && **(argv + 1) == '-') { char *arg = *++argv;
@@ -1262,15 +1303,23 @@ static char env_help_text[] = #if defined(CONFIG_CMD_IMPORTENV) "env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import environment\n" #endif +#if defined(CONFIG_EFI_LOADER)
- "env print [-a | -e [name] | name ...] - print environment\n"
+#else "env print [-a | name ...] - print environment\n" +#endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) "env save - save environment\n" #endif +#if defined(CONFIG_EFI_LOADER)
- "env set [-e | -f] name [arg ...]\n";
+#else "env set [-f] name [arg ...]\n"; #endif +#endif U_BOOT_CMD( env, CONFIG_SYS_MAXARGS, 1, do_env, @@ -1295,6 +1344,10 @@ U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", "[-a]\n - print [all] values of all environment variables\n" +#if defined(CONFIG_EFI_LOADER)
- "printenv -e [<name>]\n"
- " - print UEFI variable 'name' or all the variables\n"
+#endif "printenv name ...\n" " - print value of environment variable 'name'", var_complete @@ -1322,7 +1375,11 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables",
- "[-f] name value ...\n"
+#if defined(CONFIG_EFI_LOADER)
- "-e <name> [<value>]\n"
- " - set UEFI variable 'name' to 'value' ...'\n"
+#endif
- "setenv [-f] name value ...\n" " - [forcibly] set environment variable 'name' to 'value ...'\n" "setenv [-f] name\n" " - [forcibly] delete environment variable 'name'",
participants (2)
-
AKASHI Takahiro
-
Alexander Graf