Skip to contentSkip to conversation

efi: make efi and bootmgr more usable

PATCH New AKASHI Takahiro 2 participants 39 messages Nov 5, 2018 – Jan 7, 2019

lore
Share & tools
lore
#0 lore raw

v2 cover efi: make efi and bootmgr more usable

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:
=> efishell boot add 1 SHELL mmc 0:1 /Shell.efi "" => efishell boot add 2 HELLO mmc 0:1 /hello.efi "" => efishell boot dump
Boot0001:

	attributes: A-- (0x00000001)
	label: SHELL
	file_path: /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/HD(1,MBR,0x086246ba,0x800,0x40000)/\\Shell.efi
	data: 
Boot0002:
	attributes: A-- (0x00000001)
	label: HELLO
	file_path: /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/HD(1,MBR,0x086246ba,0x800,0x40000)/\\hello.efi
	data: 

=> efishell boot order 1 2
=> efishell boot order
1: Boot0001: SHELL
2: Boot0002: HELLO

=> run -e Boot0002 (or bootefi bootmgr - 2) ; '-' means no dtb specified
WARNING: booting without device tree
Booting: HELLO
## Starting EFI application at 000000007db8b040 ... Hello, world!
## Application terminated, r = 0

=> env set -e PlatformLang en ; important!
(or you can do "efishell setvar PlatformLang en")
=> env print -e
Boot0001: {boot,run}(blob)

00000000:  01 00 00 00 68 00 53 00  ....h.S.
00000010:  48 00 45 00 4c 00 4c 00  H.E.L.L.
00000020:  00 00 01 04 14 00 b9 73  .......s
00000030:  1d e6 84 a3 cc 4a ae ab  .....J..
00000040:  82 e8 28 f3 62 8b 03 1a  ..(.b...
00000050:  05 00 00 03 1a 05 00 00  ........
00000060:  04 01 2a 00 01 00 00 00  ..*.....
00000070:  00 08 00 00 00 00 00 00  ........
00000080:  00 00 04 00 00 00 00 00  ........
00000090:  ba 46 62 08 00 00 00 00  .Fb.....
000000a0:  00 00 00 00 00 00 00 00  ........
000000b0:  01 01 04 04 1c 00 5c 00  ......\.
000000c0:  5c 00 53 00 68 00 65 00  \.S.h.e.
000000d0:  6c 00 6c 00 2e 00 65 00  l.l...e.
000000e0:  66 00 69 00 00 00 7f ff  f.i....
000000f0:  04 00 00                 ...
Boot0002: {boot,run}(blob)
00000000:  01 00 00 00 68 00 48 00  ....h.H.
00000010:  45 00 4c 00 4c 00 4f 00  E.L.L.O.
00000020:  00 00 01 04 14 00 b9 73  .......s
00000030:  1d e6 84 a3 cc 4a ae ab  .....J..
00000040:  82 e8 28 f3 62 8b 03 1a  ..(.b...
00000050:  05 00 00 03 1a 05 00 00  ........
00000060:  04 01 2a 00 01 00 00 00  ..*.....
00000070:  00 08 00 00 00 00 00 00  ........
00000080:  00 00 04 00 00 00 00 00  ........
00000090:  ba 46 62 08 00 00 00 00  .Fb.....
000000a0:  00 00 00 00 00 00 00 00  ........
000000b0:  01 01 04 04 1c 00 5c 00  ......\.
000000c0:  5c 00 68 00 65 00 6c 00  \.h.e.l.
000000d0:  6c 00 6f 00 2e 00 65 00  l.o...e.
000000e0:  66 00 69 00 00 00 7f ff  f.i....
000000f0:  04 00 00                 ...

BootOrder: {boot,run}(blob)
00000000: 01 00 02 00 ....
OsIndicationsSupported: {ro,boot}(blob) 00000000: 00 00 00 00 00 00 00 00 ........
PlatformLang: {boot,run}(blob)
00000000: 65 6e en

=> run -e Boot0001 or bootefi bootmgr

(shell ...)

"setvar" command now supports efi shell-like syntax:

=> env set -e foo =S\"akashi\" =0x012345 =Habcdef => env print -e foo
foo: {boot,run}(blob)

00000000:  61 6b 61 73 68 69 45 23  akashiE#
00000010:  01 00 ab cd ef           .....

Other useful sub commands are:
=> efishell devices ; print uefi devices
=> efishell drivers ; print uefi drivers
=> efishell images ; print loaded images
=> efishell dh ; print uefi handles
=> efishell memmap ; dump uefi memory map

# I admit there is some room to improve the output from those commands.

Enjoy!
-Takahiro Akashi

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 (14):
efi_loader: allow device == NULL in efi_dp_from_name()
efi_loader: bootmgr: add load option helper functions
efi_loader: bootmgr: allow for running a given load option
cmd: add efishell command
cmd: efishell: add devices command
cmd: efishell: add drivers command
cmd: efishell: add images command
cmd: efishell: add memmap command
cmd: efishell: add dh command
cmd: bootefi: carve out fdt parameter handling
cmd: bootefi: run an EFI application of a specific load option
cmd: run: add "-e" option to run an EFI application
cmd: efishell: export uefi variable helper functions
cmd: env: add "-e" option for handling UEFI variables

 cmd/Makefile                     |   2 +-
 cmd/bootefi.c                    |  71 ++-
 cmd/efishell.c                   | 970 +++++++++++++++++++++++++++++++
 cmd/efishell.h                   |   6 +
 cmd/nvedit.c                     |  63 +-
 common/cli.c                     |  30 +
 include/command.h                |   5 +
 include/efi_loader.h             |  26 +-
 lib/efi_loader/efi_bootmgr.c     | 101 ++--
 lib/efi_loader/efi_device_path.c |  11 +-
 10 files changed, 1223 insertions(+), 62 deletions(-)
 create mode 100644 cmd/efishell.c
 create mode 100644 cmd/efishell.h
Signature · 1 line
2.19.0
#1 lore raw

PATCH v2 1/14 efi_loader: allow device == NULL in efi_dp_from_name()

This is a preparatory patch for use in efi_serialize_load_option() as a load option's file_path should have both a device path and a file path.

---
 lib/efi_loader/efi_device_path.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
lib/efi_loader/efi_device_path.c +7 -4
index cdf7c7be8c5c..d94982314a3e 100644
@@ -955,7 +955,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 	char filename[32] = { 0 }; /* dp->str is u16[32] long */
 	char *s;
 
-	if (!device || (path && !file))
+	if (path && !file)
 		return EFI_INVALID_PARAMETER;
 
 	is_net = !strcmp(dev, "Net");
@@ -965,10 +965,12 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 		if (part < 0)
 			return EFI_INVALID_PARAMETER;
 
-		*device = efi_dp_from_part(desc, part);
+		if (device)
+			*device = efi_dp_from_part(desc, part);
 	} else {
 #ifdef CONFIG_NET
-		*device = efi_dp_from_eth();
+		if (device)
+			*device = efi_dp_from_eth();
 #endif
 	}
 
@@ -985,7 +987,8 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 	s = filename;
 	while ((s = strchr(s, '/')))
 		*s++ = '\\';
-	*file = efi_dp_from_file(NULL, 0, filename);
+	*file = efi_dp_from_file(((!is_net && device) ? desc : NULL),
+				 part, filename);
 
 	return EFI_SUCCESS;
 }
Signature · 1 line
2.19.0
#2 lore raw

PATCH v2 2/14 efi_loader: bootmgr: add load option helper functions

In reply to AKASHI Takahiro

In this patch, helper functions for an load option variable (BootXXXX) are added:
* efi_deserialize_load_option(): parse a string into load_option data (renamed from parse_load_option and exported)
* efi_serialize_load_option(): convert load_option data into a string

Those functions will be used to implement efishell command.

---
 include/efi_loader.h         | 23 +++++++++
 lib/efi_loader/efi_bootmgr.c | 93 +++++++++++++++++++++++-------------
 2 files changed, 83 insertions(+), 33 deletions(-)
include/efi_loader.h +23 -0
index 5c2485bd03e4..d83de906fbce 100644
@@ -517,6 +517,29 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
 				     u32 attributes, efi_uintn_t data_size,
 				     void *data);
 
+/*
+ * See section 3.1.3 in the v2.7 UEFI spec for more details on
+ * the layout of EFI_LOAD_OPTION.  In short it is:
+ *
+ *    typedef struct _EFI_LOAD_OPTION {
+ *        UINT32 Attributes;
+ *        UINT16 FilePathListLength;
+ *        // CHAR16 Description[];   <-- variable length, NULL terminated
+ *        // EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+ *						 <-- FilePathListLength bytes
+ *        // UINT8 OptionalData[];
+ *    } EFI_LOAD_OPTION;
+ */
+struct efi_load_option {
+	u32 attributes;
+	u16 file_path_length;
+	u16 *label;
+	struct efi_device_path *file_path;
+	u8 *optional_data;
+};
+
+void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
+unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
 void *efi_bootmgr_load(struct efi_device_path **device_path,
 		       struct efi_device_path **file_path);
 
lib/efi_loader/efi_bootmgr.c +60 -33

122 lines not on this page · raw message

Signature · 1 line
2.19.0
#3 lore raw

PATCH v2 3/14 efi_loader: bootmgr: allow for running a given load option

In reply to AKASHI Takahiro

With an extra argument, efi_bootmgr_load() can now load an efi binary based on a "BootXXXX" variable specified.

---
 include/efi_loader.h         | 3 ++-
 lib/efi_loader/efi_bootmgr.c | 8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)
include/efi_loader.h +2 -1
index d83de906fbce..ce0f420b5004 100644
@@ -540,7 +540,8 @@ struct efi_load_option {
 
 void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path);
 
 #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
lib/efi_loader/efi_bootmgr.c +7 -1
index a095df3f540b..74eb832a8c92 100644
@@ -170,7 +170,8 @@ error:
  * available load-options, finding and returning the first one that can
  * be loaded successfully.
  */
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path)
 {
 	uint16_t *bootorder;
@@ -183,6 +184,11 @@ void *efi_bootmgr_load(struct efi_device_path **device_path,
 	bs = systab.boottime;
 	rs = systab.runtime;
 
+	if (boot_id != -1) {
+		image = try_load_entry(boot_id, device_path, file_path);
+		goto error;
+	}
+
 	bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
 	if (!bootorder)
 		goto error;
Signature · 1 line
2.19.0
#4 lore raw

PATCH v2 3/14 efi_loader: bootmgr: allow for running a given load option

Quoted 4 lines · AKASHI Takahiro

With an extra argument, efi_bootmgr_load() can now load an efi binary based on a "BootXXXX" variable specified.

I don't see you changing the caller, so this hunk won't compile on its own?

Please make sure that every single step in your patch set compiles.

Quoted 34 lines
---
 include/efi_loader.h         | 3 ++-
 lib/efi_loader/efi_bootmgr.c | 8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)
include/efi_loader.h +2 -1
index d83de906fbce..ce0f420b5004 100644
@@ -540,7 +540,8 @@ struct efi_load_option {
 
 void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path);
 
 #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
lib/efi_loader/efi_bootmgr.c +2 -1
index a095df3f540b..74eb832a8c92 100644
@@ -170,7 +170,8 @@ error:
  * available load-options, finding and returning the first one that can
  * be loaded successfully.
  */
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path)
 {
 	uint16_t *bootorder;

lib/efi_loader/efi_bootmgr.c void *efi_bootmgr_load(struct efi_device_path **device_path, · line 189

Quoted 6 lines
lib/efi_loader/efi_bootmgr.c +3 -0
@@ -183,6 +184,11 @@ void *efi_bootmgr_load(struct efi_device_path **device_path,
 	bs = systab.boottime;
 	rs = systab.runtime;
 
+	if (boot_id != -1) {
+		image = try_load_entry(boot_id, device_path, file_path);
+		goto error;

I think at this point it might be better to split the function, no? You're not actually reusing any code from efi_bootmgr_load with the 2 instantiation types (explicit boot id, loop through boot order).

Alex

Quoted 6 lines
lib/efi_loader/efi_bootmgr.c +2 -0
+	}
+
 	bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
 	if (!bootorder)
 		goto error;
#5 lore raw

PATCH v2 3/14 efi_loader: bootmgr: allow for running a given load option

Quoted 9 lines · Alexander Graf
Quoted 4 lines · AKASHI Takahiro

With an extra argument, efi_bootmgr_load() can now load an efi binary based on a "BootXXXX" variable specified.

I don't see you changing the caller, so this hunk won't compile on its own?

You're correct.

Quoted 1 line

Please make sure that every single step in your patch set compiles.

I will try to double-check in the future.

Quoted 37 lines
Quoted 37 lines
---
 include/efi_loader.h         | 3 ++-
 lib/efi_loader/efi_bootmgr.c | 8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)
include/efi_loader.h +2 -1
index d83de906fbce..ce0f420b5004 100644
@@ -540,7 +540,8 @@ struct efi_load_option {
 
 void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path);
 
 #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
lib/efi_loader/efi_bootmgr.c +2 -1
index a095df3f540b..74eb832a8c92 100644
@@ -170,7 +170,8 @@ error:
  * available load-options, finding and returning the first one that can
  * be loaded successfully.
  */
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path)
 {
 	uint16_t *bootorder;
@@ -183,6 +184,11 @@ void *efi_bootmgr_load(struct efi_device_path **device_path,
 	bs = systab.boottime;
 	rs = systab.runtime;
 
Quoted 5 lines

lib/efi_loader/efi_bootmgr.c void *efi_bootmgr_load(struct efi_device_path **device_path, · line 189

Quoted 3 lines
lib/efi_loader/efi_bootmgr.c +3 -0
+	if (boot_id != -1) {
+		image = try_load_entry(boot_id, device_path, file_path);
+		goto error;

I think at this point it might be better to split the function, no?

It's one way to fix, but I want simply to fix the issue by modifying the caller, do_bootefi_bootmgr_exec() because

Quoted 2 lines

You're not actually reusing any code from efi_bootmgr_load with the 2 instantiation types (explicit boot id, loop through boot order).

I will add "BootNext" support to efi_bootmgr_load() so that it will be a single point of loading. See my relevant patch:
https://lists.denx.de/pipermail/u-boot/2018-November/349281.html

Thanks,
-Takahiro Akashi

Quoted 9 lines

Alex

Quoted 6 lines
lib/efi_loader/efi_bootmgr.c +2 -0
+	}
+
 	bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
 	if (!bootorder)
 		goto error;
#6 lore raw

PATCH v2 3/14 efi_loader: bootmgr: allow for running a given load option

Quoted 63 lines · AKASHI Takahiro
Quoted 9 lines · Alexander Graf
Quoted 4 lines · AKASHI Takahiro

With an extra argument, efi_bootmgr_load() can now load an efi binary based on a "BootXXXX" variable specified.

I don't see you changing the caller, so this hunk won't compile on its own?

You're correct.

Quoted 1 line

Please make sure that every single step in your patch set compiles.

I will try to double-check in the future.

Quoted 37 lines
Quoted 37 lines
---
 include/efi_loader.h         | 3 ++-
 lib/efi_loader/efi_bootmgr.c | 8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)
include/efi_loader.h +2 -1
index d83de906fbce..ce0f420b5004 100644
@@ -540,7 +540,8 @@ struct efi_load_option {
 
 void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path);
 
 #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
lib/efi_loader/efi_bootmgr.c +2 -1
index a095df3f540b..74eb832a8c92 100644
@@ -170,7 +170,8 @@ error:
  * available load-options, finding and returning the first one that can
  * be loaded successfully.
  */
-void *efi_bootmgr_load(struct efi_device_path **device_path,
+void *efi_bootmgr_load(int boot_id,
+		       struct efi_device_path **device_path,
 		       struct efi_device_path **file_path)
 {
 	uint16_t *bootorder;
@@ -183,6 +184,11 @@ void *efi_bootmgr_load(struct efi_device_path **device_path,
 	bs = systab.boottime;
 	rs = systab.runtime;
 
Quoted 5 lines

lib/efi_loader/efi_bootmgr.c void *efi_bootmgr_load(struct efi_device_path **device_path, · line 189

Quoted 3 lines
lib/efi_loader/efi_bootmgr.c +3 -0
+	if (boot_id != -1) {
+		image = try_load_entry(boot_id, device_path, file_path);
+		goto error;

I think at this point it might be better to split the function, no?

It's one way to fix, but I want simply to fix the issue by modifying the caller, do_bootefi_bootmgr_exec() because

Quoted 6 lines
Quoted 2 lines

You're not actually reusing any code from efi_bootmgr_load with the 2 instantiation types (explicit boot id, loop through boot order).

I will add "BootNext" support to efi_bootmgr_load() so that it will be a single point of loading. See my relevant patch:
https://lists.denx.de/pipermail/u-boot/2018-November/349281.html

I don't fully understand. I would expect BootNext to only take effect when *not* booting an explicit ID? So that would fit quite nicely into a function based split.

Alex

#7 lore raw

PATCH v2 4/14 cmd: add efishell command

In reply to AKASHI Takahiro

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, efishell, helps address these issues and give us more friendly interfaces:
* efishell boot add: add BootXXXX variable
* efishell boot rm: remove BootXXXX variable
* efishell boot dump: display all BootXXXX variables
* efishell boot order: set/display a boot order (BootOrder)
* efishell setvar: set an UEFI variable (with limited functionality)
* efishell dumpvar: display all UEFI variables

As the name suggests, this command basically provides a subset fo UEFI shell commands with simplified functionality.

---
 cmd/Makefile   |   2 +-
 cmd/efishell.c | 673 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd/efishell.h |   5 +
 3 files changed, 679 insertions(+), 1 deletion(-)
 create mode 100644 cmd/efishell.c
 create mode 100644 cmd/efishell.h
cmd/Makefile +1 -1
index d9cdaf6064b8..bd531d505a8e 100644
@@ -24,7 +24,7 @@ obj-$(CONFIG_CMD_BINOP) += binop.o
 obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_CMD_BMP) += bmp.o
 obj-$(CONFIG_CMD_BOOTCOUNT) += bootcount.o
-obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
+obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o efishell.o
 obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
 obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o
 obj-$(CONFIG_CMD_BOOTZ) += bootz.o
cmd/efishell.c new file +673 -0

673 lines not on this page · raw message

cmd/efishell.h new file +5 -0
new file mode 100644
index 000000000000..6f70b402b26b
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <efi.h>
+
+efi_status_t efi_init_obj_list(void);
Signature · 1 line
2.19.0
#8 lore raw

PATCH v2 4/14 cmd: add efishell command

Quoted 31 lines · AKASHI Takahiro

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, efishell, helps address these issues and give us more friendly interfaces:
* efishell boot add: add BootXXXX variable
* efishell boot rm: remove BootXXXX variable
* efishell boot dump: display all BootXXXX variables
* efishell boot order: set/display a boot order (BootOrder)
* efishell setvar: set an UEFI variable (with limited functionality)
* efishell dumpvar: display all UEFI variables

As the name suggests, this command basically provides a subset fo UEFI shell commands with simplified functionality.

---
 cmd/Makefile   |   2 +-
 cmd/efishell.c | 673 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd/efishell.h |   5 +
 3 files changed, 679 insertions(+), 1 deletion(-)
 create mode 100644 cmd/efishell.c
 create mode 100644 cmd/efishell.h
cmd/Makefile +0 -0
index d9cdaf6064b8..bd531d505a8e 100644

cmd/Makefile obj-$(CONFIG_CMD_BINOP) += binop.o · line 27

Quoted 5 lines
cmd/Makefile +1 -1
@@ -24,7 +24,7 @@ obj-$(CONFIG_CMD_BINOP) += binop.o
 obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_CMD_BMP) += bmp.o
 obj-$(CONFIG_CMD_BOOTCOUNT) += bootcount.o
-obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
+obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o efishell.o

Please create a separate command line option for efishell and make it disabled by default.

I think it's a really really useful debugging aid, but in a normal environment people should only need to run efi binaries (plus bootmgr) and modify efi variables, no?

Quoted 21 lines
cmd/Makefile +0 -0
 obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
 obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o
 obj-$(CONFIG_CMD_BOOTZ) += bootz.o
cmd/efishell.c new file +12 -0
new file mode 100644
index 000000000000..abc8216c7bd6
@@ -0,0 +1,673 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  EFI 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>

cmd/efishell.c line 22

Quoted 10 lines
cmd/efishell.c new file +10 -0
+#include <errno.h>
+#include <exports.h>
+#include <hexdump.h>
+#include <malloc.h>
+#include <search.h>
+#include <linux/ctype.h>
+#include <asm/global_data.h>
+#include "efishell.h"
+
+DECLARE_GLOBAL_DATA_PTR;

Where in this file do you need gd?

Quoted 303 lines
cmd/efishell.c new file +303 -0
+
+static void dump_var_data(char *data, unsigned long len)
+{
+	char *start, *end, *p;
+	unsigned long pos, count;
+	char hex[3], line[9];
+	int i;
+
+	end = data + len;
+	for (start = data, pos = 0; start < end; start += count, pos += count) {
+		count = end - start;
+		if (count > 16)
+			count = 16;
+
+		/* count should be multiple of two */
+		printf("%08lx: ", pos);
+
+		/* in hex format */
+		p = start;
+		for (i = 0; i < count / 2; p += 2, i++)
+			printf(" %c%c", *p, *(p + 1));
+		for (; i < 8; i++)
+			printf("   ");
+
+		/* in character format */
+		p = start;
+		hex[2] = '\0';
+		for (i = 0; i < count / 2; i++) {
+			hex[0] = *p++;
+			hex[1] = *p++;
+			line[i] = simple_strtoul(hex, 0, 16);
+			if (line[i] < 0x20 || line[i] > 0x7f)
+				line[i] = '.';
+		}
+		line[i] = '\0';
+		printf("  %s\n", line);
+	}
+}
+
+/*
+ * From efi_variable.c,
+ *
+ * Mapping between EFI variables and u-boot variables:
+ *
+ *   efi_$guid_$varname = {attributes}(type)value
+ */
+static int do_efi_dump_var(int argc, char * const argv[])
+{
+	char regex[256];
+	char * const regexlist[] = {regex};
+	char *res = NULL, *start, *end;
+	int len;
+
+	if (argc > 2)
+		return CMD_RET_USAGE;
+
+	if (argc == 2)
+		snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_%s", argv[1]);
+	else
+		snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
+	debug("%s:%d grep uefi var %s\n", __func__, __LINE__, regex);
+
+	len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
+			&res, 0, 1, regexlist);
+
+	if (len < 0)
+		return CMD_RET_FAILURE;
+
+	if (len > 0) {
+		end = res;
+		while (true) {
+			/* variable name */
+			start = strchr(end, '_');
+			if (!start)
+				break;
+			start = strchr(++start, '_');
+			if (!start)
+				break;
+			end = strchr(++start, '=');
+			if (!end)
+				break;
+			printf("%.*s:", (int)(end - start), start);
+			end++;
+
+			/* value */
+			start = end;
+			end = strstr(start, "(blob)");
+			if (!end) {
+				putc('\n');
+				break;
+			}
+			end += 6;
+			printf(" %.*s\n", (int)(end - start), start);
+
+			start = end;
+			end = strchr(start, '\n');
+			if (!end)
+				break;
+			dump_var_data(start,  end - start);
+		}
+		free(res);
+
+		if (len < 2 && argc == 2)
+			printf("%s: not found\n", argv[1]);
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int append_value(char **bufp, unsigned long *sizep, char *data)
+{
+	char *tmp_buf = NULL, *new_buf = NULL, *value;
+	unsigned long len = 0;
+
+	if (!strncmp(data, "=0x", 2)) { /* hexadecimal number */
+		union {
+			u8 u8;
+			u16 u16;
+			u32 u32;
+			u64 u64;
+		} tmp_data;
+		unsigned long hex_value;
+		void *hex_ptr;
+
+		data += 3;
+		len = strlen(data);
+		if ((len & 0x1)) /* not multiple of two */
+			return -1;
+
+		len /= 2;
+		if (len > 8)
+			return -1;
+		else if (len > 4)
+			len = 8;
+		else if (len > 2)
+			len = 4;
+
+		/* convert hex hexadecimal number */
+		if (strict_strtoul(data, 16, &hex_value) < 0)
+			return -1;
+
+		tmp_buf = malloc(len);
+		if (!tmp_buf)
+			return -1;
+
+		if (len == 1) {
+			tmp_data.u8 = hex_value;
+			hex_ptr = &tmp_data.u8;
+		} else if (len == 2) {
+			tmp_data.u16 = hex_value;
+			hex_ptr = &tmp_data.u16;
+		} else if (len == 4) {
+			tmp_data.u32 = hex_value;
+			hex_ptr = &tmp_data.u32;
+		} else {
+			tmp_data.u64 = hex_value;
+			hex_ptr = &tmp_data.u64;
+		}
+		memcpy(tmp_buf, hex_ptr, len);
+		value = tmp_buf;
+
+	} else if (!strncmp(data, "=H", 2)) { /* hexadecimal-byte array */
+		data += 2;
+		len = strlen(data);
+		if (len & 0x1) /* not multiple of two */
+			return -1;
+
+		len /= 2;
+		tmp_buf = malloc(len);
+		if (!tmp_buf)
+			return -1;
+
+		if (hex2bin((u8 *)tmp_buf, data, len) < 0)
+			return -1;
+
+		value = tmp_buf;
+	} else { /* string */
+		if (!strncmp(data, "=\"", 2) || !strncmp(data, "=S\"", 3)) {
+			if (data[1] == '"')
+				data += 2;
+			else
+				data += 3;
+			value = data;
+			len = strlen(data) - 1;
+			if (data[len] != '"')
+				return -1;
+		} else {
+			value = data;
+			len = strlen(data);
+		}
+	}
+
+	new_buf = realloc(*bufp, *sizep + len);
+	if (!new_buf)
+		goto out;
+
+	memcpy(new_buf + *sizep, value, len);
+	*bufp = new_buf;
+	*sizep += len;
+
+out:
+	free(tmp_buf);
+
+	return 0;
+}
+
+static int do_efi_set_var(int argc, char * const argv[])
+{
+	char *var_name, *value = NULL;
+	unsigned long size = 0;
+	u16 *var_name16, *p;
+	efi_guid_t guid;
+	efi_status_t ret;
+
+	if (argc == 1)
+		return CMD_RET_SUCCESS;
+
+	var_name = argv[1];
+	if (argc == 2) {
+		/* remove */
+		value = NULL;
+		size = 0;
+	} else { /* set */
+		argc -= 2;
+		argv += 2;
+
+		for ( ; argc > 0; argc--, argv++)
+			if (append_value(&value, &size, argv[0]) < 0) {
+				ret = CMD_RET_FAILURE;
+				goto out;
+			}
+	}
+
+	var_name16 = malloc((strlen(var_name) + 1) * 2);
+	p = var_name16;
+	utf8_utf16_strncpy(&p, var_name, strlen(var_name) + 1);
+
+	guid = efi_global_variable_guid;
+	ret = efi_set_variable(var_name16, &guid,
+			       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			       EFI_VARIABLE_RUNTIME_ACCESS, size, value);
+	ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
+out:
+	return ret;
+}
+
+static int do_efi_boot_add(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;
+	unsigned long size;
+	int ret;
+
+	if (argc < 6 || argc > 7)
+		return CMD_RET_USAGE;
+
+	id = (int)simple_strtoul(argv[1], &endp, 0);
+	if (*endp != '\0' || id > 0xffff)
+		return CMD_RET_FAILURE;
+
+	sprintf(var_name, "Boot%04X", id);
+	p = var_name16;
+	utf8_utf16_strncpy(&p, var_name, 9);
+
+	guid = efi_global_variable_guid;
+
+	/* attributes */
+	lo.attributes = 0x1; /* always ACTIVE */
+
+	/* label */
+	label_len = strlen(argv[2]);
+	label_len16 = utf8_utf16_strnlen(argv[2], label_len);
+	label = malloc((label_len16 + 1) * sizeof(u16));
+	if (!label)
+		return CMD_RET_FAILURE;
+	lo.label = label; /* label will be changed below */
+	utf8_utf16_strncpy(&label, argv[2], label_len);
+
+	/* file path */
+	ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
+			       &file_path);
+	if (ret != EFI_SUCCESS) {
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}
+	lo.file_path = file_path;
+	lo.file_path_length = efi_dp_size(file_path)
+				+ sizeof(struct efi_device_path); /* for END */
+
+	/* optional data */
+	lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]);
+
+	size = efi_serialize_load_option(&lo, (u8 **)&data);
+	if (!size) {
+		ret = CMD_RET_FAILURE;

cmd/efishell.c line 335

Quoted 10 lines
cmd/efishell.c new file +10 -0
+		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);
+#if 0 /* FIXME */

Eh, what? :)

Quoted 92 lines
cmd/efishell.c new file +92 -0
+	free(device_path);
+	free(file_path);
+#endif
+	free(lo.label);
+	return ret;
+}
+
+static int do_efi_boot_rm(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, 0);
+		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,
+				       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				       EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
+		if (ret) {
+			printf("cannot remove Boot%04X", id);
+			return CMD_RET_FAILURE;
+		}
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static void show_efi_boot_opt_data(int id, void *data)
+{
+	struct efi_load_option lo;
+	char *label, *p;
+	size_t label_len16, label_len;
+	u16 *dp_str;
+
+	efi_deserialize_load_option(&lo, data);
+
+	label_len16 = u16_strlen(lo.label);
+	label_len = utf16_utf8_strnlen(lo.label, label_len16);
+	label = malloc(label_len + 1);
+	if (!label)
+		return;
+	p = label;
+	utf16_utf8_strncpy(&p, lo.label, label_len16);
+
+	printf("Boot%04X:\n", id);
+	printf("\tattributes: %c%c%c (0x%08x)\n",
+	       /* ACTIVE */
+	       lo.attributes & 0x1 ? 'A' : '-',
+	       /* FORCE RECONNECT */
+	       lo.attributes & 0x2 ? 'R' : '-',
+	       /* HIDDEN */
+	       lo.attributes & 0x8 ? 'H' : '-',
+	       lo.attributes);
+	printf("\tlabel: %s\n", label);
+
+	dp_str = efi_dp_str(lo.file_path);
+	printf("\tfile_path: %ls\n", dp_str);
+	efi_free_pool(dp_str);
+
+	printf("\tdata: %s\n", lo.optional_data);
+
+	free(label);
+}
+
+static void show_efi_boot_opt(int id)
+{
+	char var_name[9];
+	u16 var_name16[9], *p;
+	efi_guid_t guid;
+	void *data = NULL;
+	unsigned long 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;

cmd/efishell.c line 437

Quoted 10 lines
cmd/efishell.c new file +10 -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);
+		free(data);
+	} else if (ret == EFI_NOT_FOUND) {
+		printf("Boot%04X: not found\n", id);

Missing free?

Quoted 54 lines
cmd/efishell.c new file +54 -0
+	}
+}
+
+static int do_efi_boot_dump(int argc, char * const argv[])
+{
+	char regex[256];
+	char * const regexlist[] = {regex};
+	char *variables = NULL, *boot, *value;
+	int len;
+	int id;
+
+	if (argc > 1)
+		return CMD_RET_USAGE;
+
+	snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+");
+
+	len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
+			&variables, 0, 1, regexlist);
+
+	if (!len)
+		return CMD_RET_SUCCESS;
+
+	if (len < 0)
+		return CMD_RET_FAILURE;
+
+	boot = variables;
+	while (*boot) {
+		value = strstr(boot, "Boot") + 4;
+		id = (int)simple_strtoul(value, NULL, 16);
+		show_efi_boot_opt(id);
+		boot = strchr(boot, '\n');
+		if (!*boot)
+			break;
+		boot++;
+	}
+	free(variables);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int show_efi_boot_order(void)
+{
+	efi_guid_t guid;
+	u16 *bootorder = NULL;
+	unsigned long 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 = CMD_RET_SUCCESS;
+

cmd/efishell.c line 501

Quoted 10 lines
cmd/efishell.c new file +10 -0
+	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_SUCCESS) {
+		printf("BootOrder not defined\n");

Missing free(bootorder)

Quoted 17 lines
cmd/efishell.c new file +17 -0
+		return CMD_RET_SUCCESS;
+	}
+
+	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;
+		}
+

cmd/efishell.c line 528

Quoted 10 lines
cmd/efishell.c new file +10 -0
+		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;

Probably better to free(data) at out:, no?

Quoted 151 lines
cmd/efishell.c new file +145 -0
+		}
+
+		efi_deserialize_load_option(&lo, data);
+
+		label_len16 = u16_strlen(lo.label);
+		label_len = utf16_utf8_strnlen(lo.label, label_len16);
+		label = malloc(label_len + 1);
+		if (!label) {
+			free(data);
+			ret = CMD_RET_FAILURE;
+			goto out;
+		}
+		p = label;
+		utf16_utf8_strncpy(&p, lo.label, label_len16);
+		printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
+		free(label);
+
+		free(data);
+	}
+out:
+	free(bootorder);
+
+	return ret;
+}
+
+static int do_efi_boot_order(int argc, char * const argv[])
+{
+	u16 *bootorder = NULL;
+	unsigned long 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, 0);
+		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 int do_efi_boot_opt(int argc, char * const argv[])
+{
+	char *sub_command;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	argc--; argv++;
+	sub_command = argv[0];
+
+	if (!strcmp(sub_command, "add"))
+		return do_efi_boot_add(argc, argv);
+	else if (!strcmp(sub_command, "rm"))
+		return do_efi_boot_rm(argc, argv);
+	else if (!strcmp(sub_command, "dump"))
+		return do_efi_boot_dump(argc, argv);
+	else if (!strcmp(sub_command, "order"))
+		return do_efi_boot_order(argc, argv);
+	else
+		return CMD_RET_USAGE;
+}
+
+/* Interpreter command to configure EFI environment */
+static int do_efishell(cmd_tbl_t *cmdtp, int flag,
+		       int argc, char * const argv[])
+{
+	char *command;
+	efi_status_t r;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	argc--; argv++;
+	command = argv[0];
+
+	/* Initialize EFI drivers */
+	r = efi_init_obj_list();
+	if (r != EFI_SUCCESS) {
+		printf("Error: Cannot set up EFI drivers, r = %lu\n",
+		       r & ~EFI_ERROR_MASK);
+		return CMD_RET_FAILURE;
+	}
+
+	if (!strcmp(command, "boot"))
+		return do_efi_boot_opt(argc, argv);
+	else if (!strcmp(command, "dumpvar") || !strcmp(command, "dmpstore"))
+		return do_efi_dump_var(argc, argv);
+	else if (!strcmp(command, "setvar"))
+		return do_efi_set_var(argc, argv);
+	else
+		return CMD_RET_USAGE;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char efishell_help_text[] =
+	"  - EFI Shell-like interface to configure EFI environment\n"
+	"\n"
+	"efishell boot add <bootid> <label> <interface> <device>[:<part>] <file path> <option>\n"
+	"  - set uefi's BOOT variable\n"
+	"efishell boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
+	"  - set/display uefi boot order\n"
+	"efishell boot dump\n"
+	"  - display all uefi's BOOT variables\n"
+	"efishell boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
+	"  - set/display uefi boot order\n"
+	"\n"
+	"efishell dumpvar [<name>]\n"
+	"  - get uefi variable's value\n"
+	"efishell setvar <name> [<value>]\n"
+	"  - set/delete uefi variable's value\n"
+	"    <value> may be \"=\"...\"\", \"=0x...\" (set) or \"=\" (delete)\n";
+#endif
+
+U_BOOT_CMD(
+	efishell, 10, 0, do_efishell,
+	"Configure EFI environment",
+	efishell_help_text
+);
cmd/efishell.h new file +0 -0
new file mode 100644
index 000000000000..6f70b402b26b

cmd/efishell.h line 5

Quoted 5 lines
cmd/efishell.h new file +5 -0
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <efi.h>
+
+efi_status_t efi_init_obj_list(void);

Why isn't this in efi_loader.h? That's the subsystem that exports it, no?

Alex

#9 lore raw

PATCH v2 4/14 cmd: add efishell command

Quoted 29 lines · Alexander Graf
Quoted 26 lines · AKASHI Takahiro

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, efishell, helps address these issues and give us more friendly interfaces:
* efishell boot add: add BootXXXX variable
* efishell boot rm: remove BootXXXX variable
* efishell boot dump: display all BootXXXX variables
* efishell boot order: set/display a boot order (BootOrder)
* efishell setvar: set an UEFI variable (with limited functionality)
* efishell dumpvar: display all UEFI variables

As the name suggests, this command basically provides a subset fo UEFI shell commands with simplified functionality.

---
 cmd/Makefile   |   2 +-
 cmd/efishell.c | 673 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd/efishell.h |   5 +
 3 files changed, 679 insertions(+), 1 deletion(-)
 create mode 100644 cmd/efishell.c
 create mode 100644 cmd/efishell.h
Quoted 13 lines

cmd/Makefile obj-$(CONFIG_CMD_BINOP) += binop.o · line 27

Quoted 10 lines
cmd/Makefile +1 -1
index d9cdaf6064b8..bd531d505a8e 100644
@@ -24,7 +24,7 @@ obj-$(CONFIG_CMD_BINOP) += binop.o
 obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_CMD_BMP) += bmp.o
 obj-$(CONFIG_CMD_BOOTCOUNT) += bootcount.o
-obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
+obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o efishell.o

Please create a separate command line option for efishell and make it disabled by default.

OK.

Quoted 3 lines

I think it's a really really useful debugging aid, but in a normal environment people should only need to run efi binaries (plus bootmgr) and modify efi variables, no?

The ultimate goal would be to provide this command as a separate application. In this case, however, it won't much different from uefi shell itself :)

Quoted 27 lines
Quoted 27 lines
cmd/Makefile +0 -0
 obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
 obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o
 obj-$(CONFIG_CMD_BOOTZ) += bootz.o
cmd/efishell.c new file +16 -0
new file mode 100644
index 000000000000..abc8216c7bd6
@@ -0,0 +1,673 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  EFI Shell-like command
+ *
+ *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
+ */
+
+#include <charset.h>
+#include <common.h>
+#include <command.h>
+#include <efi_loader.h>
+#include <environment.h>
+#include <errno.h>
+#include <exports.h>
+#include <hexdump.h>
+#include <malloc.h>
Quoted 8 lines

cmd/efishell.c line 22

Quoted 6 lines
cmd/efishell.c new file +6 -0
+#include <search.h>
+#include <linux/ctype.h>
+#include <asm/global_data.h>
+#include "efishell.h"
+
+DECLARE_GLOBAL_DATA_PTR;

Where in this file do you need gd?

OK.
# I thought this should always be declared in any file by default.

Quoted 307 lines
Quoted 307 lines
cmd/efishell.c new file +307 -0
+
+static void dump_var_data(char *data, unsigned long len)
+{
+	char *start, *end, *p;
+	unsigned long pos, count;
+	char hex[3], line[9];
+	int i;
+
+	end = data + len;
+	for (start = data, pos = 0; start < end; start += count, pos += count) {
+		count = end - start;
+		if (count > 16)
+			count = 16;
+
+		/* count should be multiple of two */
+		printf("%08lx: ", pos);
+
+		/* in hex format */
+		p = start;
+		for (i = 0; i < count / 2; p += 2, i++)
+			printf(" %c%c", *p, *(p + 1));
+		for (; i < 8; i++)
+			printf("   ");
+
+		/* in character format */
+		p = start;
+		hex[2] = '\0';
+		for (i = 0; i < count / 2; i++) {
+			hex[0] = *p++;
+			hex[1] = *p++;
+			line[i] = simple_strtoul(hex, 0, 16);
+			if (line[i] < 0x20 || line[i] > 0x7f)
+				line[i] = '.';
+		}
+		line[i] = '\0';
+		printf("  %s\n", line);
+	}
+}
+
+/*
+ * From efi_variable.c,
+ *
+ * Mapping between EFI variables and u-boot variables:
+ *
+ *   efi_$guid_$varname = {attributes}(type)value
+ */
+static int do_efi_dump_var(int argc, char * const argv[])
+{
+	char regex[256];
+	char * const regexlist[] = {regex};
+	char *res = NULL, *start, *end;
+	int len;
+
+	if (argc > 2)
+		return CMD_RET_USAGE;
+
+	if (argc == 2)
+		snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_%s", argv[1]);
+	else
+		snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
+	debug("%s:%d grep uefi var %s\n", __func__, __LINE__, regex);
+
+	len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
+			&res, 0, 1, regexlist);
+
+	if (len < 0)
+		return CMD_RET_FAILURE;
+
+	if (len > 0) {
+		end = res;
+		while (true) {
+			/* variable name */
+			start = strchr(end, '_');
+			if (!start)
+				break;
+			start = strchr(++start, '_');
+			if (!start)
+				break;
+			end = strchr(++start, '=');
+			if (!end)
+				break;
+			printf("%.*s:", (int)(end - start), start);
+			end++;
+
+			/* value */
+			start = end;
+			end = strstr(start, "(blob)");
+			if (!end) {
+				putc('\n');
+				break;
+			}
+			end += 6;
+			printf(" %.*s\n", (int)(end - start), start);
+
+			start = end;
+			end = strchr(start, '\n');
+			if (!end)
+				break;
+			dump_var_data(start,  end - start);
+		}
+		free(res);
+
+		if (len < 2 && argc == 2)
+			printf("%s: not found\n", argv[1]);
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int append_value(char **bufp, unsigned long *sizep, char *data)
+{
+	char *tmp_buf = NULL, *new_buf = NULL, *value;
+	unsigned long len = 0;
+
+	if (!strncmp(data, "=0x", 2)) { /* hexadecimal number */
+		union {
+			u8 u8;
+			u16 u16;
+			u32 u32;
+			u64 u64;
+		} tmp_data;
+		unsigned long hex_value;
+		void *hex_ptr;
+
+		data += 3;
+		len = strlen(data);
+		if ((len & 0x1)) /* not multiple of two */
+			return -1;
+
+		len /= 2;
+		if (len > 8)
+			return -1;
+		else if (len > 4)
+			len = 8;
+		else if (len > 2)
+			len = 4;
+
+		/* convert hex hexadecimal number */
+		if (strict_strtoul(data, 16, &hex_value) < 0)
+			return -1;
+
+		tmp_buf = malloc(len);
+		if (!tmp_buf)
+			return -1;
+
+		if (len == 1) {
+			tmp_data.u8 = hex_value;
+			hex_ptr = &tmp_data.u8;
+		} else if (len == 2) {
+			tmp_data.u16 = hex_value;
+			hex_ptr = &tmp_data.u16;
+		} else if (len == 4) {
+			tmp_data.u32 = hex_value;
+			hex_ptr = &tmp_data.u32;
+		} else {
+			tmp_data.u64 = hex_value;
+			hex_ptr = &tmp_data.u64;
+		}
+		memcpy(tmp_buf, hex_ptr, len);
+		value = tmp_buf;
+
+	} else if (!strncmp(data, "=H", 2)) { /* hexadecimal-byte array */
+		data += 2;
+		len = strlen(data);
+		if (len & 0x1) /* not multiple of two */
+			return -1;
+
+		len /= 2;
+		tmp_buf = malloc(len);
+		if (!tmp_buf)
+			return -1;
+
+		if (hex2bin((u8 *)tmp_buf, data, len) < 0)
+			return -1;
+
+		value = tmp_buf;
+	} else { /* string */
+		if (!strncmp(data, "=\"", 2) || !strncmp(data, "=S\"", 3)) {
+			if (data[1] == '"')
+				data += 2;
+			else
+				data += 3;
+			value = data;
+			len = strlen(data) - 1;
+			if (data[len] != '"')
+				return -1;
+		} else {
+			value = data;
+			len = strlen(data);
+		}
+	}
+
+	new_buf = realloc(*bufp, *sizep + len);
+	if (!new_buf)
+		goto out;
+
+	memcpy(new_buf + *sizep, value, len);
+	*bufp = new_buf;
+	*sizep += len;
+
+out:
+	free(tmp_buf);
+
+	return 0;
+}
+
+static int do_efi_set_var(int argc, char * const argv[])
+{
+	char *var_name, *value = NULL;
+	unsigned long size = 0;
+	u16 *var_name16, *p;
+	efi_guid_t guid;
+	efi_status_t ret;
+
+	if (argc == 1)
+		return CMD_RET_SUCCESS;
+
+	var_name = argv[1];
+	if (argc == 2) {
+		/* remove */
+		value = NULL;
+		size = 0;
+	} else { /* set */
+		argc -= 2;
+		argv += 2;
+
+		for ( ; argc > 0; argc--, argv++)
+			if (append_value(&value, &size, argv[0]) < 0) {
+				ret = CMD_RET_FAILURE;
+				goto out;
+			}
+	}
+
+	var_name16 = malloc((strlen(var_name) + 1) * 2);
+	p = var_name16;
+	utf8_utf16_strncpy(&p, var_name, strlen(var_name) + 1);
+
+	guid = efi_global_variable_guid;
+	ret = efi_set_variable(var_name16, &guid,
+			       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			       EFI_VARIABLE_RUNTIME_ACCESS, size, value);
+	ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
+out:
+	return ret;
+}
+
+static int do_efi_boot_add(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;
+	unsigned long size;
+	int ret;
+
+	if (argc < 6 || argc > 7)
+		return CMD_RET_USAGE;
+
+	id = (int)simple_strtoul(argv[1], &endp, 0);
+	if (*endp != '\0' || id > 0xffff)
+		return CMD_RET_FAILURE;
+
+	sprintf(var_name, "Boot%04X", id);
+	p = var_name16;
+	utf8_utf16_strncpy(&p, var_name, 9);
+
+	guid = efi_global_variable_guid;
+
+	/* attributes */
+	lo.attributes = 0x1; /* always ACTIVE */
+
+	/* label */
+	label_len = strlen(argv[2]);
+	label_len16 = utf8_utf16_strnlen(argv[2], label_len);
+	label = malloc((label_len16 + 1) * sizeof(u16));
+	if (!label)
+		return CMD_RET_FAILURE;
+	lo.label = label; /* label will be changed below */
+	utf8_utf16_strncpy(&label, argv[2], label_len);
+
+	/* file path */
+	ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
+			       &file_path);
+	if (ret != EFI_SUCCESS) {
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}
+	lo.file_path = file_path;
+	lo.file_path_length = efi_dp_size(file_path)
+				+ sizeof(struct efi_device_path); /* for END */
+
+	/* optional data */
+	lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]);
+
+	size = efi_serialize_load_option(&lo, (u8 **)&data);
+	if (!size) {
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}
+
+	ret = efi_set_variable(var_name16, &guid,
Quoted 8 lines

cmd/efishell.c line 335

Quoted 6 lines
cmd/efishell.c new file +6 -0
+			       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			       EFI_VARIABLE_RUNTIME_ACCESS, size, data);
+	ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
+out:
+	free(data);
+#if 0 /* FIXME */

Eh, what? :)

Well, in the past, I saw u-boot hang-out if free()'s were enabled. Now I found that we must free data with efi_free_pool() instead of free().

Quoted 96 lines
Quoted 96 lines
cmd/efishell.c new file +96 -0
+	free(device_path);
+	free(file_path);
+#endif
+	free(lo.label);
+	return ret;
+}
+
+static int do_efi_boot_rm(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, 0);
+		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,
+				       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				       EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
+		if (ret) {
+			printf("cannot remove Boot%04X", id);
+			return CMD_RET_FAILURE;
+		}
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static void show_efi_boot_opt_data(int id, void *data)
+{
+	struct efi_load_option lo;
+	char *label, *p;
+	size_t label_len16, label_len;
+	u16 *dp_str;
+
+	efi_deserialize_load_option(&lo, data);
+
+	label_len16 = u16_strlen(lo.label);
+	label_len = utf16_utf8_strnlen(lo.label, label_len16);
+	label = malloc(label_len + 1);
+	if (!label)
+		return;
+	p = label;
+	utf16_utf8_strncpy(&p, lo.label, label_len16);
+
+	printf("Boot%04X:\n", id);
+	printf("\tattributes: %c%c%c (0x%08x)\n",
+	       /* ACTIVE */
+	       lo.attributes & 0x1 ? 'A' : '-',
+	       /* FORCE RECONNECT */
+	       lo.attributes & 0x2 ? 'R' : '-',
+	       /* HIDDEN */
+	       lo.attributes & 0x8 ? 'H' : '-',
+	       lo.attributes);
+	printf("\tlabel: %s\n", label);
+
+	dp_str = efi_dp_str(lo.file_path);
+	printf("\tfile_path: %ls\n", dp_str);
+	efi_free_pool(dp_str);
+
+	printf("\tdata: %s\n", lo.optional_data);
+
+	free(label);
+}
+
+static void show_efi_boot_opt(int id)
+{
+	char var_name[9];
+	u16 var_name16[9], *p;
+	efi_guid_t guid;
+	void *data = NULL;
+	unsigned long 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);
Quoted 8 lines

cmd/efishell.c line 437

Quoted 6 lines
cmd/efishell.c new file +6 -0
+	}
+	if (ret == EFI_SUCCESS) {
+		show_efi_boot_opt_data(id, data);
+		free(data);
+	} else if (ret == EFI_NOT_FOUND) {
+		printf("Boot%04X: not found\n", id);

Missing free?

Fix it.

Quoted 58 lines
Quoted 58 lines
cmd/efishell.c new file +58 -0
+	}
+}
+
+static int do_efi_boot_dump(int argc, char * const argv[])
+{
+	char regex[256];
+	char * const regexlist[] = {regex};
+	char *variables = NULL, *boot, *value;
+	int len;
+	int id;
+
+	if (argc > 1)
+		return CMD_RET_USAGE;
+
+	snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+");
+
+	len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
+			&variables, 0, 1, regexlist);
+
+	if (!len)
+		return CMD_RET_SUCCESS;
+
+	if (len < 0)
+		return CMD_RET_FAILURE;
+
+	boot = variables;
+	while (*boot) {
+		value = strstr(boot, "Boot") + 4;
+		id = (int)simple_strtoul(value, NULL, 16);
+		show_efi_boot_opt(id);
+		boot = strchr(boot, '\n');
+		if (!*boot)
+			break;
+		boot++;
+	}
+	free(variables);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int show_efi_boot_order(void)
+{
+	efi_guid_t guid;
+	u16 *bootorder = NULL;
+	unsigned long 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 = CMD_RET_SUCCESS;
+
+	guid = efi_global_variable_guid;
+	size = 0;
+	ret = efi_get_variable(L"BootOrder", &guid, NULL, &size, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
Quoted 8 lines

cmd/efishell.c line 501

Quoted 6 lines
cmd/efishell.c new file +6 -0
+		bootorder = malloc(size);
+		ret = efi_get_variable(L"BootOrder", &guid, NULL, &size,
+				       bootorder);
+	}
+	if (ret != EFI_SUCCESS) {
+		printf("BootOrder not defined\n");

Missing free(bootorder)

OK. In addition, I will modify the code to check for EFI_NOT_FOUND.

Quoted 21 lines
Quoted 21 lines
cmd/efishell.c new file +21 -0
+		return CMD_RET_SUCCESS;
+	}
+
+	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;
Quoted 8 lines

cmd/efishell.c line 528

Quoted 6 lines
cmd/efishell.c new file +6 -0
+		}
+		ret = efi_get_variable(var_name16, &guid, NULL, &size, data);
+		if (ret != EFI_SUCCESS) {
+			free(data);
+			ret = CMD_RET_FAILURE;
+			goto out;

Probably better to free(data) at out:, no?

It's possible, but 'data' is only allocated and used repeatedly in a loop, so freeing it within a loop would look to be a good manner.

Quoted 150 lines
Quoted 150 lines
cmd/efishell.c new file +145 -0
+		}
+
+		efi_deserialize_load_option(&lo, data);
+
+		label_len16 = u16_strlen(lo.label);
+		label_len = utf16_utf8_strnlen(lo.label, label_len16);
+		label = malloc(label_len + 1);
+		if (!label) {
+			free(data);
+			ret = CMD_RET_FAILURE;
+			goto out;
+		}
+		p = label;
+		utf16_utf8_strncpy(&p, lo.label, label_len16);
+		printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
+		free(label);
+
+		free(data);
+	}
+out:
+	free(bootorder);
+
+	return ret;
+}
+
+static int do_efi_boot_order(int argc, char * const argv[])
+{
+	u16 *bootorder = NULL;
+	unsigned long 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, 0);
+		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 int do_efi_boot_opt(int argc, char * const argv[])
+{
+	char *sub_command;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	argc--; argv++;
+	sub_command = argv[0];
+
+	if (!strcmp(sub_command, "add"))
+		return do_efi_boot_add(argc, argv);
+	else if (!strcmp(sub_command, "rm"))
+		return do_efi_boot_rm(argc, argv);
+	else if (!strcmp(sub_command, "dump"))
+		return do_efi_boot_dump(argc, argv);
+	else if (!strcmp(sub_command, "order"))
+		return do_efi_boot_order(argc, argv);
+	else
+		return CMD_RET_USAGE;
+}
+
+/* Interpreter command to configure EFI environment */
+static int do_efishell(cmd_tbl_t *cmdtp, int flag,
+		       int argc, char * const argv[])
+{
+	char *command;
+	efi_status_t r;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	argc--; argv++;
+	command = argv[0];
+
+	/* Initialize EFI drivers */
+	r = efi_init_obj_list();
+	if (r != EFI_SUCCESS) {
+		printf("Error: Cannot set up EFI drivers, r = %lu\n",
+		       r & ~EFI_ERROR_MASK);
+		return CMD_RET_FAILURE;
+	}
+
+	if (!strcmp(command, "boot"))
+		return do_efi_boot_opt(argc, argv);
+	else if (!strcmp(command, "dumpvar") || !strcmp(command, "dmpstore"))
+		return do_efi_dump_var(argc, argv);
+	else if (!strcmp(command, "setvar"))
+		return do_efi_set_var(argc, argv);
+	else
+		return CMD_RET_USAGE;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char efishell_help_text[] =
+	"  - EFI Shell-like interface to configure EFI environment\n"
+	"\n"
+	"efishell boot add <bootid> <label> <interface> <device>[:<part>] <file path> <option>\n"
+	"  - set uefi's BOOT variable\n"
+	"efishell boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
+	"  - set/display uefi boot order\n"
+	"efishell boot dump\n"
+	"  - display all uefi's BOOT variables\n"
+	"efishell boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
+	"  - set/display uefi boot order\n"
+	"\n"
+	"efishell dumpvar [<name>]\n"
+	"  - get uefi variable's value\n"
+	"efishell setvar <name> [<value>]\n"
+	"  - set/delete uefi variable's value\n"
+	"    <value> may be \"=\"...\"\", \"=0x...\" (set) or \"=\" (delete)\n";
+#endif
+
+U_BOOT_CMD(
+	efishell, 10, 0, do_efishell,
+	"Configure EFI environment",
+	efishell_help_text
+);
cmd/efishell.h new file +0 -0
new file mode 100644
index 000000000000..6f70b402b26b
Quoted 8 lines

cmd/efishell.h line 5

Quoted 6 lines
cmd/efishell.h new file +5 -0
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <efi.h>
+
+efi_status_t efi_init_obj_list(void);

Why isn't this in efi_loader.h? That's the subsystem that exports it, no?

Agree. Moreover, I think of refactoring the code and moving efi_init_obj_list() to a new file, lib/efi_loader/efi_setup.c, so that we can add more features directly as part of the initialization code.
Features may include USB removable disk support for which I already posted a patch set[1] and yet-coming capsule-on-disk support.

Actually, I have this refactoring patch in my local dev branch. May I submit it as a separate one?

[1] https://lists.denx.de/pipermail/u-boot/2018-November/347493.html

Thanks,
-Takahiro Akashi

Quoted 2 lines

Alex

#10 lore raw

PATCH v2 4/14 cmd: add efishell command

Quoted 90 lines · AKASHI Takahiro
Quoted 29 lines · Alexander Graf
Quoted 26 lines · AKASHI Takahiro

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, efishell, helps address these issues and give us more friendly interfaces:
* efishell boot add: add BootXXXX variable
* efishell boot rm: remove BootXXXX variable
* efishell boot dump: display all BootXXXX variables
* efishell boot order: set/display a boot order (BootOrder)
* efishell setvar: set an UEFI variable (with limited functionality)
* efishell dumpvar: display all UEFI variables

As the name suggests, this command basically provides a subset fo UEFI shell commands with simplified functionality.

---
 cmd/Makefile   |   2 +-
 cmd/efishell.c | 673 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd/efishell.h |   5 +
 3 files changed, 679 insertions(+), 1 deletion(-)
 create mode 100644 cmd/efishell.c
 create mode 100644 cmd/efishell.h
Quoted 13 lines

cmd/Makefile obj-$(CONFIG_CMD_BINOP) += binop.o · line 27

Quoted 10 lines
cmd/Makefile +1 -1
index d9cdaf6064b8..bd531d505a8e 100644
@@ -24,7 +24,7 @@ obj-$(CONFIG_CMD_BINOP) += binop.o
 obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_CMD_BMP) += bmp.o
 obj-$(CONFIG_CMD_BOOTCOUNT) += bootcount.o
-obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
+obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o efishell.o

Please create a separate command line option for efishell and make it disabled by default.

OK.

Quoted 3 lines

I think it's a really really useful debugging aid, but in a normal environment people should only need to run efi binaries (plus bootmgr) and modify efi variables, no?

The ultimate goal would be to provide this command as a separate application. In this case, however, it won't much different from uefi shell itself :)

Quoted 27 lines
Quoted 27 lines
cmd/Makefile +0 -0
 obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
 obj-$(CONFIG_CMD_BOOTSTAGE) += bootstage.o
 obj-$(CONFIG_CMD_BOOTZ) += bootz.o
cmd/efishell.c new file +16 -0
new file mode 100644
index 000000000000..abc8216c7bd6
@@ -0,0 +1,673 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  EFI Shell-like command
+ *
+ *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
+ */
+
+#include <charset.h>
+#include <common.h>
+#include <command.h>
+#include <efi_loader.h>
+#include <environment.h>
+#include <errno.h>
+#include <exports.h>
+#include <hexdump.h>
+#include <malloc.h>
Quoted 8 lines

cmd/efishell.c line 22

Quoted 6 lines
cmd/efishell.c new file +6 -0
+#include <search.h>
+#include <linux/ctype.h>
+#include <asm/global_data.h>
+#include "efishell.h"
+
+DECLARE_GLOBAL_DATA_PTR;

Where in this file do you need gd?

Quoted 2 lines

OK.
# I thought this should always be declared in any file by default.

You only need to declare it when you need gd :). Most efi_loader code should be able to live just fine without.

[...]

Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
cmd/efishell.c new file +10 -0
+	/* 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,
Quoted 8 lines

cmd/efishell.c line 335

Quoted 6 lines
cmd/efishell.c new file +6 -0
+			       EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			       EFI_VARIABLE_RUNTIME_ACCESS, size, data);
+	ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
+out:
+	free(data);
+#if 0 /* FIXME */

Eh, what? :)

Quoted 2 lines

Well, in the past, I saw u-boot hang-out if free()'s were enabled. Now I found that we must free data with efi_free_pool() instead of free().

It depends on how data was allocated, yes.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
cmd/efishell.c new file +7 -0
+	free(device_path);
+	free(file_path);
+#endif
+	free(lo.label);
+	return ret;
+}
+

[...]

Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
cmd/efishell.h new file +0 -0
new file mode 100644
index 000000000000..6f70b402b26b
Quoted 8 lines

cmd/efishell.h line 5

Quoted 6 lines
cmd/efishell.h new file +5 -0
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <efi.h>
+
+efi_status_t efi_init_obj_list(void);

Why isn't this in efi_loader.h? That's the subsystem that exports it, no?

Quoted 3 lines

Agree. Moreover, I think of refactoring the code and moving efi_init_obj_list() to a new file, lib/efi_loader/efi_setup.c, so that we can add more features directly as part of the initialization code.

Well, as Heinrich already indicated, the long term goal would be to have UEFI handles implicitly generated for DM devices. So we wouldn't need to maintain our own copy of the already existing object model.

Alex

Quoted 14 lines

Features may include USB removable disk support for which I already posted a patch set[1] and yet-coming capsule-on-disk support.

Actually, I have this refactoring patch in my local dev branch. May I submit it as a separate one?

[1] https://lists.denx.de/pipermail/u-boot/2018-November/347493.html

Thanks,
-Takahiro Akashi

Quoted 2 lines

Alex

#11 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

In reply to AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +87 -1
index abc8216c7bd6..f4fa3fdf28a7 100644
@@ -21,6 +21,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;
+
 static void dump_var_data(char *data, unsigned long len)
 {
 	char *start, *end, *p;
@@ -266,6 +268,84 @@ out:
 	return ret;
 }
 
+static efi_handle_t *efi_get_handles_by_proto(efi_guid_t *guid)
+{
+	efi_handle_t *handles = NULL;
+	efi_uintn_t size = 0;
+	efi_status_t ret;
+
+	if (guid) {
+		ret = bs->locate_handle(BY_PROTOCOL, guid, NULL, &size,
+					handles);
+		if (ret == EFI_BUFFER_TOO_SMALL) {
+			handles = calloc(1, size);
+			if (!handles)
+				return NULL;
+
+			ret = bs->locate_handle(BY_PROTOCOL, guid, NULL, &size,
+						handles);
+		}
+		if (ret != EFI_SUCCESS) {
+			free(handles);
+			return NULL;
+		}
+	} else {
+		ret = bs->locate_handle(ALL_HANDLES, NULL, NULL, &size, NULL);
+		if (ret == EFI_BUFFER_TOO_SMALL) {
+			handles = calloc(1, size);
+			if (!handles)
+				return NULL;
+
+			ret = bs->locate_handle(ALL_HANDLES, NULL, NULL, &size,
+						handles);
+		}
+		if (ret != EFI_SUCCESS) {
+			free(handles);
+			return NULL;
+		}
+	}
+
+	return handles;
+}
+
+static int efi_get_device_handle_info(efi_handle_t handle, u16 **name)
+{
+	struct efi_device_path *dp;
+	efi_status_t ret;
+
+	ret = bs->open_protocol(handle, &efi_guid_device_path,
+				(void **)&dp, NULL /* FIXME */, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret == EFI_SUCCESS) {
+		*name = efi_dp_str(dp);
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+static int do_efi_show_devices(int argc, char * const argv[])
+{
+	efi_handle_t *handles = NULL, *handle;
+	u16 *devname;
+
+	handles = efi_get_handles_by_proto(NULL);
+	if (!handles)
+		return CMD_RET_SUCCESS;
+
+	printf("Device Name\n");
+	printf("============================================\n");
+	for (handle = handles; *handle; handle++) {
+		if (!efi_get_device_handle_info(*handle, &devname)) {
+			printf("%ls\n", devname);
+			efi_free_pool(devname);
+		}
+		handle++;
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -625,6 +705,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
+	bs = systab.boottime;
+
 	argc--; argv++;
 	command = argv[0];
 
@@ -642,6 +724,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_dump_var(argc, argv);
 	else if (!strcmp(command, "setvar"))
 		return do_efi_set_var(argc, argv);
+	else if (!strcmp(command, "devices"))
+		return do_efi_show_devices(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -663,7 +747,9 @@ static char efishell_help_text[] =
 	"  - get uefi variable's value\n"
 	"efishell setvar <name> [<value>]\n"
 	"  - set/delete uefi variable's value\n"
-	"    <value> may be \"=\"...\"\", \"=0x...\" (set) or \"=\" (delete)\n";
+	"    <value> may be \"=\"...\"\", \"=0x...\" (set) or \"=\" (delete)\n"
+	"efishell devices\n"
+	"  - show uefi devices\n";
 #endif
 
 U_BOOT_CMD(
Signature · 1 line
2.19.0
#12 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

Quoted 21 lines · AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +0 -0
index abc8216c7bd6..f4fa3fdf28a7 100644

cmd/efishell.c line 24

Quoted 4 lines
cmd/efishell.c +1 -0
@@ -21,6 +21,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;

Why do you need a local copy of this?

Alex

#13 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

Quoted 25 lines · Alexander Graf
Quoted 22 lines · AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +0 -0
index abc8216c7bd6..f4fa3fdf28a7 100644
@@ -21,6 +21,8 @@
 
Quoted 5 lines

cmd/efishell.c line 24

Quoted 3 lines
cmd/efishell.c +1 -0
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;

Why do you need a local copy of this?

Good point. It's because I followed the way boot manager does :)

I think that it would be good to do so since either boot manager or efishell should ultimately be an independent efi application in its nature.

What do you think?

FYI, one of the reasons why efishell cannot be an application is that we lack an runtime service interface of GetNextVariableName() which can be used to enumerate variables in dumpvar sub-command.

I also have a patch for adding GetNextVariableName() in my local dev branch. I intend to post this patch along with capsule-on-disk support, but I may be able to submit it separately if you like.

Thanks,
-Takahiro Akashi

Quoted 2 lines

Alex

#14 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

Quoted 32 lines · AKASHI Takahiro
Quoted 25 lines · Alexander Graf
Quoted 22 lines · AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +0 -0
index abc8216c7bd6..f4fa3fdf28a7 100644
@@ -21,6 +21,8 @@
 
Quoted 5 lines

cmd/efishell.c line 24

Quoted 3 lines
cmd/efishell.c +1 -0
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;

Why do you need a local copy of this?

Quoted 7 lines

Good point. It's because I followed the way boot manager does :)

I think that it would be good to do so since either boot manager or efishell should ultimately be an independent efi application in its nature.

What do you think?

As mentioned in the other email thread, I think that we should definitely evaluate to add the edk2 shell as built-in option.

That way for the "full-fledged" shell experience, your built-in code is not needed. But I still believe it would be useful for quick and built-in debugging.

Alex

#15 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

Quoted 35 lines · Alexander Graf
Quoted 32 lines · AKASHI Takahiro
Quoted 30 lines · Alexander Graf
Quoted 21 lines · AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +0 -0
index abc8216c7bd6..f4fa3fdf28a7 100644

cmd/efishell.c line 24

Quoted 4 lines
cmd/efishell.c +1 -0
@@ -21,6 +21,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;

Why do you need a local copy of this?

Quoted 7 lines
Quoted 7 lines

Good point. It's because I followed the way boot manager does :)

I think that it would be good to do so since either boot manager or efishell should ultimately be an independent efi application in its nature.

What do you think?

Back to your original comment: Why do you need a local copy of this?

Do you think we should use systab.boottime,runtime instead?

Quoted 2 lines

As mentioned in the other email thread, I think that we should definitely evaluate to add the edk2 shell as built-in option.

Do you expect that I will add a new config, say, CONFIG_EFI_SHELL_PATH?

-Takahiro Akashi

Quoted 6 lines

That way for the "full-fledged" shell experience, your built-in code is not needed. But I still believe it would be useful for quick and built-in debugging.

Alex

#16 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

Quoted 42 lines · AKASHI Takahiro
Quoted 41 lines · Alexander Graf
Quoted 38 lines · AKASHI Takahiro
Quoted 25 lines · Alexander Graf
Quoted 22 lines · AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +0 -0
index abc8216c7bd6..f4fa3fdf28a7 100644
@@ -21,6 +21,8 @@
 
Quoted 5 lines

cmd/efishell.c line 24

Quoted 3 lines
cmd/efishell.c +1 -0
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;

Why do you need a local copy of this?

Good point. It's because I followed the way boot manager does :)

I think that it would be good to do so since either boot manager or efishell should ultimately be an independent efi application in its nature.

Quoted 5 lines
Quoted 1 line
Quoted 1 line

What do you think?

Back to your original comment: Why do you need a local copy of this?

Do you think we should use systab.boottime,runtime instead?

Sure, that's one thing. Or you could make it a local variable. Or you could even do a #define in the file. But that static const here will most likely waste space in .bss and does not take into account when someone patches the systab.

Quoted 4 lines
Quoted 2 lines

As mentioned in the other email thread, I think that we should definitely evaluate to add the edk2 shell as built-in option.

Do you expect that I will add a new config, say, CONFIG_EFI_SHELL_PATH?

Doesn't have to be you, but it might be useful to have something like that, yes.

CONFIG_CMD_BOOTEFI_SHELL=y
CONFIG_CMD_BOOTEFI_SHELL_PATH=shell.efi

which then would work the same as CONFIG_CMD_BOOTEFI_HELLO, but simply execute a precompiled version of the UEFI shell. IIRC the UEFI shell also supports passing arguments via the command line (load_options -> "bootargs" variable).

So with that you should be able to run

U-Boot# setenv bootargs memmap; bootefi shell

and get a list of the UEFI memory map.

Alex

#17 lore raw

PATCH v2 5/14 cmd: efishell: add devices command

Quoted 47 lines · Alexander Graf
Quoted 44 lines · AKASHI Takahiro
Quoted 42 lines · Alexander Graf
Quoted 39 lines · AKASHI Takahiro
Quoted 25 lines · Alexander Graf
Quoted 22 lines · AKASHI Takahiro

"devices" command prints all the uefi variables on the system. => efishell devices
Device Name
============================================
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)

/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(2,MBR,0x086246ba,0x40800,0x3f800)
/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/\
				HD(1,MBR,0x086246ba,0x800,0x40000)
---
 cmd/efishell.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)
cmd/efishell.c +0 -0
index abc8216c7bd6..f4fa3fdf28a7 100644
@@ -21,6 +21,8 @@
 
Quoted 5 lines

cmd/efishell.c line 24

Quoted 3 lines
cmd/efishell.c +1 -0
 DECLARE_GLOBAL_DATA_PTR;
 
+static const struct efi_boot_services *bs;

Why do you need a local copy of this?

Good point. It's because I followed the way boot manager does :)

I think that it would be good to do so since either boot manager or efishell should ultimately be an independent efi application in its nature.

What do you think?

Quoted 8 lines
Quoted 3 lines

Back to your original comment: Why do you need a local copy of this?

Do you think we should use systab.boottime,runtime instead?

Sure, that's one thing. Or you could make it a local variable. Or you could even do a #define in the file. But that static const here will most likely waste space in .bss and does not take into account when someone patches the systab.

OK, I will add a macro definition.

-Takahiro Akashi

Quoted 24 lines
Quoted 4 lines
Quoted 2 lines

As mentioned in the other email thread, I think that we should definitely evaluate to add the edk2 shell as built-in option.

Do you expect that I will add a new config, say, CONFIG_EFI_SHELL_PATH?

Doesn't have to be you, but it might be useful to have something like that, yes.

CONFIG_CMD_BOOTEFI_SHELL=y
CONFIG_CMD_BOOTEFI_SHELL_PATH=shell.efi

which then would work the same as CONFIG_CMD_BOOTEFI_HELLO, but simply execute a precompiled version of the UEFI shell. IIRC the UEFI shell also supports passing arguments via the command line (load_options -> "bootargs" variable).

So with that you should be able to run

U-Boot# setenv bootargs memmap; bootefi shell

and get a list of the UEFI memory map.

Alex

#18 lore raw

PATCH v2 6/14 cmd: efishell: add drivers command

In reply to AKASHI Takahiro

"drivers" command prints all the uefi drivers on the system. => efi drivers
Driver Name Image Path
============================================
(unknown) <NULL>+(not found)

    guid: 18a031ab-b443-4d1a-a5c0-0c09261e9f71

Currently, no useful information can be printed.

---
 cmd/efishell.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 94 insertions(+), 1 deletion(-)
cmd/efishell.c +94 -1
index f4fa3fdf28a7..2f54f7803ac5 100644
@@ -346,6 +346,95 @@ static int do_efi_show_devices(int argc, char * const argv[])
 	return CMD_RET_SUCCESS;
 }
 
+static int efi_get_driver_handle_info(efi_handle_t handle, u16 **name,
+				      u16 **devname, u16 **filename)
+{
+	struct efi_driver_binding_protocol *binding;
+	struct efi_loaded_image *image;
+	efi_status_t ret;
+
+	ret = bs->open_protocol(handle, &efi_guid_driver_binding_protocol,
+				(void **)&binding, NULL, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS)
+		return -1;
+
+	ret = bs->open_protocol(binding->image_handle, &efi_guid_loaded_image,
+				(void **)&image, NULL /* FIXME */, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS)
+		goto e_out;
+
+	/*
+	 * TODO:
+	 * handle image->device_handle,
+	 * use append_device_path()
+	 */
+	*devname = NULL;
+	*filename = efi_dp_str(image->file_path);
+
+	return 0;
+
+e_out:
+	*devname = NULL;
+	*filename = L"(not found)";
+
+	return 0;
+}
+
+static int do_efi_show_drivers(int argc, char * const argv[])
+{
+	efi_handle_t *handles = NULL, *handle;
+	efi_uintn_t size = 0;
+	u16 *drvname, *devname, *filename;
+	efi_status_t ret;
+	int i;
+
+	ret = bs->locate_handle(BY_PROTOCOL, &efi_guid_driver_binding_protocol,
+				NULL, &size, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		handles = calloc(1, size);
+		if (!handles)
+			return CMD_RET_FAILURE;
+
+		ret = bs->locate_handle(BY_PROTOCOL,
+					&efi_guid_driver_binding_protocol,
+					NULL, &size, handles);
+	}
+	if (ret != EFI_SUCCESS) {
+		free(handles);
+		return CMD_RET_FAILURE;
+	}
+
+	printf("Driver Name     Image Path\n");
+	printf("============================================\n");
+	handle = handles;
+	for (i = 0; i < size / sizeof(*handle); i++) {
+		if (!efi_get_driver_handle_info(*handle, &drvname, &devname,
+						&filename)) {
+			printf("%-16s%ls+%ls\n",
+			       "(unknown)", devname, filename);
+			efi_free_pool(devname);
+			efi_free_pool(filename);
+
+			/* TODO: no other info */
+			struct efi_object *efiobj;
+			struct list_head *lhandle;
+			struct efi_handler *protocol;
+
+			efiobj = efi_search_obj(*handle);
+			list_for_each(lhandle, &efiobj->protocols) {
+				protocol = list_entry(lhandle,
+						      struct efi_handler, link);
+				printf("    guid: %pUl\n", protocol->guid);
+			}
+		}
+		handle++;
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -726,6 +815,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_set_var(argc, argv);
 	else if (!strcmp(command, "devices"))
 		return do_efi_show_devices(argc, argv);
+	else if (!strcmp(command, "drivers"))
+		return do_efi_show_drivers(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -749,7 +840,9 @@ static char efishell_help_text[] =
 	"  - set/delete uefi variable's value\n"
 	"    <value> may be \"=\"...\"\", \"=0x...\" (set) or \"=\" (delete)\n"
 	"efishell devices\n"
-	"  - show uefi devices\n";
+	"  - show uefi devices\n"
+	"efishell drivers\n"
+	"  - show uefi drivers\n";
 #endif
 
 U_BOOT_CMD(
Signature · 1 line
2.19.0
#19 lore raw

PATCH v2 7/14 cmd: efishell: add images command

In reply to AKASHI Takahiro

"images" command prints loaded images-related information.

---
 cmd/efishell.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
cmd/efishell.c +12 -1
index 2f54f7803ac5..b5050d63fa22 100644
@@ -435,6 +435,13 @@ static int do_efi_show_drivers(int argc, char * const argv[])
 	return CMD_RET_SUCCESS;
 }
 
+static int do_efi_show_images(int argc, char * const argv[])
+{
+	efi_print_image_infos(NULL);
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -817,6 +824,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_show_devices(argc, argv);
 	else if (!strcmp(command, "drivers"))
 		return do_efi_show_drivers(argc, argv);
+	else if (!strcmp(command, "images"))
+		return do_efi_show_images(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -842,7 +851,9 @@ static char efishell_help_text[] =
 	"efishell devices\n"
 	"  - show uefi devices\n"
 	"efishell drivers\n"
-	"  - show uefi drivers\n";
+	"  - show uefi drivers\n"
+	"efishell images\n"
+	"  - show loaded images\n";
 #endif
 
 U_BOOT_CMD(
Signature · 1 line
2.19.0
#20 lore raw

PATCH v2 8/14 cmd: efishell: add memmap command

In reply to AKASHI Takahiro

"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
---
 cmd/efishell.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)
cmd/efishell.c +77 -1
index b5050d63fa22..3e1118a407ff 100644
@@ -442,6 +442,78 @@ static int do_efi_show_images(int argc, char * const argv[])
 	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",
+};
+
+#define EFI_MEM_ATTR(attribute, bit, string) \
+	if ((attribute) & (bit)) {	\
+		if (sep)		\
+			putc('|');	\
+		sep = 1;		\
+		printf(string);		\
+	}
+
+static int do_efi_show_memmap(int argc, char * const argv[])
+{
+	struct efi_mem_desc *map = NULL;
+	efi_uintn_t map_size = 0;
+	int i, sep;
+	efi_status_t ret;
+
+	ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		map = malloc(map_size);
+		if (!map)
+			return CMD_RET_FAILURE;
+		ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	}
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	printf("Type             Start            End              Attributes\n");
+	printf("================ ================ ================ ==========\n");
+	for (i = 0; i < map_size / sizeof(*map); map++, i++) {
+		sep = 0;
+		printf("%-16s %016llx-%016llx ",
+		       efi_mem_type_string[map->type],
+		       map->physical_start,
+		       map->physical_start + map->num_pages * EFI_PAGE_SIZE);
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_UC, "UC");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WC, "WC");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WT, "WT");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WB, "WB");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_UCE, "UCE");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WP, "WP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RP, "RP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_XP, "WP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_NV, "NV");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_MORE_RELIABLE, "REL");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RO, "RO");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RUNTIME, "RT");
+		putc('\n');
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -826,6 +898,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_show_drivers(argc, argv);
 	else if (!strcmp(command, "images"))
 		return do_efi_show_images(argc, argv);
+	else if (!strcmp(command, "memmap"))
+		return do_efi_show_memmap(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -853,7 +927,9 @@ static char efishell_help_text[] =
 	"efishell drivers\n"
 	"  - show uefi drivers\n"
 	"efishell images\n"
-	"  - show loaded images\n";
+	"  - show loaded images\n"
+	"efishell memmap\n"
+	"  - show uefi memory map\n";
 #endif
 
 U_BOOT_CMD(
Signature · 1 line
2.19.0
#21 lore raw

PATCH v2 8/14 cmd: efishell: add memmap command

Quoted 52 lines · AKASHI Takahiro

"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
---
 cmd/efishell.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)
cmd/efishell.c +25 -0
index b5050d63fa22..3e1118a407ff 100644
@@ -442,6 +442,78 @@ static int do_efi_show_images(int argc, char * const argv[])
 	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",
+};
+
+#define EFI_MEM_ATTR(attribute, bit, string) \
+	if ((attribute) & (bit)) {	\
+		if (sep)		\
+			putc('|');	\
+		sep = 1;		\
+		printf(string);		\
+	}
+

cmd/efishell.c static int do_efi_show_images(int argc, char * const argv[]) · line 479

Quoted 10 lines
cmd/efishell.c +10 -0
+static int do_efi_show_memmap(int argc, char * const argv[])
+{
+	struct efi_mem_desc *map = NULL;
+	efi_uintn_t map_size = 0;
+	int i, sep;
+	efi_status_t ret;
+
+	ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		map = malloc(map_size);

Where is the free() to this malloc()?

Alex

Quoted 61 lines
cmd/efishell.c +42 -1
+		if (!map)
+			return CMD_RET_FAILURE;
+		ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	}
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	printf("Type             Start            End              Attributes\n");
+	printf("================ ================ ================ ==========\n");
+	for (i = 0; i < map_size / sizeof(*map); map++, i++) {
+		sep = 0;
+		printf("%-16s %016llx-%016llx ",
+		       efi_mem_type_string[map->type],
+		       map->physical_start,
+		       map->physical_start + map->num_pages * EFI_PAGE_SIZE);
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_UC, "UC");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WC, "WC");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WT, "WT");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WB, "WB");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_UCE, "UCE");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WP, "WP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RP, "RP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_XP, "WP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_NV, "NV");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_MORE_RELIABLE, "REL");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RO, "RO");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RUNTIME, "RT");
+		putc('\n');
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -826,6 +898,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_show_drivers(argc, argv);
 	else if (!strcmp(command, "images"))
 		return do_efi_show_images(argc, argv);
+	else if (!strcmp(command, "memmap"))
+		return do_efi_show_memmap(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -853,7 +927,9 @@ static char efishell_help_text[] =
 	"efishell drivers\n"
 	"  - show uefi drivers\n"
 	"efishell images\n"
-	"  - show loaded images\n";
+	"  - show loaded images\n"
+	"efishell memmap\n"
+	"  - show uefi memory map\n";
 #endif
 
 U_BOOT_CMD(
#22 lore raw

PATCH v2 8/14 cmd: efishell: add memmap command

Quoted 59 lines · Alexander Graf
Quoted 56 lines · AKASHI Takahiro

"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
---
 cmd/efishell.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)
cmd/efishell.c +29 -0
index b5050d63fa22..3e1118a407ff 100644
@@ -442,6 +442,78 @@ static int do_efi_show_images(int argc, char * const argv[])
 	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",
+};
+
+#define EFI_MEM_ATTR(attribute, bit, string) \
+	if ((attribute) & (bit)) {	\
+		if (sep)		\
+			putc('|');	\
+		sep = 1;		\
+		printf(string);		\
+	}
+
+static int do_efi_show_memmap(int argc, char * const argv[])
+{
+	struct efi_mem_desc *map = NULL;
+	efi_uintn_t map_size = 0;
Quoted 8 lines

cmd/efishell.c static int do_efi_show_images(int argc, char * const argv[]) · line 479

Quoted 6 lines
cmd/efishell.c +6 -0
+	int i, sep;
+	efi_status_t ret;
+
+	ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		map = malloc(map_size);

Where is the free() to this malloc()?

OK, fix it.

Thanks,
-Takahiro Akashi

Quoted 64 lines

Alex

Quoted 61 lines
cmd/efishell.c +42 -1
+		if (!map)
+			return CMD_RET_FAILURE;
+		ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	}
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	ret = efi_get_memory_map(&map_size, map, NULL, NULL, NULL);
+	if (ret != EFI_SUCCESS)
+		return CMD_RET_FAILURE;
+
+	printf("Type             Start            End              Attributes\n");
+	printf("================ ================ ================ ==========\n");
+	for (i = 0; i < map_size / sizeof(*map); map++, i++) {
+		sep = 0;
+		printf("%-16s %016llx-%016llx ",
+		       efi_mem_type_string[map->type],
+		       map->physical_start,
+		       map->physical_start + map->num_pages * EFI_PAGE_SIZE);
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_UC, "UC");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WC, "WC");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WT, "WT");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WB, "WB");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_UCE, "UCE");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_WP, "WP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RP, "RP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_XP, "WP");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_NV, "NV");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_MORE_RELIABLE, "REL");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RO, "RO");
+		EFI_MEM_ATTR(map->attribute, EFI_MEMORY_RUNTIME, "RT");
+		putc('\n');
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -826,6 +898,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_show_drivers(argc, argv);
 	else if (!strcmp(command, "images"))
 		return do_efi_show_images(argc, argv);
+	else if (!strcmp(command, "memmap"))
+		return do_efi_show_memmap(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -853,7 +927,9 @@ static char efishell_help_text[] =
 	"efishell drivers\n"
 	"  - show uefi drivers\n"
 	"efishell images\n"
-	"  - show loaded images\n";
+	"  - show loaded images\n"
+	"efishell memmap\n"
+	"  - show uefi memory map\n";
 #endif
 
 U_BOOT_CMD(
#23 lore raw

PATCH v2 9/14 cmd: efishell: add dh command

In reply to AKASHI Takahiro

"dh" command prints all the uefi handles used in the system. => efishell dh
(T.B.D.)
0: (protocol info not available)
1: (protocol info not available)
2: (protocol info not available)
3: (protocol info not available)
4: (protocol info not available)
5: (protocol info not available)
6: (protocol info not available)
7: (protocol info not available)
8: (protocol info not available)
9: (protocol info not available)
10: (protocol info not available)
11: (protocol info not available)
12: (protocol info not available)
13: (protocol info not available)
14: (protocol info not available)
15: (protocol info not available)

---
 cmd/efishell.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)
cmd/efishell.c +32 -1
index 3e1118a407ff..bd2b99e74079 100644
@@ -514,6 +514,33 @@ static int do_efi_show_memmap(int argc, char * const argv[])
 	return CMD_RET_SUCCESS;
 }
 
+static char *efi_get_proto_info(efi_handle_t handle)
+{
+	return strdup("(protocol info not available)");
+}
+
+static int do_efi_show_handles(int argc, char * const argv[])
+{
+	efi_handle_t *handles = NULL, *handle;
+	char *info;
+	int i;
+
+	handles = efi_get_handles_by_proto(NULL);
+	if (!handles)
+		return CMD_RET_SUCCESS;
+
+	for (handle = handles, i = 0; *handle; handle++, i++) {
+		/* TODO: depends on protocols */
+		info = efi_get_proto_info(*handle);
+		printf("%d: %s\n", i, info ?: "");
+		free(info);
+	}
+
+	free(handles);
+
+	return CMD_RET_SUCCESS;
+}
+
 static int do_efi_boot_add(int argc, char * const argv[])
 {
 	int id;
@@ -900,6 +927,8 @@ static int do_efishell(cmd_tbl_t *cmdtp, int flag,
 		return do_efi_show_images(argc, argv);
 	else if (!strcmp(command, "memmap"))
 		return do_efi_show_memmap(argc, argv);
+	else if (!strcmp(command, "dh"))
+		return do_efi_show_handles(argc, argv);
 	else
 		return CMD_RET_USAGE;
 }
@@ -929,7 +958,9 @@ static char efishell_help_text[] =
 	"efishell images\n"
 	"  - show loaded images\n"
 	"efishell memmap\n"
-	"  - show uefi memory map\n";
+	"  - show uefi memory map\n"
+	"efishell dh\n"
+	"  - show uefi handles\n";
 #endif
 
 U_BOOT_CMD(
Signature · 1 line
2.19.0
#24 lore raw

PATCH v2 10/14 cmd: bootefi: carve out fdt parameter handling

In reply to AKASHI Takahiro

The current way how command parameters, particularly "fdt addr," are handled makes it a bit complicated to add a subcommand-specific parameter. So just refactor the code and extract efi_handle_fdt().

This commit is a preparatory change for enhancing bootmgr sub-command.

---
 cmd/bootefi.c  | 51 +++++++++++++++++++++++++++++++++-----------------
 cmd/efishell.h |  1 +
 2 files changed, 35 insertions(+), 17 deletions(-)
cmd/bootefi.c +34 -17
index 5d61819f1f5c..3aedf5a09f93 100644
@@ -356,6 +356,31 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
 	return ret;
 }
 
+int efi_handle_fdt(char *fdt_opt)
+{
+	unsigned long fdt_addr;
+	efi_status_t r;
+
+	if (fdt_opt) {
+		fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
+		if (!fdt_addr && *fdt_opt != '0')
+			return CMD_RET_USAGE;
+
+		/* Install device tree */
+		r = efi_install_fdt(fdt_addr);
+		if (r != EFI_SUCCESS) {
+			printf("ERROR: failed to install device tree\n");
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
+		efi_install_configuration_table(&efi_guid_fdt, NULL);
+		printf("WARNING: booting without device tree\n");
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_bootefi_exec() - execute EFI binary
  *
@@ -511,7 +536,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	unsigned long addr;
 	char *saddr;
 	efi_status_t r;
-	unsigned long fdt_addr;
 
 	/* Allow unaligned memory access */
 	allow_unaligned();
@@ -527,21 +551,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	if (argc > 2) {
-		fdt_addr = simple_strtoul(argv[2], NULL, 16);
-		if (!fdt_addr && *argv[2] != '0')
-			return CMD_RET_USAGE;
-		/* Install device tree */
-		r = efi_install_fdt(fdt_addr);
-		if (r != EFI_SUCCESS) {
-			printf("ERROR: failed to install device tree\n");
-			return CMD_RET_FAILURE;
-		}
-	} else {
-		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
-		efi_install_configuration_table(&efi_guid_fdt, NULL);
-		printf("WARNING: booting without device tree\n");
-	}
 #ifdef CONFIG_CMD_BOOTEFI_HELLO
 	if (!strcmp(argv[1], "hello")) {
 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
@@ -559,6 +568,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		struct efi_loaded_image_obj *image_obj;
 		struct efi_loaded_image *loaded_image_info;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
 		/* Construct a dummy device path. */
 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
 						      (uintptr_t)&efi_selftest,
@@ -583,7 +595,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else
 #endif
 	if (!strcmp(argv[1], "bootmgr")) {
-		return do_bootefi_bootmgr_exec();
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
 	} else {
 		saddr = argv[1];
 
@@ -592,6 +607,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (!addr && *saddr != '0')
 			return CMD_RET_USAGE;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
 	}
 
 	printf("## Starting EFI application at %08lx ...\n", addr);
cmd/efishell.h +1 -0
index 6f70b402b26b..1e5764a8a38d 100644
@@ -3,3 +3,4 @@
 #include <efi.h>
 
 efi_status_t efi_init_obj_list(void);
+int efi_handle_fdt(char *fdt_opt);
Signature · 1 line
2.19.0
#25 lore raw

PATCH v2 10/14 cmd: bootefi: carve out fdt parameter handling

Quoted 114 lines · AKASHI Takahiro

The current way how command parameters, particularly "fdt addr," are handled makes it a bit complicated to add a subcommand-specific parameter. So just refactor the code and extract efi_handle_fdt().

This commit is a preparatory change for enhancing bootmgr sub-command.

---
 cmd/bootefi.c  | 51 +++++++++++++++++++++++++++++++++-----------------
 cmd/efishell.h |  1 +
 2 files changed, 35 insertions(+), 17 deletions(-)
cmd/bootefi.c +34 -17
index 5d61819f1f5c..3aedf5a09f93 100644
@@ -356,6 +356,31 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
 	return ret;
 }
 
+int efi_handle_fdt(char *fdt_opt)
+{
+	unsigned long fdt_addr;
+	efi_status_t r;
+
+	if (fdt_opt) {
+		fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
+		if (!fdt_addr && *fdt_opt != '0')
+			return CMD_RET_USAGE;
+
+		/* Install device tree */
+		r = efi_install_fdt(fdt_addr);
+		if (r != EFI_SUCCESS) {
+			printf("ERROR: failed to install device tree\n");
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
+		efi_install_configuration_table(&efi_guid_fdt, NULL);
+		printf("WARNING: booting without device tree\n");
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_bootefi_exec() - execute EFI binary
  *
@@ -511,7 +536,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	unsigned long addr;
 	char *saddr;
 	efi_status_t r;
-	unsigned long fdt_addr;
 
 	/* Allow unaligned memory access */
 	allow_unaligned();
@@ -527,21 +551,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	if (argc > 2) {
-		fdt_addr = simple_strtoul(argv[2], NULL, 16);
-		if (!fdt_addr && *argv[2] != '0')
-			return CMD_RET_USAGE;
-		/* Install device tree */
-		r = efi_install_fdt(fdt_addr);
-		if (r != EFI_SUCCESS) {
-			printf("ERROR: failed to install device tree\n");
-			return CMD_RET_FAILURE;
-		}
-	} else {
-		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
-		efi_install_configuration_table(&efi_guid_fdt, NULL);
-		printf("WARNING: booting without device tree\n");
-	}
 #ifdef CONFIG_CMD_BOOTEFI_HELLO
 	if (!strcmp(argv[1], "hello")) {
 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
@@ -559,6 +568,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		struct efi_loaded_image_obj *image_obj;
 		struct efi_loaded_image *loaded_image_info;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
 		/* Construct a dummy device path. */
 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
 						      (uintptr_t)&efi_selftest,
@@ -583,7 +595,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else
 #endif
 	if (!strcmp(argv[1], "bootmgr")) {
-		return do_bootefi_bootmgr_exec();
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
 	} else {
 		saddr = argv[1];
 
@@ -592,6 +607,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (!addr && *saddr != '0')
 			return CMD_RET_USAGE;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
 	}
 
 	printf("## Starting EFI application at %08lx ...\n", addr);
cmd/efishell.h +0 -0
index 6f70b402b26b..1e5764a8a38d 100644

cmd/efishell.h line 6

Quoted 4 lines
cmd/efishell.h +1 -0
@@ -3,3 +3,4 @@
 #include <efi.h>
 
 efi_status_t efi_init_obj_list(void);
+int efi_handle_fdt(char *fdt_opt);

This should also go into efi_loader.h, as that's the subsystem that exports the function.

Alex

#26 lore raw

PATCH v2 10/14 cmd: bootefi: carve out fdt parameter handling

Quoted 119 lines · Alexander Graf
Quoted 116 lines · AKASHI Takahiro

The current way how command parameters, particularly "fdt addr," are handled makes it a bit complicated to add a subcommand-specific parameter. So just refactor the code and extract efi_handle_fdt().

This commit is a preparatory change for enhancing bootmgr sub-command.

---
 cmd/bootefi.c  | 51 +++++++++++++++++++++++++++++++++-----------------
 cmd/efishell.h |  1 +
 2 files changed, 35 insertions(+), 17 deletions(-)
cmd/bootefi.c +34 -17
index 5d61819f1f5c..3aedf5a09f93 100644
@@ -356,6 +356,31 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
 	return ret;
 }
 
+int efi_handle_fdt(char *fdt_opt)
+{
+	unsigned long fdt_addr;
+	efi_status_t r;
+
+	if (fdt_opt) {
+		fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
+		if (!fdt_addr && *fdt_opt != '0')
+			return CMD_RET_USAGE;
+
+		/* Install device tree */
+		r = efi_install_fdt(fdt_addr);
+		if (r != EFI_SUCCESS) {
+			printf("ERROR: failed to install device tree\n");
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
+		efi_install_configuration_table(&efi_guid_fdt, NULL);
+		printf("WARNING: booting without device tree\n");
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_bootefi_exec() - execute EFI binary
  *
@@ -511,7 +536,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	unsigned long addr;
 	char *saddr;
 	efi_status_t r;
-	unsigned long fdt_addr;
 
 	/* Allow unaligned memory access */
 	allow_unaligned();
@@ -527,21 +551,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	if (argc > 2) {
-		fdt_addr = simple_strtoul(argv[2], NULL, 16);
-		if (!fdt_addr && *argv[2] != '0')
-			return CMD_RET_USAGE;
-		/* Install device tree */
-		r = efi_install_fdt(fdt_addr);
-		if (r != EFI_SUCCESS) {
-			printf("ERROR: failed to install device tree\n");
-			return CMD_RET_FAILURE;
-		}
-	} else {
-		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
-		efi_install_configuration_table(&efi_guid_fdt, NULL);
-		printf("WARNING: booting without device tree\n");
-	}
 #ifdef CONFIG_CMD_BOOTEFI_HELLO
 	if (!strcmp(argv[1], "hello")) {
 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
@@ -559,6 +568,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		struct efi_loaded_image_obj *image_obj;
 		struct efi_loaded_image *loaded_image_info;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
 		/* Construct a dummy device path. */
 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
 						      (uintptr_t)&efi_selftest,
@@ -583,7 +595,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else
 #endif
 	if (!strcmp(argv[1], "bootmgr")) {
-		return do_bootefi_bootmgr_exec();
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
 	} else {
 		saddr = argv[1];
 
@@ -592,6 +607,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (!addr && *saddr != '0')
 			return CMD_RET_USAGE;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
 	}
 
 	printf("## Starting EFI application at %08lx ...\n", addr);
cmd/efishell.h +0 -0
index 6f70b402b26b..1e5764a8a38d 100644
@@ -3,3 +3,4 @@
 #include <efi.h>
 
Quoted 5 lines

cmd/efishell.h line 6

Quoted 2 lines
cmd/efishell.h +1 -0
 efi_status_t efi_init_obj_list(void);
+int efi_handle_fdt(char *fdt_opt);

This should also go into efi_loader.h, as that's the subsystem that exports the function.

I hesitate to agree with you here as this function is provided as part of bootefi in the first place. Run command is just a variant of bootefi for efi binary. So it won't be seen as part of efi_loader function.

# In this sense, efishell.h should be renamed to bootefi.h?

Thanks,
-Takahiro Akashi

Quoted 2 lines

Alex

#27 lore raw

PATCH v2 10/14 cmd: bootefi: carve out fdt parameter handling

Quoted 126 lines · AKASHI Takahiro
Quoted 119 lines · Alexander Graf
Quoted 116 lines · AKASHI Takahiro

The current way how command parameters, particularly "fdt addr," are handled makes it a bit complicated to add a subcommand-specific parameter. So just refactor the code and extract efi_handle_fdt().

This commit is a preparatory change for enhancing bootmgr sub-command.

---
 cmd/bootefi.c  | 51 +++++++++++++++++++++++++++++++++-----------------
 cmd/efishell.h |  1 +
 2 files changed, 35 insertions(+), 17 deletions(-)
cmd/bootefi.c +34 -17
index 5d61819f1f5c..3aedf5a09f93 100644
@@ -356,6 +356,31 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
 	return ret;
 }
 
+int efi_handle_fdt(char *fdt_opt)
+{
+	unsigned long fdt_addr;
+	efi_status_t r;
+
+	if (fdt_opt) {
+		fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
+		if (!fdt_addr && *fdt_opt != '0')
+			return CMD_RET_USAGE;
+
+		/* Install device tree */
+		r = efi_install_fdt(fdt_addr);
+		if (r != EFI_SUCCESS) {
+			printf("ERROR: failed to install device tree\n");
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
+		efi_install_configuration_table(&efi_guid_fdt, NULL);
+		printf("WARNING: booting without device tree\n");
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_bootefi_exec() - execute EFI binary
  *
@@ -511,7 +536,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	unsigned long addr;
 	char *saddr;
 	efi_status_t r;
-	unsigned long fdt_addr;
 
 	/* Allow unaligned memory access */
 	allow_unaligned();
@@ -527,21 +551,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	if (argc > 2) {
-		fdt_addr = simple_strtoul(argv[2], NULL, 16);
-		if (!fdt_addr && *argv[2] != '0')
-			return CMD_RET_USAGE;
-		/* Install device tree */
-		r = efi_install_fdt(fdt_addr);
-		if (r != EFI_SUCCESS) {
-			printf("ERROR: failed to install device tree\n");
-			return CMD_RET_FAILURE;
-		}
-	} else {
-		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
-		efi_install_configuration_table(&efi_guid_fdt, NULL);
-		printf("WARNING: booting without device tree\n");
-	}
 #ifdef CONFIG_CMD_BOOTEFI_HELLO
 	if (!strcmp(argv[1], "hello")) {
 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
@@ -559,6 +568,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		struct efi_loaded_image_obj *image_obj;
 		struct efi_loaded_image *loaded_image_info;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
 		/* Construct a dummy device path. */
 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
 						      (uintptr_t)&efi_selftest,
@@ -583,7 +595,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else
 #endif
 	if (!strcmp(argv[1], "bootmgr")) {
-		return do_bootefi_bootmgr_exec();
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
 	} else {
 		saddr = argv[1];
 
@@ -592,6 +607,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (!addr && *saddr != '0')
 			return CMD_RET_USAGE;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
 	}
 
 	printf("## Starting EFI application at %08lx ...\n", addr);
cmd/efishell.h +0 -0
index 6f70b402b26b..1e5764a8a38d 100644
@@ -3,3 +3,4 @@
 #include <efi.h>
 
Quoted 5 lines

cmd/efishell.h line 6

Quoted 2 lines
cmd/efishell.h +1 -0
 efi_status_t efi_init_obj_list(void);
+int efi_handle_fdt(char *fdt_opt);

This should also go into efi_loader.h, as that's the subsystem that exports the function.

Quoted 5 lines

I hesitate to agree with you here as this function is provided as part of bootefi in the first place. Run command is just a variant of bootefi for efi binary. So it won't be seen as part of efi_loader function.

# In this sense, efishell.h should be renamed to bootefi.h?

Feel free to introduce a bootefi.h that contains all exports from bootefi.c, yes :).

Alex

#28 lore raw

PATCH v2 10/14 cmd: bootefi: carve out fdt parameter handling

Quoted 129 lines · Alexander Graf
Quoted 126 lines · AKASHI Takahiro
Quoted 124 lines · Alexander Graf
Quoted 114 lines · AKASHI Takahiro

The current way how command parameters, particularly "fdt addr," are handled makes it a bit complicated to add a subcommand-specific parameter. So just refactor the code and extract efi_handle_fdt().

This commit is a preparatory change for enhancing bootmgr sub-command.

---
 cmd/bootefi.c  | 51 +++++++++++++++++++++++++++++++++-----------------
 cmd/efishell.h |  1 +
 2 files changed, 35 insertions(+), 17 deletions(-)
cmd/bootefi.c +34 -17
index 5d61819f1f5c..3aedf5a09f93 100644
@@ -356,6 +356,31 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
 	return ret;
 }
 
+int efi_handle_fdt(char *fdt_opt)
+{
+	unsigned long fdt_addr;
+	efi_status_t r;
+
+	if (fdt_opt) {
+		fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
+		if (!fdt_addr && *fdt_opt != '0')
+			return CMD_RET_USAGE;
+
+		/* Install device tree */
+		r = efi_install_fdt(fdt_addr);
+		if (r != EFI_SUCCESS) {
+			printf("ERROR: failed to install device tree\n");
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
+		efi_install_configuration_table(&efi_guid_fdt, NULL);
+		printf("WARNING: booting without device tree\n");
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 /**
  * do_bootefi_exec() - execute EFI binary
  *
@@ -511,7 +536,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	unsigned long addr;
 	char *saddr;
 	efi_status_t r;
-	unsigned long fdt_addr;
 
 	/* Allow unaligned memory access */
 	allow_unaligned();
@@ -527,21 +551,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	if (argc > 2) {
-		fdt_addr = simple_strtoul(argv[2], NULL, 16);
-		if (!fdt_addr && *argv[2] != '0')
-			return CMD_RET_USAGE;
-		/* Install device tree */
-		r = efi_install_fdt(fdt_addr);
-		if (r != EFI_SUCCESS) {
-			printf("ERROR: failed to install device tree\n");
-			return CMD_RET_FAILURE;
-		}
-	} else {
-		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
-		efi_install_configuration_table(&efi_guid_fdt, NULL);
-		printf("WARNING: booting without device tree\n");
-	}
 #ifdef CONFIG_CMD_BOOTEFI_HELLO
 	if (!strcmp(argv[1], "hello")) {
 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
@@ -559,6 +568,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		struct efi_loaded_image_obj *image_obj;
 		struct efi_loaded_image *loaded_image_info;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
 		/* Construct a dummy device path. */
 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
 						      (uintptr_t)&efi_selftest,
@@ -583,7 +595,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else
 #endif
 	if (!strcmp(argv[1], "bootmgr")) {
-		return do_bootefi_bootmgr_exec();
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
 	} else {
 		saddr = argv[1];
 
@@ -592,6 +607,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (!addr && *saddr != '0')
 			return CMD_RET_USAGE;
 
+		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
+			return CMD_RET_FAILURE;
 	}
 
 	printf("## Starting EFI application at %08lx ...\n", addr);
cmd/efishell.h +0 -0
index 6f70b402b26b..1e5764a8a38d 100644

cmd/efishell.h line 6

Quoted 4 lines
cmd/efishell.h +1 -0
@@ -3,3 +3,4 @@
 #include <efi.h>
 
 efi_status_t efi_init_obj_list(void);
+int efi_handle_fdt(char *fdt_opt);

This should also go into efi_loader.h, as that's the subsystem that exports the function.

Quoted 8 lines
Quoted 5 lines

I hesitate to agree with you here as this function is provided as part of bootefi in the first place. Run command is just a variant of bootefi for efi binary. So it won't be seen as part of efi_loader function.

# In this sense, efishell.h should be renamed to bootefi.h?

Feel free to introduce a bootefi.h that contains all exports from bootefi.c, yes :).

OK, but due to your comment on a new do_bootefi_run() function, we may no longer need to export efi_handle_fdt() (at least for now). That's good.

-Takahiro Akashi

Quoted 2 lines

Alex

#29 lore raw

PATCH v2 11/14 cmd: bootefi: run an EFI application of a specific load option

In reply to AKASHI Takahiro

With this patch applied, we will be able to selectively execute an EFI application by specifying a load option, say "1" for Boot0001, "2" for Boot0002 and so on.

=> bootefi bootmgr <fdt addr> 1, or
bootefi bootmgr - 1

Please note that BootXXXX need not be included in "BootOrder".

---
 cmd/bootefi.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
cmd/bootefi.c +18 -6
index 3aedf5a09f93..7580008f691b 100644
@@ -509,13 +509,13 @@ exit:
 	return ret;
 }
 
-static int do_bootefi_bootmgr_exec(void)
+static int do_bootefi_bootmgr_exec(int boot_id)
 {
 	struct efi_device_path *device_path, *file_path;
 	void *addr;
 	efi_status_t r;
 
-	addr = efi_bootmgr_load(&device_path, &file_path);
+	addr = efi_bootmgr_load(boot_id, &device_path, &file_path);
 	if (!addr)
 		return 1;
 
@@ -595,8 +595,20 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else
 #endif
 	if (!strcmp(argv[1], "bootmgr")) {
-		if (efi_handle_fdt(argc > 2 ? argv[2] : NULL))
-			return CMD_RET_FAILURE;
+		char *endp;
+		int boot_id = -1;
+
+		if (argc > 2)
+			if (efi_handle_fdt((argv[2][0] == '-') ?
+					   NULL : argv[2]))
+				return CMD_RET_FAILURE;
+
+		if (argc > 3) {
+			boot_id = (int)simple_strtoul(argv[3], &endp, 0);
+			if ((argv[3] + strlen(argv[3]) != endp) ||
+			    boot_id > 0xffff)
+				return CMD_RET_USAGE;
+		}
 
 		return do_bootefi_bootmgr_exec(boot_id);
 	} else {
@@ -639,7 +651,7 @@ static char bootefi_help_text[] =
 	"    Use environment variable efi_selftest to select a single test.\n"
 	"    Use 'setenv efi_selftest list' to enumerate all tests.\n"
 #endif
-	"bootefi bootmgr [fdt addr]\n"
+	"bootefi bootmgr [<fdt addr>|'-' [<boot id>]]\n"
 	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
 	"\n"
 	"    If specified, the device tree located at <fdt address> gets\n"
@@ -647,7 +659,7 @@ static char bootefi_help_text[] =
 #endif
 
 U_BOOT_CMD(
-	bootefi, 3, 0, do_bootefi,
+	bootefi, 5, 0, do_bootefi,
 	"Boots an EFI payload from memory",
 	bootefi_help_text
 );
Signature · 1 line
2.19.0
#30 lore raw

PATCH v2 12/14 cmd: run: add "-e" option to run an EFI application

In reply to AKASHI Takahiro

"run -e" allows for executing EFI application with a specific "BootXXXX" variable. If no "BootXXXX" is specified or "BootOrder" is specified, it tries to run an EFI application specified in the order of "bootOrder."

---
 cmd/bootefi.c     |  2 +-
 cmd/nvedit.c      |  5 +++++
 common/cli.c      | 30 ++++++++++++++++++++++++++++++
 include/command.h |  3 +++
 4 files changed, 39 insertions(+), 1 deletion(-)
cmd/bootefi.c +1 -1
index 7580008f691b..3cefb4d0ecaa 100644
@@ -509,7 +509,7 @@ exit:
 	return ret;
 }
 
-static int do_bootefi_bootmgr_exec(int boot_id)
+int do_bootefi_bootmgr_exec(int boot_id)
 {
 	struct efi_device_path *device_path, *file_path;
 	void *addr;
cmd/nvedit.c +5 -0
index de16c72c23f2..c0facabfc4fe 100644
@@ -1343,8 +1343,13 @@ U_BOOT_CMD(
 U_BOOT_CMD_COMPLETE(
 	run,	CONFIG_SYS_MAXARGS,	1,	do_run,
 	"run commands in an environment variable",
+#if defined(CONFIG_CMD_BOOTEFI)
+	"var -e [BootXXXX]\n"
+	"    - load and run UEFI app based on 'BootXXXX' UEFI variable",
+#else
 	"var [...]\n"
 	"    - run the commands in the environment variable(s) 'var'",
+#endif
 	var_complete
 );
 #endif
common/cli.c +30 -0
index 51b8d5f85cbb..e4ec35b5eb00 100644
@@ -14,6 +14,7 @@
 #include <console.h>
 #include <fdtdec.h>
 #include <malloc.h>
+#include "../cmd/efishell.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -125,6 +126,35 @@ int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
+#ifdef CONFIG_CMD_BOOTEFI
+	if (!strcmp(argv[1], "-e")) {
+		int boot_id = -1;
+		char *endp;
+
+		if (argc == 3) {
+			if (!strcmp(argv[2], "BootOrder")) {
+				/* boot_id = -1 */;
+			} else if (!strncmp(argv[2], "Boot", 4)) {
+				boot_id = (int)simple_strtoul(&argv[2][4],
+							      &endp, 0);
+				if ((argv[2] + strlen(argv[2]) != endp) ||
+				    boot_id > 0xffff)
+					return CMD_RET_USAGE;
+			} else {
+				return CMD_RET_USAGE;
+			}
+		}
+
+		if (efi_init_obj_list())
+			return CMD_RET_FAILURE;
+
+		if (efi_handle_fdt(NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
+	}
+#endif
+
 	for (i = 1; i < argc; ++i) {
 		char *arg;
 
include/command.h +3 -0
index 5b1577f3b477..5bb675122cce 100644
@@ -48,6 +48,9 @@ typedef struct cmd_tbl_s	cmd_tbl_t;
 #if defined(CONFIG_CMD_RUN)
 extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
+#if defined(CONFIG_CMD_BOOTEFI)
+int do_bootefi_bootmgr_exec(int boot_id);
+#endif
 
 /* common/command.c */
 int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
Signature · 1 line
2.19.0
#31 lore raw

PATCH v2 12/14 cmd: run: add "-e" option to run an EFI application

Quoted 48 lines · AKASHI Takahiro

"run -e" allows for executing EFI application with a specific "BootXXXX" variable. If no "BootXXXX" is specified or "BootOrder" is specified, it tries to run an EFI application specified in the order of "bootOrder."

---
 cmd/bootefi.c     |  2 +-
 cmd/nvedit.c      |  5 +++++
 common/cli.c      | 30 ++++++++++++++++++++++++++++++
 include/command.h |  3 +++
 4 files changed, 39 insertions(+), 1 deletion(-)
cmd/bootefi.c +1 -1
index 7580008f691b..3cefb4d0ecaa 100644
@@ -509,7 +509,7 @@ exit:
 	return ret;
 }
 
-static int do_bootefi_bootmgr_exec(int boot_id)
+int do_bootefi_bootmgr_exec(int boot_id)
 {
 	struct efi_device_path *device_path, *file_path;
 	void *addr;
cmd/nvedit.c +5 -0
index de16c72c23f2..c0facabfc4fe 100644
@@ -1343,8 +1343,13 @@ U_BOOT_CMD(
 U_BOOT_CMD_COMPLETE(
 	run,	CONFIG_SYS_MAXARGS,	1,	do_run,
 	"run commands in an environment variable",
+#if defined(CONFIG_CMD_BOOTEFI)
+	"var -e [BootXXXX]\n"
+	"    - load and run UEFI app based on 'BootXXXX' UEFI variable",
+#else
 	"var [...]\n"
 	"    - run the commands in the environment variable(s) 'var'",
+#endif
 	var_complete
 );
 #endif
common/cli.c +0 -0
index 51b8d5f85cbb..e4ec35b5eb00 100644

common/cli.c line 17

Quoted 4 lines
common/cli.c +1 -0
@@ -14,6 +14,7 @@
 #include <console.h>
 #include <fdtdec.h>
 #include <malloc.h>
+#include "../cmd/efishell.h"

I guess this already shows that something is going wrong ;).

Please move the depending functions into lib/efi_loader. That way we can have the efishell command be optional, but keep this logic around regardless.

Quoted 5 lines
common/cli.c +0 -0
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -125,6 +126,35 @@ int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)

common/cli.c int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 136

Quoted 10 lines
common/cli.c +8 -0
 		return CMD_RET_USAGE;
 
+#ifdef CONFIG_CMD_BOOTEFI
+	if (!strcmp(argv[1], "-e")) {
+		int boot_id = -1;
+		char *endp;
+
+		if (argc == 3) {
+			if (!strcmp(argv[2], "BootOrder")) {
+				/* boot_id = -1 */;

Just write that in code. The compiler will optimize it out.

Quoted 29 lines
common/cli.c +21 -0
+			} else if (!strncmp(argv[2], "Boot", 4)) {
+				boot_id = (int)simple_strtoul(&argv[2][4],
+							      &endp, 0);
+				if ((argv[2] + strlen(argv[2]) != endp) ||
+				    boot_id > 0xffff)
+					return CMD_RET_USAGE;
+			} else {
+				return CMD_RET_USAGE;
+			}
+		}
+
+		if (efi_init_obj_list())
+			return CMD_RET_FAILURE;
+
+		if (efi_handle_fdt(NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
+	}
+#endif
+
 	for (i = 1; i < argc; ++i) {
 		char *arg;
 
include/command.h +0 -0
index 5b1577f3b477..5bb675122cce 100644

include/command.h typedef struct cmd_tbl_s cmd_tbl_t; · line 53

Quoted 6 lines
include/command.h +3 -0
@@ -48,6 +48,9 @@ typedef struct cmd_tbl_s	cmd_tbl_t;
 #if defined(CONFIG_CMD_RUN)
 extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
+#if defined(CONFIG_CMD_BOOTEFI)
+int do_bootefi_bootmgr_exec(int boot_id);
+#endif

This needs to be in efi_loader.h which then needs to get included from cli.c.

Alex

#32 lore raw

PATCH v2 12/14 cmd: run: add "-e" option to run an EFI application

Quoted 49 lines · Alexander Graf
Quoted 46 lines · AKASHI Takahiro

"run -e" allows for executing EFI application with a specific "BootXXXX" variable. If no "BootXXXX" is specified or "BootOrder" is specified, it tries to run an EFI application specified in the order of "bootOrder."

---
 cmd/bootefi.c     |  2 +-
 cmd/nvedit.c      |  5 +++++
 common/cli.c      | 30 ++++++++++++++++++++++++++++++
 include/command.h |  3 +++
 4 files changed, 39 insertions(+), 1 deletion(-)
cmd/bootefi.c +1 -1
index 7580008f691b..3cefb4d0ecaa 100644
@@ -509,7 +509,7 @@ exit:
 	return ret;
 }
 
-static int do_bootefi_bootmgr_exec(int boot_id)
+int do_bootefi_bootmgr_exec(int boot_id)
 {
 	struct efi_device_path *device_path, *file_path;
 	void *addr;
cmd/nvedit.c +5 -0
index de16c72c23f2..c0facabfc4fe 100644
@@ -1343,8 +1343,13 @@ U_BOOT_CMD(
 U_BOOT_CMD_COMPLETE(
 	run,	CONFIG_SYS_MAXARGS,	1,	do_run,
 	"run commands in an environment variable",
+#if defined(CONFIG_CMD_BOOTEFI)
+	"var -e [BootXXXX]\n"
+	"    - load and run UEFI app based on 'BootXXXX' UEFI variable",
+#else
 	"var [...]\n"
 	"    - run the commands in the environment variable(s) 'var'",
+#endif
 	var_complete
 );
 #endif
common/cli.c +0 -1
index 51b8d5f85cbb..e4ec35b5eb00 100644
--- a/common/cli.c
Quoted 8 lines

common/cli.c line 17

Quoted 6 lines

+++ b/common/cli.c

common/cli.c +1 -0
@@ -14,6 +14,7 @@
 #include <console.h>
 #include <fdtdec.h>
 #include <malloc.h>
+#include "../cmd/efishell.h"

I guess this already shows that something is going wrong ;).

efishell.h here is included solely for efi_init_obj_list() definition and so

Quoted 3 lines

Please move the depending functions into lib/efi_loader. That way we can have the efishell command be optional, but keep this logic around regardless.

I can assume that you agree to this function being moved to efi_setup.c.

Quoted 7 lines
Quoted 7 lines
common/cli.c +0 -0
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -125,6 +126,35 @@ int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
Quoted 10 lines

common/cli.c int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 136

Quoted 8 lines
common/cli.c +8 -0
+#ifdef CONFIG_CMD_BOOTEFI
+	if (!strcmp(argv[1], "-e")) {
+		int boot_id = -1;
+		char *endp;
+
+		if (argc == 3) {
+			if (!strcmp(argv[2], "BootOrder")) {
+				/* boot_id = -1 */;

Just write that in code. The compiler will optimize it out.

OK.

Quoted 24 lines
Quoted 24 lines
common/cli.c +21 -0
+			} else if (!strncmp(argv[2], "Boot", 4)) {
+				boot_id = (int)simple_strtoul(&argv[2][4],
+							      &endp, 0);
+				if ((argv[2] + strlen(argv[2]) != endp) ||
+				    boot_id > 0xffff)
+					return CMD_RET_USAGE;
+			} else {
+				return CMD_RET_USAGE;
+			}
+		}
+
+		if (efi_init_obj_list())
+			return CMD_RET_FAILURE;
+
+		if (efi_handle_fdt(NULL))
+			return CMD_RET_FAILURE;
+
+		return do_bootefi_bootmgr_exec(boot_id);
+	}
+#endif
+
 	for (i = 1; i < argc; ++i) {
 		char *arg;
 
Quoted 14 lines

include/command.h typedef struct cmd_tbl_s cmd_tbl_t; · line 53

Quoted 11 lines
include/command.h +3 -0
index 5b1577f3b477..5bb675122cce 100644
@@ -48,6 +48,9 @@ typedef struct cmd_tbl_s	cmd_tbl_t;
 #if defined(CONFIG_CMD_RUN)
 extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
+#if defined(CONFIG_CMD_BOOTEFI)
+int do_bootefi_bootmgr_exec(int boot_id);
+#endif

This needs to be in efi_loader.h which then needs to get included from cli.c.

After your comment above, you expect that do_bootefi_bootmgr_exec(), hence do_bootefi_exec() (and efi_handle_fdt()?) as well, be also moved to lib/efi_loader/(efi_bootmgr.c)?

Thanks,
-Takahiro Akashi

Quoted 2 lines

Alex

#33 lore raw

PATCH v2 13/14 cmd: efishell: export uefi variable helper functions

In reply to AKASHI Takahiro

Those function will be used for integration with 'env' command so as to handle uefi variables.

---
 cmd/efishell.c    | 4 ++--
 include/command.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)
cmd/efishell.c +2 -2
index bd2b99e74079..8122b842dd76 100644
@@ -68,7 +68,7 @@ static void dump_var_data(char *data, unsigned long len)
  *
  *   efi_$guid_$varname = {attributes}(type)value
  */
-static int do_efi_dump_var(int argc, char * const argv[])
+int do_efi_dump_var(int argc, char * const argv[])
 {
 	char regex[256];
 	char * const regexlist[] = {regex};
@@ -228,7 +228,7 @@ out:
 	return 0;
 }
 
-static int do_efi_set_var(int argc, char * const argv[])
+int do_efi_set_var(int argc, char * const argv[])
 {
 	char *var_name, *value = NULL;
 	unsigned long size = 0;
include/command.h +2 -0
index 5bb675122cce..2ce8b53f74c8 100644
@@ -50,6 +50,8 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
 #if defined(CONFIG_CMD_BOOTEFI)
 int do_bootefi_bootmgr_exec(int boot_id);
+int do_efi_dump_var(int argc, char * const argv[]);
+int do_efi_set_var(int argc, char * const argv[]);
 #endif
 
 /* common/command.c */
Signature · 1 line
2.19.0
#34 lore raw

PATCH v2 13/14 cmd: efishell: export uefi variable helper functions

Quoted 36 lines · AKASHI Takahiro

Those function will be used for integration with 'env' command so as to handle uefi variables.

---
 cmd/efishell.c    | 4 ++--
 include/command.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)
cmd/efishell.c +2 -2
index bd2b99e74079..8122b842dd76 100644
@@ -68,7 +68,7 @@ static void dump_var_data(char *data, unsigned long len)
  *
  *   efi_$guid_$varname = {attributes}(type)value
  */
-static int do_efi_dump_var(int argc, char * const argv[])
+int do_efi_dump_var(int argc, char * const argv[])
 {
 	char regex[256];
 	char * const regexlist[] = {regex};
@@ -228,7 +228,7 @@ out:
 	return 0;
 }
 
-static int do_efi_set_var(int argc, char * const argv[])
+int do_efi_set_var(int argc, char * const argv[])
 {
 	char *var_name, *value = NULL;
 	unsigned long size = 0;
include/command.h +0 -0
index 5bb675122cce..2ce8b53f74c8 100644

include/command.h extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); · line 54

Quoted 5 lines
include/command.h +2 -0
@@ -50,6 +50,8 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
 #if defined(CONFIG_CMD_BOOTEFI)
 int do_bootefi_bootmgr_exec(int boot_id);
+int do_efi_dump_var(int argc, char * const argv[]);
+int do_efi_set_var(int argc, char * const argv[]);

I guess you're seeing a pattern to my comments by now. This needs to go into efi_loader.h. The respective functions need to go into lib/efi_loader.

Alex

#35 lore raw

PATCH v2 13/14 cmd: efishell: export uefi variable helper functions

Quoted 38 lines · Alexander Graf
Quoted 35 lines · AKASHI Takahiro

Those function will be used for integration with 'env' command so as to handle uefi variables.

---
 cmd/efishell.c    | 4 ++--
 include/command.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)
cmd/efishell.c +2 -2
index bd2b99e74079..8122b842dd76 100644
@@ -68,7 +68,7 @@ static void dump_var_data(char *data, unsigned long len)
  *
  *   efi_$guid_$varname = {attributes}(type)value
  */
-static int do_efi_dump_var(int argc, char * const argv[])
+int do_efi_dump_var(int argc, char * const argv[])
 {
 	char regex[256];
 	char * const regexlist[] = {regex};
@@ -228,7 +228,7 @@ out:
 	return 0;
 }
 
-static int do_efi_set_var(int argc, char * const argv[])
+int do_efi_set_var(int argc, char * const argv[])
 {
 	char *var_name, *value = NULL;
 	unsigned long size = 0;
include/command.h +0 -0
index 5bb675122cce..2ce8b53f74c8 100644
Quoted 8 lines

include/command.h extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); · line 54

Quoted 6 lines
include/command.h +2 -0
@@ -50,6 +50,8 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
 #if defined(CONFIG_CMD_BOOTEFI)
 int do_bootefi_bootmgr_exec(int boot_id);
+int do_efi_dump_var(int argc, char * const argv[]);
+int do_efi_set_var(int argc, char * const argv[]);

I guess you're seeing a pattern to my comments by now.

Definitely, but

Quoted 2 lines

This needs to go
into efi_loader.h. The respective functions need to go into lib/efi_loader.

Those two functions are dedicated for command interfaces, and in my opinion, it is hard for them to be seen as part of efi_loader functionality.

Thanks,
-Takahiro Akashi

Quoted 3 lines

Alex

#36 lore raw

PATCH v2 13/14 cmd: efishell: export uefi variable helper functions

Quoted 48 lines · AKASHI Takahiro
Quoted 38 lines · Alexander Graf
Quoted 35 lines · AKASHI Takahiro

Those function will be used for integration with 'env' command so as to handle uefi variables.

---
 cmd/efishell.c    | 4 ++--
 include/command.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)
cmd/efishell.c +2 -2
index bd2b99e74079..8122b842dd76 100644
@@ -68,7 +68,7 @@ static void dump_var_data(char *data, unsigned long len)
  *
  *   efi_$guid_$varname = {attributes}(type)value
  */
-static int do_efi_dump_var(int argc, char * const argv[])
+int do_efi_dump_var(int argc, char * const argv[])
 {
 	char regex[256];
 	char * const regexlist[] = {regex};
@@ -228,7 +228,7 @@ out:
 	return 0;
 }
 
-static int do_efi_set_var(int argc, char * const argv[])
+int do_efi_set_var(int argc, char * const argv[])
 {
 	char *var_name, *value = NULL;
 	unsigned long size = 0;
include/command.h +0 -0
index 5bb675122cce..2ce8b53f74c8 100644
Quoted 8 lines

include/command.h extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); · line 54

Quoted 6 lines
include/command.h +2 -0
@@ -50,6 +50,8 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
 #if defined(CONFIG_CMD_BOOTEFI)
 int do_bootefi_bootmgr_exec(int boot_id);
+int do_efi_dump_var(int argc, char * const argv[]);
+int do_efi_set_var(int argc, char * const argv[]);

I guess you're seeing a pattern to my comments by now.

Quoted 7 lines

Definitely, but

Quoted 2 lines

This needs to go
into efi_loader.h. The respective functions need to go into lib/efi_loader.

Those two functions are dedicated for command interfaces, and in my opinion, it is hard for them to be seen as part of efi_loader functionality.

Same comment here then :). Feel free to introduce a new header file for bootefi bits, but I'm not a big fan of a giant command.h that just exposes all possible command handlers in the world.

Alex

#37 lore raw

PATCH v2 13/14 cmd: efishell: export uefi variable helper functions

Quoted 56 lines · Alexander Graf
Quoted 53 lines · AKASHI Takahiro
Quoted 38 lines · Alexander Graf
Quoted 35 lines · AKASHI Takahiro

Those function will be used for integration with 'env' command so as to handle uefi variables.

---
 cmd/efishell.c    | 4 ++--
 include/command.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)
cmd/efishell.c +2 -2
index bd2b99e74079..8122b842dd76 100644
@@ -68,7 +68,7 @@ static void dump_var_data(char *data, unsigned long len)
  *
  *   efi_$guid_$varname = {attributes}(type)value
  */
-static int do_efi_dump_var(int argc, char * const argv[])
+int do_efi_dump_var(int argc, char * const argv[])
 {
 	char regex[256];
 	char * const regexlist[] = {regex};
@@ -228,7 +228,7 @@ out:
 	return 0;
 }
 
-static int do_efi_set_var(int argc, char * const argv[])
+int do_efi_set_var(int argc, char * const argv[])
 {
 	char *var_name, *value = NULL;
 	unsigned long size = 0;
include/command.h +0 -0
index 5bb675122cce..2ce8b53f74c8 100644
Quoted 8 lines

include/command.h extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); · line 54

Quoted 6 lines
include/command.h +2 -0
@@ -50,6 +50,8 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 #endif
 #if defined(CONFIG_CMD_BOOTEFI)
 int do_bootefi_bootmgr_exec(int boot_id);
+int do_efi_dump_var(int argc, char * const argv[]);
+int do_efi_set_var(int argc, char * const argv[]);

I guess you're seeing a pattern to my comments by now.

Definitely, but

Quoted 2 lines

This needs to go
into efi_loader.h. The respective functions need to go into lib/efi_loader.

Quoted 6 lines
Quoted 2 lines

Those two functions are dedicated for command interfaces, and in my opinion, it is hard for them to be seen as part of efi_loader functionality.

Same comment here then :). Feel free to introduce a new header file for bootefi bits, but I'm not a big fan of a giant command.h that just exposes all possible command handlers in the world.

I've assumed that all the do_xxx() stuff should go into command.h. I will leave them in command.h for now.

-Takahiro Akashi

Quoted 2 lines

Alex

#38 lore raw

PATCH v2 14/14 cmd: env: add "-e" option for handling UEFI variables

In reply to AKASHI Takahiro

"env [print|set] -e" allows for handling uefi variables without knowing details about mapping to corresponding u-boot variables.

---
 cmd/nvedit.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)
cmd/nvedit.c +57 -1
index c0facabfc4fe..1925483c0285 100644
@@ -36,6 +36,7 @@
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
+#include "efishell.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -119,6 +120,25 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
 	int rcode = 0;
 	int env_flag = H_HIDE_DOT;
 
+#if defined(CONFIG_CMD_BOOTEFI)
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
+		efi_status_t r;
+
+		argc--;
+		argv++;
+
+		/* Initialize EFI drivers */
+		r = efi_init_obj_list();
+		if (r != EFI_SUCCESS) {
+			printf("Error: Cannot set up EFI drivers, r = %lu\n",
+			       r & ~EFI_ERROR_MASK);
+			return CMD_RET_FAILURE;
+		}
+
+		return do_efi_dump_var(argc, argv);
+	}
+#endif
+
 	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
 		argc--;
 		argv++;
@@ -216,6 +236,26 @@ static int _do_env_set(int flag, int argc, char * const argv[], int env_flag)
 	ENTRY e, *ep;
 
 	debug("Initial value for argc=%d\n", argc);
+
+#if defined(CONFIG_CMD_BOOTEFI)
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
+		efi_status_t r;
+
+		argc--;
+		argv++;
+
+		/* Initialize EFI drivers */
+		r = efi_init_obj_list();
+		if (r != EFI_SUCCESS) {
+			printf("Error: Cannot set up EFI drivers, r = %lu\n",
+			       r & ~EFI_ERROR_MASK);
+			return CMD_RET_FAILURE;
+		}
+
+		return do_efi_set_var(argc, argv);
+	}
+#endif
+
 	while (argc > 1 && **(argv + 1) == '-') {
 		char *arg = *++argv;
 
@@ -1262,15 +1302,23 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_IMPORTENV)
 	"env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import environment\n"
 #endif
+#if defined(CONFIG_CMD_BOOTEFI)
+	"env print [-a | -e [name] | name ...] - print environment\n"
+#else
 	"env print [-a | name ...] - print environment\n"
+#endif
 #if defined(CONFIG_CMD_RUN)
 	"env run var [...] - run commands in an environment variable\n"
 #endif
 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
 	"env save - save environment\n"
 #endif
+#if defined(CONFIG_CMD_BOOTEFI)
+	"env set [-e | -f] name [arg ...]\n";
+#else
 	"env set [-f] name [arg ...]\n";
 #endif
+#endif
 
 U_BOOT_CMD(
 	env, CONFIG_SYS_MAXARGS, 1, do_env,
@@ -1295,6 +1343,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_BOOTEFI)
+	"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 +1374,11 @@ U_BOOT_CMD_COMPLETE(
 U_BOOT_CMD_COMPLETE(
 	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
 	"set environment variables",
-	"[-f] name value ...\n"
+#if defined(CONFIG_CMD_BOOTEFI)
+	"-e <name> [<value>]\n"
+	"    - set UEFI variable 'name' to 'value' ...'\n"
+#endif
+	"setenv [-f] name value ...\n"
 	"    - [forcibly] set environment variable 'name' to 'value ...'\n"
 	"setenv [-f] name\n"
 	"    - [forcibly] delete environment variable 'name'",
Signature · 1 line
2.19.0