]> code.delx.au - refind/blobdiff - refind/main.c
Added new fold_linux_kernels option, which combines Linux kernels in a
[refind] / refind / main.c
index 835082608e03874190f2ffd78f81f97aea1ba2e7..586fdd98d8804db55a4746337fe1186c3e722dd4 100644 (file)
@@ -87,6 +87,7 @@
 #define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootx64.efi"
 #define FALLBACK_BASENAME       L"bootx64.efi"
 #define EFI_STUB_ARCH           0x8664
+EFI_GUID gFreedesktopRootGuid = { 0x4f68bce3, 0xe8cd, 0x4db1, { 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7, 0x09 }};
 #elif defined (EFI32)
 #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"
@@ -97,6 +98,7 @@
 #define FALLBACK_FULLNAME       L"EFI\\BOOT\\bootia32.efi"
 #define FALLBACK_BASENAME       L"bootia32.efi"
 #define EFI_STUB_ARCH           0x014c
+EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a }};
 #else
 #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 */
+// Below is GUID for ARM64
+EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }};
 #endif
 #define FAT_ARCH                0x0ef1fab9 /* ID for Apple "fat" binary */
 
@@ -136,9 +140,9 @@ REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"
                                      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, TRUE, FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC,
+REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE,  0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC,
                               0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, BANNER_NOSCALE,
-                              NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                              NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                               { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL,
                                 TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, 0, 0, 0, 0, 0, 0, 0, 0 }
                             };
@@ -166,7 +170,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.5.4");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.7.14");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith");
@@ -176,7 +180,8 @@ static VOID AboutrEFInd(VOID)
         AddMenuInfoLine(&AboutMenu, L"Running on:");
         AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1)));
 #if defined(EFI32)
-        AddMenuInfoLine(&AboutMenu, L" Platform: x86 (32 bit)");
+        AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86 (32 bit); Secure Boot %s",
+                                              secure_mode() ? L"active" : L"inactive"));
 #elif defined(EFIX64)
         AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s",
                                               secure_mode() ? L"active" : L"inactive"));
@@ -668,7 +673,7 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
    return SubScreen;
 } // REFIT_MENU_SCREEN *InitializeSubScreen()
 
-VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
+VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) {
    REFIT_MENU_SCREEN  *SubScreen;
    LOADER_ENTRY       *SubEntry;
    CHAR16             *InitrdName;
@@ -772,7 +777,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
          // first entry requires special processing, since it was initially set
          // up with a default title but correct options by InitializeSubScreen(),
          // earlier....
-         if ((SubScreen->Entries != NULL) && (SubScreen->Entries[0] != NULL)) {
+         if ((TokenCount > 1) && (SubScreen->Entries != NULL) && (SubScreen->Entries[0] != NULL)) {
             MyFreePool(SubScreen->Entries[0]->Title);
             SubScreen->Entries[0]->Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux");
          } // if
@@ -802,7 +807,6 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
       SubEntry = InitializeLoaderEntry(Entry);
       if (SubEntry != NULL) {
          SubEntry->me.Title        = L"Boot Linux for a 17\" iMac or a 15\" MacBook Pro (*)";
-         SubEntry->UseGraphicsMode = TRUE;
          SubEntry->LoadOptions     = L"-d 0 i17";
          SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
          AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
@@ -811,7 +815,6 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
       SubEntry = InitializeLoaderEntry(Entry);
       if (SubEntry != NULL) {
          SubEntry->me.Title        = L"Boot Linux for a 20\" iMac (*)";
-         SubEntry->UseGraphicsMode = TRUE;
          SubEntry->LoadOptions     = L"-d 0 i20";
          SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
          AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
@@ -820,7 +823,6 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
       SubEntry = InitializeLoaderEntry(Entry);
       if (SubEntry != NULL) {
          SubEntry->me.Title        = L"Boot Linux for a Mac Mini (*)";
-         SubEntry->UseGraphicsMode = TRUE;
          SubEntry->LoadOptions     = L"-d 0 mini";
          SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
          AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
@@ -852,13 +854,13 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
         SubEntry = InitializeLoaderEntry(Entry);
         if (SubEntry != NULL) {
            SubEntry->me.Title        = L"Run XOM in text mode";
-           SubEntry->UseGraphicsMode = FALSE;
            SubEntry->LoadOptions     = L"-v";
            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
         }
    } // entries for xom.efi
-   AddMenuEntry(SubScreen, &MenuEntryReturn);
+   if (GenerateReturn)
+       AddMenuEntry(SubScreen, &MenuEntryReturn);
    Entry->me.SubScreen = SubScreen;
 } // VOID GenerateSubScreen()
 
@@ -1001,13 +1003,12 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo
               StriCmp(NameClues, L"bootmgr.efi") == 0 ||
               StriCmp(NameClues, L"bootmgfw.efi") == 0 ||
               StriCmp(NameClues, L"bkpbootmgfw.efi") == 0) {
-      MergeStrings(&OSIconName, L"win", L',');
+      MergeStrings(&OSIconName, L"win8", L',');
       Entry->OSType = 'W';
       ShortcutLetter = 'W';
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
    } else if (StriCmp(NameClues, L"xom.efi") == 0) {
-      MergeStrings(&OSIconName, L"xom,win", L',');
-      Entry->UseGraphicsMode = TRUE;
+      MergeStrings(&OSIconName, L"xom,win,win8", L',');
       Entry->OSType = 'X';
       ShortcutLetter = 'W';
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
@@ -1028,7 +1029,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo
 
 // Add a specified EFI boot loader to the list, using automatic settings
 // for icons, options, etc.
-LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) {
+static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN BOOLEAN SubScreenReturn) {
    LOADER_ENTRY  *Entry;
 
    CleanUpPathNameSlashes(LoaderPath);
@@ -1054,13 +1055,50 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN
       Entry->VolName = Volume->VolName;
       Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath);
       SetLoaderDefaults(Entry, LoaderPath, Volume);
-      GenerateSubScreen(Entry, Volume);
+      GenerateSubScreen(Entry, Volume, SubScreenReturn);
       AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
    }
 
    return(Entry);
 } // LOADER_ENTRY * AddLoaderEntry()
 
+// Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry.
+static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) {
+    REFIT_FILE          *File;
+    CHAR16              **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL, *Path = NULL, *Title;
+    REFIT_MENU_SCREEN   *SubScreen;
+    LOADER_ENTRY        *SubEntry;
+    UINTN               TokenCount;
+
+    File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume);
+    if (File != NULL) {
+        SubScreen = TargetLoader->me.SubScreen;
+        InitrdName = FindInitrd(FileName, Volume);
+        while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
+            SubEntry = InitializeLoaderEntry(TargetLoader);
+            SplitPathName(FileName, &VolName, &Path, &SubmenuName);
+            MyFreePool(VolName);
+            MyFreePool(Path);
+            MergeStrings(&SubmenuName, L": ", '\0');
+            MergeStrings(&SubmenuName, TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"), '\0');
+            Title = StrDuplicate(SubmenuName);
+            SubEntry->me.Title = Title;
+            MyFreePool(SubEntry->LoadOptions);
+            SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName);
+            MyFreePool(SubEntry->LoaderPath);
+            SubEntry->LoaderPath = StrDuplicate(FileName);
+            CleanUpPathNameSlashes(SubEntry->LoaderPath);
+            SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath);
+            FreeTokenLine(&TokenList, &TokenCount);
+            SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX;
+            AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+        } // while
+        MyFreePool(SubmenuName);
+        MyFreePool(InitrdName);
+        MyFreePool(File);
+    } // if
+} // static VOID AddKernelToSubmenu()
+
 // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if
 // (Time1 == Time2). Precision is only to the nearest second; since
 // this is used for sorting boot loader entries, differences smaller
@@ -1296,7 +1334,8 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
     EFI_FILE_INFO           *DirEntry;
     CHAR16                  FileName[256], *Extension;
     struct LOADER_LIST      *LoaderList = NULL, *NewLoader;
-    BOOLEAN                 FoundFallbackDuplicate = FALSE;
+    LOADER_ENTRY            *FirstKernel = NULL, *LatestEntry = NULL;
+    BOOLEAN                 FoundFallbackDuplicate = FALSE, IsLinux = FALSE;
 
     if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) ||
            (StriCmp(Path, SelfDirPath) != 0)) && (ShouldScan(Volume, Path))) {
@@ -1336,9 +1375,18 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
 
        NewLoader = LoaderList;
        while (NewLoader != NULL) {
-          AddLoaderEntry(NewLoader->FileName, NULL, Volume);
-          NewLoader = NewLoader->NextEntry;
+           IsLinux = (StriSubCmp(L"bzImage", NewLoader->FileName) || StriSubCmp(L"vmlinuz", NewLoader->FileName));
+           if ((FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) {
+               AddKernelToSubmenu(FirstKernel, NewLoader->FileName, Volume);
+           } else {
+               LatestEntry = AddLoaderEntry(NewLoader->FileName, NULL, Volume, !(IsLinux && GlobalConfig.FoldLinuxKernels));
+               if (IsLinux && (FirstKernel == NULL))
+                   FirstKernel = LatestEntry;
+           }
+           NewLoader = NewLoader->NextEntry;
        } // while
+       if ((NewLoader != NULL) && (FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels)
+           AddMenuEntry(FirstKernel->me.SubScreen, &MenuEntryReturn);
 
        CleanUpLoaderList(LoaderList);
        Status = DirIterClose(&DirIter);
@@ -1399,7 +1447,7 @@ static VOID ScanNetboot() {
          NetVolume->DiskKind = DISK_KIND_NET;
          NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET);
          NetVolume->PartName = NetVolume->VolName = NULL;
-         AddLoaderEntry(iPXEFileName, Location, NetVolume);
+         AddLoaderEntry(iPXEFileName, Location, NetVolume, TRUE);
          MyFreePool(NetVolume);
       } // if support files exist and are valid
    } 
@@ -1414,7 +1462,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    BOOLEAN                 ScanFallbackLoader = TRUE;
    BOOLEAN                 FoundBRBackup = FALSE;
 
-   if ((Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) {
+   if (Volume && (Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) {
       MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS);
       if (GlobalConfig.ScanAllLinux)
          MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L',');
@@ -1423,7 +1471,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
       if (ShouldScan(Volume, MACOSX_LOADER_DIR)) {
          StrCpy(FileName, MACOSX_LOADER_PATH);
          if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"boot.efi", GlobalConfig.DontScanFiles)) {
-            AddLoaderEntry(FileName, L"Mac OS X", Volume);
+            AddLoaderEntry(FileName, L"Mac OS X", Volume, TRUE);
             if (DuplicatesFallback(Volume, FileName))
                ScanFallbackLoader = FALSE;
          }
@@ -1431,7 +1479,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
          // check for XOM
          StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi");
          if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"xom.efi", GlobalConfig.DontScanFiles)) {
-            AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume);
+            AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume, TRUE);
             if (DuplicatesFallback(Volume, FileName))
                ScanFallbackLoader = FALSE;
          }
@@ -1442,17 +1490,18 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
          StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi");
          if (FileExists(Volume->RootDir, FileName) &&  !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bkpbootmgfw.efi",
              GlobalConfig.DontScanFiles)) {
-            AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume);
+            AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume, TRUE);
             FoundBRBackup = TRUE;
             if (DuplicatesFallback(Volume, FileName))
                ScanFallbackLoader = FALSE;
          }
          StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi");
-         if (FileExists(Volume->RootDir, FileName) &&  !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) {
+         if (FileExists(Volume->RootDir, FileName) &&
+             !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) {
             if (FoundBRBackup)
-               AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume);
+               AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume, TRUE);
             else
-               AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume);
+               AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume, TRUE);
             if (DuplicatesFallback(Volume, FileName))
                ScanFallbackLoader = FALSE;
          }
@@ -1472,7 +1521,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
             ScanFallbackLoader = FALSE;
       } // while()
       Status = DirIterClose(&EfiDirIter);
-      if (Status != EFI_NOT_FOUND)
+      if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER))
          CheckError(Status, L"while scanning the EFI directory");
 
       // Scan user-specified (or additional default) directories....
@@ -1497,8 +1546,9 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
 
       // 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"))
-         AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume);
+      if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT")) {
+         AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume, TRUE);
+      }
    } // if
 } // static VOID ScanEfiFiles()
 
@@ -1613,7 +1663,7 @@ static UINTN ScanDriverDir(IN CHAR16 *Path)
                                L"", TYPE_EFI, DirEntry->FileName, 0, NULL, FALSE, TRUE);
     }
     Status = DirIterClose(&DirIter);
-    if (Status != EFI_NOT_FOUND) {
+    if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) {
         SPrint(FileName, 255, L"while scanning the %s directory", Path);
         CheckError(Status, FileName);
     }
@@ -1726,8 +1776,9 @@ static VOID LoadDrivers(VOID)
     } // while
 
     // connect all devices
-    if (NumFound > 0)
+    if (NumFound > 0) {
        ConnectAllDriversToAllControllers();
+    }
 } /* static VOID LoadDrivers() */
 
 // Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly.