X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e63c2d65be451323f51c85910d1e125deb1ad1ea..0864ac754bdb02cb63e8d2323a2ad6b081fdc612:/refind/main.c diff --git a/refind/main.c b/refind/main.c index ba3368b..eeb7719 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-2015 Roderick W. Smith + * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. @@ -98,7 +98,6 @@ #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_x64.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.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" #define EFI_STUB_ARCH 0x8664 @@ -109,11 +108,20 @@ EFI_GUID gFreedesktopRootGuid = { 0x4f68bce3, 0xe8cd, 0x4db1, { 0x96, 0xe7, 0xfb #define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_ia32.efi" #define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.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" #define EFI_STUB_ARCH 0x014c EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a }}; +#elif defined (EFIAARCH64) +#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellaa64.efi,\\shell.efi,\\shellaa64.efi" +#define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_aa64.efi" +#define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_aa64.efi" +#define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" +#define MEMTEST_NAMES L"memtest86.efi,memtest86_aa64.efi,memtest86aa64.efi,bootaa64.efi" +#define FALLBACK_FULLNAME L"EFI\\BOOT\\bootaa64.efi" +#define FALLBACK_BASENAME L"bootaa64.efi" +#define EFI_STUB_ARCH 0xaa64 +EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }}; #else #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shell.efi" #define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi" @@ -123,21 +131,14 @@ EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1 #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 */ -// Below is GUID for ARM64 -EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }}; +// Below is GUID for ARM32 +EFI_GUID gFreedesktopRootGuid = { 0x69dad710, 0x2ce4, 0x4e3c, { 0xb1, 0x6c, 0x21, 0xa1, 0xd4, 0x9a, 0xbe, 0xd3 }}; #endif #define FAT_ARCH 0x0ef1fab9 /* ID for Apple "fat" binary */ #define IPXE_DISCOVER_NAME L"\\efi\\tools\\ipxe_discover.efi" #define IPXE_NAME L"\\efi\\tools\\ipxe.efi" -// 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 -// no harm on other computers, AFAIK. In theory, every case variation should be done for -// completeness, but that's ridiculous.... -#define LOADER_MATCH_PATTERNS L"*.efi,*.EFI" - // Patterns that identify Linux kernels. Added to the loader match pattern when the // scan_all_linux_kernels option is set in the configuration file. Causes kernels WITHOUT // a ".efi" extension to be found when scanning for boot loaders. @@ -156,16 +157,16 @@ static REFIT_MENU_ENTRY MenuEntryRotateCsr = { L"Change SIP Policy", TAG_CSR_ROT REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot", L"Use arrow keys to move cursor; Enter to boot;", - L"Insert or F2 for more options; Esc to refresh" }; + L"Insert, Tab, or F2 for more options; Esc or Backspace to refresh" }; static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; -REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, +REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, BANNER_NOSCALE, NULL, NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, - TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, + TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, TAG_FWUPDATE_TOOL, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -193,10 +194,10 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.10.0.3"); + AddMenuInfoLine(&AboutMenu, PoolPrint(L"rEFInd Version %s", REFIND_VERSION)); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); - AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith"); + AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2016 Roderick W. Smith"); AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others"); AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license"); AddMenuInfoLine(&AboutMenu, L""); @@ -208,6 +209,9 @@ static VOID AboutrEFInd(VOID) #elif defined(EFIX64) AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive")); +#elif defined(EFIAARCH64) + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: ARM (64 bit); Secure Boot %s", + secure_mode() ? L"active" : L"inactive")); #else AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); #endif @@ -259,7 +263,7 @@ static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) { // 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) +#if defined (EFIX64) | defined (EFI32) | defined (EFIAARCH64) EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; CHAR8 Header[512]; @@ -406,6 +410,12 @@ EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, if (ErrorInStep != NULL) *ErrorInStep = 3; } + if (IsDriver) { + // Below should have no effect on most systems, but works + // around bug with some EFIs that prevents filesystem drivers + // from binding to partitions. + ConnectFilesystemDriver(ChildImageHandle); + } // re-open file handles ReinitRefitLib(); @@ -420,13 +430,12 @@ bailout: return ReturnStatus; } /* EFI_STATUS StartEFIImageList() */ -static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, - IN CHAR16 *LoadOptions, IN UINTN LoaderType, - IN CHAR16 *ImageTitle, IN CHAR8 OSType, - OUT UINTN *ErrorInStep, - IN BOOLEAN Verbose, - IN BOOLEAN IsDriver - ) +EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, + IN CHAR16 *LoadOptions, IN UINTN LoaderType, + IN CHAR16 *ImageTitle, IN CHAR8 OSType, + OUT UINTN *ErrorInStep, + IN BOOLEAN Verbose, + IN BOOLEAN IsDriver) { EFI_DEVICE_PATH *DevicePaths[2]; @@ -483,6 +492,7 @@ VOID StoreLoaderName(IN CHAR16 *Name) { // for information on Intel VMX features static VOID DoEnableAndLockVMX(VOID) { +#if defined (EFIX64) | defined (EFI32) UINT32 msr = 0x3a; UINT32 low_bits = 0, high_bits = 0; @@ -495,7 +505,8 @@ static VOID DoEnableAndLockVMX(VOID) low_bits = 0x05; msr = 0x3a; __asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits)); - } + } +#endif } // VOID DoEnableAndLockVMX() static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName) @@ -519,13 +530,16 @@ static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName) // For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels // has a file called initramfs-3.3.0.img, this function will return the string // '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file -// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match; -// however, initmine-3.3.0.img might match. (FindInitrd() returns the first match it -// finds.) Thus, care should be taken to avoid placing duplicate matching files in -// the kernel's directory. +// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match. +// If more than one initrd file matches the extracted version string, the one +// that matches more characters AFTER (actually, from the start of) the version +// string is used. // If no matching init file can be found, returns NULL. static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *InitrdName = NULL, *FileName, *KernelVersion, *InitrdVersion, *Path; + CHAR16 *KernelPostNum, *InitrdPostNum; + UINTN MaxSharedChars, SharedChars; + STRING_LIST *InitrdNames = NULL, *FinalInitrdName = NULL, *CurrentInitrdName = NULL, *MaxSharedInitrd; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; @@ -544,20 +558,44 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { // building the InitrdName later.... if ((StrLen(Path) > 0) && (Path[StrLen(Path) - 1] != L'\\')) MergeStrings(&Path, L"\\", 0); - while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) { + while (DirIterNext(&DirIter, 2, L"init*", &DirEntry)) { InitrdVersion = FindNumbers(DirEntry->FileName); - if (KernelVersion != NULL) { - if (MyStriCmp(InitrdVersion, KernelVersion)) { - InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); - } // if + if (((KernelVersion != NULL) && (MyStriCmp(InitrdVersion, KernelVersion))) || + ((KernelVersion == NULL) && (InitrdVersion == NULL))) { + CurrentInitrdName = AllocateZeroPool(sizeof(STRING_LIST)); + if (InitrdNames == NULL) + InitrdNames = FinalInitrdName = CurrentInitrdName; + if (CurrentInitrdName) { + CurrentInitrdName->Value = PoolPrint(L"%s%s", Path, DirEntry->FileName); + if (CurrentInitrdName != FinalInitrdName) { + FinalInitrdName->Next = CurrentInitrdName; + FinalInitrdName = CurrentInitrdName; + } // if + } // if + } // if + } // while + if (InitrdNames) { + if (InitrdNames->Next == NULL) { + InitrdName = StrDuplicate(InitrdNames -> Value); } else { - if (InitrdVersion == NULL) { - InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); - } // if + MaxSharedInitrd = CurrentInitrdName = InitrdNames; + MaxSharedChars = 0; + while (CurrentInitrdName != NULL) { + KernelPostNum = MyStrStr(LoaderPath, KernelVersion); + InitrdPostNum = MyStrStr(CurrentInitrdName->Value, KernelVersion); + SharedChars = NumCharsInCommon(KernelPostNum, InitrdPostNum); + if (SharedChars > MaxSharedChars) { + MaxSharedChars = SharedChars; + MaxSharedInitrd = CurrentInitrdName; + } // if + // TODO: Compute number of shared characters & compare with max. + CurrentInitrdName = CurrentInitrdName->Next; + } + if (MaxSharedInitrd) + InitrdName = StrDuplicate(MaxSharedInitrd->Value); } // if/else - MyFreePool(InitrdVersion); - } // while - DirIterClose(&DirIter); + } // if + DeleteStringList(InitrdNames); // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed. MyFreePool(KernelVersion); @@ -719,7 +757,7 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) { REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; - CHAR16 *InitrdName; + CHAR16 *InitrdName, *KernelVersion = NULL; CHAR16 DiagsFileName[256]; REFIT_FILE *File; UINTN TokenCount; @@ -817,6 +855,8 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN if (File != NULL) { InitrdName = FindInitrd(Entry->LoaderPath, Volume); TokenCount = ReadTokenLine(File, &TokenList); + KernelVersion = FindNumbers(Entry->LoaderPath); + ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); // first entry requires special processing, since it was initially set // up with a default title but correct options by InitializeSubScreen(), // earlier.... @@ -826,6 +866,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN } // if FreeTokenLine(&TokenList, &TokenCount); while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { + ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); SubEntry = InitializeLoaderEntry(Entry); SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); MyFreePool(SubEntry->LoadOptions); @@ -905,20 +946,24 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN if (GenerateReturn) AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; + MyFreePool(KernelVersion); } // VOID GenerateSubScreen() // Returns options for a Linux kernel. Reads them from an options file in the // kernel's directory; and if present, adds an initrd= option for an initial // RAM disk file with the same version number as the kernel file. static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) { - CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL; + CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL, *KernelVersion; Options = GetFirstOptionsFromFile(LoaderPath, Volume); InitrdName = FindInitrd(LoaderPath, Volume); + KernelVersion = FindNumbers(InitrdName); + ReplaceSubstring(&Options, KERNEL_VERSION, KernelVersion); FullOptions = AddInitrdToOptions(Options, InitrdName); MyFreePool(Options); MyFreePool(InitrdName); + MyFreePool(KernelVersion); return (FullOptions); } // static CHAR16 * GetMainLinuxOptions() @@ -1105,16 +1150,19 @@ static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTit // Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry. static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) { REFIT_FILE *File; - CHAR16 **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL, *Path = NULL, *Title; + CHAR16 **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL; + CHAR16 *Path = NULL, *Title, *KernelVersion; REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; UINTN TokenCount; + KernelVersion = FindNumbers(FileName); File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume); if (File != NULL) { SubScreen = TargetLoader->me.SubScreen; InitrdName = FindInitrd(FileName, Volume); while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { + ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion); SubEntry = InitializeLoaderEntry(TargetLoader); SplitPathName(FileName, &VolName, &Path, &SubmenuName); MergeStrings(&SubmenuName, L": ", '\0'); @@ -1138,6 +1186,7 @@ static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, RE MyFreePool(InitrdName); MyFreePool(File); } // if + MyFreePool(KernelVersion); } // static VOID AddKernelToSubmenu() // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if @@ -1161,16 +1210,22 @@ INTN TimeComp(IN EFI_TIME *Time1, IN EFI_TIME *Time2) { return 0; } // INTN TimeComp() -// Adds a loader list element, keeping it sorted by date. Returns the new -// first element (the one with the most recent date). +// Adds a loader list element, keeping it sorted by date. EXCEPTION: Fedora's rescue +// kernel, which begins with "vmlinuz-0-rescue," should not be at the top of the list, +// since that will make it the default if kernel folding is enabled, so float it to +// the end. +// Returns the new first element (the one with the most recent date). static struct LOADER_LIST * AddLoaderListEntry(struct LOADER_LIST *LoaderList, struct LOADER_LIST *NewEntry) { struct LOADER_LIST *LatestEntry, *CurrentEntry, *PrevEntry = NULL; + BOOLEAN LinuxRescue = FALSE; LatestEntry = CurrentEntry = LoaderList; if (LoaderList == NULL) { LatestEntry = NewEntry; } else { - while ((CurrentEntry != NULL) && (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0)) { + if (StriSubCmp(L"vmlinuz-0-rescue", NewEntry->FileName)) + LinuxRescue = TRUE; + while ((CurrentEntry != NULL) && (LinuxRescue || (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0))) { PrevEntry = CurrentEntry; CurrentEntry = CurrentEntry->NextEntry; } // while @@ -1283,9 +1338,7 @@ static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) return FALSE; } - if (FallbackSize != FileSize) { // not same size, so can't be identical - AreIdentical = FALSE; - } else { // could be identical; do full check.... + if (FallbackSize == FileSize) { // could be identical; do full check.... FileContents = AllocatePool(FileSize); FallbackContents = AllocatePool(FallbackSize); if (FileContents && FallbackContents) { @@ -1316,25 +1369,20 @@ static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) // file to fail to open, which would return a false positive -- but as I use // this function to exclude symbolic links from the list of boot loaders, // that would be fine, since such boot loaders wouldn't work.) -static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO *DirEntry) { +// CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) +static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *FullName, EFI_FILE_INFO *DirEntry) { EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo = NULL; EFI_STATUS Status; UINTN FileSize2 = 0; - CHAR16 *FileName; - FileName = StrDuplicate(Path); - MergeStrings(&FileName, DirEntry->FileName, L'\\'); - CleanUpPathNameSlashes(FileName); - - Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FullName, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FileInfo = LibFileInfo(FileHandle); if (FileInfo != NULL) FileSize2 = FileInfo->FileSize; } - MyFreePool(FileName); MyFreePool(FileInfo); return (DirEntry->FileSize != FileSize2); @@ -1346,15 +1394,14 @@ static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO // there's no point in cluttering the display with two kernels that will // behave identically on non-SB systems, or when one will fail when SB // is active. -static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Filename) { +// CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) +static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *FullName) { CHAR16 *NewFile = NULL; BOOLEAN retval = FALSE; - MergeStrings(&NewFile, Path, 0); - MergeStrings(&NewFile, Filename, L'\\'); + MergeStrings(&NewFile, FullName, 0); MergeStrings(&NewFile, L".efi.signed", 0); if (NewFile != NULL) { - CleanUpPathNameSlashes(NewFile); if (FileExists(Volume->RootDir, NewFile)) retval = TRUE; MyFreePool(NewFile); @@ -1373,7 +1420,7 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 EFI_STATUS Status; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; - CHAR16 FileName[256], *Extension; + CHAR16 Message[256], *Extension, *FullName; struct LOADER_LIST *LoaderList = NULL, *NewLoader; LOADER_ENTRY *FirstKernel = NULL, *LatestEntry = NULL; BOOLEAN FoundFallbackDuplicate = FALSE, IsLinux = FALSE, InSelfPath; @@ -1385,34 +1432,31 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 DirIterOpen(Volume->RootDir, Path, &DirIter); while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) { Extension = FindExtension(DirEntry->FileName); + FullName = StrDuplicate(Path); + MergeStrings(&FullName, DirEntry->FileName, L'\\'); + CleanUpPathNameSlashes(FullName); if (DirEntry->FileName[0] == '.' || MyStriCmp(Extension, L".icns") || MyStriCmp(Extension, L".png") || (MyStriCmp(DirEntry->FileName, FALLBACK_BASENAME) && (MyStriCmp(Path, L"EFI\\BOOT"))) || - StriSubCmp(L"shell", DirEntry->FileName) || - IsSymbolicLink(Volume, Path, DirEntry) || /* is symbolic link */ - HasSignedCounterpart(Volume, Path, DirEntry->FileName) || /* a file with same name plus ".efi.signed" is present */ - FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles)) + FilenameIn(Volume, Path, DirEntry->FileName, SHELL_NAMES) || + IsSymbolicLink(Volume, FullName, DirEntry) || /* is symbolic link */ + HasSignedCounterpart(Volume, FullName) || /* a file with same name plus ".efi.signed" is present */ + FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles) || + !IsValidLoader(Volume->RootDir, FullName)) { continue; // skip this - - if (Path) - SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName); - else - SPrint(FileName, 255, L"\\%s", DirEntry->FileName); - CleanUpPathNameSlashes(FileName); - - if(!IsValidLoader(Volume->RootDir, FileName)) - continue; + } NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST)); if (NewLoader != NULL) { - NewLoader->FileName = StrDuplicate(FileName); + NewLoader->FileName = StrDuplicate(FullName); NewLoader->TimeStamp = DirEntry->ModificationTime; LoaderList = AddLoaderListEntry(LoaderList, NewLoader); - if (DuplicatesFallback(Volume, FileName)) + if (DuplicatesFallback(Volume, FullName)) FoundFallbackDuplicate = TRUE; } // if MyFreePool(Extension); + MyFreePool(FullName); } // while NewLoader = LoaderList; @@ -1440,10 +1484,10 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 // it down to buggy EFI implementations and ignoring that particular error.... if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { if (Path) - SPrint(FileName, 255, L"while scanning the %s directory", Path); + SPrint(Message, 255, L"while scanning the %s directory", Path); else - StrCpy(FileName, L"while scanning the root directory"); - CheckError(Status, FileName); + StrCpy(Message, L"while scanning the root directory"); + CheckError(Status, Message); } // if (Status != EFI_NOT_FOUND) } // if not scanning a blacklisted directory @@ -1681,149 +1725,6 @@ static LOADER_ENTRY * AddToolEntry(EFI_HANDLE DeviceHandle, IN CHAR16 *LoaderPat return Entry; } /* static LOADER_ENTRY * AddToolEntry() */ -// -// pre-boot driver functions -// - -static UINTN ScanDriverDir(IN CHAR16 *Path) -{ - EFI_STATUS Status; - REFIT_DIR_ITER DirIter; - UINTN NumFound = 0; - EFI_FILE_INFO *DirEntry; - CHAR16 FileName[256]; - - CleanUpPathNameSlashes(Path); - // look through contents of the directory - DirIterOpen(SelfRootDir, Path, &DirIter); - while (DirIterNext(&DirIter, 2, LOADER_MATCH_PATTERNS, &DirEntry)) { - if (DirEntry->FileName[0] == '.') - continue; // skip this - - SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName); - NumFound++; - Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName), - L"", TYPE_EFI, DirEntry->FileName, 0, NULL, FALSE, TRUE); - } - Status = DirIterClose(&DirIter); - if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { - SPrint(FileName, 255, L"while scanning the %s directory", Path); - CheckError(Status, FileName); - } - return (NumFound); -} - -#ifdef __MAKEWITH_GNUEFI -static EFI_STATUS ConnectAllDriversToAllControllers(VOID) -{ - EFI_STATUS Status; - UINTN AllHandleCount; - EFI_HANDLE *AllHandleBuffer; - UINTN Index; - UINTN HandleCount; - EFI_HANDLE *HandleBuffer; - UINT32 *HandleType; - UINTN HandleIndex; - BOOLEAN Parent; - BOOLEAN Device; - - Status = LibLocateHandle(AllHandles, - NULL, - NULL, - &AllHandleCount, - &AllHandleBuffer); - if (EFI_ERROR(Status)) - return Status; - - for (Index = 0; Index < AllHandleCount; Index++) { - // - // Scan the handle database - // - Status = LibScanHandleDatabase(NULL, - NULL, - AllHandleBuffer[Index], - NULL, - &HandleCount, - &HandleBuffer, - &HandleType); - if (EFI_ERROR (Status)) - goto Done; - - Device = TRUE; - if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE) - Device = FALSE; - if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE) - Device = FALSE; - - if (Device) { - Parent = FALSE; - for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { - if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE) - Parent = TRUE; - } // for - - if (!Parent) { - if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) { - Status = refit_call4_wrapper(BS->ConnectController, - AllHandleBuffer[Index], - NULL, - NULL, - TRUE); - } - } - } - - MyFreePool (HandleBuffer); - MyFreePool (HandleType); - } - -Done: - MyFreePool (AllHandleBuffer); - return Status; -} /* EFI_STATUS ConnectAllDriversToAllControllers() */ -#else -static EFI_STATUS ConnectAllDriversToAllControllers(VOID) { - BdsLibConnectAllDriversToAllControllers(); - return 0; -} -#endif - -// Load all EFI drivers from rEFInd's "drivers" subdirectory and from the -// directories specified by the user in the "scan_driver_dirs" configuration -// file line. -static VOID LoadDrivers(VOID) -{ - CHAR16 *Directory, *SelfDirectory; - UINTN i = 0, Length, NumFound = 0; - - // load drivers from the subdirectories of rEFInd's home directory specified - // in the DRIVER_DIRS constant. - while ((Directory = FindCommaDelimited(DRIVER_DIRS, i++)) != NULL) { - SelfDirectory = SelfDirPath ? StrDuplicate(SelfDirPath) : NULL; - CleanUpPathNameSlashes(SelfDirectory); - MergeStrings(&SelfDirectory, Directory, L'\\'); - NumFound += ScanDriverDir(SelfDirectory); - MyFreePool(Directory); - MyFreePool(SelfDirectory); - } - - // Scan additional user-specified driver directories.... - i = 0; - while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) { - CleanUpPathNameSlashes(Directory); - Length = StrLen(Directory); - if (Length > 0) { - NumFound += ScanDriverDir(Directory); - } // if - MyFreePool(Directory); - } // while - - // connect all devices - if (NumFound > 0) { - ConnectAllDriversToAllControllers(); - } -} /* static VOID LoadDrivers() */ - // Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly. static VOID ScanForBootloaders(VOID) { UINTN i; @@ -2046,6 +1947,10 @@ static VOID ScanForTools(VOID) { FindTool(MokLocations, MOK_NAMES, L"MOK utility", BUILTIN_ICON_TOOL_MOK_TOOL); break; + case TAG_FWUPDATE_TOOL: + FindTool(MokLocations, FWUPDATE_NAMES, L"firmware update utility", BUILTIN_ICON_TOOL_FWUPDATE); + break; + case TAG_CSR_ROTATE: if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) { TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr); @@ -2075,9 +1980,10 @@ static VOID RescanAll(BOOLEAN DisplayMessage) { FreeList((VOID ***) &(MainMenu.Entries), &MainMenu.EntryCount); MainMenu.Entries = NULL; MainMenu.EntryCount = 0; - ReadConfig(GlobalConfig.ConfigFilename); ConnectAllDriversToAllControllers(); ScanVolumes(); + ReadConfig(GlobalConfig.ConfigFilename); + SetVolumeIcons(); ScanForBootloaders(); ScanForTools(); SetupScreen(); @@ -2190,7 +2096,11 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) CopyMem(GlobalConfig.ScanFor, "ihebocm ", NUM_SCAN_OPTIONS); SetConfigFilename(ImageHandle); + MokProtocol = SecureBootSetup(); + LoadDrivers(); + ScanVolumes(); // Do before ReadConfig() because it needs SelfVolume->VolName ReadConfig(GlobalConfig.ConfigFilename); + SetVolumeIcons(); if (GlobalConfig.SpoofOSXVersion && GlobalConfig.SpoofOSXVersion[0] != L'\0') SetAppleOSInfo(); @@ -2203,9 +2113,6 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL); // further bootstrap (now with config available) - MokProtocol = SecureBootSetup(); - LoadDrivers(); - ScanVolumes(); ScanForBootloaders(); ScanForTools(); SetupScreen();