X-Git-Url: https://code.delx.au/refind/blobdiff_plain/7c898f4a26b66344e4cc8ed5c2e272d5ea0a71dc..293749865fc028016e6896402afd37d7021a5e48:/refind/main.c diff --git a/refind/main.c b/refind/main.c index 8f4cf39..7297c62 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,15 +48,20 @@ #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" #include "../include/syslinux_mbr.h" +#ifdef __MAKEWITH_TIANO +#include "../EfiLib/BdsHelper.h" +#endif // __MAKEWITH_TIANO + // // 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" @@ -68,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 @@ -89,8 +96,9 @@ 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, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - {TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }}; +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, 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. @@ -110,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.5"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.7.10"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -124,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 @@ -150,92 +160,144 @@ 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 CHAR16 *ImageTitle, IN CHAR8 OSType, OUT UINTN *ErrorInStep, IN BOOLEAN Verbose) { 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, SecureMode; - 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, L" ", 0); - // NOTE: That last space is also added by the EFI shell and seems to be significant - // when passing options to Apple's boot.efi... + if (OSType == 'M') { + MergeStrings(&FullLoadOptions, L" ", 0); + // NOTE: That last space is also added by the EFI shell and seems to be significant + // when passing options to Apple's boot.efi... + } // if } else { 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 + 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. + // 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) { + 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, 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 (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: - if (FullLoadOptions != NULL) - FreePool(FullLoadOptions); + MyFreePool(FullLoadOptions); return ReturnStatus; } /* static EFI_STATUS StartEFIImageList() */ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, - IN CHAR16 *ImageTitle, + IN CHAR16 *ImageTitle, IN CHAR8 OSType, OUT UINTN *ErrorInStep, IN BOOLEAN Verbose) { @@ -243,7 +305,7 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, DevicePaths[0] = DevicePath; DevicePaths[1] = NULL; - return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep, Verbose); + return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, OSType, ErrorInStep, Verbose); } /* static EFI_STATUS StartEFIImage() */ // @@ -255,8 +317,8 @@ static VOID StartLoader(IN LOADER_ENTRY *Entry) UINTN ErrorInStep = 0; BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); - StartEFIImage(Entry->DevicePath, Entry->LoadOptions, - Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), &ErrorInStep, !Entry->UseGraphicsMode); + StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath), + Basename(Entry->LoaderPath), Entry->OSType, &ErrorInStep, !Entry->UseGraphicsMode); FinishExternalScreen(); } @@ -304,14 +366,13 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { MergeStrings(&InitrdName, DirEntry->FileName, 0); } // if } // if/else - if (InitrdVersion != NULL) - FreePool(InitrdVersion); + MyFreePool(InitrdVersion); } // while DirIterClose(&DirIter); // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed. - FreePool(KernelVersion); - FreePool(Path); + MyFreePool(KernelVersion); + MyFreePool(Path); return (InitrdName); } // static CHAR16 * FindInitrd() @@ -330,8 +391,8 @@ static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) { NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); if ((Entry != NULL) && (NewEntry != NULL)) { CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_SCREEN)); - NewEntry->Title = StrDuplicate(Entry->Title); - NewEntry->TimeoutText = StrDuplicate(Entry->TimeoutText); + NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; + NewEntry->TimeoutText = (Entry->TimeoutText) ? StrDuplicate(Entry->TimeoutText) : NULL; if (Entry->TitleImage != NULL) { NewEntry->TitleImage = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->TitleImage != NULL) @@ -339,7 +400,7 @@ static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) { } // if NewEntry->InfoLines = (CHAR16**) AllocateZeroPool(Entry->InfoLineCount * (sizeof(CHAR16*))); for (i = 0; i < Entry->InfoLineCount && NewEntry->InfoLines; i++) { - NewEntry->InfoLines[i] = StrDuplicate(Entry->InfoLines[i]); + NewEntry->InfoLines[i] = (Entry->InfoLines[i]) ? StrDuplicate(Entry->InfoLines[i]) : NULL; } // for NewEntry->Entries = (REFIT_MENU_ENTRY**) AllocateZeroPool(Entry->EntryCount * (sizeof (REFIT_MENU_ENTRY*))); for (i = 0; i < Entry->EntryCount && NewEntry->Entries; i++) { @@ -360,7 +421,7 @@ static REFIT_MENU_ENTRY* CopyMenuEntry(REFIT_MENU_ENTRY *Entry) { NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY)); if ((Entry != NULL) && (NewEntry != NULL)) { CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_ENTRY)); - NewEntry->Title = StrDuplicate(Entry->Title); + NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; if (Entry->BadgeImage != NULL) { NewEntry->BadgeImage = AllocatePool(sizeof(EG_IMAGE)); if (NewEntry->BadgeImage != NULL) @@ -394,12 +455,12 @@ LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) { NewEntry->UseGraphicsMode = FALSE; NewEntry->OSType = 0; if (Entry != NULL) { - NewEntry->LoaderPath = StrDuplicate(Entry->LoaderPath); - NewEntry->VolName = StrDuplicate(Entry->VolName); + NewEntry->LoaderPath = (Entry->LoaderPath) ? StrDuplicate(Entry->LoaderPath) : NULL; + NewEntry->VolName = (Entry->VolName) ? StrDuplicate(Entry->VolName) : NULL; NewEntry->DevicePath = Entry->DevicePath; NewEntry->UseGraphicsMode = Entry->UseGraphicsMode; - NewEntry->LoadOptions = StrDuplicate(Entry->LoadOptions); - NewEntry->InitrdPath = StrDuplicate(Entry->InitrdPath); + NewEntry->LoadOptions = (Entry->LoadOptions) ? StrDuplicate(Entry->LoadOptions) : NULL; + NewEntry->InitrdPath = (Entry->InitrdPath) ? StrDuplicate(Entry->InitrdPath) : NULL; } } // if return (NewEntry); @@ -433,7 +494,7 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { MergeStrings(&Temp, L"initrd=", 0); MergeStrings(&Temp, SubEntry->InitrdPath, 0); MergeStrings(&SubEntry->LoadOptions, Temp, L' '); - FreePool(Temp); + MyFreePool(Temp); } // if AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if (SubEntry != NULL) @@ -455,7 +516,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { // create the submenu if (StrLen(Entry->Title) == 0) { - FreePool(Entry->Title); + MyFreePool(Entry->Title); Entry->Title = NULL; } SubScreen = InitializeSubScreen(Entry); @@ -522,7 +583,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Run Apple Hardware Test"; - FreePool(SubEntry->LoaderPath); + MyFreePool(SubEntry->LoaderPath); SubEntry->LoaderPath = StrDuplicate(DiagsFileName); SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; @@ -542,19 +603,16 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { SubEntry = InitializeLoaderEntry(Entry); SubEntry->me.Title = StrDuplicate(TokenList[0]); - if (SubEntry->LoadOptions != NULL) - FreePool(SubEntry->LoadOptions); + MyFreePool(SubEntry->LoadOptions); SubEntry->LoadOptions = StrDuplicate(TokenList[1]); MergeStrings(&SubEntry->LoadOptions, InitrdOption, L' '); FreeTokenLine(&TokenList, &TokenCount); SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // while - if (InitrdOption) - FreePool(InitrdOption); - if (Temp) - FreePool(Temp); - FreePool(File); + MyFreePool(InitrdOption); + MyFreePool(Temp); + MyFreePool(File); } // if Linux options file exists } else if (Entry->OSType == 'E') { // entries for ELILO @@ -642,10 +700,8 @@ static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Vol MergeStrings(&InitrdOption, InitrdName, 0); } // if MergeStrings(&Options, InitrdOption, ' '); - if (InitrdOption != NULL) - FreePool(InitrdOption); - if (InitrdName != NULL) - FreePool(InitrdName); + MyFreePool(InitrdOption); + MyFreePool(InitrdName); return (Options); } // static CHAR16 * GetMainLinuxOptions() @@ -671,7 +727,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME Temp = FindLastDirName(LoaderPath); MergeStrings(&OSIconName, Temp, L','); - FreePool(Temp); + MyFreePool(Temp); if (OSIconName != NULL) { ShortcutLetter = OSIconName[0]; } @@ -728,8 +784,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME Entry->me.ShortcutLetter = ShortcutLetter; if (Entry->me.Image == NULL) Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); - if (PathOnly != NULL) - FreePool(PathOnly); + MyFreePool(PathOnly); } // VOID SetLoaderDefaults() // Add a specified EFI boot loader to the list, using automatic settings @@ -813,8 +868,8 @@ static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) { while (LoaderList != NULL) { Temp = LoaderList; LoaderList = LoaderList->NextEntry; - FreePool(Temp->FileName); - FreePool(Temp); + MyFreePool(Temp->FileName); + MyFreePool(Temp); } // while } // static VOID CleanUpLoaderList() @@ -830,17 +885,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) @@ -854,7 +907,7 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *P NewLoader->TimeStamp = DirEntry->ModificationTime; LoaderList = AddLoaderListEntry(LoaderList, NewLoader); } // if - FreePool(Extension); + MyFreePool(Extension); } // while NewLoader = LoaderList; while (NewLoader != NULL) { @@ -865,9 +918,9 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *P Status = DirIterClose(&DirIter); if (Status != EFI_NOT_FOUND) { if (Path) - SPrint(FileName, 255, L"while scanning the %s directory", Path); + SPrint(FileName, 255, L"while scanning the %s directory", Path); else - StrCpy(FileName, L"while scanning the root directory"); + StrCpy(FileName, L"while scanning the root directory"); CheckError(Status, FileName); } // if (Status != EFI_NOT_FOUND) } // if not scanning our own directory @@ -880,28 +933,29 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { CHAR16 FileName[256], *Directory, *MatchPatterns; UINTN i, Length; - MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS); - if (GlobalConfig.ScanAllLinux) - MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L','); + MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS); + if (GlobalConfig.ScanAllLinux) + MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L','); 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); } @@ -913,7 +967,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); @@ -927,7 +981,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { Length = StrLen(Directory); if (Length > 0) ScanLoaderDir(Volume, Directory, MatchPatterns); - FreePool(Directory); + MyFreePool(Directory); } // while } // if } // static VOID ScanEfiFiles() @@ -1130,7 +1184,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) UINTN ErrorInStep = 0; EFI_DEVICE_PATH *DiscoveredPathList[MAX_DISCOVERED_PATHS]; - BeginExternalScreen(TRUE, L"Booting Legacy OS"); + BeginExternalScreen(TRUE, L"Booting Legacy OS (Mac mode)"); BootLogoImage = LoadOSIcon(Entry->Volume->OSIconName, L"legacy", TRUE); if (BootLogoImage != NULL) @@ -1145,7 +1199,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); - Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &ErrorInStep, TRUE); + Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", 0, &ErrorInStep, TRUE); if (Status == EFI_NOT_FOUND) { if (ErrorInStep == 1) { Print(L"\nPlease make sure that you have the latest firmware update installed.\n"); @@ -1157,6 +1211,22 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) FinishExternalScreen(); } /* static VOID StartLegacy() */ +// Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL +#ifdef __MAKEWITH_TIANO +static VOID StartLegacyUEFI(IN LEGACY_ENTRY *Entry) +{ + BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)"); + + BdsLibConnectDevicePath (Entry->BdsOption->DevicePath); + BdsLibDoLegacyBoot(Entry->BdsOption); + + // If we get here, it means that there was a failure.... + Print(L"Failure booting legacy (BIOS) OS."); + PauseForKey(); + FinishExternalScreen(); +} // static VOID StartLegacyUEFI() +#endif // __MAKEWITH_TIANO + static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) { LEGACY_ENTRY *Entry, *SubEntry; @@ -1212,6 +1282,135 @@ static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Vo return Entry; } /* static LEGACY_ENTRY * AddLegacyEntry() */ + +#ifdef __MAKEWITH_TIANO +// default volume badge icon based on disk kind +static EG_IMAGE * GetDiskBadge(IN UINTN DiskType) { + EG_IMAGE * Badge = NULL; + + switch (DiskType) { + case BBS_HARDDISK: + Badge = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); + break; + case BBS_USB: + Badge = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); + break; + case BBS_CDROM: + Badge = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); + break; + } // switch() + return Badge; +} // static EG_IMAGE * GetDiskBadge() + +/** + Create a rEFInd boot option from a Legacy BIOS protocol option. +*/ +static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16 DiskType) +{ + LEGACY_ENTRY *Entry, *SubEntry; + REFIT_MENU_SCREEN *SubScreen; + CHAR16 ShortcutLetter = 0; + CHAR16 *LegacyDescription = BdsOption->Description; + +// ScanVolume(Volume); + + // prepare the menu entry + Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(Entry->me.Title, 255, L"Boot legacy target %s", LegacyDescription); + Entry->me.Tag = TAG_LEGACY_UEFI; + Entry->me.Row = 0; + Entry->me.ShortcutLetter = ShortcutLetter; + Entry->me.Image = LoadOSIcon(L"legacy", L"legacy", TRUE); + Entry->LoadOptions = (DiskType == BBS_CDROM) ? L"CD" : + ((DiskType == BBS_USB) ? L"USB" : L"HD"); + Entry->me.BadgeImage = GetDiskBadge(DiskType); +// Entry->me.BadgeImage = Volume->VolBadgeImage; + Entry->BdsOption = BdsOption; + Entry->Enabled = TRUE; + + // create the submenu + SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubScreen->Title, 255, L"No boot options for legacy target"); + SubScreen->TitleImage = Entry->me.Image; + + // default entry + SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubEntry->me.Title, 255, L"Boot %s", LegacyDescription); + SubEntry->me.Tag = TAG_LEGACY_UEFI; + Entry->BdsOption = BdsOption; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + + AddMenuEntry(SubScreen, &MenuEntryReturn); + Entry->me.SubScreen = SubScreen; + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + return Entry; +} /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */ + +/** + Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL. + In testing, protocol has not been implemented on Macs but has been + implemented on several Dell PCs and an ASUS motherboard. + Restricts output to disks of the specified DiskType. +*/ +static VOID ScanLegacyUEFI(IN UINTN DiskType) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 *BootOrder = NULL; + UINTN Index = 0; + CHAR16 BootOption[10]; + UINTN BootOrderSize = 0; + CHAR16 Buffer[20]; + BDS_COMMON_OPTION *BdsOption; + LIST_ENTRY TempList; + BBS_BBS_DEVICE_PATH * BbsDevicePath = NULL; +// REFIT_VOLUME Volume; + + InitializeListHead (&TempList); + ZeroMem (Buffer, sizeof (Buffer)); + + // If LegacyBios protocol is not implemented on this platform, then + //we do not support this type of legacy boot on this machine. + Status = gBS->LocateProtocol(&gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) + return; + + // Grab the boot order + BootOrder = BdsLibGetVariableAndSize(L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize); + if (BootOrder == NULL) { + BootOrderSize = 0; + } + + Index = 0; + while (Index < BootOrderSize / sizeof (UINT16)) + { + // Grab each boot option variable from the boot order, and convert + // the variable into a BDS boot option + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BdsOption = BdsLibVariableToOption (&TempList, BootOption); + + if (BdsOption != NULL) { + BbsDevicePath = (BBS_BBS_DEVICE_PATH *)BdsOption->DevicePath; + + // Only add the entry if it is of a requested type (e.g. USB, HD) + + // Two checks necessary because some systems return EFI boot loaders + // with a DeviceType value that would inappropriately include them + // as legacy loaders.... + if ((BbsDevicePath->DeviceType == DiskType) && (BdsOption->DevicePath->Type == DEVICE_TYPE_BIOS)) { + AddLegacyEntryUEFI(BdsOption, BbsDevicePath->DeviceType); + } + } + Index++; + } +} /* static VOID ScanLegacyUEFI() */ +#else +static VOID ScanLegacyUEFI(IN UINTN DiskType){} +#endif // __MAKEWITH_TIANO + static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) { UINTN VolumeIndex2; BOOLEAN ShowVolume, HideIfOthersFound; @@ -1249,11 +1448,15 @@ static VOID ScanLegacyDisc(VOID) UINTN VolumeIndex; REFIT_VOLUME *Volume; - for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { - Volume = Volumes[VolumeIndex]; - if (Volume->DiskKind == DISK_KIND_OPTICAL) - ScanLegacyVolume(Volume, VolumeIndex); - } // for + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_OPTICAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for + } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { + ScanLegacyUEFI(BBS_CDROM); + } } /* static VOID ScanLegacyDisc() */ // Scan internal hard disks for legacy (BIOS) boot code @@ -1263,11 +1466,15 @@ static VOID ScanLegacyInternal(VOID) UINTN VolumeIndex; REFIT_VOLUME *Volume; - for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { - Volume = Volumes[VolumeIndex]; - if (Volume->DiskKind == DISK_KIND_INTERNAL) - ScanLegacyVolume(Volume, VolumeIndex); - } // for + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_INTERNAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for + } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { + ScanLegacyUEFI(BBS_HARDDISK); + } } /* static VOID ScanLegacyInternal() */ // Scan external disks for legacy (BIOS) boot code @@ -1277,11 +1484,15 @@ static VOID ScanLegacyExternal(VOID) UINTN VolumeIndex; REFIT_VOLUME *Volume; - for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { - Volume = Volumes[VolumeIndex]; - if (Volume->DiskKind == DISK_KIND_EXTERNAL) - ScanLegacyVolume(Volume, VolumeIndex); - } // for + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_EXTERNAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for + } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { + ScanLegacyUEFI(BBS_USB); + } } /* static VOID ScanLegacyExternal() */ // @@ -1292,11 +1503,11 @@ static VOID StartTool(IN LOADER_ENTRY *Entry) { BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start " as assigned below StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath), - Basename(Entry->LoaderPath), NULL, TRUE); + Basename(Entry->LoaderPath), Entry->OSType, NULL, TRUE); 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; @@ -1311,8 +1522,8 @@ static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle Entry->me.Row = 1; Entry->me.ShortcutLetter = ShortcutLetter; Entry->me.Image = Image; - Entry->LoaderPath = StrDuplicate(LoaderPath); - Entry->DevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, Entry->LoaderPath); + Entry->LoaderPath = (LoaderPath) ? StrDuplicate(LoaderPath) : NULL; + Entry->DevicePath = FileDevicePath(DeviceHandle, Entry->LoaderPath); Entry->UseGraphicsMode = UseGraphicsMode; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); @@ -1341,7 +1552,7 @@ static UINTN ScanDriverDir(IN CHAR16 *Path) SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName); NumFound++; Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName), - L"", DirEntry->FileName, DirEntry->FileName, NULL, FALSE); + L"", DirEntry->FileName, DirEntry->FileName, 0, NULL, FALSE); } Status = DirIterClose(&DirIter); if (Status != EFI_NOT_FOUND) { @@ -1411,12 +1622,12 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID) } } - FreePool (HandleBuffer); - FreePool (HandleType); + MyFreePool (HandleBuffer); + MyFreePool (HandleType); } Done: - FreePool (AllHandleBuffer); + MyFreePool (AllHandleBuffer); return Status; } /* EFI_STATUS ConnectAllDriversToAllControllers() */ #else @@ -1437,12 +1648,12 @@ static VOID LoadDrivers(VOID) // load drivers from the subdirectories of rEFInd's home directory specified // in the DRIVER_DIRS constant. while ((Directory = FindCommaDelimited(DRIVER_DIRS, i++)) != NULL) { - SelfDirectory = StrDuplicate(SelfDirPath); + SelfDirectory = SelfDirPath ? StrDuplicate(SelfDirPath) : NULL; CleanUpPathNameSlashes(SelfDirectory); MergeStrings(&SelfDirectory, Directory, L'\\'); NumFound += ScanDriverDir(SelfDirectory); - FreePool(Directory); - FreePool(SelfDirectory); + MyFreePool(Directory); + MyFreePool(SelfDirectory); } // Scan additional user-specified driver directories.... @@ -1450,9 +1661,10 @@ 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); - FreePool(Directory); + } // if + MyFreePool(Directory); } // while // connect all devices @@ -1460,8 +1672,64 @@ static VOID LoadDrivers(VOID) ConnectAllDriversToAllControllers(); } /* static VOID LoadDrivers() */ +// Determine what (if any) type of legacy (BIOS) boot support is available +static VOID FindLegacyBootType(VOID) { +#ifdef __MAKEWITH_TIANO + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; +#endif + + GlobalConfig.LegacyType = LEGACY_TYPE_NONE; + + // UEFI-style legacy BIOS support is available only with the TianoCore EDK2 + // build environment, and then only with some implementations.... +#ifdef __MAKEWITH_TIANO + Status = gBS->LocateProtocol (&gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (!EFI_ERROR (Status)) + GlobalConfig.LegacyType = LEGACY_TYPE_UEFI; +#endif + + // Macs have their own system. If the firmware vendor code contains the + // string "Apple", assume it's available. Note that this overrides the + // UEFI type, and might yield false positives if the vendor string + // contains "Apple" as part of something bigger, so this isn't 100% + // perfect. + if (StriSubCmp(L"Apple", ST->FirmwareVendor)) + GlobalConfig.LegacyType = LEGACY_TYPE_MAC; +} // static VOID FindLegacyBootType + +// Warn the user if legacy OS scans are enabled but the firmware or this +// application can't support them.... +static VOID WarnIfLegacyProblems() { + BOOLEAN found = FALSE; + UINTN i = 0; + + if (GlobalConfig.LegacyType == LEGACY_TYPE_NONE) { + do { + if (GlobalConfig.ScanFor[i] == 'h' || GlobalConfig.ScanFor[i] == 'b' || GlobalConfig.ScanFor[i] == 'c') + found = TRUE; + i++; + } while ((i < NUM_SCAN_OPTIONS) && (!found)); + if (found) { + Print(L"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n"); + Print(L"(BIOS) boot options; however, this is not possible because "); +#ifdef __MAKEWITH_TIANO + Print(L"your computer lacks\n"); + Print(L"the necessary Compatibility Support Module (CSM) support.\n"); +#else + Print(L"this program was\n"); + Print(L"compiled without the necessary support. Please visit\n"); + Print(L"http://www.rodsbooks.com/refind/getting.html and download and install a rEFInd\n"); + Print(L"binary built with the TianoCore EDK2 to enable legacy boot support.\n"); +#endif + PauseForKey(); + } // if (found) + } // if no legacy support +} // static VOID WarnIfLegacyProblems() + +// Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly. static VOID ScanForBootloaders(VOID) { - UINTN i; + UINTN i; ScanVolumes(); @@ -1503,9 +1771,9 @@ static VOID ScanForBootloaders(VOID) { // 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]) { @@ -1531,23 +1799,56 @@ static VOID ScanForTools(VOID) { 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() - if (FileName != NULL) { - FreePool(FileName); - FileName = NULL; - } + MyFreePool(FileName); + FileName = NULL; } // for } // static VOID ScanForTools @@ -1565,6 +1866,7 @@ VOID RescanAll(VOID) { MainMenu.EntryCount = 0; ReadConfig(); ConnectAllDriversToAllControllers(); + ScanVolumes(); ScanForBootloaders(); ScanForTools(); SetupScreen(); @@ -1578,6 +1880,7 @@ static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *System // gImageHandle = ImageHandle; gBS = SystemTable->BootServices; // gRS = SystemTable->RuntimeServices; + gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS); InitializeConsoleSim(); @@ -1595,8 +1898,9 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) EFI_STATUS Status; BOOLEAN MainLoopRunning = TRUE; REFIT_MENU_ENTRY *ChosenEntry; - UINTN MenuExit; + UINTN MenuExit, i; CHAR16 *Selection; + EG_PIXEL BGColor; // bootstrap InitializeLib(ImageHandle, SystemTable); @@ -1606,8 +1910,12 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) return Status; // read configuration - CopyMem(GlobalConfig.ScanFor, "ieo ", NUM_SCAN_OPTIONS); + CopyMem(GlobalConfig.ScanFor, "ieom ", NUM_SCAN_OPTIONS); + FindLegacyBootType(); + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) + CopyMem(GlobalConfig.ScanFor, "ihebocm ", NUM_SCAN_OPTIONS); ReadConfig(); + WarnIfLegacyProblems(); MainMenu.TimeoutSeconds = GlobalConfig.Timeout; // disable EFI watchdog timer @@ -1615,10 +1923,22 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) // further bootstrap (now with config available) SetupScreen(); + ScanVolumes(); LoadDrivers(); ScanForBootloaders(); ScanForTools(); + if (GlobalConfig.ScanDelay > 0) { + BGColor.b = 255; + BGColor.g = 175; + BGColor.r = 100; + BGColor.a = 0; + egDisplayMessage(L"Pausing before disk scan; please wait....", &BGColor); + for (i = 0; i < GlobalConfig.ScanDelay; i++) + refit_call1_wrapper(BS->Stall, 1000000); + RescanAll(); + } // if + Selection = StrDuplicate(GlobalConfig.DefaultSelection); while (MainLoopRunning) { MenuExit = RunMainMenu(&MainMenu, Selection, &ChosenEntry); @@ -1655,6 +1975,12 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) StartLegacy((LEGACY_ENTRY *)ChosenEntry); break; +#ifdef __MAKEWITH_TIANO + case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac + StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry); + break; +#endif // __MAKEWITH_TIANO + case TAG_TOOL: // Start a EFI tool StartTool((LOADER_ENTRY *)ChosenEntry); break; @@ -1665,8 +1991,8 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) break; } // switch() - FreePool(Selection); - Selection = StrDuplicate(ChosenEntry->Title); + MyFreePool(Selection); + Selection = (ChosenEntry->Title) ? StrDuplicate(ChosenEntry->Title) : NULL; } // while() // If we end up here, things have gone wrong. Try to reboot, and if that