]> code.delx.au - refind/blobdiff - refind/main.c
Improved submenu and information menu appearance over a full-screen
[refind] / refind / main.c
index 011489b69e7d74e5c647031450c8993187c13303..4638a62938a843266d6c2391ee2c8d54b82eace3 100644 (file)
 #include "icns.h"
 #include "menu.h"
 #include "mok.h"
+#include "security_policy.h"
 #include "../include/Handle.h"
 #include "../include/refit_call_wrapper.h"
 #include "driver_support.h"
 #include "../include/syslinux_mbr.h"
 
-#ifdef __MAKEWITH_TIANO
+#ifdef __MAKEWITH_GNUEFI
+#define EFI_SECURITY_VIOLATION    EFIERR (26)
+#else
 #include "../EfiLib/BdsHelper.h"
-#endif // __MAKEWITH_TIANO
+#endif // __MAKEWITH_GNUEFI
 
-// 
+//
 // variables
 
 #define MACOSX_LOADER_PATH      L"System\\Library\\CoreServices\\boot.efi"
@@ -66,7 +69,7 @@
 #define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shellx64.efi"
 #define DRIVER_DIRS             L"drivers,drivers_x64"
 #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,\\shellia32.efi"
 #define DRIVER_DIRS             L"drivers,drivers_ia32"
 #else
 #define SHELL_NAMES             L"\\EFI\\tools\\shell.efi"
 // a ".efi" extension to be found when scanning for boot loaders.
 #define LINUX_MATCH_PATTERNS    L"vmlinuz*,bzImage*"
 
+// Default hint text for program-launch submenus
+#define SUBSCREEN_HINT1            L"Use arrow keys to move cursor; Enter to boot;"
+#define SUBSCREEN_HINT2            L"Insert or F2 to edit options; Esc to return to main menu"
+#define SUBSCREEN_HINT2_NO_EDITOR  L"Esc to return to main menu"
+
 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 MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL };
 
-static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot" };
-static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0, 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, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0,
-                              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,
+                              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 }};
 
 // Structure used to hold boot loader filenames and time stamps in
@@ -118,7 +128,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.0.2");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.4.6");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
@@ -170,15 +180,9 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     EFI_STATUS              Status, ReturnStatus;
     EFI_HANDLE              ChildImageHandle;
     EFI_LOADED_IMAGE        *ChildLoadedImage = NULL;
-    REFIT_FILE              File;
-    VOID                    *ImageData = NULL;
-    UINTN                   ImageSize;
-    REFIT_VOLUME            *DeviceVolume = NULL;
     UINTN                   DevicePathIndex;
     CHAR16                  ErrorInfo[256];
     CHAR16                  *FullLoadOptions = NULL;
-    CHAR16                  *loader = NULL;
-    BOOLEAN                 UseMok = FALSE;
 
     if (ErrorInStep != NULL)
         *ErrorInStep = 0;
@@ -186,7 +190,6 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     // set load options
     if (LoadOptions != NULL) {
         if (LoadOptionsPrefix != NULL) {
-//            MergeStrings(&FullLoadOptions, LoadOptionsPrefix, 0);
             MergeStrings(&FullLoadOptions, LoadOptions, L' ');
             if (OSType == 'M') {
                MergeStrings(&FullLoadOptions, L" ", 0);
@@ -208,8 +211,8 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     // load the image into memory (and execute it, in the case of a shim/MOK image).
     ReturnStatus = Status = EFI_NOT_FOUND;  // in case the list is empty
     for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
-       // NOTE: Below commented-out line could be more efficient if the ReadFile() and
-       // FindVolumeAndFilename() calls were moved earlier, but it doesn't work on my
+       // NOTE: Below commented-out line could be more efficient if file were read ahead of
+       // time and passed as a pre-loaded image to LoadImage(), but it doesn't work on my
        // 32-bit Mac Mini or my 64-bit Intel box when launching a Linux kernel; the
        // kernel returns a "Failed to handle fs_proto" error message.
        // TODO: Track down the cause of this error and fix it, if possible.
@@ -217,25 +220,6 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
        //                                            ImageData, ImageSize, &ChildImageHandle);
        ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
                                                    NULL, 0, &ChildImageHandle);
-       if ((Status == EFI_ACCESS_DENIED) && (ShimLoaded())) {
-          FindVolumeAndFilename(DevicePaths[DevicePathIndex], &DeviceVolume, &loader);
-          if (DeviceVolume != NULL) {
-             Status = ReadFile(DeviceVolume->RootDir, loader, &File, &ImageSize);
-             ImageData = File.Buffer;
-          } else {
-             Status = EFI_NOT_FOUND;
-             Print(L"Error: device volume not found!\n");
-          } // if/else
-          if (Status != EFI_NOT_FOUND) {
-             ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions,
-                                                 DeviceVolume, FileDevicePath(DeviceVolume->DeviceHandle, loader));
-//             ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions,
-//                                                 DeviceVolume, DevicePaths[DevicePathIndex]);
-          }
-          if (ReturnStatus == EFI_SUCCESS) {
-             UseMok = TRUE;
-          } // if
-       } // if (UEFI SB failed; use shim)
        if (ReturnStatus != EFI_NOT_FOUND) {
           break;
        }
@@ -247,37 +231,35 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
         goto bailout;
     }
 
-    if (!UseMok) {
-       ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol,
-                                                   (VOID **) &ChildLoadedImage);
-       if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
-          if (ErrorInStep != NULL)
-             *ErrorInStep = 2;
-          goto bailout_unload;
-       }
-       ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions;
-       ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16);
-       // turn control over to the image
-       // TODO: (optionally) re-enable the EFI watchdog timer!
-
-       // close open file handles
-       UninitRefitLib();
-       ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL);
-       // control returns here when the child image calls Exit()
-       SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle);
-       if (CheckError(Status, ErrorInfo)) {
-           if (ErrorInStep != NULL)
-               *ErrorInStep = 3;
-       }
+    ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol,
+                                                (VOID **) &ChildLoadedImage);
+    if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
+       if (ErrorInStep != NULL)
+          *ErrorInStep = 2;
+       goto bailout_unload;
+    }
+    ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions;
+    ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16);
+    // turn control over to the image
+    // TODO: (optionally) re-enable the EFI watchdog timer!
 
-       // re-open file handles
-       ReinitRefitLib();
-    } // if
+    // close open file handles
+    UninitRefitLib();
+    ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL);
+
+    // control returns here when the child image calls Exit()
+    SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle);
+    if (CheckError(Status, ErrorInfo)) {
+        if (ErrorInStep != NULL)
+            *ErrorInStep = 3;
+    }
+
+    // re-open file handles
+    ReinitRefitLib();
 
 bailout_unload:
     // unload the image, we don't care if it works or not...
-    if (!UseMok)
-       Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle);
+    Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle);
 
 bailout:
     MyFreePool(FullLoadOptions);
@@ -395,6 +377,8 @@ static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) {
       for (i = 0; i < Entry->EntryCount && NewEntry->Entries; i++) {
          AddMenuEntry(NewEntry, Entry->Entries[i]);
       } // for
+      NewEntry->Hint1 = (Entry->Hint1) ? StrDuplicate(Entry->Hint1) : NULL;
+      NewEntry->Hint2 = (Entry->Hint2) ? StrDuplicate(Entry->Hint2) : NULL;
    } // if
    return (NewEntry);
 } // static REFIT_MENU_SCREEN* CopyMenuScreen()
@@ -501,6 +485,12 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
             MyFreePool(MainOptions);
             AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
          } // if (SubEntry != NULL)
+         SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+         if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+            SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+         } else {
+            SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+         } // if/else
       } // if (SubScreen != NULL)
    } else { // existing subscreen; less initialization, and just add new entry later....
       SubScreen = Entry->me.SubScreen;
@@ -578,7 +568,17 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
             SubEntry->LoadOptions     = L"-v -s";
             AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
          } // if
-      } // not single-user
+      } // single-user mode allowed
+
+      if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SAFEMODE)) {
+         SubEntry = InitializeLoaderEntry(Entry);
+         if (SubEntry != NULL) {
+            SubEntry->me.Title        = L"Boot Mac OS X in safe mode";
+            SubEntry->UseGraphicsMode = FALSE;
+            SubEntry->LoadOptions     = L"-v -x";
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+         } // if
+      } // safe mode allowed
 
       // check for Apple hardware diagnostics
       StrCpy(DiagsFileName, L"System\\Library\\CoreServices\\.diagnostics\\diags.efi");
@@ -710,23 +710,29 @@ static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Vol
 // Sets a few defaults for a loader entry -- mainly the icon, but also the OS type
 // code and shortcut letter. For Linux EFI stub loaders, also sets kernel options
 // that will (with luck) work fairly automatically.
-VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
-   CHAR16          IconFileName[256];
-   CHAR16          *FileName, *PathOnly, *OSIconName = NULL, *Temp;
-   CHAR16          ShortcutLetter = 0;
+VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Volume) {
+   CHAR16      *FileName, *PathOnly, *IconNames = NULL, *NoExtension, *OSIconName = NULL, *Temp, *SubString;
+   CHAR16      ShortcutLetter = 0;
+   UINTN       i = 0, Length;
 
    FileName = Basename(LoaderPath);
    PathOnly = FindPath(LoaderPath);
+   NoExtension = StripEfiExtension(FileName);
 
    // locate a custom icon for the loader
-   StrCpy(IconFileName, LoaderPath);
-   ReplaceEfiExtension(IconFileName, L".icns");
-   if (FileExists(Volume->RootDir, IconFileName)) {
-      Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128);
-   } else if ((StrLen(PathOnly) == 0) && (Volume->VolIconImage != NULL)) {
+   // Anything found here takes precedence over the "hints" in the OSIconName variable
+   while ((Temp = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) {
+      MergeStrings(&IconNames, NoExtension, L',');
+      MergeStrings(&IconNames, Temp, L'.');
+      MyFreePool(Temp);
+   }
+   Entry->me.Image = LoadIcns(Volume->RootDir, IconNames, 128);
+   if (!Entry->me.Image)
       Entry->me.Image = Volume->VolIconImage;
-   } // icon matched to loader or volume
+   MyFreePool(IconNames);
 
+   // Begin creating icon "hints" by using last part of directory path leading
+   // to the loader
    Temp = FindLastDirName(LoaderPath);
    MergeStrings(&OSIconName, Temp, L',');
    MyFreePool(Temp);
@@ -735,6 +741,26 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME
       ShortcutLetter = OSIconName[0];
    }
 
+   // Add every "word" in the volume label, delimited by spaces, dashes (-), or
+   // underscores (_), to the list of hints to be used in searching for OS
+   // icons.
+   if ((Volume->VolName) && (StrLen(Volume->VolName) > 0)) {
+      Temp = SubString = StrDuplicate(Volume->VolName);
+      if (Temp != NULL) {
+         Length = StrLen(Temp);
+         for (i = 0; i < Length; i++) {
+            if ((Temp[i] == L' ') || (Temp[i] == L'_') || (Temp[i] == L'-')) {
+               Temp[i] = 0;
+               if (StrLen(SubString) > 0)
+                  MergeStrings(&OSIconName, SubString, L',');
+               SubString = Temp + i + 1;
+            } // if
+         } // for
+         MergeStrings(&OSIconName, SubString, L',');
+         MyFreePool(Temp);
+      } // if
+   } // if
+
    // detect specific loaders
    if (StriSubCmp(L"bzImage", LoaderPath) || StriSubCmp(L"vmlinuz", LoaderPath)) {
       MergeStrings(&OSIconName, L"linux", L',');
@@ -769,7 +795,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_GRUB;
    } else if (StriCmp(FileName, L"cdboot.efi") == 0 ||
               StriCmp(FileName, L"bootmgr.efi") == 0 ||
-              StriCmp(FileName, L"Bootmgfw.efi") == 0) {
+              StriCmp(FileName, L"bootmgfw.efi") == 0) {
       MergeStrings(&OSIconName, L"win", L',');
       Entry->OSType = 'W';
       ShortcutLetter = 'W';
@@ -823,7 +849,7 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN
 // (Time1 == Time2). Precision is only to the nearest second; since
 // this is used for sorting boot loader entries, differences smaller
 // than this are likely to be meaningless (and unlikely!).
-INTN TimeComp(EFI_TIME *Time1, EFI_TIME *Time2) {
+INTN TimeComp(IN EFI_TIME *Time1, IN EFI_TIME *Time2) {
    INT64 Time1InSeconds, Time2InSeconds;
 
    // Following values are overestimates; I'm assuming 31 days in every month.
@@ -875,6 +901,40 @@ static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) {
    } // while
 } // static VOID CleanUpLoaderList()
 
+// 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.
+static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) {
+   CHAR16   *VolName = NULL, *DontScanDir;
+   UINTN    i = 0, VolNum;
+   BOOLEAN  ScanIt = TRUE;
+
+   if (IsIn(Volume->VolName, GlobalConfig.DontScanVolumes))
+      return FALSE;
+
+   while ((DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++)) && ScanIt) {
+      SplitVolumeAndFilename(&DontScanDir, &VolName);
+      CleanUpPathNameSlashes(DontScanDir);
+      if (VolName != NULL) {
+         if ((StriCmp(VolName, Volume->VolName) == 0) && (StriCmp(DontScanDir, Path) == 0))
+            ScanIt = FALSE;
+         if ((StrLen(VolName) > 2) && (VolName[0] == L'f') && (VolName[1] == L's') && (VolName[2] >= L'0') && (VolName[2] <= L'9')) {
+            VolNum = Atoi(VolName + 2);
+            if ((VolNum == Volume->VolNumber) && (StriCmp(DontScanDir, Path) == 0))
+               ScanIt = FALSE;
+         }
+      } else {
+         if (StriCmp(DontScanDir, Path) == 0)
+            ScanIt = FALSE;
+      }
+      MyFreePool(DontScanDir);
+      DontScanDir = NULL;
+   }
+   return ScanIt;
+} // BOOLEAN ShouldScan()
+
 // Scan an individual directory for EFI boot loader files and, if found,
 // add them to the list. Sorts the entries within the loader directory
 // so that the most recent one appears first in the list.
@@ -888,14 +948,14 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *P
 
     if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) ||
            (StriCmp(Path, SelfDirPath) != 0)) &&
-         (!IsIn(Path, GlobalConfig.DontScanDirs)) &&
-         (!IsIn(Volume->VolName, GlobalConfig.DontScanVolumes))) {
+           (ShouldScan(Volume, Path))) {
        // look through contents of the directory
        DirIterOpen(Volume->RootDir, Path, &DirIter);
        while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) {
           Extension = FindExtension(DirEntry->FileName);
           if (DirEntry->FileName[0] == '.' ||
               StriCmp(Extension, L".icns") == 0 ||
+              StriCmp(Extension, L".png") == 0 ||
               StriSubCmp(L"shell", DirEntry->FileName) ||
               IsIn(DirEntry->FileName, GlobalConfig.DontScanFiles))
                 continue;   // skip this
@@ -934,8 +994,8 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    EFI_STATUS              Status;
    REFIT_DIR_ITER          EfiDirIter;
    EFI_FILE_INFO           *EfiDirEntry;
-   CHAR16                  FileName[256], *Directory, *MatchPatterns;
-   UINTN                   i, Length;
+   CHAR16                  FileName[256], *Directory, *MatchPatterns, *VolName = NULL;
+   UINTN                   i, Length, VolNum;
 
    MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS);
    if (GlobalConfig.ScanAllLinux)
@@ -981,11 +1041,17 @@ 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 (Length > 0)
+         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)))
             ScanLoaderDir(Volume, Directory, MatchPatterns);
          MyFreePool(Directory);
+         MyFreePool(VolName);
       } // while
    } // if
 } // static VOID ScanEfiFiles()
@@ -1270,6 +1336,12 @@ static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Vo
     SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16));
     SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", LoaderTitle, VolDesc);
     SubScreen->TitleImage = Entry->me.Image;
+    SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+    if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+    } else {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+    } // if/else
 
     // default entry
     SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
@@ -1287,7 +1359,9 @@ static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Vo
 } /* static LEGACY_ENTRY * AddLegacyEntry() */
 
 
-#ifdef __MAKEWITH_TIANO
+#ifdef __MAKEWITH_GNUEFI
+static VOID ScanLegacyUEFI(IN UINTN DiskType){}
+#else
 // default volume badge icon based on disk kind
 static EG_IMAGE * GetDiskBadge(IN UINTN DiskType) {
    EG_IMAGE * Badge = NULL;
@@ -1338,6 +1412,12 @@ static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16
     SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16));
     SPrint(SubScreen->Title, 255, L"No boot options for legacy target");
     SubScreen->TitleImage = Entry->me.Image;
+    SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+    if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+    } else {
+       SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+    } // if/else
 
     // default entry
     SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
@@ -1371,7 +1451,6 @@ static VOID ScanLegacyUEFI(IN UINTN DiskType)
     BDS_COMMON_OPTION *BdsOption;
     LIST_ENTRY        TempList;
     BBS_BBS_DEVICE_PATH * BbsDevicePath = NULL;
-//    REFIT_VOLUME          Volume;
 
     InitializeListHead (&TempList);
     ZeroMem (Buffer, sizeof (Buffer));
@@ -1411,9 +1490,7 @@ static VOID ScanLegacyUEFI(IN UINTN DiskType)
         Index++;
     }
 } /* static VOID ScanLegacyUEFI() */
-#else
-static VOID ScanLegacyUEFI(IN UINTN DiskType){}
-#endif // __MAKEWITH_TIANO
+#endif // __MAKEWITH_GNUEFI
 
 static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) {
    UINTN VolumeIndex2;
@@ -1686,7 +1763,7 @@ static VOID FindLegacyBootType(VOID) {
    GlobalConfig.LegacyType = LEGACY_TYPE_NONE;
 
    // UEFI-style legacy BIOS support is available only with the TianoCore EDK2
-   // build environment, and then only with some implementations....
+   // build environment, and then only with some EFI implementations....
 #ifdef __MAKEWITH_TIANO
    Status = gBS->LocateProtocol (&gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
    if (!EFI_ERROR (Status))
@@ -1876,7 +1953,7 @@ VOID RescanAll(VOID) {
    SetupScreen();
 } // VOID RescanAll()
 
-#ifndef __MAKEWITH_GNUEFI
+#ifdef __MAKEWITH_TIANO
 
 // Minimal initialization function
 static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
@@ -1892,15 +1969,52 @@ static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *System
 
 #endif
 
+// Set up our own Secure Boot extensions....
+// Returns TRUE on success, FALSE otherwise
+static BOOLEAN SecureBootSetup(VOID) {
+   EFI_STATUS Status;
+   BOOLEAN    Success = FALSE;
+
+   if (secure_mode() && ShimLoaded()) {
+      Status = security_policy_install();
+      if (Status == EFI_SUCCESS) {
+         Success = TRUE;
+      } else {
+         Print(L"Failed to install MOK Secure Boot extensions");
+      }
+   }
+   return Success;
+} // VOID SecureBootSetup()
+
+// Remove our own Secure Boot extensions....
+// Returns TRUE on success, FALSE otherwise
+static BOOLEAN SecureBootUninstall(VOID) {
+   EFI_STATUS Status;
+   BOOLEAN    Success = TRUE;
+
+   if (secure_mode()) {
+      Status = security_policy_uninstall();
+      if (Status != EFI_SUCCESS) {
+         Success = FALSE;
+         BeginTextScreen(L"Secure Boot Policy Failure");
+         Print(L"Failed to uninstall MOK Secure Boot extensions; forcing a reboot.");
+         PauseForKey();
+         refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
+      }
+   }
+   return Success;
+} // VOID SecureBootUninstall
+
 //
 // main entry point
 //
 EFI_STATUS
 EFIAPI
-efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
 {
     EFI_STATUS         Status;
     BOOLEAN            MainLoopRunning = TRUE;
+    BOOLEAN            MokProtocol;
     REFIT_MENU_ENTRY   *ChosenEntry;
     UINTN              MenuExit, i;
     CHAR16             *Selection;
@@ -1908,7 +2022,6 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
 
     // bootstrap
     InitializeLib(ImageHandle, SystemTable);
-    InitScreen();
     Status = InitRefitLib(ImageHandle);
     if (EFI_ERROR(Status))
         return Status;
@@ -1918,7 +2031,10 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
     FindLegacyBootType();
     if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)
        CopyMem(GlobalConfig.ScanFor, "ihebocm   ", NUM_SCAN_OPTIONS);
+    ScanVolumes();
     ReadConfig(CONFIG_FILE_NAME);
+
+    InitScreen();
     WarnIfLegacyProblems();
     MainMenu.TimeoutSeconds = GlobalConfig.Timeout;
 
@@ -1927,7 +2043,8 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
 
     // further bootstrap (now with config available)
     SetupScreen();
-    ScanVolumes();
+    MokProtocol = SecureBootSetup();
+//    ScanVolumes();
     LoadDrivers();
     ScanForBootloaders();
     ScanForTools();
@@ -1983,15 +2100,19 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
             case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac
                 StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry);
                 break;
-#endif // __MAKEWITH_TIANO
+#endif
 
             case TAG_TOOL:     // Start a EFI tool
                 StartTool((LOADER_ENTRY *)ChosenEntry);
                 break;
 
             case TAG_EXIT:    // Terminate rEFInd
-                BeginTextScreen(L" ");
-                return EFI_SUCCESS;
+                if ((MokProtocol) && !SecureBootUninstall()) {
+                   MainLoopRunning = FALSE;   // just in case we get this far
+                } else {
+                   BeginTextScreen(L" ");
+                   return EFI_SUCCESS;
+                }
                 break;
 
         } // switch()