*/
/*
* Modifications copyright (c) 2012 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
* with this source code or binaries made from it.
- *
+ *
*/
#include "global.h"
#include "lib.h"
#include "icns.h"
#include "menu.h"
+#include "mok.h"
#include "../include/Handle.h"
#include "../include/refit_call_wrapper.h"
#include "driver_support.h"
//
// variables
-#define MACOSX_LOADER_PATH L"System\\Library\\CoreServices\\boot.efi"
+#define MACOSX_LOADER_PATH L"\\System\\Library\\CoreServices\\boot.efi"
#if defined (EFIX64)
#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shellx64.efi"
#define DRIVER_DIRS L"drivers,drivers_x64"
#define DRIVER_DIRS L"drivers"
#endif
+#define MOK_NAMES L"\\EFI\\tools\\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
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,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- {TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 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 }};
// 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.4.6.3");
+ AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.5.0.1");
AddMenuInfoLine(&AboutMenu, L"");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
#if defined(EFI32)
AddMenuInfoLine(&AboutMenu, L" Platform: x86 (32 bit)");
#elif defined(EFIX64)
- AddMenuInfoLine(&AboutMenu, L" Platform: x86_64 (64 bit)");
+ TempStr = AllocateZeroPool(256 * sizeof(CHAR16));
+ SPrint(TempStr, 255, L" Platform: x86_64 (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive");
+ AddMenuInfoLine(&AboutMenu, TempStr);
#else
AddMenuInfoLine(&AboutMenu, L" Platform: unknown");
#endif
RunMenu(&AboutMenu, NULL);
} /* VOID AboutrEFInd() */
+// Launch an EFI binary.
static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
IN CHAR16 *ImageTitle, IN CHAR8 OSType,
{
EFI_STATUS Status, ReturnStatus;
EFI_HANDLE ChildImageHandle;
- EFI_LOADED_IMAGE *ChildLoadedImage;
+ EFI_LOADED_IMAGE *ChildLoadedImage = NULL;
+ REFIT_FILE File;
+ VOID *ImageData = NULL;
+ UINTN ImageSize;
+ REFIT_VOLUME *DeviceVolume = NULL;
UINTN DevicePathIndex;
CHAR16 ErrorInfo[256];
CHAR16 *FullLoadOptions = NULL;
+ CHAR16 *loader = NULL;
+ BOOLEAN UseMok = FALSE;
- if (Verbose)
- Print(L"Starting %s\n", ImageTitle);
if (ErrorInStep != NULL)
*ErrorInStep = 0;
- // load the image into memory
- ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty
- for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
- ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], NULL, 0, &ChildImageHandle);
- if (ReturnStatus != EFI_NOT_FOUND) {
- break;
- }
- }
- SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle);
- if (CheckError(Status, ErrorInfo)) {
- if (ErrorInStep != NULL)
- *ErrorInStep = 1;
- goto bailout;
- }
-
// set load options
if (LoadOptions != NULL) {
- ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage);
- if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
- if (ErrorInStep != NULL)
- *ErrorInStep = 2;
- goto bailout_unload;
- }
-
if (LoadOptionsPrefix != NULL) {
MergeStrings(&FullLoadOptions, LoadOptionsPrefix, 0);
MergeStrings(&FullLoadOptions, LoadOptions, L' ');
MergeStrings(&FullLoadOptions, LoadOptions, 0);
} // if/else
// NOTE: We also include the terminating null in the length for safety.
- ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions;
- ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16);
- if (Verbose)
- Print(L"Using load options '%s'\n", FullLoadOptions);
- }
-
- // close open file handles
- UninitRefitLib();
+ } // if (LoadOptions != NULL)
+ if (Verbose)
+ Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions);
- // turn control over to the image
- // TODO: (optionally) re-enable the EFI watchdog timer!
- ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL);
- // control returns here when the child image calls Exit()
- SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle);
+ // 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
+ for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
+ // 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);
+ 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);
+ ImageData = File.Buffer;
+ } else {
+ Status = EFI_NOT_FOUND;
+ Print(L"Error: device volume not found!\n");
+ } // if/else
+ if (Status != EFI_NOT_FOUND) {
+ ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions,
+ 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 (UEFI SB failed; use shim)
+ if (ReturnStatus != EFI_NOT_FOUND) {
+ break;
+ }
+ }
+ SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle);
if (CheckError(Status, ErrorInfo)) {
if (ErrorInStep != NULL)
- *ErrorInStep = 3;
+ *ErrorInStep = 1;
+ goto bailout;
}
- // re-open file handles
- ReinitRefitLib();
+ if (!UseMok) {
+ ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol,
+ (VOID **) &ChildLoadedImage);
+ if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
+ if (ErrorInStep != NULL)
+ *ErrorInStep = 2;
+ goto bailout_unload;
+ }
+ ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions;
+ ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16);
+ // turn control over to the image
+ // TODO: (optionally) re-enable the EFI watchdog timer!
+
+ // close open file handles
+ UninitRefitLib();
+ ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL);
+ // control returns here when the child image calls Exit()
+ SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle);
+ if (CheckError(Status, ErrorInfo)) {
+ if (ErrorInStep != NULL)
+ *ErrorInStep = 3;
+ }
+
+ // re-open file handles
+ ReinitRefitLib();
+ } // if
bailout_unload:
// unload the image, we don't care if it works or not...
- Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle);
+ if (!UseMok)
+ Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle);
+
bailout:
MyFreePool(FullLoadOptions);
return ReturnStatus;
Temp = FindLastDirName(LoaderPath);
MergeStrings(&OSIconName, Temp, L',');
MyFreePool(Temp);
+ Temp = NULL;
if (OSIconName != NULL) {
ShortcutLetter = OSIconName[0];
}
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 (secure_mode()) { // hack to enable ELILO to boot in secure mode
+ Temp = StrDuplicate(L"-C ");
+ MergeStrings(&Temp, PathOnly, 0);
+ MergeStrings(&Temp, L"elilo.conf", L'\\');
+ Entry->LoadOptions = Temp;
+ }
if (ShortcutLetter == 0)
ShortcutLetter = 'L';
Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
struct LOADER_LIST *LoaderList = NULL, *NewLoader;
if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && Volume->DeviceHandle != SelfVolume->DeviceHandle) ||
- (StriCmp(Path, SelfDirPath) != 0)) && (!IsIn(Path, GlobalConfig.DontScan))) {
+ (StriCmp(Path, SelfDirPath) != 0)) && (!IsIn(Path, GlobalConfig.DontScanDirs))) {
// look through contents of the directory
DirIterOpen(Volume->RootDir, Path, &DirIter);
while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) {
Extension = FindExtension(DirEntry->FileName);
if (DirEntry->FileName[0] == '.' ||
- StriCmp(DirEntry->FileName, L"TextMode.efi") == 0 ||
- StriCmp(DirEntry->FileName, L"ebounce.efi") == 0 ||
- StriCmp(DirEntry->FileName, L"GraphicsConsole.efi") == 0 ||
StriCmp(Extension, L".icns") == 0 ||
- StriSubCmp(L"shell", DirEntry->FileName))
+ StriSubCmp(L"shell", DirEntry->FileName) ||
+ IsIn(DirEntry->FileName, GlobalConfig.DontScanFiles))
continue; // skip this
if (Path)
if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
// check for Mac OS X boot loader
- if (!IsIn(L"System\\Library\\CoreServices", GlobalConfig.DontScan)) {
+ if (!IsIn(L"\\System\\Library\\CoreServices", GlobalConfig.DontScanDirs)) {
StrCpy(FileName, MACOSX_LOADER_PATH);
- if (FileExists(Volume->RootDir, FileName)) {
+ if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) {
AddLoaderEntry(FileName, L"Mac OS X", Volume);
}
// check for XOM
- StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi");
- if (FileExists(Volume->RootDir, FileName)) {
+ StrCpy(FileName, L"\\System\\Library\\CoreServices\\xom.efi");
+ if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) {
AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume);
}
- } // if Mac directory not in GlobalConfig.DontScan list
+ } // if Mac directory not in GlobalConfig.DontScanDirs list
// check for Microsoft boot loader/menu
- StrCpy(FileName, L"EFI\\Microsoft\\Boot\\Bootmgfw.efi");
- if (FileExists(Volume->RootDir, FileName) && !IsIn(L"EFI\\Microsoft\\Boot", GlobalConfig.DontScan)) {
+ StrCpy(FileName, L"\\EFI\\Microsoft\\Boot\\Bootmgfw.efi");
+ if (FileExists(Volume->RootDir, FileName) && !IsIn(L"\\EFI\\Microsoft\\Boot", GlobalConfig.DontScanDirs) &&
+ !IsIn(L"bootmgfw.efi", GlobalConfig.DontScanFiles)) {
AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume);
}
while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) {
if (StriCmp(EfiDirEntry->FileName, L"tools") == 0 || EfiDirEntry->FileName[0] == '.')
continue; // skip this, doesn't contain boot loaders
- SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName);
+ SPrint(FileName, 255, L"\\EFI\\%s", EfiDirEntry->FileName);
ScanLoaderDir(Volume, FileName, MatchPatterns);
} // while()
Status = DirIterClose(&EfiDirIter);
FinishExternalScreen();
} /* static VOID StartTool() */
-static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image,
+static LOADER_ENTRY * AddToolEntry(EFI_HANDLE DeviceHandle, IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image,
IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode)
{
LOADER_ENTRY *Entry;
Entry->me.ShortcutLetter = ShortcutLetter;
Entry->me.Image = Image;
Entry->LoaderPath = (LoaderPath) ? StrDuplicate(LoaderPath) : NULL;
- Entry->DevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, Entry->LoaderPath);
+ Entry->DevicePath = FileDevicePath(DeviceHandle, Entry->LoaderPath);
Entry->UseGraphicsMode = UseGraphicsMode;
AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) {
CleanUpPathNameSlashes(Directory);
Length = StrLen(Directory);
- if (Length > 0)
+ if (Length > 0) {
NumFound += ScanDriverDir(Directory);
+ } // if
MyFreePool(Directory);
} // while
// Add the second-row tags containing built-in and external tools (EFI shell,
// reboot, etc.)
static VOID ScanForTools(VOID) {
- CHAR16 *FileName = NULL;
+ CHAR16 *FileName = NULL, Description[256];
REFIT_MENU_ENTRY *TempMenuEntry;
- UINTN i, j;
+ UINTN i, j, VolumeIndex;
for (i = 0; i < NUM_TOOLS; i++) {
switch(GlobalConfig.ShowTools[i]) {
break;
case TAG_SHELL:
j = 0;
+ MyFreePool(FileName);
while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
if (FileExists(SelfRootDir, FileName)) {
- AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'S', FALSE);
+ AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL),
+ 'S', FALSE);
}
} // while
break;
case TAG_GPTSYNC:
+ MyFreePool(FileName);
+ FileName = NULL;
MergeStrings(&FileName, L"\\efi\\tools\\gptsync.efi", 0);
if (FileExists(SelfRootDir, FileName)) {
- AddToolEntry(FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE);
+ AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE);
+ }
+ break;
+ case TAG_APPLE_RECOVERY:
+ MyFreePool(FileName);
+ FileName = NULL;
+ MergeStrings(&FileName, L"\\com.apple.recovery.boot\\boot.efi", 0);
+ for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+ if ((Volumes[VolumeIndex]->RootDir != NULL) && (FileExists(Volumes[VolumeIndex]->RootDir, FileName))) {
+ SPrint(Description, 255, L"Apple Recovery on %s", Volumes[VolumeIndex]->VolName);
+ AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description,
+ BuiltinIcon(BUILTIN_ICON_TOOL_APPLE_RESCUE), 'R', TRUE);
+ }
+ } // for
+ 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")) {
+ MyFreePool(FileName);
+ FileName = StrDuplicate(SelfDirPath);
+ 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);
}
break;
} // switch()
MainMenu.EntryCount = 0;
ReadConfig();
ConnectAllDriversToAllControllers();
+ ScanVolumes();
ScanForBootloaders();
ScanForTools();
SetupScreen();
// further bootstrap (now with config available)
SetupScreen();
+ ScanVolumes();
LoadDrivers();
ScanForBootloaders();
ScanForTools();