All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment
@ 2019-02-21  6:26 AKASHI Takahiro
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables AKASHI Takahiro
                   ` (6 more replies)
  0 siblings, 7 replies; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

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 scsi 1:1 /Shell.efi ""
=> efidebug boot add 2 HELLO scsi 1:1 /hello.efi ""
=> efidebug boot dump
Boot0001:
	attributes: A-- (0x00000001)
	label: SHELL
	file_path: /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)/HD(1,MBR,0x086246ba,0x800,0x40000)/\\Shell.efi
	data: 
Boot0002:
	attributes: A-- (0x00000001)
	label: HELLO
	file_path: /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,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!
=> env print -e
Boot0001: BS|RT, DataSize = 0x79
    00000000: 01 00 00 00 66 00 53 00 48 00 45 00 4c 00 4c 00  ....f.S.H.E.L.L.
    00000010: 00 00 01 04 14 00 b9 73 1d e6 84 a3 cc 4a ae ab  .......s.....J..
    00000020: 82 e8 28 f3 62 8b 03 02 08 00 01 00 00 00 04 01  ..(.b...........
    00000030: 2a 00 01 00 00 00 00 08 00 00 00 00 00 00 00 00  *...............
    00000040: 04 00 00 00 00 00 ba 46 62 08 00 00 00 00 00 00  .......Fb.......
    00000050: 00 00 00 00 00 00 01 01 04 04 1c 00 5c 00 5c 00  ............\.\.
    00000060: 53 00 68 00 65 00 6c 00 6c 00 2e 00 65 00 66 00  S.h.e.l.l...e.f.
    00000070: 69 00 00 00 7f ff 04 00 00                       i........
Boot0002: BS|RT, DataSize = 0x79
    00000000: 01 00 00 00 66 00 48 00 45 00 4c 00 4c 00 4f 00  ....f.H.E.L.L.O.
    00000010: 00 00 01 04 14 00 b9 73 1d e6 84 a3 cc 4a ae ab  .......s.....J..
    00000020: 82 e8 28 f3 62 8b 03 02 08 00 01 00 00 00 04 01  ..(.b...........
    00000030: 2a 00 01 00 00 00 00 08 00 00 00 00 00 00 00 00  *...............
    00000040: 04 00 00 00 00 00 ba 46 62 08 00 00 00 00 00 00  .......Fb.......
    00000050: 00 00 00 00 00 00 01 01 04 04 1c 00 5c 00 5c 00  ............\.\.
    00000060: 68 00 65 00 6c 00 6c 00 6f 00 2e 00 65 00 66 00  h.e.l.l.o...e.f.
    00000070: 69 00 00 00 7f ff 04 00 00                       i........
BootOrder: BS|RT, DataSize = 0x4
    00000000: 01 00 02 00                                      ....
PlatformLang: BS|RT, DataSize = 0x2
    00000000: 65 6e                                            en

=> run -e Boot0001 or bootefi bootmgr

   (UEFI shell ...)

"env set" command now supports UEFI shell-like syntax:

=> env set -e foo =S\"akashi\" =0x012345 =Habcdef
=> env print -e foo
foo: BS|RT, DataSize = 0xd
    00000000: 61 6b 61 73 68 69 45 23 01 00 ab cd ef           akashiE#.....

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 v7 (Feb 21, 2019)
* fix travis errors
* make CMD_NVEDIT_EFI configurable
* improve command help text
* add function descriptions at every function
* output error message when "boot add" fails
* use locate_handle_buffer() instead of locate_handle()
* use allocate_pool() instead of malloc()
* wrap EFI function calls with EFI_CALL

* Travis CI result:
    https://travis-ci.org/t-akashi/u-boot/builds/496298404

Changes in v6 (Jan 24, 2019)
* re-organize the code so that we can compile in "env [set|print] -e"
  support with or without CONFIG_CMD_EFIDEBUG
* remove "efidebug setvar" and "efidebug dumpvar" sub-commands
* re-implement "env print -e" using GetNextVariableName API
  and print_hex_dump()
* "env print -e" print more information, including attributes and size
* change a header format at "devices" and "drivers" sub-commands

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: env: add "-e" option for handling UEFI variables
  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

 MAINTAINERS       |    2 +
 cmd/Kconfig       |   20 +
 cmd/Makefile      |    2 +
 cmd/efidebug.c    | 1038 +++++++++++++++++++++++++++++++++++++++++++++
 cmd/nvedit.c      |   28 +-
 cmd/nvedit_efi.c  |  395 +++++++++++++++++
 include/command.h |    8 +
 7 files changed, 1492 insertions(+), 1 deletion(-)
 create mode 100644 cmd/efidebug.c
 create mode 100644 cmd/nvedit_efi.c

-- 
2.20.1

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21 19:42   ` Heinrich Schuchardt
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 2/7] cmd: add efidebug command AKASHI Takahiro
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

"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>
---
 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)
+	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);
+	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
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 2/7] cmd: add efidebug command
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21 19:24   ` Heinrich Schuchardt
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 3/7] cmd: efidebug: add devices command AKASHI Takahiro
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

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)

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 MAINTAINERS    |   1 +
 cmd/Kconfig    |  10 +
 cmd/Makefile   |   1 +
 cmd/efidebug.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 590 insertions(+)
 create mode 100644 cmd/efidebug.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0cce9db2660e..4fabb75eda37 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/efidebug.c
 F:	cmd/nvedit_efi.c
 F:	tools/file2include.c
 
diff --git a/cmd/Kconfig b/cmd/Kconfig
index ddcdee44538d..88b086b074be 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1407,6 +1407,16 @@ config CMD_DISPLAY
 	  displayed on a simple board-specific display. Implement
 	  display_putc() to use it.
 
+config CMD_EFIDEBUG
+	bool "efidebug - display/configure 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 b9ee51869d48..acb85f49fba8 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_CMD_EFIDEBUG) += 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..641ec98a4d32
--- /dev/null
+++ b/cmd/efidebug.c
@@ -0,0 +1,578 @@
+// 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 <exports.h>
+#include <malloc.h>
+#include <search.h>
+#include <linux/ctype.h>
+
+/**
+ * do_efi_boot_add() - set UEFI boot option
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success,
+ *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "boot add" sub-command.
+ * Create or change UEFI boot option.
+ *   - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
+ */
+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) {
+		printf("Cannot create device path for \"%s %s\"\n",
+		       argv[3], argv[4]);
+		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;
+}
+
+/**
+ * do_efi_boot_rm() - delete UEFI boot options
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "boot rm" sub-command.
+ * Delete UEFI boot options.
+ *   - boot rm <id> ...
+ */
+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;
+}
+
+/**
+ * show_efi_boot_opt_data() - dump UEFI boot option
+ *
+ * @id:		Boot opton number
+ * @data:	Value of UEFI boot option variable
+ *
+ * Decode the value of UEFI boot option variable and print information.
+ */
+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);
+}
+
+/**
+ * show_efi_boot_opt() - dump UEFI boot option
+ *
+ * @id:		Boot opton number
+ *
+ * Dump information defined by UEFI boot option.
+ */
+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);
+}
+
+/**
+ * show_efi_boot_dump() - dump all UEFI boot options
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "boot dump" sub-command.
+ * Dump information of all UEFI boot options defined.
+ *   - boot dump
+ */
+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]+");
+
+	/* TODO: use GetNextVariableName? */
+	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;
+}
+
+/**
+ * show_efi_boot_order() - show order of UEFI boot options
+ *
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Show order of UEFI boot options defined by BootOrder variable.
+ */
+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;
+}
+
+/**
+ * do_efi_boot_next() - manage UEFI BootNext variable
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success,
+ *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "boot next" sub-command.
+ * Set BootNext variable.
+ *   - boot next <id>
+ */
+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;
+}
+
+/**
+ * do_efi_boot_order() - manage UEFI BootOrder variable
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "boot order" sub-command.
+ * Show order of UEFI boot options, or change it in BootOrder variable.
+ *   - boot order [<id> ...]
+ */
+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,
+			 "", ""),
+};
+
+/**
+ * do_efi_boot_opt() - manage UEFI boot options
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success,
+ *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "boot" sub-command.
+ * See above for details of sub-commands.
+ */
+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, "", ""),
+};
+
+/**
+ * do_efidebug() - display and configure UEFI environment
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success,
+ *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug command which allows us to dsiplay and
+ * configure UEFI environment.
+ * See above for details of sub-commands.
+ */
+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> <devnum>[:<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"
+	"  - dump 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";
+#endif
+
+U_BOOT_CMD(
+	efidebug, 10, 0, do_efidebug,
+	"Configure UEFI environment",
+	efidebug_help_text
+);
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 3/7] cmd: efidebug: add devices command
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables AKASHI Takahiro
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 2/7] cmd: add efidebug command AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21 19:25   ` Heinrich Schuchardt
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command AKASHI Takahiro
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

"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
Device           Device Path
================ ====================
000000007ef07ea0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)
000000007ef00c10 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(0,0)
000000007ef00dd0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)
000000007ef07be0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)/HD(1,MBR,0x086246ba,0x800,0x40000)
000000007ef07510 /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 | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 641ec98a4d32..72e0652fc3e4 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -15,6 +15,80 @@
 #include <search.h>
 #include <linux/ctype.h>
 
+#define BS systab.boottime
+
+/**
+ * efi_get_device_handle_info() - get information of UEFI device
+ *
+ * @handle:		Handle of UEFI device
+ * @dev_path_text:	Pointer to text of device path
+ * Return:		0 on success, -1 on failure
+ *
+ * Currently return a formatted text of device path.
+ */
+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 = EFI_CALL(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;
+	}
+}
+
+#define EFI_HANDLE_WIDTH ((int)sizeof(efi_handle_t) * 2)
+
+static const char spc[] = "                ";
+static const char sep[] = "================";
+
+/**
+ * do_efi_show_devices() - show UEFI devices
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "devices" sub-command.
+ * Show all UEFI devices and their information.
+ */
+static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
+			       int argc, char * const argv[])
+{
+	efi_handle_t *handles;
+	efi_uintn_t num, i;
+	u16 *dev_path_text;
+	efi_status_t ret;
+
+	ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
+						&num, &handles));
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	if (!num)
+		return CMD_RET_SUCCESS;
+
+	printf("Device%.*s Device Path\n", EFI_HANDLE_WIDTH - 6, spc);
+	printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
+	for (i = 0; i < num; i++) {
+		if (!efi_get_device_handle_info(handles[i], &dev_path_text)) {
+			printf("%p %ls\n", handles[i], dev_path_text);
+			efi_free_pool(dev_path_text);
+		}
+	}
+
+	EFI_CALL(BS->free_pool(handles));
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_efi_boot_add() - set UEFI boot option
  *
@@ -510,6 +584,8 @@ static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag,
 
 static cmd_tbl_t cmd_efidebug_sub[] = {
 	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
+	U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
+			 "", ""),
 };
 
 /**
@@ -568,7 +644,9 @@ static char efidebug_help_text[] =
 	"  - set UEFI BootNext variable\n"
 	"efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
 	"  - set/show UEFI boot order\n"
-	"\n";
+	"\n"
+	"efidebug devices\n"
+	"  - show uefi devices\n";
 #endif
 
 U_BOOT_CMD(
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
                   ` (2 preceding siblings ...)
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 3/7] cmd: efidebug: add devices command AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21 19:32   ` Heinrich Schuchardt
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 5/7] cmd: efidebug: add dh command AKASHI Takahiro
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

"drivers" command prints all the uefi drivers on the system.

=> efi drivers
Driver           Name                 Image Path
================ ==================== ====================
000000007ef003d0 <NULL>               <built-in>

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 72e0652fc3e4..04fc170867fc 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -89,6 +89,95 @@ static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
 	return CMD_RET_SUCCESS;
 }
 
+/**
+ * efi_get_driver_handle_info() - get information of UEFI driver
+ *
+ * @handle:		Handle of UEFI device
+ * @driver_name:	Driver name
+ * @image_path:		Pointer to text of device path
+ * Return:		0 on success, -1 on failure
+ *
+ * Currently return no useful information as all UEFI drivers are
+ * built-in..
+ */
+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;
+}
+
+/**
+ * do_efi_show_drivers() - show UEFI drivers
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "drivers" sub-command.
+ * Show all UEFI drivers and their information.
+ */
+static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag,
+			       int argc, char * const argv[])
+{
+	efi_handle_t *handles;
+	efi_uintn_t num, i;
+	u16 *driver_name, *image_path_text;
+	efi_status_t ret;
+
+	ret = EFI_CALL(BS->locate_handle_buffer(BY_PROTOCOL,
+					&efi_guid_driver_binding_protocol, NULL,
+					&num, &handles));
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	if (!num)
+		return CMD_RET_SUCCESS;
+
+	printf("Driver%.*s Name                 Image Path\n",
+	       EFI_HANDLE_WIDTH - 6, spc);
+	printf("%.*s ==================== ====================\n",
+	       EFI_HANDLE_WIDTH, sep);
+	for (i = 0; i < num; i++) {
+		if (!efi_get_driver_handle_info(handles[i], &driver_name,
+						&image_path_text)) {
+			if (image_path_text)
+				printf("%p %-20ls %ls\n", handles[i],
+				       driver_name, image_path_text);
+			else
+				printf("%p %-20ls <built-in>\n",
+				       handles[i], driver_name);
+			EFI_CALL(BS->free_pool(driver_name));
+			EFI_CALL(BS->free_pool(image_path_text));
+		}
+	}
+
+	EFI_CALL(BS->free_pool(handles));
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_efi_boot_add() - set UEFI boot option
  *
@@ -586,6 +675,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = {
 	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
 	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,
+			 "", ""),
 };
 
 /**
@@ -646,7 +737,9 @@ static char efidebug_help_text[] =
 	"  - set/show UEFI boot order\n"
 	"\n"
 	"efidebug devices\n"
-	"  - show uefi devices\n";
+	"  - show uefi devices\n"
+	"efidebug drivers\n"
+	"  - show uefi drivers\n";
 #endif
 
 U_BOOT_CMD(
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 5/7] cmd: efidebug: add dh command
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
                   ` (3 preceding siblings ...)
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21 19:33   ` Heinrich Schuchardt
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 6/7] cmd: efidebug: add images command AKASHI Takahiro
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 7/7] cmd: efidebug: add memmap command AKASHI Takahiro
  6 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

"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 | 142 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 141 insertions(+), 1 deletion(-)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 04fc170867fc..0bbca7376be9 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -178,6 +178,142 @@ 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,
+	},
+};
+
+/**
+ * get_guid_text - get string of protocol guid
+ * @guid:	Protocol guid
+ * Return:	String
+ *
+ * Return string for display to represent the protocol.
+ */
+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;
+}
+
+/**
+ * do_efi_show_handles() - show UEFI handles
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "dh" sub-command.
+ * Show all UEFI handles and their information, currently all protocols
+ * added to handle.
+ */
+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 num, count, i, j;
+	const char *guid_text;
+	efi_status_t ret;
+
+	ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
+						&num, &handles));
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	if (!num)
+		return CMD_RET_SUCCESS;
+
+	printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
+	printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
+	for (i = 0; i < num; i++) {
+		printf("%p", handles[i]);
+		ret = EFI_CALL(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');
+	}
+
+	EFI_CALL(BS->free_pool(handles));
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_efi_boot_add() - set UEFI boot option
  *
@@ -677,6 +813,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,
+			 "", ""),
 };
 
 /**
@@ -739,7 +877,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(
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 6/7] cmd: efidebug: add images command
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
                   ` (4 preceding siblings ...)
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 5/7] cmd: efidebug: add dh command AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 7/7] cmd: efidebug: add memmap command AKASHI Takahiro
  6 siblings, 0 replies; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

"images" command prints loaded images-related information.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 cmd/efidebug.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 0bbca7376be9..e68db6d82739 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -314,6 +314,26 @@ static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag,
 	return CMD_RET_SUCCESS;
 }
 
+/**
+ * do_efi_show_images() - show UEFI images
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "images" sub-command.
+ * Show all UEFI loaded images and their information.
+ */
+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;
+}
+
 /**
  * do_efi_boot_add() - set UEFI boot option
  *
@@ -815,6 +835,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,
+			 "", ""),
 };
 
 /**
@@ -879,7 +901,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(
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 7/7] cmd: efidebug: add memmap command
  2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
                   ` (5 preceding siblings ...)
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 6/7] cmd: efidebug: add images command AKASHI Takahiro
@ 2019-02-21  6:26 ` AKASHI Takahiro
  2019-02-21 19:35   ` Heinrich Schuchardt
  6 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-21  6:26 UTC (permalink / raw)
  To: u-boot

"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 | 127 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 126 insertions(+), 1 deletion(-)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index e68db6d82739..5dd087a7cc45 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -334,6 +334,127 @@ 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"},
+};
+
+/**
+ * print_memory_attributes() - print memory map attributes
+ * @attributes:	Attribute value
+ *
+ * Print memory map attributes
+ */
+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);
+		}
+}
+
+#define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
+
+/**
+ * do_efi_show_memmap() - show UEFI memory map
+ *
+ * @cmdtp:	Command table
+ * @flag:	Command flag
+ * @argc:	Number of arguments
+ * @argv:	Argument array
+ * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "memmap" sub-command.
+ * Show UEFI memory map.
+ */
+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;
+	const char *type;
+	int i;
+	efi_status_t ret;
+
+	ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, NULL, NULL, NULL));
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		map_size += sizeof(struct efi_mem_desc); /* for my own */
+		ret = EFI_CALL(BS->allocate_pool(EFI_LOADER_DATA,
+						 map_size, (void *)&memmap));
+		if (ret != EFI_SUCCESS)
+			return CMD_RET_FAILURE;
+		ret = EFI_CALL(BS->get_memory_map(&map_size, memmap,
+						  NULL, NULL, NULL));
+	}
+	if (ret != EFI_SUCCESS) {
+		EFI_CALL(BS->free_pool(memmap));
+		return CMD_RET_FAILURE;
+	}
+
+	printf("Type             Start%.*s End%.*s Attributes\n",
+	       EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
+	printf("================ %.*s %.*s ==========\n",
+	       EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
+	for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
+		if (map->type < EFI_MAX_MEMORY_TYPE)
+			type = efi_mem_type_string[map->type];
+		else
+			type = "(unknown)";
+
+		printf("%-16s %.*llx-%.*llx", type,
+		       EFI_PHYS_ADDR_WIDTH,
+		       map->physical_start,
+		       EFI_PHYS_ADDR_WIDTH,
+		       map->physical_start + map->num_pages * EFI_PAGE_SIZE);
+
+		print_memory_attributes(map->attribute);
+		putc('\n');
+	}
+
+	EFI_CALL(BS->free_pool(memmap));
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_efi_boot_add() - set UEFI boot option
  *
@@ -837,6 +958,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,
+			 "", ""),
 };
 
 /**
@@ -903,7 +1026,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(
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 2/7] cmd: add efidebug command
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 2/7] cmd: add efidebug command AKASHI Takahiro
@ 2019-02-21 19:24   ` Heinrich Schuchardt
  2019-02-22  1:04     ` AKASHI Takahiro
  0 siblings, 1 reply; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-21 19:24 UTC (permalink / raw)
  To: u-boot

On 2/21/19 7:26 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)
> 
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>  MAINTAINERS    |   1 +
>  cmd/Kconfig    |  10 +
>  cmd/Makefile   |   1 +
>  cmd/efidebug.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 590 insertions(+)
>  create mode 100644 cmd/efidebug.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0cce9db2660e..4fabb75eda37 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/efidebug.c
>  F:	cmd/nvedit_efi.c
>  F:	tools/file2include.c
>  
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index ddcdee44538d..88b086b074be 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1407,6 +1407,16 @@ config CMD_DISPLAY
>  	  displayed on a simple board-specific display. Implement
>  	  display_putc() to use it.
>  
> +config CMD_EFIDEBUG
> +	bool "efidebug - display/configure 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 b9ee51869d48..acb85f49fba8 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_CMD_EFIDEBUG) += 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..641ec98a4d32
> --- /dev/null
> +++ b/cmd/efidebug.c
> @@ -0,0 +1,578 @@
> +// 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 <exports.h>
> +#include <malloc.h>
> +#include <search.h>
> +#include <linux/ctype.h>
> +
> +/**
> + * do_efi_boot_add() - set UEFI boot option
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success,
> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "boot add" sub-command.
> + * Create or change UEFI boot option.
> + *   - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
> + */
> +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 */

I would prefer the usage of a constant.

We should move the definitions from lib/efi_loader/efi_bootmgr.c to
efi_api.h:

#define LOAD_OPTION_ACTIVE		0x00000001
#define LOAD_OPTION_FORCE_RECONNECT	0x00000002
#define LOAD_OPTION_HIDDEN		0x00000008

And add the missing values:

#define LOAD_OPTION_CATEGORY		0x00001F00
#define LOAD_OPTION_CATEGORY_BOOT	0x00000000
#define LOAD_OPTION_CATEGORY_APP	0x00000100

> +
> +	/* 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) {
> +		printf("Cannot create device path for \"%s %s\"\n",
> +		       argv[3], argv[4]);
> +		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;
> +}
> +
> +/**
> + * do_efi_boot_rm() - delete UEFI boot options
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "boot rm" sub-command.
> + * Delete UEFI boot options.
> + *   - boot rm <id> ...
> + */
> +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;
> +}
> +
> +/**
> + * show_efi_boot_opt_data() - dump UEFI boot option
> + *
> + * @id:		Boot opton number
> + * @data:	Value of UEFI boot option variable
> + *
> + * Decode the value of UEFI boot option variable and print information.
> + */
> +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' : '-',

Please, use constants here.

> +	       /* FORCE RECONNECT */
> +	       lo.attributes & 0x2 ? 'R' : '-',
> +	       /* HIDDEN */
> +	       lo.attributes & 0x8 ? 'H' : '-',
> +	       lo.attributes);

How about LOAD_OPTION_CATEGORY_APP?
It is not supported by us yet. So it is not strictly necessary now.

Otherwise

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>


> +	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);
> +}
> +
> +/**
> + * show_efi_boot_opt() - dump UEFI boot option
> + *
> + * @id:		Boot opton number
> + *
> + * Dump information defined by UEFI boot option.
> + */
> +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);
> +}
> +
> +/**
> + * show_efi_boot_dump() - dump all UEFI boot options
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "boot dump" sub-command.
> + * Dump information of all UEFI boot options defined.
> + *   - boot dump
> + */
> +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]+");
> +
> +	/* TODO: use GetNextVariableName? */
> +	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;
> +}
> +
> +/**
> + * show_efi_boot_order() - show order of UEFI boot options
> + *
> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> + *
> + * Show order of UEFI boot options defined by BootOrder variable.
> + */
> +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;
> +}
> +
> +/**
> + * do_efi_boot_next() - manage UEFI BootNext variable
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success,
> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "boot next" sub-command.
> + * Set BootNext variable.
> + *   - boot next <id>
> + */
> +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;
> +}
> +
> +/**
> + * do_efi_boot_order() - manage UEFI BootOrder variable
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "boot order" sub-command.
> + * Show order of UEFI boot options, or change it in BootOrder variable.
> + *   - boot order [<id> ...]
> + */
> +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,
> +			 "", ""),
> +};
> +
> +/**
> + * do_efi_boot_opt() - manage UEFI boot options
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success,
> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "boot" sub-command.
> + * See above for details of sub-commands.
> + */
> +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, "", ""),
> +};
> +
> +/**
> + * do_efidebug() - display and configure UEFI environment
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success,
> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug command which allows us to dsiplay and
> + * configure UEFI environment.
> + * See above for details of sub-commands.
> + */
> +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> <devnum>[:<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"
> +	"  - dump 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";
> +#endif
> +
> +U_BOOT_CMD(
> +	efidebug, 10, 0, do_efidebug,
> +	"Configure UEFI environment",
> +	efidebug_help_text
> +);
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 3/7] cmd: efidebug: add devices command
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 3/7] cmd: efidebug: add devices command AKASHI Takahiro
@ 2019-02-21 19:25   ` Heinrich Schuchardt
  0 siblings, 0 replies; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-21 19:25 UTC (permalink / raw)
  To: u-boot

On 2/21/19 7:26 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
> Device           Device Path
> ================ ====================
> 000000007ef07ea0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)
> 000000007ef00c10 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(0,0)
> 000000007ef00dd0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)
> 000000007ef07be0 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)/HD(1,MBR,0x086246ba,0x800,0x40000)
> 000000007ef07510 /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/Scsi(1,0)/HD(2,MBR,0x086246ba,0x40800,0x3f800)
> 
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command AKASHI Takahiro
@ 2019-02-21 19:32   ` Heinrich Schuchardt
  2019-02-22  0:05     ` AKASHI Takahiro
  0 siblings, 1 reply; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-21 19:32 UTC (permalink / raw)
  To: u-boot

On 2/21/19 7:26 AM, AKASHI Takahiro wrote:
> "drivers" command prints all the uefi drivers on the system.
> 
> => efi drivers
> Driver           Name                 Image Path
> ================ ==================== ====================
> 000000007ef003d0 <NULL>               <built-in>
> 
> 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 72e0652fc3e4..04fc170867fc 100644
> --- a/cmd/efidebug.c
> +++ b/cmd/efidebug.c
> @@ -89,6 +89,95 @@ static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
>  	return CMD_RET_SUCCESS;
>  }
>  
> +/**
> + * efi_get_driver_handle_info() - get information of UEFI driver
> + *
> + * @handle:		Handle of UEFI device
> + * @driver_name:	Driver name
> + * @image_path:		Pointer to text of device path
> + * Return:		0 on success, -1 on failure
> + *
> + * Currently return no useful information as all UEFI drivers are
> + * built-in..
> + */
> +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;
> +}
> +
> +/**
> + * do_efi_show_drivers() - show UEFI drivers
> + *
> + * @cmdtp:	Command table
> + * @flag:	Command flag
> + * @argc:	Number of arguments
> + * @argv:	Argument array
> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> + *
> + * Implement efidebug "drivers" sub-command.
> + * Show all UEFI drivers and their information.
> + */
> +static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag,
> +			       int argc, char * const argv[])
> +{
> +	efi_handle_t *handles;
> +	efi_uintn_t num, i;
> +	u16 *driver_name, *image_path_text;
> +	efi_status_t ret;
> +
> +	ret = EFI_CALL(BS->locate_handle_buffer(BY_PROTOCOL,
> +					&efi_guid_driver_binding_protocol, NULL,
> +					&num, &handles));

nits:

scripts/checkpatch.pl is complaining:
Alignment should match open parenthesis

Just will have to move 'BY_PROTOCOL' to the next line to get rid of it.

Otherwise:

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

> +	if (ret != EFI_SUCCESS)
> +		return CMD_RET_FAILURE;
> +
> +	if (!num)
> +		return CMD_RET_SUCCESS;
> +
> +	printf("Driver%.*s Name                 Image Path\n",
> +	       EFI_HANDLE_WIDTH - 6, spc);
> +	printf("%.*s ==================== ====================\n",
> +	       EFI_HANDLE_WIDTH, sep);
> +	for (i = 0; i < num; i++) {
> +		if (!efi_get_driver_handle_info(handles[i], &driver_name,
> +						&image_path_text)) {
> +			if (image_path_text)
> +				printf("%p %-20ls %ls\n", handles[i],
> +				       driver_name, image_path_text);
> +			else
> +				printf("%p %-20ls <built-in>\n",
> +				       handles[i], driver_name);
> +			EFI_CALL(BS->free_pool(driver_name));
> +			EFI_CALL(BS->free_pool(image_path_text));
> +		}
> +	}
> +
> +	EFI_CALL(BS->free_pool(handles));
> +
> +	return CMD_RET_SUCCESS;
> +}
> +
>  /**
>   * do_efi_boot_add() - set UEFI boot option
>   *
> @@ -586,6 +675,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = {
>  	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
>  	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,
> +			 "", ""),
>  };
>  
>  /**
> @@ -646,7 +737,9 @@ static char efidebug_help_text[] =
>  	"  - set/show UEFI boot order\n"
>  	"\n"
>  	"efidebug devices\n"
> -	"  - show uefi devices\n";
> +	"  - show uefi devices\n"
> +	"efidebug drivers\n"
> +	"  - show uefi drivers\n";
>  #endif
>  
>  U_BOOT_CMD(
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 5/7] cmd: efidebug: add dh command
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 5/7] cmd: efidebug: add dh command AKASHI Takahiro
@ 2019-02-21 19:33   ` Heinrich Schuchardt
  0 siblings, 0 replies; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-21 19:33 UTC (permalink / raw)
  To: u-boot

On 2/21/19 7:26 AM, AKASHI Takahiro wrote:
> "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>

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 7/7] cmd: efidebug: add memmap command
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 7/7] cmd: efidebug: add memmap command AKASHI Takahiro
@ 2019-02-21 19:35   ` Heinrich Schuchardt
  0 siblings, 0 replies; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-21 19:35 UTC (permalink / raw)
  To: u-boot

On 2/21/19 7:26 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>

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables
  2019-02-21  6:26 ` [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables AKASHI Takahiro
@ 2019-02-21 19:42   ` Heinrich Schuchardt
  2019-02-22  0:21     ` AKASHI Takahiro
  0 siblings, 1 reply; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-21 19:42 UTC (permalink / raw)
  To: u-boot

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.akashi@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'.

> +	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().

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
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command
  2019-02-21 19:32   ` Heinrich Schuchardt
@ 2019-02-22  0:05     ` AKASHI Takahiro
  2019-02-22  3:01       ` Heinrich Schuchardt
  0 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-22  0:05 UTC (permalink / raw)
  To: u-boot

On Thu, Feb 21, 2019 at 08:32:06PM +0100, Heinrich Schuchardt wrote:
> On 2/21/19 7:26 AM, AKASHI Takahiro wrote:
> > "drivers" command prints all the uefi drivers on the system.
> > 
> > => efi drivers
> > Driver           Name                 Image Path
> > ================ ==================== ====================
> > 000000007ef003d0 <NULL>               <built-in>
> > 
> > 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 72e0652fc3e4..04fc170867fc 100644
> > --- a/cmd/efidebug.c
> > +++ b/cmd/efidebug.c
> > @@ -89,6 +89,95 @@ static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
> >  	return CMD_RET_SUCCESS;
> >  }
> >  
> > +/**
> > + * efi_get_driver_handle_info() - get information of UEFI driver
> > + *
> > + * @handle:		Handle of UEFI device
> > + * @driver_name:	Driver name
> > + * @image_path:		Pointer to text of device path
> > + * Return:		0 on success, -1 on failure
> > + *
> > + * Currently return no useful information as all UEFI drivers are
> > + * built-in..
> > + */
> > +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;
> > +}
> > +
> > +/**
> > + * do_efi_show_drivers() - show UEFI drivers
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "drivers" sub-command.
> > + * Show all UEFI drivers and their information.
> > + */
> > +static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag,
> > +			       int argc, char * const argv[])
> > +{
> > +	efi_handle_t *handles;
> > +	efi_uintn_t num, i;
> > +	u16 *driver_name, *image_path_text;
> > +	efi_status_t ret;
> > +
> > +	ret = EFI_CALL(BS->locate_handle_buffer(BY_PROTOCOL,
> > +					&efi_guid_driver_binding_protocol, NULL,
> > +					&num, &handles));
> 
> nits:
> 
> scripts/checkpatch.pl is complaining:
> Alignment should match open parenthesis
> 
> Just will have to move 'BY_PROTOCOL' to the next line to get rid of it.

No,you can't.
Ending the line with '(' will cause another error.
Or dare you prefer such a style?

-Takahiro Akashi


> Otherwise:
> 
> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> 
> > +	if (ret != EFI_SUCCESS)
> > +		return CMD_RET_FAILURE;
> > +
> > +	if (!num)
> > +		return CMD_RET_SUCCESS;
> > +
> > +	printf("Driver%.*s Name                 Image Path\n",
> > +	       EFI_HANDLE_WIDTH - 6, spc);
> > +	printf("%.*s ==================== ====================\n",
> > +	       EFI_HANDLE_WIDTH, sep);
> > +	for (i = 0; i < num; i++) {
> > +		if (!efi_get_driver_handle_info(handles[i], &driver_name,
> > +						&image_path_text)) {
> > +			if (image_path_text)
> > +				printf("%p %-20ls %ls\n", handles[i],
> > +				       driver_name, image_path_text);
> > +			else
> > +				printf("%p %-20ls <built-in>\n",
> > +				       handles[i], driver_name);
> > +			EFI_CALL(BS->free_pool(driver_name));
> > +			EFI_CALL(BS->free_pool(image_path_text));
> > +		}
> > +	}
> > +
> > +	EFI_CALL(BS->free_pool(handles));
> > +
> > +	return CMD_RET_SUCCESS;
> > +}
> > +
> >  /**
> >   * do_efi_boot_add() - set UEFI boot option
> >   *
> > @@ -586,6 +675,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = {
> >  	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
> >  	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,
> > +			 "", ""),
> >  };
> >  
> >  /**
> > @@ -646,7 +737,9 @@ static char efidebug_help_text[] =
> >  	"  - set/show UEFI boot order\n"
> >  	"\n"
> >  	"efidebug devices\n"
> > -	"  - show uefi devices\n";
> > +	"  - show uefi devices\n"
> > +	"efidebug drivers\n"
> > +	"  - show uefi drivers\n";
> >  #endif
> >  
> >  U_BOOT_CMD(
> > 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables
  2019-02-21 19:42   ` Heinrich Schuchardt
@ 2019-02-22  0:21     ` AKASHI Takahiro
  2019-02-22  2:34       ` Heinrich Schuchardt
  2019-02-22 10:13       ` Philipp Tomsich
  0 siblings, 2 replies; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-22  0:21 UTC (permalink / raw)
  To: u-boot

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.akashi@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.

> > +	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
> > 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 2/7] cmd: add efidebug command
  2019-02-21 19:24   ` Heinrich Schuchardt
@ 2019-02-22  1:04     ` AKASHI Takahiro
  2019-02-22  2:43       ` Heinrich Schuchardt
  0 siblings, 1 reply; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-22  1:04 UTC (permalink / raw)
  To: u-boot

On Thu, Feb 21, 2019 at 08:24:21PM +0100, Heinrich Schuchardt wrote:
> On 2/21/19 7:26 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)
> > 
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > ---
> >  MAINTAINERS    |   1 +
> >  cmd/Kconfig    |  10 +
> >  cmd/Makefile   |   1 +
> >  cmd/efidebug.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 590 insertions(+)
> >  create mode 100644 cmd/efidebug.c
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 0cce9db2660e..4fabb75eda37 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/efidebug.c
> >  F:	cmd/nvedit_efi.c
> >  F:	tools/file2include.c
> >  
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index ddcdee44538d..88b086b074be 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1407,6 +1407,16 @@ config CMD_DISPLAY
> >  	  displayed on a simple board-specific display. Implement
> >  	  display_putc() to use it.
> >  
> > +config CMD_EFIDEBUG
> > +	bool "efidebug - display/configure 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 b9ee51869d48..acb85f49fba8 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_CMD_EFIDEBUG) += 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..641ec98a4d32
> > --- /dev/null
> > +++ b/cmd/efidebug.c
> > @@ -0,0 +1,578 @@
> > +// 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 <exports.h>
> > +#include <malloc.h>
> > +#include <search.h>
> > +#include <linux/ctype.h>
> > +
> > +/**
> > + * do_efi_boot_add() - set UEFI boot option
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success,
> > + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "boot add" sub-command.
> > + * Create or change UEFI boot option.
> > + *   - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
> > + */
> > +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 */
> 
> I would prefer the usage of a constant.
> 
> We should move the definitions from lib/efi_loader/efi_bootmgr.c to
> efi_api.h:

Okay, but in efi_loader.h as struct efi_load_option is defined there.

> #define LOAD_OPTION_ACTIVE		0x00000001
> #define LOAD_OPTION_FORCE_RECONNECT	0x00000002
> #define LOAD_OPTION_HIDDEN		0x00000008
> 
> And add the missing values:
> 
> #define LOAD_OPTION_CATEGORY		0x00001F00
> #define LOAD_OPTION_CATEGORY_BOOT	0x00000000
> #define LOAD_OPTION_CATEGORY_APP	0x00000100
> 
> > +
> > +	/* 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) {
> > +		printf("Cannot create device path for \"%s %s\"\n",
> > +		       argv[3], argv[4]);
> > +		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;
> > +}
> > +
> > +/**
> > + * do_efi_boot_rm() - delete UEFI boot options
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "boot rm" sub-command.
> > + * Delete UEFI boot options.
> > + *   - boot rm <id> ...
> > + */
> > +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;
> > +}
> > +
> > +/**
> > + * show_efi_boot_opt_data() - dump UEFI boot option
> > + *
> > + * @id:		Boot opton number
> > + * @data:	Value of UEFI boot option variable
> > + *
> > + * Decode the value of UEFI boot option variable and print information.
> > + */
> > +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' : '-',
> 
> Please, use constants here.

Okay.

> > +	       /* FORCE RECONNECT */
> > +	       lo.attributes & 0x2 ? 'R' : '-',
> > +	       /* HIDDEN */
> > +	       lo.attributes & 0x8 ? 'H' : '-',
> > +	       lo.attributes);
> 
> How about LOAD_OPTION_CATEGORY_APP?
> It is not supported by us yet. So it is not strictly necessary now.

Next time when "boot menu" or "hot key" will be supported.

Thanks,
-Takahiro Akashi

> Otherwise
> 
> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> 
> 
> > +	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);
> > +}
> > +
> > +/**
> > + * show_efi_boot_opt() - dump UEFI boot option
> > + *
> > + * @id:		Boot opton number
> > + *
> > + * Dump information defined by UEFI boot option.
> > + */
> > +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);
> > +}
> > +
> > +/**
> > + * show_efi_boot_dump() - dump all UEFI boot options
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "boot dump" sub-command.
> > + * Dump information of all UEFI boot options defined.
> > + *   - boot dump
> > + */
> > +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]+");
> > +
> > +	/* TODO: use GetNextVariableName? */
> > +	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;
> > +}
> > +
> > +/**
> > + * show_efi_boot_order() - show order of UEFI boot options
> > + *
> > + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> > + *
> > + * Show order of UEFI boot options defined by BootOrder variable.
> > + */
> > +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;
> > +}
> > +
> > +/**
> > + * do_efi_boot_next() - manage UEFI BootNext variable
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success,
> > + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "boot next" sub-command.
> > + * Set BootNext variable.
> > + *   - boot next <id>
> > + */
> > +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;
> > +}
> > +
> > +/**
> > + * do_efi_boot_order() - manage UEFI BootOrder variable
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "boot order" sub-command.
> > + * Show order of UEFI boot options, or change it in BootOrder variable.
> > + *   - boot order [<id> ...]
> > + */
> > +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,
> > +			 "", ""),
> > +};
> > +
> > +/**
> > + * do_efi_boot_opt() - manage UEFI boot options
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success,
> > + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug "boot" sub-command.
> > + * See above for details of sub-commands.
> > + */
> > +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, "", ""),
> > +};
> > +
> > +/**
> > + * do_efidebug() - display and configure UEFI environment
> > + *
> > + * @cmdtp:	Command table
> > + * @flag:	Command flag
> > + * @argc:	Number of arguments
> > + * @argv:	Argument array
> > + * Return:	CMD_RET_SUCCESS on success,
> > + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
> > + *
> > + * Implement efidebug command which allows us to dsiplay and
> > + * configure UEFI environment.
> > + * See above for details of sub-commands.
> > + */
> > +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> <devnum>[:<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"
> > +	"  - dump 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";
> > +#endif
> > +
> > +U_BOOT_CMD(
> > +	efidebug, 10, 0, do_efidebug,
> > +	"Configure UEFI environment",
> > +	efidebug_help_text
> > +);
> > 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables
  2019-02-22  0:21     ` AKASHI Takahiro
@ 2019-02-22  2:34       ` Heinrich Schuchardt
  2019-02-22 10:13       ` Philipp Tomsich
  1 sibling, 0 replies; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-22  2:34 UTC (permalink / raw)
  To: u-boot

On 2/22/19 1:21 AM, AKASHI Takahiro 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.akashi@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.

You are right.

One day this nvedit.c should be split into two files. One with SPL
relevant functions and one for the rest. That would save us a lot of
ifdef's.

Regards

Heinrich

> 
>>> +	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
>>>
>>
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 2/7] cmd: add efidebug command
  2019-02-22  1:04     ` AKASHI Takahiro
@ 2019-02-22  2:43       ` Heinrich Schuchardt
  0 siblings, 0 replies; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-22  2:43 UTC (permalink / raw)
  To: u-boot

On 2/22/19 2:04 AM, AKASHI Takahiro wrote:
> On Thu, Feb 21, 2019 at 08:24:21PM +0100, Heinrich Schuchardt wrote:
>> On 2/21/19 7:26 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)
>>>
>>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>>> ---
>>>  MAINTAINERS    |   1 +
>>>  cmd/Kconfig    |  10 +
>>>  cmd/Makefile   |   1 +
>>>  cmd/efidebug.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>  4 files changed, 590 insertions(+)
>>>  create mode 100644 cmd/efidebug.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 0cce9db2660e..4fabb75eda37 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/efidebug.c
>>>  F:	cmd/nvedit_efi.c
>>>  F:	tools/file2include.c
>>>  
>>> diff --git a/cmd/Kconfig b/cmd/Kconfig
>>> index ddcdee44538d..88b086b074be 100644
>>> --- a/cmd/Kconfig
>>> +++ b/cmd/Kconfig
>>> @@ -1407,6 +1407,16 @@ config CMD_DISPLAY
>>>  	  displayed on a simple board-specific display. Implement
>>>  	  display_putc() to use it.
>>>  
>>> +config CMD_EFIDEBUG
>>> +	bool "efidebug - display/configure 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 b9ee51869d48..acb85f49fba8 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_CMD_EFIDEBUG) += 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..641ec98a4d32
>>> --- /dev/null
>>> +++ b/cmd/efidebug.c
>>> @@ -0,0 +1,578 @@
>>> +// 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 <exports.h>
>>> +#include <malloc.h>
>>> +#include <search.h>
>>> +#include <linux/ctype.h>
>>> +
>>> +/**
>>> + * do_efi_boot_add() - set UEFI boot option
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success,
>>> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "boot add" sub-command.
>>> + * Create or change UEFI boot option.
>>> + *   - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
>>> + */
>>> +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 */
>>
>> I would prefer the usage of a constant.
>>
>> We should move the definitions from lib/efi_loader/efi_bootmgr.c to
>> efi_api.h:
> 
> Okay, but in efi_loader.h as struct efi_load_option is defined there.

struct efi_load_option is nothing that is defined in the UEFI spec but a
U-Boot specific structure (it is not the same as EFI_LOAD_OPTION).

The constants are defined in the UEFI spec.

To my understanding we are using efi_loader only for U-Boot specific
stuff up to now.

Best regards

Heinrich

> 
>> #define LOAD_OPTION_ACTIVE		0x00000001
>> #define LOAD_OPTION_FORCE_RECONNECT	0x00000002
>> #define LOAD_OPTION_HIDDEN		0x00000008
>>
>> And add the missing values:
>>
>> #define LOAD_OPTION_CATEGORY		0x00001F00
>> #define LOAD_OPTION_CATEGORY_BOOT	0x00000000
>> #define LOAD_OPTION_CATEGORY_APP	0x00000100
>>
>>> +
>>> +	/* 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) {
>>> +		printf("Cannot create device path for \"%s %s\"\n",
>>> +		       argv[3], argv[4]);
>>> +		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;
>>> +}
>>> +
>>> +/**
>>> + * do_efi_boot_rm() - delete UEFI boot options
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "boot rm" sub-command.
>>> + * Delete UEFI boot options.
>>> + *   - boot rm <id> ...
>>> + */
>>> +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;
>>> +}
>>> +
>>> +/**
>>> + * show_efi_boot_opt_data() - dump UEFI boot option
>>> + *
>>> + * @id:		Boot opton number
>>> + * @data:	Value of UEFI boot option variable
>>> + *
>>> + * Decode the value of UEFI boot option variable and print information.
>>> + */
>>> +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' : '-',
>>
>> Please, use constants here.
> 
> Okay.
> 
>>> +	       /* FORCE RECONNECT */
>>> +	       lo.attributes & 0x2 ? 'R' : '-',
>>> +	       /* HIDDEN */
>>> +	       lo.attributes & 0x8 ? 'H' : '-',
>>> +	       lo.attributes);
>>
>> How about LOAD_OPTION_CATEGORY_APP?
>> It is not supported by us yet. So it is not strictly necessary now.
> 
> Next time when "boot menu" or "hot key" will be supported.
> 
> Thanks,
> -Takahiro Akashi
> 
>> Otherwise
>>
>> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>>
>>
>>> +	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);
>>> +}
>>> +
>>> +/**
>>> + * show_efi_boot_opt() - dump UEFI boot option
>>> + *
>>> + * @id:		Boot opton number
>>> + *
>>> + * Dump information defined by UEFI boot option.
>>> + */
>>> +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);
>>> +}
>>> +
>>> +/**
>>> + * show_efi_boot_dump() - dump all UEFI boot options
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "boot dump" sub-command.
>>> + * Dump information of all UEFI boot options defined.
>>> + *   - boot dump
>>> + */
>>> +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]+");
>>> +
>>> +	/* TODO: use GetNextVariableName? */
>>> +	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;
>>> +}
>>> +
>>> +/**
>>> + * show_efi_boot_order() - show order of UEFI boot options
>>> + *
>>> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Show order of UEFI boot options defined by BootOrder variable.
>>> + */
>>> +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;
>>> +}
>>> +
>>> +/**
>>> + * do_efi_boot_next() - manage UEFI BootNext variable
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success,
>>> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "boot next" sub-command.
>>> + * Set BootNext variable.
>>> + *   - boot next <id>
>>> + */
>>> +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;
>>> +}
>>> +
>>> +/**
>>> + * do_efi_boot_order() - manage UEFI BootOrder variable
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "boot order" sub-command.
>>> + * Show order of UEFI boot options, or change it in BootOrder variable.
>>> + *   - boot order [<id> ...]
>>> + */
>>> +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,
>>> +			 "", ""),
>>> +};
>>> +
>>> +/**
>>> + * do_efi_boot_opt() - manage UEFI boot options
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success,
>>> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "boot" sub-command.
>>> + * See above for details of sub-commands.
>>> + */
>>> +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, "", ""),
>>> +};
>>> +
>>> +/**
>>> + * do_efidebug() - display and configure UEFI environment
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success,
>>> + *		CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug command which allows us to dsiplay and
>>> + * configure UEFI environment.
>>> + * See above for details of sub-commands.
>>> + */
>>> +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> <devnum>[:<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"
>>> +	"  - dump 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";
>>> +#endif
>>> +
>>> +U_BOOT_CMD(
>>> +	efidebug, 10, 0, do_efidebug,
>>> +	"Configure UEFI environment",
>>> +	efidebug_help_text
>>> +);
>>>
>>
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command
  2019-02-22  0:05     ` AKASHI Takahiro
@ 2019-02-22  3:01       ` Heinrich Schuchardt
  2019-02-22  4:16         ` AKASHI Takahiro
  0 siblings, 1 reply; 23+ messages in thread
From: Heinrich Schuchardt @ 2019-02-22  3:01 UTC (permalink / raw)
  To: u-boot

On 2/22/19 1:05 AM, AKASHI Takahiro wrote:
> On Thu, Feb 21, 2019 at 08:32:06PM +0100, Heinrich Schuchardt wrote:
>> On 2/21/19 7:26 AM, AKASHI Takahiro wrote:
>>> "drivers" command prints all the uefi drivers on the system.
>>>
>>> => efi drivers
>>> Driver           Name                 Image Path
>>> ================ ==================== ====================
>>> 000000007ef003d0 <NULL>               <built-in>
>>>
>>> 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 72e0652fc3e4..04fc170867fc 100644
>>> --- a/cmd/efidebug.c
>>> +++ b/cmd/efidebug.c
>>> @@ -89,6 +89,95 @@ static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
>>>  	return CMD_RET_SUCCESS;
>>>  }
>>>  
>>> +/**
>>> + * efi_get_driver_handle_info() - get information of UEFI driver
>>> + *
>>> + * @handle:		Handle of UEFI device
>>> + * @driver_name:	Driver name
>>> + * @image_path:		Pointer to text of device path
>>> + * Return:		0 on success, -1 on failure
>>> + *
>>> + * Currently return no useful information as all UEFI drivers are
>>> + * built-in..
>>> + */
>>> +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;
>>> +}
>>> +
>>> +/**
>>> + * do_efi_show_drivers() - show UEFI drivers
>>> + *
>>> + * @cmdtp:	Command table
>>> + * @flag:	Command flag
>>> + * @argc:	Number of arguments
>>> + * @argv:	Argument array
>>> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
>>> + *
>>> + * Implement efidebug "drivers" sub-command.
>>> + * Show all UEFI drivers and their information.
>>> + */
>>> +static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag,
>>> +			       int argc, char * const argv[])
>>> +{
>>> +	efi_handle_t *handles;
>>> +	efi_uintn_t num, i;
>>> +	u16 *driver_name, *image_path_text;
>>> +	efi_status_t ret;
>>> +
>>> +	ret = EFI_CALL(BS->locate_handle_buffer(BY_PROTOCOL,
>>> +					&efi_guid_driver_binding_protocol, NULL,
>>> +					&num, &handles));
>>
>> nits:
>>
>> scripts/checkpatch.pl is complaining:
>> Alignment should match open parenthesis
>>
>> Just will have to move 'BY_PROTOCOL' to the next line to get rid of it.
> 
> No,you can't.
> Ending the line with '(' will cause another error.
> Or dare you prefer such a style?

ret = EFI_CALL(BS->locate_handle_buffer
		(BY_PROTOCOL,
		 &efi_guid_driver_binding_protocol, NULL,
		 &num, &handles));

is what goes without warning. But I would not mind if you left the
parenthesis on the line with the function name.

Regards

Heinrich

> 
> -Takahiro Akashi
> 
> 
>> Otherwise:
>>
>> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>>
>>> +	if (ret != EFI_SUCCESS)
>>> +		return CMD_RET_FAILURE;
>>> +
>>> +	if (!num)
>>> +		return CMD_RET_SUCCESS;
>>> +
>>> +	printf("Driver%.*s Name                 Image Path\n",
>>> +	       EFI_HANDLE_WIDTH - 6, spc);
>>> +	printf("%.*s ==================== ====================\n",
>>> +	       EFI_HANDLE_WIDTH, sep);
>>> +	for (i = 0; i < num; i++) {
>>> +		if (!efi_get_driver_handle_info(handles[i], &driver_name,
>>> +						&image_path_text)) {
>>> +			if (image_path_text)
>>> +				printf("%p %-20ls %ls\n", handles[i],
>>> +				       driver_name, image_path_text);
>>> +			else
>>> +				printf("%p %-20ls <built-in>\n",
>>> +				       handles[i], driver_name);
>>> +			EFI_CALL(BS->free_pool(driver_name));
>>> +			EFI_CALL(BS->free_pool(image_path_text));
>>> +		}
>>> +	}
>>> +
>>> +	EFI_CALL(BS->free_pool(handles));
>>> +
>>> +	return CMD_RET_SUCCESS;
>>> +}
>>> +
>>>  /**
>>>   * do_efi_boot_add() - set UEFI boot option
>>>   *
>>> @@ -586,6 +675,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = {
>>>  	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
>>>  	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,
>>> +			 "", ""),
>>>  };
>>>  
>>>  /**
>>> @@ -646,7 +737,9 @@ static char efidebug_help_text[] =
>>>  	"  - set/show UEFI boot order\n"
>>>  	"\n"
>>>  	"efidebug devices\n"
>>> -	"  - show uefi devices\n";
>>> +	"  - show uefi devices\n"
>>> +	"efidebug drivers\n"
>>> +	"  - show uefi drivers\n";
>>>  #endif
>>>  
>>>  U_BOOT_CMD(
>>>
>>
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command
  2019-02-22  3:01       ` Heinrich Schuchardt
@ 2019-02-22  4:16         ` AKASHI Takahiro
  0 siblings, 0 replies; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-22  4:16 UTC (permalink / raw)
  To: u-boot

On Fri, Feb 22, 2019 at 04:01:52AM +0100, Heinrich Schuchardt wrote:
> On 2/22/19 1:05 AM, AKASHI Takahiro wrote:
> > On Thu, Feb 21, 2019 at 08:32:06PM +0100, Heinrich Schuchardt wrote:
> >> On 2/21/19 7:26 AM, AKASHI Takahiro wrote:
> >>> "drivers" command prints all the uefi drivers on the system.
> >>>
> >>> => efi drivers
> >>> Driver           Name                 Image Path
> >>> ================ ==================== ====================
> >>> 000000007ef003d0 <NULL>               <built-in>
> >>>
> >>> 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 72e0652fc3e4..04fc170867fc 100644
> >>> --- a/cmd/efidebug.c
> >>> +++ b/cmd/efidebug.c
> >>> @@ -89,6 +89,95 @@ static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
> >>>  	return CMD_RET_SUCCESS;
> >>>  }
> >>>  
> >>> +/**
> >>> + * efi_get_driver_handle_info() - get information of UEFI driver
> >>> + *
> >>> + * @handle:		Handle of UEFI device
> >>> + * @driver_name:	Driver name
> >>> + * @image_path:		Pointer to text of device path
> >>> + * Return:		0 on success, -1 on failure
> >>> + *
> >>> + * Currently return no useful information as all UEFI drivers are
> >>> + * built-in..
> >>> + */
> >>> +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;
> >>> +}
> >>> +
> >>> +/**
> >>> + * do_efi_show_drivers() - show UEFI drivers
> >>> + *
> >>> + * @cmdtp:	Command table
> >>> + * @flag:	Command flag
> >>> + * @argc:	Number of arguments
> >>> + * @argv:	Argument array
> >>> + * Return:	CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
> >>> + *
> >>> + * Implement efidebug "drivers" sub-command.
> >>> + * Show all UEFI drivers and their information.
> >>> + */
> >>> +static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag,
> >>> +			       int argc, char * const argv[])
> >>> +{
> >>> +	efi_handle_t *handles;
> >>> +	efi_uintn_t num, i;
> >>> +	u16 *driver_name, *image_path_text;
> >>> +	efi_status_t ret;
> >>> +
> >>> +	ret = EFI_CALL(BS->locate_handle_buffer(BY_PROTOCOL,
> >>> +					&efi_guid_driver_binding_protocol, NULL,
> >>> +					&num, &handles));
> >>
> >> nits:
> >>
> >> scripts/checkpatch.pl is complaining:
> >> Alignment should match open parenthesis
> >>
> >> Just will have to move 'BY_PROTOCOL' to the next line to get rid of it.
> > 
> > No,you can't.
> > Ending the line with '(' will cause another error.
> > Or dare you prefer such a style?
> 
> ret = EFI_CALL(BS->locate_handle_buffer
> 		(BY_PROTOCOL,
> 		 &efi_guid_driver_binding_protocol, NULL,
> 		 &num, &handles));
> is what goes without warning.  

I have never seen such a coding style either in u-boot or kernel.
Even more, "(BY_PROTOCOL" and so on are not arguments of EFI_CALL,
but local_hander_buffer's.

> But I would not mind if you left the
> parenthesis on the line with the function name.

So this is the only option to be left although I don't like it.

-Takahiro Akashi

> 
> Regards
> 
> Heinrich
> 
> > 
> > -Takahiro Akashi
> > 
> > 
> >> Otherwise:
> >>
> >> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> >>
> >>> +	if (ret != EFI_SUCCESS)
> >>> +		return CMD_RET_FAILURE;
> >>> +
> >>> +	if (!num)
> >>> +		return CMD_RET_SUCCESS;
> >>> +
> >>> +	printf("Driver%.*s Name                 Image Path\n",
> >>> +	       EFI_HANDLE_WIDTH - 6, spc);
> >>> +	printf("%.*s ==================== ====================\n",
> >>> +	       EFI_HANDLE_WIDTH, sep);
> >>> +	for (i = 0; i < num; i++) {
> >>> +		if (!efi_get_driver_handle_info(handles[i], &driver_name,
> >>> +						&image_path_text)) {
> >>> +			if (image_path_text)
> >>> +				printf("%p %-20ls %ls\n", handles[i],
> >>> +				       driver_name, image_path_text);
> >>> +			else
> >>> +				printf("%p %-20ls <built-in>\n",
> >>> +				       handles[i], driver_name);
> >>> +			EFI_CALL(BS->free_pool(driver_name));
> >>> +			EFI_CALL(BS->free_pool(image_path_text));
> >>> +		}
> >>> +	}
> >>> +
> >>> +	EFI_CALL(BS->free_pool(handles));
> >>> +
> >>> +	return CMD_RET_SUCCESS;
> >>> +}
> >>> +
> >>>  /**
> >>>   * do_efi_boot_add() - set UEFI boot option
> >>>   *
> >>> @@ -586,6 +675,8 @@ static cmd_tbl_t cmd_efidebug_sub[] = {
> >>>  	U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
> >>>  	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,
> >>> +			 "", ""),
> >>>  };
> >>>  
> >>>  /**
> >>> @@ -646,7 +737,9 @@ static char efidebug_help_text[] =
> >>>  	"  - set/show UEFI boot order\n"
> >>>  	"\n"
> >>>  	"efidebug devices\n"
> >>> -	"  - show uefi devices\n";
> >>> +	"  - show uefi devices\n"
> >>> +	"efidebug drivers\n"
> >>> +	"  - show uefi drivers\n";
> >>>  #endif
> >>>  
> >>>  U_BOOT_CMD(
> >>>
> >>
> > 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables
  2019-02-22  0:21     ` AKASHI Takahiro
  2019-02-22  2:34       ` Heinrich Schuchardt
@ 2019-02-22 10:13       ` Philipp Tomsich
  2019-02-25  0:31         ` AKASHI Takahiro
  1 sibling, 1 reply; 23+ messages in thread
From: Philipp Tomsich @ 2019-02-22 10:13 UTC (permalink / raw)
  To: u-boot

Heinrich,

> On 22.02.2019, at 01:21, AKASHI Takahiro <takahiro.akashi@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.akashi@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.

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 at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables
  2019-02-22 10:13       ` Philipp Tomsich
@ 2019-02-25  0:31         ` AKASHI Takahiro
  0 siblings, 0 replies; 23+ messages in thread
From: AKASHI Takahiro @ 2019-02-25  0:31 UTC (permalink / raw)
  To: u-boot

On Fri, Feb 22, 2019 at 11:13:20AM +0100, Philipp Tomsich wrote:
> Heinrich,
> 
> > On 22.02.2019, at 01:21, AKASHI Takahiro <takahiro.akashi@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.akashi@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 at lists.denx.de
> > https://lists.denx.de/listinfo/u-boot
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2019-02-25  0:31 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-21  6:26 [U-Boot] [PATCH v7 0/7] cmd: add efidebug for efi environment AKASHI Takahiro
2019-02-21  6:26 ` [U-Boot] [PATCH v7 1/7] cmd: env: add "-e" option for handling UEFI variables AKASHI Takahiro
2019-02-21 19:42   ` Heinrich Schuchardt
2019-02-22  0:21     ` AKASHI Takahiro
2019-02-22  2:34       ` Heinrich Schuchardt
2019-02-22 10:13       ` Philipp Tomsich
2019-02-25  0:31         ` AKASHI Takahiro
2019-02-21  6:26 ` [U-Boot] [PATCH v7 2/7] cmd: add efidebug command AKASHI Takahiro
2019-02-21 19:24   ` Heinrich Schuchardt
2019-02-22  1:04     ` AKASHI Takahiro
2019-02-22  2:43       ` Heinrich Schuchardt
2019-02-21  6:26 ` [U-Boot] [PATCH v7 3/7] cmd: efidebug: add devices command AKASHI Takahiro
2019-02-21 19:25   ` Heinrich Schuchardt
2019-02-21  6:26 ` [U-Boot] [PATCH v7 4/7] cmd: efidebug: add drivers command AKASHI Takahiro
2019-02-21 19:32   ` Heinrich Schuchardt
2019-02-22  0:05     ` AKASHI Takahiro
2019-02-22  3:01       ` Heinrich Schuchardt
2019-02-22  4:16         ` AKASHI Takahiro
2019-02-21  6:26 ` [U-Boot] [PATCH v7 5/7] cmd: efidebug: add dh command AKASHI Takahiro
2019-02-21 19:33   ` Heinrich Schuchardt
2019-02-21  6:26 ` [U-Boot] [PATCH v7 6/7] cmd: efidebug: add images command AKASHI Takahiro
2019-02-21  6:26 ` [U-Boot] [PATCH v7 7/7] cmd: efidebug: add memmap command AKASHI Takahiro
2019-02-21 19:35   ` Heinrich Schuchardt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.