]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: Add keys to reboot into firmware interface
authorJan Janssen <medhefgo@web.de>
Wed, 20 Oct 2021 10:15:03 +0000 (12:15 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 22 Oct 2021 17:12:55 +0000 (19:12 +0200)
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.

man/loader.conf.xml
man/systemd-boot.xml
src/boot/efi/boot.c

index 26e83dfcab8d5b8943e10145ed009b6416b2d932..3a954a3ce9420cc49801136082b62e04ed2bfb3d 100644 (file)
       <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>
index b7b06bd5eb276820054df8e12e559af3a5ad8110..3fad947b0d23fac7e4fd71c8c5163821e9e70781 100644 (file)
         <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
index ba097bf20cefc389ee07e054c31f180effbe49b7..729e199fcc4a24e3f46ab41e04bbccd72c8c10a9 100644 (file)
@@ -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++)