]> code.delx.au - refind/blobdiff - refind/main.c
ChromeOS icon.
[refind] / refind / main.c
index e27e149e3c63e31a5051feb381ab6cdfeb5b5df9..3c4f958fa2e81838ef5aa0cb2c8bb3cfa50f0643 100644 (file)
@@ -34,7 +34,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*
- * Modifications copyright (c) 2012 Roderick W. Smith
+ * Modifications copyright (c) 2012-2013 Roderick W. Smith
  *
  * Modifications distributed under the terms of the GNU General Public
  * License (GPL) version 3 (GPLv3), a copy of which must be distributed
 #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
 
 #define MACOSX_LOADER_PATH      L"System\\Library\\CoreServices\\boot.efi"
 #if defined (EFIX64)
-#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shellx64.efi"
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shell.efi,\\shellx64.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_x64.efi"
 #define DRIVER_DIRS             L"drivers,drivers_x64"
 #define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootx64.efi"
 #define FALLBACK_BASENAME       L"bootx64.efi"
 #elif defined (EFI32)
-#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellia32.efi,\\shellia32.efi"
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellia32.efi,\\shell.efi,\\shellia32.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_ia32.efi"
 #define DRIVER_DIRS             L"drivers,drivers_ia32"
 #define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootia32.efi"
 #define FALLBACK_BASENAME       L"bootia32.efi"
 #else
-#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi"
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\shell.efi"
+#define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi"
 #define DRIVER_DIRS             L"drivers"
 #define FALLBACK_FULLNAME       L"EFI\\BOOT\\boot.efi" /* Not really correct */
 #define FALLBACK_BASENAME       L"boot.efi"            /* Not really correct */
 #endif
 
-#define MOK_NAMES               L"\\EFI\\tools\\MokManager.efi,\\EFI\\fedora\\MokManager.efi,\\EFI\\redhat\\MokManager.efi,\\EFI\\ubuntu\\MokManager.efi,\\EFI\\suse\\MokManager"
-
 // Filename patterns that identify EFI boot loaders. Note that a single case (either L"*.efi" or
 // L"*.EFI") is fine for most systems; but Gigabyte's buggy Hybrid EFI does a case-sensitive
 // comparison when it should do a case-insensitive comparison, so I'm doubling this up. It does
 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 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;",
                                             L"Insert or F2 for more options; Esc to refresh" };
 static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" };
 
-REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 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,
-                              {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.
@@ -134,10 +144,10 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.6.4");
+        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 Roderick W. Smith");
+        AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2013 Roderick W. Smith");
         AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others");
         AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license");
         AddMenuInfoLine(&AboutMenu, L"");
@@ -176,6 +186,27 @@ static VOID AboutrEFInd(VOID)
     RunMenu(&AboutMenu, NULL);
 } /* VOID AboutrEFInd() */
 
+static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) {
+   if (Name == NULL)
+      Name = L"the loader";
+
+   refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR);
+   Print(L"Secure Boot validation failure loading %s!\n", Name);
+   refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC);
+   if (Verbose && secure_mode()) {
+      Print(L"\nThis computer is configured with Secure Boot active, but\n%s has failed validation.\n", Name);
+      Print(L"\nYou can:\n * Launch another boot loader\n");
+      Print(L" * Disable Secure Boot in your firmware\n");
+      Print(L" * Sign %s with a machine owner key (MOK)\n", Name);
+      Print(L" * Use a MOK utility (often present on the second row) to add a MOK with which\n");
+      Print(L"   %s has already been signed.\n", Name);
+      Print(L" * Use a MOK utility to register %s (\"enroll its hash\") without\n", Name);
+      Print(L"   signing it.\n");
+      Print(L"\nSee http://www.rodsbooks.com/refind/secureboot.html for more information\n");
+      PauseForKey();
+   } // if
+} // VOID WarnSecureBootError()
+
 // Launch an EFI binary.
 static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
                                     IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
@@ -230,6 +261,10 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
           break;
        }
     }
+    if ((Status == EFI_ACCESS_DENIED) || (Status == EFI_SECURITY_VIOLATION)) {
+       WarnSecureBootError(ImageTitle, Verbose);
+       goto bailout;
+    }
     SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle);
     if (CheckError(Status, ErrorInfo)) {
         if (ErrorInStep != NULL)
@@ -285,6 +320,69 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
     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;
+   EFI_GUID vendor2;
+
+   CopyMem(&vendor2, vendor, sizeof(EFI_GUID));
+   l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
+   buf = AllocatePool(l);
+   if (!buf)
+      return EFI_OUT_OF_RESOURCES;
+
+   err = refit_call5_wrapper(RT->GetVariable, name, &vendor2, 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;
+   EFI_GUID vendor2;
+
+   CopyMem(&vendor2, vendor, sizeof(EFI_GUID));
+   flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+   if (persistent)
+      flags |= EFI_VARIABLE_NON_VOLATILE;
+
+   return refit_call5_wrapper(RT->SetVariable, name, &vendor2, 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;
+
+   refit_call4_wrapper(RT->ResetSystem, 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
 //
@@ -728,9 +826,9 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo
    // locate a custom icon for the loader
    // Anything found here takes precedence over the "hints" in the OSIconName variable
    if (!Entry->me.Image)
-      Entry->me.Image = egFindIcon(NoExtension, 128);
+      Entry->me.Image = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, 128);
    if (!Entry->me.Image)
-      Entry->me.Image = Volume->VolIconImage;
+      Entry->me.Image = egCopyImage(Volume->VolIconImage);
 
    // Begin creating icon "hints" by using last part of directory path leading
    // to the loader
@@ -904,9 +1002,9 @@ static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) {
 
 // Returns FALSE if the specified file/volume matches the GlobalConfig.DontScanDirs
 // or GlobalConfig.DontScanVolumes specification, or if Path points to a volume
-// other than the one specified by Volume. Returns TRUE if none of these conditions
-// is met -- that is, if the path is eligible for scanning. Also reduces *Path to a
-// path alone, with no volume specification.
+// other than the one specified by Volume, or if the specified path is SelfDir.
+// Returns TRUE if none of these conditions is met -- that is, if the path is
+// eligible for scanning.
 static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) {
    CHAR16   *VolName = NULL, *DontScanDir;
    UINTN    i = 0, VolNum;
@@ -915,6 +1013,9 @@ static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) {
    if (IsIn(Volume->VolName, GlobalConfig.DontScanVolumes))
       return FALSE;
 
+   if ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle == SelfVolume->DeviceHandle))
+      return FALSE;
+
    while ((DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++)) && ScanIt) {
       SplitVolumeAndFilename(&DontScanDir, &VolName);
       CleanUpPathNameSlashes(DontScanDir);
@@ -941,7 +1042,7 @@ static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) {
 // FALSE if the file is not identical to the fallback file OR if the file
 // IS the fallback file. Intended for use in excluding the fallback boot
 // loader when it's a duplicate of another boot loader.
-BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) {
+static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) {
    CHAR8           *FileContents, *FallbackContents;
    EFI_FILE_HANDLE FileHandle, FallbackHandle;
    EFI_FILE_INFO   *FileInfo, *FallbackInfo;
@@ -949,6 +1050,9 @@ BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) {
    EFI_STATUS      Status;
    BOOLEAN         AreIdentical = FALSE;
 
+   if (!FileExists(Volume->RootDir, FileName) || !FileExists(Volume->RootDir, FALLBACK_FULLNAME))
+      return FALSE;
+
    CleanUpPathNameSlashes(FileName);
 
    if (StriCmp(FileName, FALLBACK_FULLNAME) == 0)
@@ -978,8 +1082,9 @@ BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) {
       FallbackContents = AllocatePool(FallbackSize);
       if (FileContents && FallbackContents) {
          Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &FileSize, FileContents);
-         if (Status == EFI_SUCCESS)
+         if (Status == EFI_SUCCESS) {
             Status = refit_call3_wrapper(FallbackHandle->Read, FallbackHandle, &FallbackSize, FallbackContents);
+         }
          if (Status == EFI_SUCCESS) {
             AreIdentical = (CompareMem(FileContents, FallbackContents, FileSize) == 0);
          } // if
@@ -988,10 +1093,11 @@ BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) {
       MyFreePool(FallbackContents);
    } // if/else
 
-   refit_call1_wrapper(FileHandle->Close, FileHandle);
+   // BUG ALERT: Some systems (e.g., DUET, some Macs with large displays) crash if the
+   // following two calls are reversed. Go figure....
    refit_call1_wrapper(FileHandle->Close, FallbackHandle);
+   refit_call1_wrapper(FileHandle->Close, FileHandle);
    return AreIdentical;
-
 } // BOOLEAN DuplicatesFallback()
 
 // Scan an individual directory for EFI boot loader files and, if found,
@@ -1008,7 +1114,6 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
     struct LOADER_LIST      *LoaderList = NULL, *NewLoader;
     BOOLEAN                 FoundFallbackDuplicate = FALSE;
 
-//    Print(L"Entering ScanLoaderDir(), scanning '%s' for pattern '%s'\n", Path, Pattern);
     if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) ||
            (StriCmp(Path, SelfDirPath) != 0)) &&
            (ShouldScan(Volume, Path))) {
@@ -1039,22 +1144,28 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
           } // if
           MyFreePool(Extension);
        } // while
+
        NewLoader = LoaderList;
        while (NewLoader != NULL) {
           AddLoaderEntry(NewLoader->FileName, NULL, Volume);
           NewLoader = NewLoader->NextEntry;
        } // while
+
        CleanUpLoaderList(LoaderList);
        Status = DirIterClose(&DirIter);
-       if (Status != EFI_NOT_FOUND) {
+       // NOTE: EFI_INVALID_PARAMETER really is an error that should be reported;
+       // but I've gotten reports from users who are getting this error occasionally
+       // and I can't find anything wrong or reproduce the problem, so I'm putting
+       // it down to buggy EFI implementations and ignoring that particular error....
+       if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) {
           if (Path)
              SPrint(FileName, 255, L"while scanning the %s directory", Path);
           else
              StrCpy(FileName, L"while scanning the root directory");
           CheckError(Status, FileName);
        } // if (Status != EFI_NOT_FOUND)
-    } // if not scanning our own directory
-//    PauseForKey();
+    } // if not scanning a blacklisted directory
+
     return FoundFallbackDuplicate;
 } /* static VOID ScanLoaderDir() */
 
@@ -1062,19 +1173,17 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    EFI_STATUS              Status;
    REFIT_DIR_ITER          EfiDirIter;
    EFI_FILE_INFO           *EfiDirEntry;
-   CHAR16                  FileName[256], *Directory, *MatchPatterns, *VolName = NULL;
-   UINTN                   i, Length, VolNum;
+   CHAR16                  FileName[256], *Directory, *MatchPatterns, *VolName = NULL, *SelfPath;
+   UINTN                   i, Length;
    BOOLEAN                 ScanFallbackLoader = TRUE;
 
-//   Print(L"Entering ScanEfiFiles(), GlobalConfig.ScanAllLinux = %s\n", GlobalConfig.ScanAllLinux ? L"TRUE" : L"FALSE");
    MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS);
    if (GlobalConfig.ScanAllLinux)
       MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L',');
-//   Print(L"MatchPatterns = '%s'\n", MatchPatterns);
 
    if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
       // check for Mac OS X boot loader
-      if (!IsIn(L"System\\Library\\CoreServices", GlobalConfig.DontScanDirs)) {
+      if (ShouldScan(Volume, L"System\\Library\\CoreServices")) {
          StrCpy(FileName, MACOSX_LOADER_PATH);
          if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) {
             AddLoaderEntry(FileName, L"Mac OS X", Volume);
@@ -1089,11 +1198,11 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
             if (DuplicatesFallback(Volume, FileName))
                ScanFallbackLoader = FALSE;
          }
-      } // if Mac directory not in GlobalConfig.DontScanDirs list
+      } // if should scan Mac directory
 
       // check for Microsoft boot loader/menu
-      StrCpy(FileName, L"EFI\\Microsoft\\Boot\\Bootmgfw.efi");
-      if (FileExists(Volume->RootDir, FileName) && !IsIn(L"EFI\\Microsoft\\Boot", GlobalConfig.DontScanDirs) &&
+      StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi");
+      if (FileExists(Volume->RootDir, FileName) && ShouldScan(Volume, L"EFI\\Microsoft\\Boot") &&
           !IsIn(L"bootmgfw.efi", GlobalConfig.DontScanFiles)) {
          AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume);
          if (DuplicatesFallback(Volume, FileName))
@@ -1120,26 +1229,25 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
       // Scan user-specified (or additional default) directories....
       i = 0;
       while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) {
-         VolNum = VOL_DONTSCAN;
          SplitVolumeAndFilename(&Directory, &VolName);
          CleanUpPathNameSlashes(Directory);
          Length = StrLen(Directory);
-         if (VolName && (Length > 0) && (StrLen(VolName) > 2) && (VolName[0] == L'f') && (VolName[1] == L's') &&
-             (VolName[2] >= L'0') && (VolName[2] <= L'9'))
-            VolNum = Atoi(VolName + 2);
-         if ((Length > 0) && ((VolName == NULL) || (StriCmp(VolName, Volume->VolName) == 0) || (Volume->VolNumber == VolNum)))
-            if (ScanLoaderDir(Volume, Directory, MatchPatterns))
-               ScanFallbackLoader = FALSE;
+         if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns))
+            ScanFallbackLoader = FALSE;
          MyFreePool(Directory);
          MyFreePool(VolName);
       } // while
 
+      // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself....
+      SelfPath = DevicePathToStr(SelfLoadedImage->FilePath);
+      CleanUpPathNameSlashes(SelfPath);
+      if ((Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) && DuplicatesFallback(Volume, SelfPath))
+         ScanFallbackLoader = FALSE;
+
       // If not a duplicate & if it exists & if it's not us, create an entry
       // for the fallback boot loader
-      if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) &&
-          ((StriCmp(SelfDirPath, L"EFI\\BOOT") != 0) || (Volume->DeviceHandle != SelfVolume->DeviceHandle))) {
+      if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT"))
          AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume);
-      }
    } // if
 } // static VOID ScanEfiFiles()
 
@@ -1477,8 +1585,6 @@ static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16
     CHAR16                  ShortcutLetter = 0;
     CHAR16 *LegacyDescription = BdsOption->Description;
 
-//    ScanVolume(Volume);
-
     // prepare the menu entry
     Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
     Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
@@ -1490,7 +1596,6 @@ static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16
     Entry->LoadOptions     = (DiskType == BBS_CDROM) ? L"CD" :
                              ((DiskType == BBS_USB) ? L"USB" : L"HD");
     Entry->me.BadgeImage   = GetDiskBadge(DiskType);
-//    Entry->me.BadgeImage   = Volume->VolBadgeImage;
     Entry->BdsOption       = BdsOption;
     Entry->Enabled         = TRUE;
 
@@ -1600,7 +1705,7 @@ static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) {
       // check for other bootable entries on the same disk
       for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) {
          if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode &&
-            Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO)
+             Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO)
             ShowVolume = FALSE;
       }
    }
@@ -1939,12 +2044,19 @@ static VOID ScanForBootloaders(VOID) {
 // Add the second-row tags containing built-in and external tools (EFI shell,
 // reboot, etc.)
 static VOID ScanForTools(VOID) {
-   CHAR16 *FileName = NULL, Description[256];
+   CHAR16 *FileName = NULL, *MokLocations, *MokName, *PathName, Description[256];
    REFIT_MENU_ENTRY *TempMenuEntry;
-   UINTN i, j, VolumeIndex;
+   UINTN i, j, k, VolumeIndex;
+   UINT64 osind;
+   CHAR8 *b = 0;
+
+   MokLocations = StrDuplicate(MOK_LOCATIONS);
+   if (MokLocations != NULL)
+      MergeStrings(&MokLocations, SelfDirPath, L',');
 
    for (i = 0; i < NUM_TOOLS; i++) {
       switch(GlobalConfig.ShowTools[i]) {
+         // NOTE: Be sure that FileName is NULL at the end of each case.
          case TAG_SHUTDOWN:
             TempMenuEntry = CopyMenuEntry(&MenuEntryShutdown);
             TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
@@ -1965,25 +2077,38 @@ static VOID ScanForTools(VOID) {
             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;
-            MyFreePool(FileName);
             while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
                if (FileExists(SelfRootDir, FileName)) {
                   AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL),
                                'S', FALSE);
                }
+               MyFreePool(FileName);
             } // while
             break;
          case TAG_GPTSYNC:
-            MyFreePool(FileName);
-            FileName = StrDuplicate(L"\\efi\\tools\\gptsync.efi");
-            if (FileExists(SelfRootDir, FileName)) {
-               AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE);
-            }
+            j = 0;
+            while ((FileName = FindCommaDelimited(GPTSYNC_NAMES, j++)) != NULL) {
+               if (FileExists(SelfRootDir, FileName)) {
+                  AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Hybrid MBR tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART),
+                               'P', FALSE);
+               } // if
+               MyFreePool(FileName);
+            } // while
+            FileName = NULL;
             break;
          case TAG_APPLE_RECOVERY:
-            MyFreePool(FileName);
             FileName = StrDuplicate(L"\\com.apple.recovery.boot\\boot.efi");
             for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
                if ((Volumes[VolumeIndex]->RootDir != NULL) && (FileExists(Volumes[VolumeIndex]->RootDir, FileName))) {
@@ -1992,29 +2117,31 @@ static VOID ScanForTools(VOID) {
                                BuiltinIcon(BUILTIN_ICON_TOOL_APPLE_RESCUE), 'R', TRUE);
                }
             } // for
+            MyFreePool(FileName);
+            FileName = NULL;
             break;
          case TAG_MOK_TOOL:
             j = 0;
-            MyFreePool(FileName);
-            while ((FileName = FindCommaDelimited(MOK_NAMES, j++)) != NULL) {
-               if (FileExists(SelfRootDir, FileName)) {
-                  SPrint(Description, 255, L"MOK Key Manager at %s", FileName);
-                  AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, Description,
-                               BuiltinIcon(BUILTIN_ICON_TOOL_MOK_TOOL), 'S', FALSE);
-               }
-            } // while
-            if (FileExists(SelfDir, L"MokManager.efi")) {
+            while ((FileName = FindCommaDelimited(MokLocations, j++)) != NULL) {
+               k = 0;
+               while ((MokName = FindCommaDelimited(MOK_NAMES, k++)) != NULL) {
+                  PathName = StrDuplicate(FileName);
+                  MergeStrings(&PathName, MokName, (StriCmp(PathName, L"\\") == 0) ? 0 : L'\\');
+                  for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+                     if ((Volumes[VolumeIndex]->RootDir != NULL) && (FileExists(Volumes[VolumeIndex]->RootDir, PathName))) {
+                        SPrint(Description, 255, L"MOK utility at %s on %s", PathName, Volumes[VolumeIndex]->VolName);
+                        AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, PathName, Description,
+                                     BuiltinIcon(BUILTIN_ICON_TOOL_MOK_TOOL), 'S', FALSE);
+                     } // if
+                  } // for
+                  MyFreePool(PathName);
+                  MyFreePool(MokName);
+               } // while MOK_NAMES
                MyFreePool(FileName);
-               FileName = SelfDirPath ? StrDuplicate(SelfDirPath) : NULL;
-               MergeStrings(&FileName, L"\\MokManager.efi", 0);
-               SPrint(Description, 255, L"MOK Key Manager at %s", FileName);
-               AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, Description,
-                            BuiltinIcon(BUILTIN_ICON_TOOL_MOK_TOOL), 'S', FALSE);
-            }
+            } // while MokLocations
+
             break;
       } // switch()
-      MyFreePool(FileName);
-      FileName = NULL;
    } // for
 } // static VOID ScanForTools
 
@@ -2201,6 +2328,10 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
                 }
                 break;
 
+            case TAG_FIRMWARE: // Reboot into firmware's user interface
+                RebootIntoFirmware();
+                break;
+
         } // switch()
         MyFreePool(Selection);
         Selection = (ChosenEntry->Title) ? StrDuplicate(ChosenEntry->Title) : NULL;