On Fri, Feb 22, 2019 at 11:13:20AM +0100, Philipp Tomsich wrote: > Heinrich, > > > On 22.02.2019, at 01:21, AKASHI Takahiro <takahiro.aka...@linaro.org> wrote: > > > > On Thu, Feb 21, 2019 at 08:42:37PM +0100, Heinrich Schuchardt wrote: > >> On 2/21/19 7:26 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.aka...@linaro.org> > >>> --- > >>> MAINTAINERS | 1 + > >>> cmd/Kconfig | 10 ++ > >>> cmd/Makefile | 1 + > >>> cmd/nvedit.c | 28 +++- > >>> cmd/nvedit_efi.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++ > >>> include/command.h | 8 + > >>> 6 files changed, 442 insertions(+), 1 deletion(-) > >>> create mode 100644 cmd/nvedit_efi.c > >>> > >>> diff --git a/MAINTAINERS b/MAINTAINERS > >>> index f1f8818d6ba8..0cce9db2660e 100644 > >>> --- a/MAINTAINERS > >>> +++ b/MAINTAINERS > >>> @@ -471,6 +471,7 @@ F: lib/efi*/ > >>> F: test/py/tests/test_efi* > >>> F: test/unicode_ut.c > >>> F: cmd/bootefi.c > >>> +F: cmd/nvedit_efi.c > >>> F: tools/file2include.c > >>> > >>> FPGA > >>> diff --git a/cmd/Kconfig b/cmd/Kconfig > >>> index 3ea42e425611..ddcdee44538d 100644 > >>> --- a/cmd/Kconfig > >>> +++ b/cmd/Kconfig > >>> @@ -420,6 +420,16 @@ config CMD_ENV_FLAGS > >>> be deleted. This command shows the variables that have special > >>> flags. > >>> > >>> +config CMD_NVEDIT_EFI > >>> + bool "env [set|print] -e - set/print UEFI variables" > >>> + depends on EFI_LOADER > >>> + default y > >>> + imply HEXDUMP > >>> + help > >>> + UEFI variables are encoded as some form of U-Boot variables. > >>> + If enabled, we are allowed to set/print UEFI variables using > >>> + "env" command with "-e" option without knowing details. > >>> + > >>> endmenu > >>> > >>> menu "Memory commands" > >>> diff --git a/cmd/Makefile b/cmd/Makefile > >>> index a127a995394f..b9ee51869d48 100644 > >>> --- a/cmd/Makefile > >>> +++ b/cmd/Makefile > >>> @@ -98,6 +98,7 @@ obj-$(CONFIG_CMD_MTD) += mtd.o > >>> obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o > >>> obj-$(CONFIG_CMD_NAND) += nand.o > >>> obj-$(CONFIG_CMD_NET) += net.o > >>> +obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o > >>> obj-$(CONFIG_CMD_ONENAND) += onenand.o > >>> obj-$(CONFIG_CMD_OSD) += osd.o > >>> obj-$(CONFIG_CMD_PART) += part.o > >>> diff --git a/cmd/nvedit.c b/cmd/nvedit.c > >>> index ebaa16b75459..f798e5137d26 100644 > >>> --- a/cmd/nvedit.c > >>> +++ b/cmd/nvedit.c > >>> @@ -119,6 +119,11 @@ 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_CMD_NVEDIT_EFI) > >>> + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') > >>> + return do_env_print_efi(cmdtp, flag, --argc, ++argv); > >>> +#endif > >>> + > >>> if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { > >>> argc--; > >>> argv++; > >>> @@ -216,6 +221,12 @@ 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_SPL_BUILD) && defined(CONFIG_CMD_NVEDIT_EFI) > >> > >> In the Makefile you already have 'ifndef CONFIG_SPL_BUILD'. > > > > No. > > Since nvedit.c is always compiled in, we need this protection. > > How about using CONFIG_IS_ENABLED(CMD_NVEDIT_EFI)? > > This could give you fine-grained control through CONFIG_SPL_CMD_NVEDIT_EFI > and CONFIG_CMD_NVEDIT_EFI … > …and if you don’t even create the CONFIG_SPL_CMD_NVEDIT_EFI in Kconfig (i.e. > leave everything else as it is), it is equivalent to what you have today.
Nice. Since we won't expect this configuration be turned on at SPL, I haven't given it a thought. Thanks, -Takahiro Akashi > Thanks, > Philipp. > > > > >>> + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') > >>> + return do_env_set_efi(NULL, flag, --argc, ++argv); > >>> +#endif > >>> + > >>> while (argc > 1 && **(argv + 1) == '-') { > >>> char *arg = *++argv; > >>> > >>> @@ -1263,11 +1274,17 @@ static char env_help_text[] = > >>> "env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import > >>> environment\n" > >>> #endif > >>> "env print [-a | name ...] - print environment\n" > >>> +#if defined(CONFIG_CMD_NVEDIT_EFI) > >>> + "env print -e [name ...] - print UEFI 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_CMD_NVEDIT_EFI) > >>> + "env set -e name [arg ...] - set UEFI variable; unset if 'arg' not > >>> specified\n" > >>> #endif > >>> "env set [-f] name [arg ...]\n"; > >>> #endif > >>> @@ -1295,6 +1312,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_CMD_NVEDIT_EFI) > >>> + "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 +1343,12 @@ 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_CMD_NVEDIT_EFI) > >>> + "-e name [value ...]\n" > >>> + " - set UEFI variable 'name' to 'value' ...'\n" > >>> + " - delete UEFI variable 'name' if 'value' not specified\n" > >>> +#endif > >>> + "setenv [-f] name value ...\n" > >>> " - [forcibly] set environment variable 'name' to 'value ...'\n" > >>> "setenv [-f] name\n" > >>> " - [forcibly] delete environment variable 'name'", > >>> diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c > >>> new file mode 100644 > >>> index 000000000000..aaff9f51d672 > >>> --- /dev/null > >>> +++ b/cmd/nvedit_efi.c > >>> @@ -0,0 +1,395 @@ > >>> +// SPDX-License-Identifier: GPL-2.0+ > >>> +/* > >>> + * Integrate UEFI variables to u-boot env interface > >>> + * > >>> + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited > >>> + */ > >>> + > >>> +#include <charset.h> > >>> +#include <common.h> > >>> +#include <command.h> > >>> +#include <efi_loader.h> > >>> +#include <exports.h> > >>> +#include <hexdump.h> > >>> +#include <malloc.h> > >>> +#include <linux/kernel.h> > >>> + > >>> +/* > >>> + * From efi_variable.c, > >>> + * > >>> + * Mapping between UEFI variables and u-boot variables: > >>> + * > >>> + * efi_$guid_$varname = {attributes}(type)value > >>> + */ > >>> + > >>> +static const struct { > >>> + u32 mask; > >>> + char *text; > >>> +} efi_var_attrs[] = { > >>> + {EFI_VARIABLE_NON_VOLATILE, "NV"}, > >>> + {EFI_VARIABLE_BOOTSERVICE_ACCESS, "BS"}, > >>> + {EFI_VARIABLE_RUNTIME_ACCESS, "RT"}, > >>> + {EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, "AW"}, > >>> + {EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, "AT"}, > >>> +}; > >>> + > >>> +/** > >>> + * efi_dump_single_var() - show information about a UEFI variable > >>> + * > >>> + * @name: Name of the variable > >>> + * @guid: Vendor GUID > >>> + * > >>> + * Show information encoded in one UEFI variable > >>> + */ > >>> +static void efi_dump_single_var(u16 *name, efi_guid_t *guid) > >>> +{ > >>> + u32 attributes; > >>> + u8 *data; > >>> + efi_uintn_t size; > >>> + int count, i; > >>> + efi_status_t ret; > >>> + > >>> + data = NULL; > >>> + size = 0; > >>> + ret = efi_get_variable(name, guid, &attributes, &size, data); > >> > >> Please, use EFI_CALL() when calling function which themselves call > >> EFI_ENTRY(). > > > > Oops, okay. > > > > -Takahiro Akashi > > > >> Best regards > >> > >> Heinrich > >> > >>> + if (ret == EFI_BUFFER_TOO_SMALL) { > >>> + data = malloc(size); > >>> + if (!data) > >>> + goto out; > >>> + > >>> + ret = efi_get_variable(name, guid, &attributes, &size, data); > >>> + } > >>> + if (ret == EFI_NOT_FOUND) { > >>> + printf("Error: \"%ls\" not defined\n", name); > >>> + goto out; > >>> + } > >>> + if (ret != EFI_SUCCESS) > >>> + goto out; > >>> + > >>> + printf("%ls:", name); > >>> + for (count = 0, i = 0; i < ARRAY_SIZE(efi_var_attrs); i++) > >>> + if (attributes & efi_var_attrs[i].mask) { > >>> + if (count) > >>> + putc('|'); > >>> + else > >>> + putc(' '); > >>> + count++; > >>> + puts(efi_var_attrs[i].text); > >>> + } > >>> + printf(", DataSize = 0x%zx\n", size); > >>> + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, data, size, true); > >>> + > >>> + return; > >>> +out: > >>> + free(data); > >>> +} > >>> + > >>> +/** > >>> + * efi_dump_vars() - show information about named UEFI variables > >>> + * > >>> + * @argc: Number of arguments (variables) > >>> + * @argv: Argument (variable name) array > >>> + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE > >>> + * > >>> + * Show information encoded in named UEFI variables > >>> + */ > >>> +static int efi_dump_vars(int argc, char * const argv[]) > >>> +{ > >>> + u16 *var_name16, *p; > >>> + efi_uintn_t buf_size, size; > >>> + > >>> + buf_size = 128; > >>> + var_name16 = malloc(buf_size); > >>> + if (!var_name16) > >>> + return CMD_RET_FAILURE; > >>> + > >>> + for (; argc > 0; argc--, argv++) { > >>> + size = (utf8_utf16_strlen(argv[0]) + 1) * sizeof(u16); > >>> + if (buf_size < size) { > >>> + buf_size = size; > >>> + p = realloc(var_name16, buf_size); > >>> + if (!p) { > >>> + free(var_name16); > >>> + return CMD_RET_FAILURE; > >>> + } > >>> + var_name16 = p; > >>> + } > >>> + > >>> + p = var_name16; > >>> + utf8_utf16_strcpy(&p, argv[0]); > >>> + > >>> + efi_dump_single_var(var_name16, > >>> + (efi_guid_t *)&efi_global_variable_guid); > >>> + } > >>> + > >>> + free(var_name16); > >>> + > >>> + return CMD_RET_SUCCESS; > >>> +} > >>> + > >>> +/** > >>> + * efi_dump_vars() - show information about all the UEFI variables > >>> + * > >>> + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE > >>> + * > >>> + * Show information encoded in all the UEFI variables > >>> + */ > >>> +static int efi_dump_var_all(void) > >>> +{ > >>> + u16 *var_name16, *p; > >>> + efi_uintn_t buf_size, size; > >>> + efi_guid_t guid; > >>> + efi_status_t ret; > >>> + > >>> + buf_size = 128; > >>> + var_name16 = malloc(buf_size); > >>> + if (!var_name16) > >>> + return CMD_RET_FAILURE; > >>> + > >>> + var_name16[0] = 0; > >>> + for (;;) { > >>> + size = buf_size; > >>> + ret = efi_get_next_variable_name(&size, var_name16, &guid); > >>> + if (ret == EFI_NOT_FOUND) > >>> + break; > >>> + if (ret == EFI_BUFFER_TOO_SMALL) { > >>> + buf_size = size; > >>> + p = realloc(var_name16, buf_size); > >>> + if (!p) { > >>> + free(var_name16); > >>> + return CMD_RET_FAILURE; > >>> + } > >>> + var_name16 = p; > >>> + ret = efi_get_next_variable_name(&size, var_name16, > >>> + &guid); > >>> + } > >>> + if (ret != EFI_SUCCESS) { > >>> + free(var_name16); > >>> + return CMD_RET_FAILURE; > >>> + } > >>> + > >>> + efi_dump_single_var(var_name16, &guid); > >>> + } > >>> + > >>> + free(var_name16); > >>> + > >>> + return CMD_RET_SUCCESS; > >>> +} > >>> + > >>> +/** > >>> + * do_env_print_efi() - show information about UEFI variables > >>> + * > >>> + * @cmdtp: Command table > >>> + * @flag: Command flag > >>> + * @argc: Number of arguments > >>> + * @argv: Argument array > >>> + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE > >>> + * > >>> + * This function is for "env print -e" or "printenv -e" command: > >>> + * => env print -e [var [...]] > >>> + * If one or more variable names are specified, show information > >>> + * named UEFI variables, otherwise show all the UEFI variables. > >>> + */ > >>> +int do_env_print_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const > >>> argv[]) > >>> +{ > >>> + efi_status_t ret; > >>> + > >>> + /* Initialize EFI drivers */ > >>> + ret = efi_init_obj_list(); > >>> + if (ret != EFI_SUCCESS) { > >>> + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", > >>> + ret & ~EFI_ERROR_MASK); > >>> + return CMD_RET_FAILURE; > >>> + } > >>> + > >>> + if (argc > 1) > >>> + /* show specified UEFI variables */ > >>> + return efi_dump_vars(--argc, ++argv); > >>> + > >>> + /* enumerate and show all UEFI variables */ > >>> + return efi_dump_var_all(); > >>> +} > >>> + > >>> +/** > >>> + * append_value() - encode UEFI variable's value > >>> + * @bufp: Buffer of encoded UEFI variable's value > >>> + * @sizep: Size of buffer > >>> + * @data: data to be encoded into the value > >>> + * Return: 0 on success, -1 otherwise > >>> + * > >>> + * Interpret a given data string and append it to buffer. > >>> + * Buffer will be realloc'ed if necessary. > >>> + * > >>> + * Currently supported formats are: > >>> + * =0x0123...: Hexadecimal number > >>> + * =H0123...: Hexadecimal-byte array > >>> + * ="...", =S"..." or <string>: > >>> + * String > >>> + */ > >>> +static int append_value(char **bufp, size_t *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; > >>> +} > >>> + > >>> +/** > >>> + * do_env_print_efi() - set UEFI variable > >>> + * > >>> + * @cmdtp: Command table > >>> + * @flag: Command flag > >>> + * @argc: Number of arguments > >>> + * @argv: Argument array > >>> + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE > >>> + * > >>> + * This function is for "env set -e" or "setenv -e" command: > >>> + * => env set -e var [value ...]] > >>> + * Encode values specified and set given UEFI variable. > >>> + * If no value is specified, delete the variable. > >>> + */ > >>> +int do_env_set_efi(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; > >>> + size_t len; > >>> + efi_guid_t guid; > >>> + efi_status_t ret; > >>> + > >>> + if (argc == 1) > >>> + return CMD_RET_USAGE; > >>> + > >>> + /* Initialize EFI drivers */ > >>> + ret = efi_init_obj_list(); > >>> + if (ret != EFI_SUCCESS) { > >>> + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", > >>> + ret & ~EFI_ERROR_MASK); > >>> + return CMD_RET_FAILURE; > >>> + } > >>> + > >>> + var_name = argv[1]; > >>> + if (argc == 2) { > >>> + /* delete */ > >>> + 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; > >>> + } > >>> + } > >>> + > >>> + len = utf8_utf16_strnlen(var_name, strlen(var_name)); > >>> + var_name16 = malloc((len + 1) * 2); > >>> + if (!var_name16) { > >>> + ret = CMD_RET_FAILURE; > >>> + goto out; > >>> + } > >>> + p = var_name16; > >>> + utf8_utf16_strncpy(&p, var_name, len + 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; > >>> +} > >>> diff --git a/include/command.h b/include/command.h > >>> index 461b17447c0d..2e24e8ad3eef 100644 > >>> --- a/include/command.h > >>> +++ b/include/command.h > >>> @@ -139,6 +139,14 @@ extern int do_poweroff(cmd_tbl_t *cmdtp, int flag, > >>> int argc, char * const argv[] > >>> > >>> extern unsigned long do_go_exec(ulong (*entry)(int, char * const []), int > >>> argc, > >>> char * const argv[]); > >>> + > >>> +#if defined(CONFIG_CMD_NVEDIT_EFI) > >>> +extern int do_env_print_efi(cmd_tbl_t *cmdtp, int flag, int argc, > >>> + char * const argv[]); > >>> +extern int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, > >>> + char * const argv[]); > >>> +#endif > >>> + > >>> /* > >>> * Error codes that commands return to cmd_process(). We use the standard > >>> 0 > >>> * and 1 for success and failure, but add one more case - failure with a > >>> > >> > > _______________________________________________ > > U-Boot mailing list > > U-Boot@lists.denx.de > > https://lists.denx.de/listinfo/u-boot > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot