]> code.delx.au - refind/blobdiff - refind/main.c
Version 0.6.9 release
[refind] / refind / main.c
index ecb082565d3556d455a5c6bf9313e3b96857ed1c..f0803a59af5eeb89c59d761a6878f246b2344063 100644 (file)
 
 #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
@@ -112,7 +113,7 @@ static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL
                                             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 }};
 
@@ -134,10 +135,10 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.6.7");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.9");
         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 +177,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 +252,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)
@@ -728,9 +754,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
@@ -952,6 +978,9 @@ static 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)
@@ -981,8 +1010,9 @@ static 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
@@ -991,10 +1021,11 @@ static 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,
@@ -1041,21 +1072,27 @@ 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
+    } // if not scanning a blacklisted directory
 
     return FoundFallbackDuplicate;
 } /* static VOID ScanLoaderDir() */
@@ -1064,15 +1101,13 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    EFI_STATUS              Status;
    REFIT_DIR_ITER          EfiDirIter;
    EFI_FILE_INFO           *EfiDirEntry;
-   CHAR16                  FileName[256], *Directory, *MatchPatterns, *VolName = NULL;
+   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
@@ -1131,11 +1166,16 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
          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) && ShouldScan(Volume, L"EFI\\BOOT")) {
+      if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT"))
          AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume);
-      }
    } // if
 } // static VOID ScanEfiFiles()
 
@@ -1932,12 +1972,17 @@ 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;
+
+   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);
@@ -1960,23 +2005,26 @@ static VOID ScanForTools(VOID) {
             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))) {
@@ -1985,29 +2033,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