]> code.delx.au - refind/commitdiff
New "Reboot to Firmware User Interface" feature.
authorsrs5694 <srs5694@users.sourceforge.net>
Sun, 28 Apr 2013 17:58:53 +0000 (13:58 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Sun, 28 Apr 2013 17:58:53 +0000 (13:58 -0400)
CREDITS.txt
NEWS.txt
docs/refind/configfile.html
include/tiano_includes.h
refind.conf-sample
refind/config.c
refind/global.h
refind/icns.c
refind/icns.h
refind/main.c

index b21792eb10af25c217f3e1712f7de6e740f3e9d8..0ed0b4761fef58e8f653eb4caaff3a344ffe42f4 100644 (file)
@@ -24,7 +24,7 @@ Program (C source code) files:
   VirtualBox (https://www.virtualbox.org) and the Clover boot loader
   project (https://sourceforge.net/projects/cloverefiboot/). The
   filesystem-specific code comes from various sources, including Apple,
   VirtualBox (https://www.virtualbox.org) and the Clover boot loader
   project (https://sourceforge.net/projects/cloverefiboot/). The
   filesystem-specific code comes from various sources, including Apple,
-  the Linux kernel, and Christoph Phisterer.
+  the Linux kernel, and Christoph Pfisterer.
 
 * Assorted support code is borrowed from the TianoCore EDK2
   (https://sourceforge.net/projects/tianocore/), which is the reference
 
 * Assorted support code is borrowed from the TianoCore EDK2
   (https://sourceforge.net/projects/tianocore/), which is the reference
@@ -37,7 +37,8 @@ Program (C source code) files:
   OSes on UEFI-based PCs.
 
 * The code for editing boot options (cursor_left(), cursor_right(), and
   OSes on UEFI-based PCs.
 
 * The code for editing boot options (cursor_left(), cursor_right(), and
-  line_edit() in screen.c) is taken from gummiboot.
+  line_edit() in screen.c) is taken from gummiboot
+  (http://freedesktop.org/wiki/Software/gummiboot).
 
 * Stefan Agner (stefan@agner.ch) turned the original ext2fs/ext3fs driver
   into one that can read ext4fs.
 
 * Stefan Agner (stefan@agner.ch) turned the original ext2fs/ext3fs driver
   into one that can read ext4fs.
@@ -55,7 +56,8 @@ Program (C source code) files:
 
 * The PNG support, in the files libeg/lodepng.c and libeg/lodepng.h, is a
   slightly modified version of LodePNG (http://lodev.org/lodepng/) by Lode
 
 * The PNG support, in the files libeg/lodepng.c and libeg/lodepng.h, is a
   slightly modified version of LodePNG (http://lodev.org/lodepng/) by Lode
-  Vandevenne.
+  Vandevenne. (The libeg/lodepng_xtra.c file provides some necessary
+  ancillary and interface functions written by me.)
 
 Icons and graphics:
 -------------------
 
 Icons and graphics:
 -------------------
index ea04e3fe681138e8a5c1dad627b395d8ce37a6b2..46ce92fc514c43e4ef96d8755875663457d49fc1 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,6 +1,13 @@
 0.6.10 (?/??/2013):
 -------------------
 
 0.6.10 (?/??/2013):
 -------------------
 
+- Added new option to reboot the computer into the firmware's user
+  interface. This option is active by default, or can be set via the
+  "firmware" option to the "showtools" token in refind.conf. It works
+  on only some computers, though; older computers lack this feature, and
+  when rEFInd is told to use this feature on such computers, the directive
+  is quietly ignored.
+
 - Upgraded LodePNG library from version 20121216 to 20130415 and
   restructured rEFInd-specific modifications to simplify future upgrades.
 
 - Upgraded LodePNG library from version 20121216 to 20130415 and
   restructured rEFInd-specific modifications to simplify future upgrades.
 
index 85ceea9aaa09b74654153013e475b6732c5128f6..73c0ca76f44c5f5eb38f10677ee626929a3c224a 100644 (file)
@@ -238,8 +238,8 @@ timeout 20
 </tr>
 <tr>
    <td><tt>showtools</tt></td>
 </tr>
 <tr>
    <td><tt>showtools</tt></td>
-   <td><tt>shell</tt>, <tt>gptsync</tt>, <tt>apple_recovery</tt>, <tt>mok_tool</tt>, <tt>about</tt>, <tt>exit</tt>, <tt>shutdown</tt>, and <tt>reboot</tt></td>
-   <td>Specifies which tool tags to display on the second row. <tt>shell</tt> launches an EFI shell, <tt>gptsync</tt> launches a tool that creates a hybrid MBR, <tt>apple_recovery</tt> boots the OS X Recovery HD, <tt>mok_tool</tt> launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, <tt>about</tt> displays information about the program, <tt>exit</tt> terminates rEFInd, <tt>shutdown</tt> shuts down the computer (or reboots it, on some UEFI PCs), and <tt>reboot</tt> reboots the computer. The tags appear in the order in which you specify them. The default is <tt>shell, apple_recovery, mok_tool, about, shutdown, reboot</tt>. Note that the <tt>shell</tt>, <tt>apple_recovery</tt>, and <tt>mok_tool</tt> options all require the presence of programs not included with rEFInd. The <tt>gptsync</tt> option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the <a href="installing.html#addons">"Installing Additional Components"</a> section of the <a href="installing.html">Installing rEFInd</a> page for pointers to the shell and <tt>gptsync</tt> programs. The <tt>apple_recovery</tt> option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called <tt>com.apple.recovery.boot/boot.efi</tt>). See the <a href="secureboot.html">Secure Boot</a> page for information on Secure Boot and MOK management.</td>
+   <td><tt>shell</tt>, <tt>gptsync</tt>, <tt>apple_recovery</tt>, <tt>mok_tool</tt>, <tt>about</tt>, <tt>exit</tt>, <tt>shutdown</tt>, <tt>reboot</tt>, and <tt>firmware</tt></td>
+   <td>Specifies which tool tags to display on the second row. <tt>shell</tt> launches an EFI shell, <tt>gptsync</tt> launches a tool that creates a hybrid MBR, <tt>apple_recovery</tt> boots the OS X Recovery HD, <tt>mok_tool</tt> launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, <tt>about</tt> displays information about the program, <tt>exit</tt> terminates rEFInd, <tt>shutdown</tt> shuts down the computer (or reboots it, on some UEFI PCs), <tt>reboot</tt> reboots the computer, and <tt>firmware</tt> reboots the computer into the firmware's own user interface. The tags appear in the order in which you specify them. The default is <tt>shell, apple_recovery, mok_tool, about, shutdown, reboot, firmware</tt>. Note that the <tt>shell</tt>, <tt>apple_recovery</tt>, and <tt>mok_tool</tt> options all require the presence of programs not included with rEFInd. The <tt>gptsync</tt> option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the <a href="installing.html#addons">"Installing Additional Components"</a> section of the <a href="installing.html">Installing rEFInd</a> page for pointers to the shell and <tt>gptsync</tt> programs. The <tt>apple_recovery</tt> option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called <tt>com.apple.recovery.boot/boot.efi</tt>). The <tt>firmware</tt> option works only on computers that support this option; on other computers, the option is quietly ignored. See the <a href="secureboot.html">Secure Boot</a> page for information on Secure Boot and MOK management.</td>
 </tr>
 <tr>
    <td><tt>font</tt></td>
 </tr>
 <tr>
    <td><tt>font</tt></td>
index 07eb2b1697360830194ee3aa7754162e3381fe74..9611243a537e7de83b9b9e7e4d6d12587d9e00f9 100644 (file)
@@ -14,6 +14,7 @@
 #define Atoi StrDecimalToUintn
 #define SPrint UnicodeSPrint
 #define StrDuplicate EfiStrDuplicate
 #define Atoi StrDecimalToUintn
 #define SPrint UnicodeSPrint
 #define StrDuplicate EfiStrDuplicate
+#define EFI_MAXIMUM_VARIABLE_SIZE           1024
 
 #include <PiDxe.h>
 #include <Base.h>
 
 #include <PiDxe.h>
 #include <Base.h>
index a9c28df4b131226ea8477316bc48a2f2d1f47b8b..8a8b3f9f4d310ae4b4f46c9829b6ddcfdf78a156 100644 (file)
@@ -137,9 +137,11 @@ timeout 20
 #  shutdown        - shuts down the computer (a bug causes this to reboot
 #                    EFI systems)
 #  reboot          - a tag to reboot the computer
 #  shutdown        - shuts down the computer (a bug causes this to reboot
 #                    EFI systems)
 #  reboot          - a tag to reboot the computer
-# Default is shell,apple_recovery,mok_tool,about,shutdown,reboot
+#  firmware        - a tag to reboot the computer into the firmware's
+#                    user interface (ignored on older computers)
+# Default is shell,apple_recovery,mok_tool,about,shutdown,reboot,firmware
 #
 #
-#showtools shell, mok_tool, about, reboot, exit
+#showtools shell, mok_tool, about, reboot, exit, firmware
 
 # Directories in which to search for EFI drivers. These drivers can
 # provide filesystem support, give access to hard disks on plug-in
 
 # Directories in which to search for EFI drivers. These drivers can
 # provide filesystem support, give access to hard disks on plug-in
index 871b0e69e538ab2f4d7637aac9dcd8bd52ff20a3..36f0464ae4ea06aebb8f343cbc78851cdb59b02f 100644 (file)
@@ -463,6 +463,8 @@ VOID ReadConfig(CHAR16 *FileName)
                    GlobalConfig.ShowTools[i - 1] = TAG_APPLE_RECOVERY;
                 } else if (StriCmp(FlagName, L"mok_tool") == 0) {
                    GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL;
                    GlobalConfig.ShowTools[i - 1] = TAG_APPLE_RECOVERY;
                 } else if (StriCmp(FlagName, L"mok_tool") == 0) {
                    GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL;
+                } else if (StriCmp(FlagName, L"firmware") == 0) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_FIRMWARE;
                 } else {
                    Print(L" unknown showtools flag: '%s'\n", FlagName);
                 }
                 } else {
                    Print(L" unknown showtools flag: '%s'\n", FlagName);
                 }
index 0aad5f10f3c7d1c195477d954eb2ba12a1db57b6..a4d8355481449203bf81cbf34951b54c8099106c 100644 (file)
@@ -70,7 +70,8 @@
 #define TAG_LEGACY_UEFI    (10)
 #define TAG_APPLE_RECOVERY (11)
 #define TAG_MOK_TOOL       (12)
 #define TAG_LEGACY_UEFI    (10)
 #define TAG_APPLE_RECOVERY (11)
 #define TAG_MOK_TOOL       (12)
-#define NUM_TOOLS          (11)
+#define TAG_FIRMWARE       (13)
+#define NUM_TOOLS          (13)
 
 #define NUM_SCAN_OPTIONS 10
 
 
 #define NUM_SCAN_OPTIONS 10
 
index f11ab1b983a25ff09fecae667a261ded002b22a8..4a6b4d18423ff6585083ffd5fd303219684151f3 100644 (file)
@@ -55,6 +55,7 @@ BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = {
    { NULL, L"func_reset", 48 },
    { NULL, L"func_shutdown", 48 },
    { NULL, L"func_exit", 48 },
    { NULL, L"func_reset", 48 },
    { NULL, L"func_shutdown", 48 },
    { NULL, L"func_exit", 48 },
+   { NULL, L"func_firmware", 48 },
    { NULL, L"tool_shell", 48 },
    { NULL, L"tool_part", 48 },
    { NULL, L"tool_rescue", 48 },
    { NULL, L"tool_shell", 48 },
    { NULL, L"tool_part", 48 },
    { NULL, L"tool_rescue", 48 },
index c389abce23796e0bab27a8a477c02e6e81f1d7da..f709b42ba7ece9a2da552d3a13a2324eafe870aa 100644 (file)
@@ -55,19 +55,20 @@ EG_IMAGE * DummyImage(IN UINTN PixelSize);
 
 EG_IMAGE * BuiltinIcon(IN UINTN Id);
 
 
 EG_IMAGE * BuiltinIcon(IN UINTN Id);
 
-#define BUILTIN_ICON_FUNC_ABOUT     (0)
-#define BUILTIN_ICON_FUNC_RESET     (1)
-#define BUILTIN_ICON_FUNC_SHUTDOWN  (2)
-#define BUILTIN_ICON_FUNC_EXIT      (3)
-#define BUILTIN_ICON_TOOL_SHELL     (4)
-#define BUILTIN_ICON_TOOL_PART      (5)
-#define BUILTIN_ICON_TOOL_RESCUE    (6)
-#define BUILTIN_ICON_TOOL_APPLE_RESCUE (7)
-#define BUILTIN_ICON_TOOL_MOK_TOOL  (8)
-#define BUILTIN_ICON_VOL_INTERNAL   (9)
-#define BUILTIN_ICON_VOL_EXTERNAL   (10)
-#define BUILTIN_ICON_VOL_OPTICAL    (11)
-#define BUILTIN_ICON_COUNT          (12)
+#define BUILTIN_ICON_FUNC_ABOUT        (0)
+#define BUILTIN_ICON_FUNC_RESET        (1)
+#define BUILTIN_ICON_FUNC_SHUTDOWN     (2)
+#define BUILTIN_ICON_FUNC_EXIT         (3)
+#define BUILTIN_ICON_FUNC_FIRMWARE     (4)
+#define BUILTIN_ICON_TOOL_SHELL        (5)
+#define BUILTIN_ICON_TOOL_PART         (6)
+#define BUILTIN_ICON_TOOL_RESCUE       (7)
+#define BUILTIN_ICON_TOOL_APPLE_RESCUE (8)
+#define BUILTIN_ICON_TOOL_MOK_TOOL     (9)
+#define BUILTIN_ICON_VOL_INTERNAL      (10)
+#define BUILTIN_ICON_VOL_EXTERNAL      (11)
+#define BUILTIN_ICON_VOL_OPTICAL       (12)
+#define BUILTIN_ICON_COUNT             (13)
 
 #endif
 
 
 #endif
 
index cca2d1825c2fabc537912e7793978b8cdc2a2e7e..8679fd639f072b632081a071fa36ab920bd55f09 100644 (file)
 #include "../EfiLib/BdsHelper.h"
 #endif // __MAKEWITH_GNUEFI
 
 #include "../EfiLib/BdsHelper.h"
 #endif // __MAKEWITH_GNUEFI
 
+#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
+#endif
+
 //
 // variables
 
 //
 // variables
 
 static REFIT_MENU_ENTRY MenuEntryAbout    = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryReset    = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryAbout    = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryReset    = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL };
-static REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryFirmware = { L"Reboot to Firmware User Interface", TAG_FIRMWARE, 1, 0, 0, NULL, NULL, NULL };
 
 static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot",
                                             L"Use arrow keys to move cursor; Enter to boot;",
 
 static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot",
                                             L"Use arrow keys to move cursor; Enter to boot;",
@@ -115,7 +120,11 @@ static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0,
 
 REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0, 0,
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
 REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0, 0,
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                              {TAG_SHELL, TAG_APPLE_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
+                              { TAG_SHELL, TAG_APPLE_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE,
+                                0, 0, 0, 0, 0, 0 }
+                            };
+
+const EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE;
 
 // Structure used to hold boot loader filenames and time stamps in
 // a linked list; used to sort entries within a directory.
 
 // Structure used to hold boot loader filenames and time stamps in
 // a linked list; used to sort entries within a directory.
@@ -135,7 +144,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.9.1");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.9.2");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2013 Roderick W. Smith");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2013 Roderick W. Smith");
@@ -311,6 +320,65 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
     return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, OSType, ErrorInStep, Verbose);
 } /* static EFI_STATUS StartEFIImage() */
 
     return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, OSType, ErrorInStep, Verbose);
 } /* static EFI_STATUS StartEFIImage() */
 
+// From gummiboot: Retrieve a raw EFI variable.
+// Returns EFI status
+static EFI_STATUS EfivarGetRaw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
+   CHAR8 *buf;
+   UINTN l;
+   EFI_STATUS err;
+
+   l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
+   buf = AllocatePool(l);
+   if (!buf)
+      return EFI_OUT_OF_RESOURCES;
+
+   err = uefi_call_wrapper(RT->GetVariable, 5, name, vendor, NULL, &l, buf);
+   if (EFI_ERROR(err) == EFI_SUCCESS) {
+      *buffer = buf;
+      if (size)
+         *size = l;
+   } else
+      MyFreePool(buf);
+   return err;
+} // EFI_STATUS EfivarGetRaw()
+
+// From gummiboot: Set an EFI variable
+static EFI_STATUS EfivarSetRaw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) {
+   UINT32 flags;
+
+   flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+   if (persistent)
+      flags |= EFI_VARIABLE_NON_VOLATILE;
+
+   return uefi_call_wrapper(RT->SetVariable, 5, name, vendor, flags, size, buf);
+} // EFI_STATUS EfivarSetRaw()
+
+// From gummiboot: Reboot the computer into its built-in user interface
+static EFI_STATUS RebootIntoFirmware(VOID) {
+   CHAR8 *b;
+   UINTN size;
+   UINT64 osind;
+   EFI_STATUS err;
+
+   osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+
+   err = EfivarGetRaw(&GlobalGuid, L"OsIndications", &b, &size);
+   if (err == EFI_SUCCESS)
+      osind |= (UINT64)*b;
+   MyFreePool(b);
+
+   err = EfivarSetRaw(&GlobalGuid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE);
+   if (err != EFI_SUCCESS)
+      return err;
+
+   uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL);
+   Print(L"Error calling ResetSystem: %r", err);
+   PauseForKey();
+//   uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+   return err;
+}
+
+
 //
 // EFI OS loader functions
 //
 //
 // EFI OS loader functions
 //
@@ -1975,6 +2043,8 @@ static VOID ScanForTools(VOID) {
    CHAR16 *FileName = NULL, *MokLocations, *MokName, *PathName, Description[256];
    REFIT_MENU_ENTRY *TempMenuEntry;
    UINTN i, j, k, VolumeIndex;
    CHAR16 *FileName = NULL, *MokLocations, *MokName, *PathName, Description[256];
    REFIT_MENU_ENTRY *TempMenuEntry;
    UINTN i, j, k, VolumeIndex;
+   UINT64 osind;
+   CHAR8 *b = 0;
 
    MokLocations = StrDuplicate(MOK_LOCATIONS);
    if (MokLocations != NULL)
 
    MokLocations = StrDuplicate(MOK_LOCATIONS);
    if (MokLocations != NULL)
@@ -2003,6 +2073,16 @@ static VOID ScanForTools(VOID) {
             TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT);
             AddMenuEntry(&MainMenu, TempMenuEntry);
             break;
             TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT);
             AddMenuEntry(&MainMenu, TempMenuEntry);
             break;
+         case TAG_FIRMWARE:
+            if (EfivarGetRaw(&GlobalGuid, L"OsIndicationsSupported", &b, &j) == EFI_SUCCESS) {
+               osind = (UINT64)*b;
+               if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) {
+                  TempMenuEntry = CopyMenuEntry(&MenuEntryFirmware);
+                  TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_FIRMWARE);
+                  AddMenuEntry(&MainMenu, TempMenuEntry);
+               } // if
+            } // if
+            break;
          case TAG_SHELL:
             j = 0;
             while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
          case TAG_SHELL:
             j = 0;
             while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
@@ -2244,6 +2324,10 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
                 }
                 break;
 
                 }
                 break;
 
+            case TAG_FIRMWARE: // Reboot into firmware's user interface
+                RebootIntoFirmware();
+                break;
+
         } // switch()
         MyFreePool(Selection);
         Selection = (ChosenEntry->Title) ? StrDuplicate(ChosenEntry->Title) : NULL;
         } // switch()
         MyFreePool(Selection);
         Selection = (ChosenEntry->Title) ? StrDuplicate(ChosenEntry->Title) : NULL;