diff options
author | Jan Janssen <medhefgo@web.de> | 2021-10-20 12:15:03 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-10-22 19:12:55 +0200 |
commit | e6cab77eca8f6556f381c348b0452b526a752ab7 (patch) | |
tree | ea85e5a79aa0cf20091b87d876fca3daa3022ec8 | |
parent | 784c249f41f8899337975941a5b34ea9497334b7 (diff) | |
download | systemd-e6cab77eca8f6556f381c348b0452b526a752ab7.tar.gz |
sd-boot: Add keys to reboot into firmware interface
This is useful if the auto-firmware setting has been disabled. The
keys used here are based on what the majority of firmware employ in
the wild.
This also ensures there's a chance for the user to discover this in
case they were too slow during POST or simply used the wrong ones.
-rw-r--r-- | man/loader.conf.xml | 5 | ||||
-rw-r--r-- | man/systemd-boot.xml | 9 | ||||
-rw-r--r-- | src/boot/efi/boot.c | 61 |
3 files changed, 53 insertions, 22 deletions
diff --git a/man/loader.conf.xml b/man/loader.conf.xml index 26e83dfcab..3a954a3ce9 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -188,8 +188,9 @@ <varlistentry> <term>auto-firmware</term> - <listitem><para>Takes a boolean argument. Enable (the default) or disable - the "Reboot into firmware" entry.</para></listitem> + <listitem><para>A boolean controlling the presence of the "Reboot into firmware" entry + (enabled by default). If this is disabled, the firmware interface may still be reached + by using the <keycap>f</keycap> key.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml index b7b06bd5eb..3fad947b0d 100644 --- a/man/systemd-boot.xml +++ b/man/systemd-boot.xml @@ -178,6 +178,15 @@ <term><keycap>F1</keycap></term> <listitem><para>Show a help screen</para></listitem> </varlistentry> + + <varlistentry> + <term><keycap>f</keycap></term> + <listitem><para>Reboot into firmware interface.</para> + + <para>For compatibility with the keybindings of several firmware implementations this operation + may also be reached with <keycap>F2</keycap>, <keycap>F10</keycap>, <keycap>Del</keycap> and + <keycap>Esc</keycap>.</para></listitem> + </varlistentry> </variablelist> <para>The following keys may be pressed during bootup or in the boot menu to directly boot a specific diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index ba097bf20c..729e199fcc 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -543,6 +543,24 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) { } } +static EFI_STATUS reboot_into_firmware(void) { + UINT64 osind = 0; + EFI_STATUS err; + + if (!(get_os_indications_supported() & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) + return log_error_status_stall(EFI_UNSUPPORTED, L"Reboot to firmware interface not supported."); + + (void) efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &osind); + osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + + err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", osind, EFI_VARIABLE_NON_VOLATILE); + if (EFI_ERROR(err)) + return log_error_status_stall(err, L"Error setting OsIndications: %r", err); + + err = RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + return log_error_status_stall(err, L"Error calling ResetSystem: %r", err); +} + static BOOLEAN menu_run( Config *config, ConfigEntry **chosen_entry, @@ -566,7 +584,7 @@ static BOOLEAN menu_run( UINT32 timeout_efivar_saved = config->timeout_sec_efivar; UINT32 timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec; INT16 idx; - BOOLEAN exit = FALSE, run = TRUE; + BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE; INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar; graphics_mode(FALSE); @@ -738,6 +756,13 @@ static BOOLEAN menu_run( idx_highlight_prev = idx_highlight; + if (firmware_setup) { + firmware_setup = FALSE; + if (key == KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN)) + reboot_into_firmware(); + continue; + } + switch (key) { case KEYPRESS(0, SCAN_UP, 0): case KEYPRESS(0, 0, 'k'): @@ -794,7 +819,7 @@ static BOOLEAN menu_run( case KEYPRESS(0, 0, 'h'): case KEYPRESS(0, 0, 'H'): case KEYPRESS(0, 0, '?'): - /* This must stay below 80 characters! Q/v/Ctrl+l deliberately not advertised. */ + /* This must stay below 80 characters! Q/v/Ctrl+l/f deliberately not advertised. */ status = StrDuplicate(L"(d)efault (t/T)timeout (e)dit (r/R)resolution (p)rint (h)elp"); break; @@ -888,6 +913,20 @@ static BOOLEAN menu_run( new_mode = TRUE; break; + case KEYPRESS(0, 0, 'f'): + case KEYPRESS(0, 0, 'F'): + case KEYPRESS(0, SCAN_F2, 0): /* Most vendors. */ + case KEYPRESS(0, SCAN_F10, 0): /* HP and Lenovo. */ + case KEYPRESS(0, SCAN_DELETE, 0): /* Same as F2. */ + case KEYPRESS(0, SCAN_ESC, 0): /* HP. */ + if (get_os_indications_supported() & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) { + firmware_setup = TRUE; + /* Let's make sure the user really wants to do this. */ + status = PoolPrint(L"Press Enter to reboot into firmware interface."); + } else + status = PoolPrint(L"Reboot into firmware interface not supported."); + break; + default: /* jump with a hotkey directly to a matching entry */ idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key)); @@ -2180,24 +2219,6 @@ out_unload: return err; } -static EFI_STATUS reboot_into_firmware(void) { - UINT64 old, new; - EFI_STATUS err; - - new = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; - - err = efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &old); - if (!EFI_ERROR(err)) - new |= old; - - err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", new, EFI_VARIABLE_NON_VOLATILE); - if (EFI_ERROR(err)) - return err; - - err = RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); - return log_error_status_stall(err, L"Error calling ResetSystem: %r", err); -} - static void config_free(Config *config) { assert(config); for (UINTN i = 0; i < config->entry_count; i++) |