X-Git-Url: https://code.delx.au/refind/blobdiff_plain/f65fe9b450f766c1769d6eb6e3426fa24736df69..7d3dcb8b4f3e617d60b753757e97f16325b77f4b:/refind/main.c diff --git a/refind/main.c b/refind/main.c index df81018..ec39e5a 100644 --- a/refind/main.c +++ b/refind/main.c @@ -35,11 +35,11 @@ */ /* * 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" @@ -48,6 +48,7 @@ #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" @@ -60,7 +61,7 @@ // // 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" @@ -72,6 +73,8 @@ #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 @@ -94,8 +97,8 @@ static REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL 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_APPLE_RECOVERY, 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. @@ -115,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.3"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.7.12"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -129,7 +132,9 @@ static VOID AboutrEFInd(VOID) #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 @@ -155,6 +160,7 @@ static VOID AboutrEFInd(VOID) 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, @@ -163,40 +169,22 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, { 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' '); @@ -209,31 +197,84 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, 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; @@ -829,17 +870,15 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *P 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) @@ -885,22 +924,23 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { 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); } @@ -912,7 +952,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *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); @@ -1468,7 +1508,6 @@ static LOADER_ENTRY * AddToolEntry(EFI_HANDLE DeviceHandle, IN CHAR16 *LoaderPat 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; @@ -1607,8 +1646,9 @@ static VOID LoadDrivers(VOID) 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 @@ -1744,9 +1784,11 @@ static VOID ScanForTools(VOID) { break; case TAG_SHELL: j = 0; + MyFreePool(FileName); while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) { if (FileExists(SelfRootDir, FileName)) { - AddToolEntry(SelfLoadedImage->DeviceHandle, 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; @@ -1770,6 +1812,25 @@ static VOID ScanForTools(VOID) { } } // 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() MyFreePool(FileName); FileName = NULL; @@ -1790,6 +1851,7 @@ VOID RescanAll(VOID) { MainMenu.EntryCount = 0; ReadConfig(); ConnectAllDriversToAllControllers(); + ScanVolumes(); ScanForBootloaders(); ScanForTools(); SetupScreen(); @@ -1846,6 +1908,7 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) // further bootstrap (now with config available) SetupScreen(); + ScanVolumes(); LoadDrivers(); ScanForBootloaders(); ScanForTools();