summaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_bootmgr.c
diff options
context:
space:
mode:
authorAKASHI Takahiro <takahiro.akashi@linaro.org>2019-03-20 03:07:55 +0300
committerHeinrich Schuchardt <xypron.glpk@gmx.de>2019-04-07 15:17:06 +0300
commit37279ad3eeed5285c2fee4ed9eb24d110515fe3f (patch)
treec700f385b39c4cf64797ff48579953201828c620 /lib/efi_loader/efi_bootmgr.c
parentb0c3c346c6d7ec44363037ad55fdfad4c3b474d1 (diff)
downloadu-boot-37279ad3eeed5285c2fee4ed9eb24d110515fe3f.tar.xz
efi_loader: bootmgr: support BootNext and BootCurrent variable behavior
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>
Diffstat (limited to 'lib/efi_loader/efi_bootmgr.c')
-rw-r--r--lib/efi_loader/efi_bootmgr.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 417016102b..4fccadc548 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");