]> code.delx.au - refind/blobdiff - refind/main.c
ChromeOS icon.
[refind] / refind / main.c
index ba1d8508cac1b8cc8d55e9dbf919f93713252ad4..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,\\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,\\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,\\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 */
 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;",
@@ -112,7 +120,11 @@ static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 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.
@@ -132,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.8");
+        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"");
@@ -308,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
 //
@@ -975,6 +1050,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)
@@ -1004,8 +1082,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
@@ -1014,10 +1093,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,
@@ -1093,7 +1173,7 @@ 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;
 
@@ -1121,7 +1201,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
       } // if should scan Mac directory
 
       // check for Microsoft boot loader/menu
-      StrCpy(FileName, L"EFI\\Microsoft\\Boot\\Bootmgfw.efi");
+      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);
@@ -1158,11 +1238,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()
 
@@ -1962,6 +2047,8 @@ static VOID ScanForTools(VOID) {
    CHAR16 *FileName = NULL, *MokLocations, *MokName, *PathName, Description[256];
    REFIT_MENU_ENTRY *TempMenuEntry;
    UINTN i, j, k, VolumeIndex;
+   UINT64 osind;
+   CHAR8 *b = 0;
 
    MokLocations = StrDuplicate(MOK_LOCATIONS);
    if (MokLocations != NULL)
@@ -1990,6 +2077,16 @@ 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;
             while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
@@ -2001,11 +2098,14 @@ static VOID ScanForTools(VOID) {
             } // while
             break;
          case TAG_GPTSYNC:
-            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);
-            }
-            MyFreePool(FileName);
+            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:
@@ -2228,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;