* 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,\\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 */
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;",
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 }};
+ { 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.
if (AboutMenu.EntryCount == 0) {
AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
- AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.7");
+ 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"");
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
//
// 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
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)
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
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,
} // 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() */
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
} // 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);
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()
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)
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) {
} // 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:
}
break;
+ case TAG_FIRMWARE: // Reboot into firmware's user interface
+ RebootIntoFirmware();
+ break;
+
} // switch()
MyFreePool(Selection);
Selection = (ChosenEntry->Title) ? StrDuplicate(ChosenEntry->Title) : NULL;