]> code.delx.au - refind/blobdiff - refind/main.c
Ext4fs support; enable override of initrd in refind_linux.conf
[refind] / refind / main.c
index 7297c629f4ef0663f2d0ace4ff7a708d96640cf8..05d15be0a40bf2fe7ef61b9e8a33a043a322a9b9 100644 (file)
@@ -96,7 +96,7 @@ static REFIT_MENU_ENTRY MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0,
 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 };
 
-REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 0, 0, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0,
+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,
                               {TAG_SHELL, TAG_APPLE_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
 
@@ -118,7 +118,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.7.10");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.5.1.6");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
@@ -178,7 +178,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     CHAR16                  ErrorInfo[256];
     CHAR16                  *FullLoadOptions = NULL;
     CHAR16                  *loader = NULL;
-    BOOLEAN                 UseMok = FALSE, SecureMode;
+    BOOLEAN                 UseMok = FALSE;
 
     if (ErrorInStep != NULL)
         *ErrorInStep = 0;
@@ -196,32 +196,28 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
         } else {
             MergeStrings(&FullLoadOptions, LoadOptions, 0);
         } // if/else
-        // NOTE: We also include the terminating null in the length for safety.
-    } // if (LoadOptions != NULL)
+    } else { // LoadOptions == NULL
+       // NOTE: We provide a non-null string when no options are specified for safety;
+       // some systems (at least DUET) can hang when launching some programs (such as
+       // an EFI shell) without this.
+       FullLoadOptions = StrDuplicate(L" ");
+    }
     if (Verbose)
        Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions);
 
     // 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
-    SecureMode = secure_mode();
-//    SecureMode = TRUE;
     for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
-       // NOTE: Below commented-out line could simplify logic by loading the image once, 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.
+       // 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
+       // 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.
        // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
        //                                            ImageData, ImageSize, &ChildImageHandle);
-       // In Secure Boot mode, try to use shim/MOK-style loading first, and if
-       // that fails, try the standard EFI system call (LoadImage()). This is
-       // done for efficiency, to prevent loading a binary twice, which can
-       // take several seconds to load a Linux kernel with EFI stub support on
-       // some systems. Linux kernels are likely to be shim/MOK signed, so
-       // this is quickest for them; and delays for most other boot loaders
-       // will be unnoticeably short. To prevent delays or failures in case
-       // of buggy shim/MOK code on non-SB systems, skip that attempt and
-       // call LoadImage() directly when not in SB mode.
-       if (SecureMode) {
+       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);
@@ -232,21 +228,14 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
           } // if/else
           if (Status != EFI_NOT_FOUND) {
              ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions,
-                                                 DeviceVolume, DevicePaths[DevicePathIndex]);
+                                                 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 shim/MOK load fails, try regular EFI load, in case it's an unsupported
-          // binary type....
-          if (!UseMok) {
-             ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
-                                                         NULL, 0, &ChildImageHandle);
-          } // if (!UseMok)
-       } else { // Secure Boot inactive; only do standard call....
-          ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
-                                                      NULL, 0, &ChildImageHandle);
-       } // if/else (SecureMode)
+       } // if (UEFI SB failed; use shim)
        if (ReturnStatus != EFI_NOT_FOUND) {
           break;
        }
@@ -466,6 +455,22 @@ LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) {
    return (NewEntry);
 } // LOADER_ENTRY *InitializeLoaderEntry()
 
+// Adds InitrdPath to Options, but only if Options doesn't already include an
+// initrd= line. Done to enable overriding the default initrd selection in a
+// refind_linux.conf file's options list.
+// Returns a pointer to a new string. The calling function is responsible for
+// freeing its memory.
+static CHAR16 *AddInitrdToOptions(CHAR16 *Options, CHAR16 *InitrdPath) {
+   CHAR16 *NewOptions;
+
+   NewOptions = StrDuplicate(Options);
+   if ((InitrdPath != NULL) && !StriSubCmp(L"initrd=", Options)) {
+      MergeStrings(&NewOptions, L"initrd=", L' ');
+      MergeStrings(&NewOptions, InitrdPath, 0);
+   }
+   return NewOptions;
+} // CHAR16 *AddInitrdToOptions()
+
 // Prepare a REFIT_MENU_SCREEN data structure for a subscreen entry. This sets up
 // the default entry that launches the boot loader using the same options as the
 // main Entry does. Subsequent options can be added by the calling function.
@@ -474,7 +479,7 @@ LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) {
 // Returns a pointer to the new subscreen data structure, or NULL if there
 // were problems allocating memory.
 REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
-   CHAR16              *FileName, *Temp = NULL;
+   CHAR16              *FileName, *MainOptions = NULL;
    REFIT_MENU_SCREEN   *SubScreen = NULL;
    LOADER_ENTRY        *SubEntry;
 
@@ -490,12 +495,9 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
          SubEntry = InitializeLoaderEntry(Entry);
          if (SubEntry != NULL) {
             SubEntry->me.Title = L"Boot using default options";
-            if ((SubEntry->InitrdPath != NULL) && (StrLen(SubEntry->InitrdPath) > 0) && (!StriSubCmp(L"initrd", SubEntry->LoadOptions))) {
-               MergeStrings(&Temp, L"initrd=", 0);
-               MergeStrings(&Temp, SubEntry->InitrdPath, 0);
-               MergeStrings(&SubEntry->LoadOptions, Temp, L' ');
-               MyFreePool(Temp);
-            } // if
+            MainOptions = SubEntry->LoadOptions;
+            SubEntry->LoadOptions = AddInitrdToOptions(MainOptions, SubEntry->InitrdPath);
+            MyFreePool(MainOptions);
             AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
          } // if (SubEntry != NULL)
       } // if (SubScreen != NULL)
@@ -594,18 +596,14 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
    } else if (Entry->OSType == 'L') {   // entries for Linux kernels with EFI stub loaders
       File = ReadLinuxOptionsFile(Entry->LoaderPath, Volume);
       if (File != NULL) {
-         if ((Temp = FindInitrd(Entry->LoaderPath, Volume)) != NULL) {
-            MergeStrings(&InitrdOption, L"initrd=", 0);
-            MergeStrings(&InitrdOption, Temp, 0);
-         }
+         Temp =  FindInitrd(Entry->LoaderPath, Volume);
          TokenCount = ReadTokenLine(File, &TokenList); // read and discard first entry, since it's
          FreeTokenLine(&TokenList, &TokenCount);       // set up by InitializeSubScreen(), earlier....
          while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
             SubEntry = InitializeLoaderEntry(Entry);
             SubEntry->me.Title = StrDuplicate(TokenList[0]);
             MyFreePool(SubEntry->LoadOptions);
-            SubEntry->LoadOptions = StrDuplicate(TokenList[1]);
-            MergeStrings(&SubEntry->LoadOptions, InitrdOption, L' ');
+            SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], Temp);
             FreeTokenLine(&TokenList, &TokenCount);
             SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX;
             AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
@@ -691,18 +689,15 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
 // kernel's directory; and if present, adds an initrd= option for an initial
 // RAM disk file with the same version number as the kernel file.
 static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) {
-   CHAR16 *Options = NULL, *InitrdName, *InitrdOption = NULL;
+   CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL;
 
    Options = GetFirstOptionsFromFile(LoaderPath, Volume);
    InitrdName = FindInitrd(LoaderPath, Volume);
-   if (InitrdName != NULL) {
-      MergeStrings(&InitrdOption, L"initrd=", 0);
-      MergeStrings(&InitrdOption, InitrdName, 0);
-   } // if
-   MergeStrings(&Options, InitrdOption, ' ');
-   MyFreePool(InitrdOption);
+   FullOptions = AddInitrdToOptions(Options, InitrdName);
+
+   MyFreePool(Options);
    MyFreePool(InitrdName);
-   return (Options);
+   return (FullOptions);
 } // static CHAR16 * GetMainLinuxOptions()
 
 // Sets a few defaults for a loader entry -- mainly the icon, but also the OS type
@@ -728,6 +723,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME
    Temp = FindLastDirName(LoaderPath);
    MergeStrings(&OSIconName, Temp, L',');
    MyFreePool(Temp);
+   Temp = NULL;
    if (OSIconName != NULL) {
       ShortcutLetter = OSIconName[0];
    }
@@ -754,7 +750,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX;
    } else if (StriCmp(FileName, L"diags.efi") == 0) {
       MergeStrings(&OSIconName, L"hwtest", L',');
-   } else if (StriCmp(FileName, L"e.efi") == 0 || StriCmp(FileName, L"elilo.efi") == 0) {
+   } else if (StriCmp(FileName, L"e.efi") == 0 || StriCmp(FileName, L"elilo.efi") == 0 || StriSubCmp(L"elilo", FileName)) {
       MergeStrings(&OSIconName, L"elilo,linux", L',');
       Entry->OSType = 'E';
       if (ShortcutLetter == 0)
@@ -1864,7 +1860,7 @@ VOID RescanAll(VOID) {
    FreeList((VOID ***) &(MainMenu.Entries), &MainMenu.EntryCount);
    MainMenu.Entries = NULL;
    MainMenu.EntryCount = 0;
-   ReadConfig();
+   ReadConfig(CONFIG_FILE_NAME);
    ConnectAllDriversToAllControllers();
    ScanVolumes();
    ScanForBootloaders();
@@ -1914,7 +1910,7 @@ 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);
-    ReadConfig();
+    ReadConfig(CONFIG_FILE_NAME);
     WarnIfLegacyProblems();
     MainMenu.TimeoutSeconds = GlobalConfig.Timeout;