diff mbox series

[U-Boot,v4,1/1] efi_loader: bootmgr: support BootNext and BootCurrent variable behavior

Message ID 20190320000755.27049-2-takahiro.akashi@linaro.org
State Accepted, archived
Commit 37279ad3eeed5285c2fee4ed9eb24d110515fe3f
Delegated to: Heinrich Schuchardt
Headers show
Series efi_loader: support BootNext and BootCurrent | expand

Commit Message

AKASHI Takahiro March 20, 2019, 12:07 a.m. UTC
See UEFI v2.7, section 3.1.2 for details of the specification.

With efidebug command, you can run any EFI boot option as follows:
  => efi boot add 1 SHELL ...
  => efi boot add 2 HELLO ...
  => efi boot order 1 2
  => efi bootmgr
     (starting SHELL ...)

  => efi boot next 2
  => efi bootmgr
     (starting HELLO ...)
  => env print -e
  <snip ...>
  BootCurrent: {boot,run}(blob)
  00000000:  02 00                    ..
  BootOrder: {boot,run}(blob)
  00000000:  01 00 02 00              ....

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 lib/efi_loader/efi_bootmgr.c | 51 +++++++++++++++++++++++++++++++++---
 1 file changed, 47 insertions(+), 4 deletions(-)

Comments

Heinrich Schuchardt March 20, 2019, 7:01 a.m. UTC | #1
On 3/20/19 1:07 AM, AKASHI Takahiro wrote:
> See UEFI v2.7, section 3.1.2 for details of the specification.
>
> With efidebug command, you can run any EFI boot option as follows:
>   => efi boot add 1 SHELL ...
>   => efi boot add 2 HELLO ...
>   => efi boot order 1 2
>   => efi bootmgr
>      (starting SHELL ...)
>
>   => efi boot next 2
>   => efi bootmgr
>      (starting HELLO ...)
>   => env print -e
>   <snip ...>
>   BootCurrent: {boot,run}(blob)
>   00000000:  02 00                    ..
>   BootOrder: {boot,run}(blob)
>   00000000:  01 00 02 00              ....
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Heinrich Schuchardt March 27, 2019, 9:31 p.m. UTC | #2
On 3/20/19 8:01 AM, Heinrich Schuchardt wrote:
> On 3/20/19 1:07 AM, AKASHI Takahiro wrote:
>> See UEFI v2.7, section 3.1.2 for details of the specification.
>>
>> With efidebug command, you can run any EFI boot option as follows:
>>   => efi boot add 1 SHELL ...
>>   => efi boot add 2 HELLO ...
>>   => efi boot order 1 2
>>   => efi bootmgr
>>      (starting SHELL ...)
>>
>>   => efi boot next 2
>>   => efi bootmgr
>>      (starting HELLO ...)
>>   => env print -e
>>   <snip ...>
>>   BootCurrent: {boot,run}(blob)
>>   00000000:  02 00                    ..
>>   BootOrder: {boot,run}(blob)
>>   00000000:  01 00 02 00              ....
>>
>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>
> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
>

Added to efi-2019-07 branch.
diff mbox series

Patch

diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 417016102b48..4fccadc5483d 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -141,6 +141,7 @@  static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
 	efi_deserialize_load_option(&lo, load_option);
 
 	if (lo.attributes & LOAD_OPTION_ACTIVE) {
+		u32 attributes;
 		efi_status_t ret;
 
 		debug("%s: trying to load \"%ls\" from %pD\n",
@@ -151,6 +152,16 @@  static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
 		if (ret != EFI_SUCCESS)
 			goto error;
 
+		attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			     EFI_VARIABLE_RUNTIME_ACCESS;
+		size = sizeof(n);
+		ret = EFI_CALL(efi_set_variable(
+				L"BootCurrent",
+				(efi_guid_t *)&efi_global_variable_guid,
+				attributes, size, &n));
+		if (ret != EFI_SUCCESS)
+			goto error;
+
 		printf("Booting: %ls\n", lo.label);
 		efi_dp_split_file_path(lo.file_path, device_path, file_path);
 	}
@@ -162,21 +173,53 @@  error:
 }
 
 /*
- * Attempt to load, in the order specified by BootOrder EFI variable, the
- * available load-options, finding and returning the first one that can
- * be loaded successfully.
+ * Attempt to load from BootNext or in the order specified by BootOrder
+ * EFI variable, the available load-options, finding and returning
+ * the first one that can be loaded successfully.
  */
 void *efi_bootmgr_load(struct efi_device_path **device_path,
 		       struct efi_device_path **file_path)
 {
-	uint16_t *bootorder;
+	u16 bootnext, *bootorder;
 	efi_uintn_t size;
 	void *image = NULL;
 	int i, num;
+	efi_status_t ret;
 
 	bs = systab.boottime;
 	rs = systab.runtime;
 
+	/* BootNext */
+	bootnext = 0;
+	size = sizeof(bootnext);
+	ret = EFI_CALL(efi_get_variable(L"BootNext",
+					(efi_guid_t *)&efi_global_variable_guid,
+					NULL, &size, &bootnext));
+	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
+		/* BootNext does exist here */
+		if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16))
+			printf("BootNext must be 16-bit integer\n");
+
+		/* delete BootNext */
+		ret = EFI_CALL(efi_set_variable(
+					L"BootNext",
+					(efi_guid_t *)&efi_global_variable_guid,
+					0, 0, &bootnext));
+
+		/* load BootNext */
+		if (ret == EFI_SUCCESS) {
+			if (size == sizeof(u16)) {
+				image = try_load_entry(bootnext, device_path,
+						       file_path);
+				if (image)
+					return image;
+			}
+		} else {
+			printf("Deleting BootNext failed\n");
+		}
+	}
+
+	/* BootOrder */
 	bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
 	if (!bootorder) {
 		printf("BootOrder not defined\n");