summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Janssen <medhefgo@web.de>2021-10-20 12:15:03 +0200
committerLennart Poettering <lennart@poettering.net>2021-10-22 19:12:55 +0200
commite6cab77eca8f6556f381c348b0452b526a752ab7 (patch)
treeea85e5a79aa0cf20091b87d876fca3daa3022ec8
parent784c249f41f8899337975941a5b34ea9497334b7 (diff)
downloadsystemd-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.xml5
-rw-r--r--man/systemd-boot.xml9
-rw-r--r--src/boot/efi/boot.c61
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++)