X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e07b72471fa62945801b4a4e3bcac662a1b4888d..4677259a82b13dd1ab9fb6696d0ffe8976aeae34:/refind/main.c diff --git a/refind/main.c b/refind/main.c index ca7bb13..5383779 100644 --- a/refind/main.c +++ b/refind/main.c @@ -34,7 +34,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* - * Modifications copyright (c) 2012-2013 Roderick W. Smith + * Modifications copyright (c) 2012-2014 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 @@ -56,9 +56,12 @@ #include "../include/syslinux_mbr.h" #ifdef __MAKEWITH_GNUEFI +#ifndef EFI_SECURITY_VIOLATION #define EFI_SECURITY_VIOLATION EFIERR (26) +#endif #else #include "../EfiLib/BdsHelper.h" +#include "../EfiLib/legacy.h" #endif // __MAKEWITH_GNUEFI #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI @@ -66,12 +69,13 @@ #endif // -// variables +// constants #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 MEMTEST_NAMES L"memtest86.efi,memtest86_x64.efi,memtest86x64.efi,bootx64.efi" #define DRIVER_DIRS L"drivers,drivers_x64" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootx64.efi" #define FALLBACK_BASENAME L"bootx64.efi" @@ -79,6 +83,7 @@ #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 MEMTEST_NAMES L"memtest86.efi,memtest86_ia32.efi,memtest86ia32.efi,bootia32.efi" #define DRIVER_DIRS L"drivers,drivers_ia32" #define FALLBACK_FULLNAME L"EFI\\BOOT\\bootia32.efi" #define FALLBACK_BASENAME L"bootia32.efi" @@ -86,6 +91,7 @@ #else #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shell.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi" +#define MEMTEST_NAMES L"memtest86.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 */ @@ -109,6 +115,10 @@ #define SUBSCREEN_HINT2 L"Insert or F2 to edit options; Esc to return to main menu" #define SUBSCREEN_HINT2_NO_EDITOR L"Esc to return to main menu" +// Load types +#define TYPE_EFI 1 +#define TYPE_LEGACY 2 + 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 }; @@ -122,9 +132,10 @@ 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, 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, 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, TAG_FIRMWARE, - 0, 0, 0, 0, 0, 0 } + { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, BANNER_NOSCALE, + NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + { TAG_SHELL, TAG_MEMTEST, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, + TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, 0, 0, 0, 0, 0, 0 } }; EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE; @@ -143,11 +154,9 @@ struct LOADER_LIST { static VOID AboutrEFInd(VOID) { - CHAR16 *TempStr; // Note: Don't deallocate; moved to menu structure - if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.0"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.8"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2013 Roderick W. Smith"); @@ -155,25 +164,18 @@ static VOID AboutrEFInd(VOID) AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Running on:"); - TempStr = AllocateZeroPool(256 * sizeof(CHAR16)); - SPrint(TempStr, 255, L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1)); - AddMenuInfoLine(&AboutMenu, TempStr); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1))); #if defined(EFI32) AddMenuInfoLine(&AboutMenu, L" Platform: x86 (32 bit)"); #elif defined(EFIX64) - 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); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s", + secure_mode() ? L"active" : L"inactive")); #else AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); #endif - TempStr = AllocateZeroPool(256 * sizeof(CHAR16)); - SPrint(TempStr, 255, L" Firmware: %s %d.%02d", - ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & ((1 << 16) - 1)); - AddMenuInfoLine(&AboutMenu, TempStr); - TempStr = AllocateZeroPool(256 * sizeof(CHAR16)); - SPrint(TempStr, 255, L" Screen Output: %s", egScreenDescription()); - AddMenuInfoLine(&AboutMenu, TempStr); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, + ST->FirmwareRevision & ((1 << 16) - 1))); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription())); AddMenuInfoLine(&AboutMenu, L""); #if defined(__MAKEWITH_GNUEFI) AddMenuInfoLine(&AboutMenu, L"Built with GNU-EFI"); @@ -210,9 +212,44 @@ static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) { } // if } // VOID WarnSecureBootError() +// Returns TRUE if this file is a valid EFI loader file, and is proper ARCH +static BOOLEAN IsValidLoader(EFI_FILE *RootDir, CHAR16 *FileName) { + BOOLEAN IsValid = TRUE; +#if defined (EFIX64) | defined (EFI32) + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + CHAR8 Header[512]; + UINTN Size = sizeof(Header); + + if ((RootDir == NULL) || (FileName == NULL)) { + // Assume valid here, because Macs produce NULL RootDir (& maybe FileName) + // when launching from a Firewire drive. This should be handled better, but + // fix would have to be in StartEFIImageList() and/or in FindVolumeAndFilename(). + return TRUE; + } // if + + Status = refit_call5_wrapper(RootDir->Open, RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) + return FALSE; + + Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header); + refit_call1_wrapper(FileHandle->Close, FileHandle); + + IsValid = !EFI_ERROR(Status) && + Size == sizeof(Header) && + ((Header[0] == 'M' && Header[1] == 'Z' && + (Size = *(UINT32 *)&Header[0x3c]) < 0x180 && + Header[Size] == 'P' && Header[Size+1] == 'E' && + Header[Size+2] == 0 && Header[Size+3] == 0 && + *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) || + (*(UINT32 *)&Header == FAT_ARCH)); +#endif + return IsValid; +} // BOOLEAN IsValidLoader() + // Launch an EFI binary. static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, - IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, + IN CHAR16 *LoadOptions, IN UINTN LoaderType, IN CHAR16 *ImageTitle, IN CHAR8 OSType, OUT UINTN *ErrorInStep, IN BOOLEAN Verbose) @@ -220,46 +257,57 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, EFI_STATUS Status, ReturnStatus; EFI_HANDLE ChildImageHandle; EFI_LOADED_IMAGE *ChildLoadedImage = NULL; + REFIT_VOLUME *Volume = NULL; UINTN DevicePathIndex; CHAR16 ErrorInfo[256]; CHAR16 *FullLoadOptions = NULL; + CHAR16 *Filename = NULL; + CHAR16 *Temp; if (ErrorInStep != NULL) *ErrorInStep = 0; // set load options if (LoadOptions != NULL) { - if (LoadOptionsPrefix != NULL) { - MergeStrings(&FullLoadOptions, LoadOptions, L' '); - 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 - } else { // LoadOptions == NULL - // NOTE: We provide a non-null string when no options are specified for safety; - // some systems (at least DUET) can hang when launching some programs (such as - // an EFI shell) without this. - FullLoadOptions = StrDuplicate(L" "); - } + FullLoadOptions = StrDuplicate(LoadOptions); + if ((LoaderType == TYPE_EFI) && (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 + } // if (LoadOptions != NULL) if (Verbose) - Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions); + Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions ? FullLoadOptions : L""); // 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 file were read ahead of - // time and passed as a pre-loaded image to LoadImage(), 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); + FindVolumeAndFilename(DevicePaths[DevicePathIndex], &Volume, &Filename); + // Some EFIs crash if attempting to load driver for invalid architecture, so + // protect for this condition; but sometimes Volume comes back NULL, so provide + // an exception. (TODO: Handle this special condition better.) + if ((LoaderType == TYPE_LEGACY) || (Volume == NULL) || IsValidLoader(Volume->RootDir, Filename)) { + if (Filename && (LoaderType != TYPE_LEGACY)) { + Temp = PoolPrint(L"\\%s %s", Filename, FullLoadOptions ? FullLoadOptions : L""); + if (Temp != NULL) { + MyFreePool(FullLoadOptions); + FullLoadOptions = Temp; + } + } // if (Filename) + + // NOTE: Below commented-out line could be more efficient if file were read ahead of + // time and passed as a pre-loaded image to LoadImage(), 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); + } else { + Print(L"Invalid loader file!\n"); + ReturnStatus = EFI_LOAD_ERROR; + } if (ReturnStatus != EFI_NOT_FOUND) { break; } @@ -283,7 +331,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, goto bailout_unload; } ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; - ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16); + ChildLoadedImage->LoadOptionsSize = FullLoadOptions ? ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16) : 0; // turn control over to the image // TODO: (optionally) re-enable the EFI watchdog timer! @@ -311,7 +359,7 @@ bailout: } /* static EFI_STATUS StartEFIImageList() */ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, - IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, + IN CHAR16 *LoadOptions, IN UINTN LoaderType, IN CHAR16 *ImageTitle, IN CHAR8 OSType, OUT UINTN *ErrorInStep, IN BOOLEAN Verbose) @@ -320,7 +368,7 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, DevicePaths[0] = DevicePath; DevicePaths[1] = NULL; - return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, OSType, ErrorInStep, Verbose); + return StartEFIImageList(DevicePaths, LoadOptions, LoaderType, ImageTitle, OSType, ErrorInStep, Verbose); } /* static EFI_STATUS StartEFIImage() */ // From gummiboot: Retrieve a raw EFI variable. @@ -377,7 +425,6 @@ static EFI_STATUS RebootIntoFirmware(VOID) { 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; } @@ -391,7 +438,7 @@ static VOID StartLoader(LOADER_ENTRY *Entry) UINTN ErrorInStep = 0; BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); - StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath), + StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, Basename(Entry->LoaderPath), Entry->OSType, &ErrorInStep, !Entry->UseGraphicsMode); FinishExternalScreen(); } @@ -431,13 +478,11 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { InitrdVersion = FindNumbers(DirEntry->FileName); if (KernelVersion != NULL) { if (StriCmp(InitrdVersion, KernelVersion) == 0) { - MergeStrings(&InitrdName, Path, 0); - MergeStrings(&InitrdName, DirEntry->FileName, 0); + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); } // if } else { if (InitrdVersion == NULL) { - MergeStrings(&InitrdName, Path, 0); - MergeStrings(&InitrdName, DirEntry->FileName, 0); + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); } // if } // if/else MyFreePool(InitrdVersion); @@ -853,7 +898,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo // 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 = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, 128); + Entry->me.Image = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, GlobalConfig.IconSizes[ICON_SIZE_BIG]); if (!Entry->me.Image) Entry->me.Image = egCopyImage(Volume->VolIconImage); @@ -888,7 +933,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo } // if // detect specific loaders - if (StriSubCmp(L"bzImage", LoaderPath) || StriSubCmp(L"vmlinuz", LoaderPath)) { + if (StriSubCmp(L"bzImage", FileName) || StriSubCmp(L"vmlinuz", FileName)) { GuessLinuxDistribution(&OSIconName, Volume, LoaderPath); MergeStrings(&OSIconName, L"linux", L','); Entry->OSType = 'L'; @@ -926,7 +971,8 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_GRUB; } else if (StriCmp(FileName, L"cdboot.efi") == 0 || StriCmp(FileName, L"bootmgr.efi") == 0 || - StriCmp(FileName, L"bootmgfw.efi") == 0) { + StriCmp(FileName, L"bootmgfw.efi") == 0 || + StriCmp(FileName, L"bkpbootmgfw.efi") == 0) { MergeStrings(&OSIconName, L"win", L','); Entry->OSType = 'W'; ShortcutLetter = 'W'; @@ -957,7 +1003,7 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN if (Entry != NULL) { Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath); Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256); - SPrint(Entry->me.Title, 255, L"Boot %s from %s", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName); + SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName); Entry->me.Row = 0; Entry->me.BadgeImage = Volume->VolBadgeImage; if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) { @@ -1038,8 +1084,8 @@ static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) { // Returns TRUE if none of these conditions is met -- that is, if the path is // eligible for scanning. static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) { - CHAR16 *VolName = NULL, *DontScanDir; - UINTN i = 0, VolNum; + CHAR16 *VolName = NULL, *DontScanDir, *PathCopy = NULL; + UINTN i = 0; BOOLEAN ScanIt = TRUE; if (IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) @@ -1048,24 +1094,35 @@ static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) { if ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle == SelfVolume->DeviceHandle)) return FALSE; + // See if Path includes an explicit volume declaration that's NOT Volume.... + PathCopy = StrDuplicate(Path); + if (SplitVolumeAndFilename(&PathCopy, &VolName)) { + VolumeNumberToName(Volume, &VolName); + if (VolName && StriCmp(VolName, Volume->VolName) != 0) { + ScanIt = FALSE; + } // if + } // if Path includes volume specification + MyFreePool(PathCopy); + MyFreePool(VolName); + VolName = NULL; + + // See if Volume is in GlobalConfig.DontScanDirs.... while ((DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++)) && ScanIt) { SplitVolumeAndFilename(&DontScanDir, &VolName); CleanUpPathNameSlashes(DontScanDir); + VolumeNumberToName(Volume, &VolName); if (VolName != NULL) { if ((StriCmp(VolName, Volume->VolName) == 0) && (StriCmp(DontScanDir, Path) == 0)) ScanIt = FALSE; - if ((StrLen(VolName) > 2) && (VolName[0] == L'f') && (VolName[1] == L's') && (VolName[2] >= L'0') && (VolName[2] <= L'9')) { - VolNum = Atoi(VolName + 2); - if ((VolNum == Volume->VolNumber) && (StriCmp(DontScanDir, Path) == 0)) - ScanIt = FALSE; - } } else { if (StriCmp(DontScanDir, Path) == 0) ScanIt = FALSE; } MyFreePool(DontScanDir); + MyFreePool(VolName); DontScanDir = NULL; - } + } // while() + return ScanIt; } // BOOLEAN ShouldScan() @@ -1164,34 +1221,6 @@ static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO return (DirEntry->FileSize != FileSize2); } // BOOLEAN IsSymbolicLink() -// Returns TRUE if this file is a valid EFI loader file, and is proper ARCH -static BOOLEAN IsValidLoader(REFIT_VOLUME *Volume, CHAR16 *FileName) { - BOOLEAN IsValid = TRUE; -#if defined (EFIX64) | defined (EFI32) - EFI_STATUS Status; - EFI_FILE_HANDLE FileHandle; - CHAR8 Header[512]; - UINTN Size = sizeof(Header); - - Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); - if (EFI_ERROR(Status)) - return 0; - - Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header); - refit_call1_wrapper(FileHandle->Close, FileHandle); - - IsValid = !EFI_ERROR(Status) && - Size == sizeof(Header) && - ((Header[0] == 'M' && Header[1] == 'Z' && - (Size = *(UINT32 *)&Header[0x3c]) < 0x180 && - Header[Size] == 'P' && Header[Size+1] == 'E' && - Header[Size+2] == 0 && Header[Size+3] == 0 && - *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) || - (*(UINT32 *)&Header == FAT_ARCH)); -#endif - return IsValid; -} // BOOLEAN IsValidLoader() - // Scan an individual directory for EFI boot loader files and, if found, // add them to the list. Exception: Ignores FALLBACK_FULLNAME, which is picked // up in ScanEfiFiles(). Sorts the entries within the loader directory so that @@ -1219,7 +1248,7 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 (StriCmp(DirEntry->FileName, FALLBACK_BASENAME) == 0 && (StriCmp(Path, L"EFI\\BOOT") == 0)) || StriSubCmp(L"shell", DirEntry->FileName) || IsSymbolicLink(Volume, Path, DirEntry) || /* is symbolic link */ - IsIn(DirEntry->FileName, GlobalConfig.DontScanFiles)) + FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles)) continue; // skip this if (Path) @@ -1228,9 +1257,7 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 SPrint(FileName, 255, L"\\%s", DirEntry->FileName); CleanUpPathNameSlashes(FileName); - if( /* (!StriSubCmp(L"vmlinuz", DirEntry->FileName) || - !StriSubCmp(L"bzImage", DirEntry->FileName)) && */ - !IsValidLoader(Volume, FileName)) + if(!IsValidLoader(Volume->RootDir, FileName)) continue; NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST)); @@ -1272,19 +1299,20 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { EFI_STATUS Status; REFIT_DIR_ITER EfiDirIter; EFI_FILE_INFO *EfiDirEntry; - CHAR16 FileName[256], *Directory, *MatchPatterns, *VolName = NULL, *SelfPath; + CHAR16 FileName[256], *Directory = NULL, *MatchPatterns, *VolName = NULL, *SelfPath; UINTN i, Length; BOOLEAN ScanFallbackLoader = TRUE; + BOOLEAN FoundBRBackup = FALSE; MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS); if (GlobalConfig.ScanAllLinux) MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L','); - if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) { + if ((Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) { // check for Mac OS X boot loader if (ShouldScan(Volume, L"System\\Library\\CoreServices")) { StrCpy(FileName, MACOSX_LOADER_PATH); - if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) { + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, Directory, L"boot.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"Mac OS X", Volume); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; @@ -1292,7 +1320,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { // check for XOM StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi"); - if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) { + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, Directory, L"boot.efi", GlobalConfig.DontScanFiles)) { AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; @@ -1300,13 +1328,24 @@ 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"); - if (FileExists(Volume->RootDir, FileName) && ShouldScan(Volume, L"EFI\\Microsoft\\Boot") && - !IsIn(L"bootmgfw.efi", GlobalConfig.DontScanFiles)) { - AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume); - if (DuplicatesFallback(Volume, FileName)) - ScanFallbackLoader = FALSE; - } + if (ShouldScan(Volume, L"EFI\\Microsoft\\Boot")) { + StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi"); + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, Directory, L"bkpbootmgfw.efi", GlobalConfig.DontScanFiles)) { + AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume); + FoundBRBackup = TRUE; + if (DuplicatesFallback(Volume, FileName)) + ScanFallbackLoader = FALSE; + } + StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi"); + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, Directory, L"bootmgfw.efi", GlobalConfig.DontScanFiles)) { + if (FoundBRBackup) + AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume); + else + AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume); + if (DuplicatesFallback(Volume, FileName)) + ScanFallbackLoader = FALSE; + } + } // if // scan the root directory for EFI executables if (ScanLoaderDir(Volume, L"\\", MatchPatterns)) @@ -1328,13 +1367,15 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { // Scan user-specified (or additional default) directories.... i = 0; while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) { - SplitVolumeAndFilename(&Directory, &VolName); - CleanUpPathNameSlashes(Directory); - Length = StrLen(Directory); - if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns)) - ScanFallbackLoader = FALSE; + if (ShouldScan(Volume, Directory)) { + SplitVolumeAndFilename(&Directory, &VolName); + CleanUpPathNameSlashes(Directory); + Length = StrLen(Directory); + if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns)) + ScanFallbackLoader = FALSE; + MyFreePool(VolName); + } // if should scan dir MyFreePool(Directory); - MyFreePool(VolName); } // while // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself.... @@ -1563,7 +1604,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); - Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", 0, &ErrorInStep, TRUE); + Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, TYPE_LEGACY, 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"); @@ -1577,10 +1618,18 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) // Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL #ifdef __MAKEWITH_TIANO -static VOID StartLegacyUEFI(IN LEGACY_ENTRY *Entry) +static VOID StartLegacyUEFI(LEGACY_ENTRY *Entry) { +// UINTN ExitDataSize = 0; +// CHAR16 *ExitData = NULL; +// EFI_STATUS Status; + BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)"); +// Print(L"Launching from '%s'\n", DevicePathToStr(Entry->BdsOption->DevicePath)); +// PauseForKey(); +// Status = BdsLibBootViaBootOption(Entry->BdsOption, Entry->BdsOption->DevicePath, &ExitDataSize, &ExitData); +// Print(L"BdsLibBootViaBootOption() returned %d\n", Status); BdsLibConnectDevicePath (Entry->BdsOption->DevicePath); BdsLibDoLegacyBoot(Entry->BdsOption); @@ -1874,7 +1923,7 @@ static VOID ScanLegacyExternal(VOID) static VOID StartTool(IN LOADER_ENTRY *Entry) { BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start