#include "icns.h"
#include "menu.h"
#include "refit_call_wrapper.h"
+#include "driver_support.h"
#include "../include/syslinux_mbr.h"
//
// variables
-#define MACOSX_LOADER_PATH L"\\System\\Library\\CoreServices\\boot.efi"
+#define MACOSX_LOADER_PATH L"System\\Library\\CoreServices\\boot.efi"
#if defined (EFIX64)
#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shellx64.efi"
#elif defined (EFI32)
#define SHELL_NAMES L"\\EFI\\tools\\shell.efi"
#endif
+// 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.
+#define LINUX_MATCH_PATTERNS L"vmlinuz*,bzImage*"
+
static REFIT_MENU_ENTRY MenuEntryAbout = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL };
-static REFIT_MENU_ENTRY MenuEntryReset = { L"Restart Computer", TAG_RESET, 1, 0, 'R', 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 };
static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryExit = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL };
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, 20, 0, 0, 0, NULL, NULL, NULL, NULL };
+REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 0, 0, 20, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL,
+ {TAG_SHELL, 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.
+struct LOADER_LIST {
+ CHAR16 *FileName;
+ EFI_TIME TimeStamp;
+ struct LOADER_LIST *NextEntry;
+};
//
// misc functions
{
if (AboutMenu.EntryCount == 0) {
AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
- AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.3.3");
+ AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.3.2.1");
AddMenuInfoLine(&AboutMenu, L"");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
IN CHAR16 *ImageTitle,
- OUT UINTN *ErrorInStep)
+ OUT UINTN *ErrorInStep,
+ IN BOOLEAN Verbose)
{
EFI_STATUS Status, ReturnStatus;
EFI_HANDLE ChildImageHandle;
CHAR16 ErrorInfo[256];
CHAR16 *FullLoadOptions = NULL;
- Print(L"Starting %s\n", ImageTitle);
+ if (Verbose)
+ Print(L"Starting %s\n", ImageTitle);
if (ErrorInStep != NULL)
*ErrorInStep = 0;
// NOTE: We also include the terminating null in the length for safety.
ChildLoadedImage->LoadOptions = (VOID *)LoadOptions;
ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(LoadOptions) + 1) * sizeof(CHAR16);
- Print(L"Using load options '%s'\n", LoadOptions);
+ if (Verbose)
+ Print(L"Using load options '%s'\n", LoadOptions);
}
// close open file handles
if (ErrorInStep != NULL)
*ErrorInStep = 3;
}
-
+
// re-open file handles
ReinitRefitLib();
static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
IN CHAR16 *ImageTitle,
- OUT UINTN *ErrorInStep)
+ OUT UINTN *ErrorInStep,
+ IN BOOLEAN Verbose)
{
EFI_DEVICE_PATH *DevicePaths[2];
-
+
DevicePaths[0] = DevicePath;
DevicePaths[1] = NULL;
- return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep);
+ return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep, Verbose);
} /* static EFI_STATUS StartEFIImage() */
//
BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS");
StartEFIImage(Entry->DevicePath, Entry->LoadOptions,
- Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), &ErrorInStep);
+ Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), &ErrorInStep, TRUE);
FinishExternalScreen();
}
KernelVersion = FindNumbers(FileName);
Path = FindPath(LoaderPath);
+ // Add trailing backslash for root directory; necessary on some systems, but must
+ // NOT be added to all directories, since on other systems, a trailing backslash on
+ // anything but the root directory causes them to flake out!
+ if (StrLen(Path) == 0) {
+ MergeStrings(&Path, L"\\", 0);
+ } // if
DirIterOpen(Volume->RootDir, Path, &DirIter);
+ // Now add a trailing backslash if it was NOT added earlier, for consistency in
+ // 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)) {
InitrdVersion = FindNumbers(DirEntry->FileName);
if (KernelVersion != NULL) {
if (StriCmp(InitrdVersion, KernelVersion) == 0)
- InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName);
+ InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
} else {
if (InitrdVersion == NULL)
- InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName);
+ InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
} // if/else
if (InitrdVersion != NULL)
FreePool(InitrdVersion);
Entry->Title = NULL;
}
SubScreen = InitializeSubScreen(Entry);
-
+
// loader-specific submenu entries
if (Entry->OSType == 'M') { // entries for Mac OS X
#if defined(EFIX64)
} // if
#endif
- if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SINGLEUSER)) {
+ if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SINGLEUSER)) {
SubEntry = InitializeLoaderEntry(Entry);
if (SubEntry != NULL) {
SubEntry->me.Title = L"Boot Mac OS X in verbose mode";
SubEntry->LoadOptions = L"-v";
AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
} // if
-
+
#if defined(EFIX64)
SubEntry = InitializeLoaderEntry(Entry);
if (SubEntry != NULL) {
AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
}
#endif
-
+
SubEntry = InitializeLoaderEntry(Entry);
if (SubEntry != NULL) {
SubEntry->me.Title = L"Boot Mac OS X in single user mode";
// check for Apple hardware diagnostics
StrCpy(DiagsFileName, L"\\System\\Library\\CoreServices\\.diagnostics\\diags.efi");
- if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.DisableFlags & DISABLE_FLAG_HWTEST)) {
+ if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HWTEST)) {
SubEntry = InitializeLoaderEntry(Entry);
if (SubEntry != NULL) {
SubEntry->me.Title = L"Run Apple Hardware Test";
AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries");
AddMenuInfoLine(SubScreen, L"marked with (*) may not work.");
-
+
} else if (Entry->OSType == 'X') { // entries for xom.efi
// by default, skip the built-in selection and boot from hard disk only
Entry->LoadOptions = L"-s -h";
// that will (with luck) work fairly automatically.
VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
CHAR16 IconFileName[256];
- CHAR16 *FileName, *OSIconName = NULL, *Temp;
+ CHAR16 *FileName, *PathOnly, *OSIconName = NULL, *Temp;
CHAR16 ShortcutLetter = 0;
FileName = Basename(LoaderPath);
-
+ PathOnly = FindPath(LoaderPath);
+
// locate a custom icon for the loader
StrCpy(IconFileName, LoaderPath);
- ReplaceExtension(IconFileName, L".icns");
+ ReplaceEfiExtension(IconFileName, L".icns");
if (FileExists(Volume->RootDir, IconFileName)) {
Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128);
- } // if
-
+ } else if ((StrLen(PathOnly) == 0) && (Volume->VolIconImage != NULL)) {
+ Entry->me.Image = Volume->VolIconImage;
+ } // icon matched to loader or volume
+
Temp = FindLastDirName(LoaderPath);
MergeStrings(&OSIconName, Temp, L',');
FreePool(Temp);
Entry->OSType = 'R';
ShortcutLetter = 'R';
} else if (StriCmp(LoaderPath, MACOSX_LOADER_PATH) == 0) {
+ if (Volume->VolIconImage != NULL) { // custom icon file found
+ Entry->me.Image = Volume->VolIconImage;
+ }
MergeStrings(&OSIconName, L"mac", L',');
Entry->UseGraphicsMode = TRUE;
Entry->OSType = 'M';
Entry->me.ShortcutLetter = ShortcutLetter;
if (Entry->me.Image == NULL)
Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE);
+ if (PathOnly != NULL)
+ FreePool(PathOnly);
} // VOID SetLoaderDefaults()
-
+
// Add a specified EFI boot loader to the list, using automatic settings
// for icons, options, etc.
LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) {
LOADER_ENTRY *Entry;
+ CleanUpPathNameSlashes(LoaderPath);
Entry = InitializeLoaderEntry(NULL);
if (Entry != NULL) {
- Entry->Title = StrDuplicate(LoaderTitle);
- Entry->me.Title = PoolPrint(L"Boot %s from %s", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath + 1, Volume->VolName);
+ Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath);
+// Entry->Title = StrDuplicate(LoaderTitle);
+ Entry->me.Title = PoolPrint(L"Boot %s from %s", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName);
Entry->me.Row = 0;
Entry->me.BadgeImage = Volume->VolBadgeImage;
Entry->LoaderPath = StrDuplicate(LoaderPath);
GenerateSubScreen(Entry, Volume);
AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
}
-
+
return(Entry);
} // LOADER_ENTRY * AddLoaderEntry()
+// Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if
+// (Time1 == Time2). Precision is only to the nearest second; since
+// this is used for sorting boot loader entries, differences smaller
+// than this are likely to be meaningless (and unlikely!).
+INTN TimeComp(EFI_TIME *Time1, EFI_TIME *Time2) {
+ INT64 Time1InSeconds, Time2InSeconds;
+
+ // Following values are overestimates; I'm assuming 31 days in every month.
+ // This is fine for the purpose of this function, which has a limited
+ // purpose.
+ Time1InSeconds = Time1->Second + (Time1->Minute * 60) + (Time1->Hour * 3600) + (Time1->Day * 86400) +
+ (Time1->Month * 2678400) + ((Time1->Year - 1998) * 32140800);
+ Time2InSeconds = Time2->Second + (Time2->Minute * 60) + (Time2->Hour * 3600) + (Time2->Day * 86400) +
+ (Time2->Month * 2678400) + ((Time2->Year - 1998) * 32140800);
+ if (Time1InSeconds < Time2InSeconds)
+ return (-1);
+ else if (Time1InSeconds > Time2InSeconds)
+ return (1);
+
+ 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).
+static struct LOADER_LIST * AddLoaderListEntry(struct LOADER_LIST *LoaderList, struct LOADER_LIST *NewEntry) {
+ struct LOADER_LIST *LatestEntry, *CurrentEntry, *PrevEntry = NULL;
+
+ LatestEntry = CurrentEntry = LoaderList;
+ if (LoaderList == NULL) {
+ LatestEntry = NewEntry;
+ } else {
+ while ((CurrentEntry != NULL) && (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0)) {
+ PrevEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->NextEntry;
+ } // while
+ NewEntry->NextEntry = CurrentEntry;
+ if (PrevEntry == NULL) {
+ LatestEntry = NewEntry;
+ } else {
+ PrevEntry->NextEntry = NewEntry;
+ } // if/else
+ } // if/else
+ return (LatestEntry);
+} // static VOID AddLoaderListEntry()
+
+// Delete the LOADER_LIST linked list
+static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) {
+ struct LOADER_LIST *Temp;
+
+ while (LoaderList != NULL) {
+ Temp = LoaderList;
+ LoaderList = LoaderList->NextEntry;
+ FreePool(Temp->FileName);
+ FreePool(Temp);
+ } // while
+} // static VOID CleanUpLoaderList()
+
// Scan an individual directory for EFI boot loader files and, if found,
-// add them to the list.
-static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path)
+// add them to the list. Sorts the entries within the loader directory
+// so that the most recent one appears first in the list.
+static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Pattern)
{
EFI_STATUS Status;
REFIT_DIR_ITER DirIter;
EFI_FILE_INFO *DirEntry;
- CHAR16 FileName[256];
+ CHAR16 FileName[256], *Extension;
+ struct LOADER_LIST *LoaderList = NULL, *NewLoader;
- // Note: SelfDirPath includes a leading backslash ('\'), but Path
- // doesn't, so we rejigger the string to compensate....
- if (!SelfDirPath || !Path || ((StriCmp(Path, &SelfDirPath[1]) == 0) && Volume != SelfVolume) ||
- (StriCmp(Path, &SelfDirPath[1]) != 0)) {
+ if (!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && Volume != SelfVolume) ||
+ (StriCmp(Path, SelfDirPath) != 0)) {
// look through contents of the directory
DirIterOpen(Volume->RootDir, Path, &DirIter);
- while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
+ 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))
continue; // skip this
SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName);
else
SPrint(FileName, 255, L"\\%s", DirEntry->FileName);
- AddLoaderEntry(FileName, NULL, Volume);
- }
+ CleanUpPathNameSlashes(FileName);
+ NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST));
+ if (NewLoader != NULL) {
+ NewLoader->FileName = StrDuplicate(FileName);
+ NewLoader->TimeStamp = DirEntry->ModificationTime;
+ LoaderList = AddLoaderListEntry(LoaderList, NewLoader);
+ } // if
+ FreePool(Extension);
+ } // while
+ NewLoader = LoaderList;
+ while (NewLoader != NULL) {
+ AddLoaderEntry(NewLoader->FileName, NULL, Volume);
+ NewLoader = NewLoader->NextEntry;
+ } // while
+ CleanUpLoaderList(LoaderList);
Status = DirIterClose(&DirIter);
if (Status != EFI_NOT_FOUND) {
if (Path)
EFI_STATUS Status;
REFIT_DIR_ITER EfiDirIter;
EFI_FILE_INFO *EfiDirEntry;
- CHAR16 FileName[256];
+ CHAR16 FileName[256], *Directory, *MatchPatterns;
+ UINTN i, Length;
+
+ 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
}
// check for XOM
- StrCpy(FileName, L"\\System\\Library\\CoreServices\\xom.efi");
+ StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi");
if (FileExists(Volume->RootDir, FileName)) {
AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume);
}
// check for Microsoft boot loader/menu
- StrCpy(FileName, L"\\EFI\\Microsoft\\Boot\\Bootmgfw.efi");
+ StrCpy(FileName, L"EFI\\Microsoft\\Boot\\Bootmgfw.efi");
if (FileExists(Volume->RootDir, FileName)) {
AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume);
}
// scan the root directory for EFI executables
- ScanLoaderDir(Volume, NULL);
- // scan the elilo directory (as used on gimli's first Live CD)
- ScanLoaderDir(Volume, L"elilo");
- // scan the boot directory
- ScanLoaderDir(Volume, L"boot");
+ ScanLoaderDir(Volume, L"\\", MatchPatterns);
// scan subdirectories of the EFI directory (as per the standard)
DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter);
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);
- ScanLoaderDir(Volume, FileName);
+ ScanLoaderDir(Volume, FileName, MatchPatterns);
} // while()
Status = DirIterClose(&EfiDirIter);
if (Status != EFI_NOT_FOUND)
CheckError(Status, L"while scanning the EFI directory");
+
+ // Scan user-specified (or additional default) directories....
+ i = 0;
+ while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) {
+ CleanUpPathNameSlashes(Directory);
+ Length = StrLen(Directory);
+ if (Length > 0)
+ ScanLoaderDir(Volume, Directory, MatchPatterns);
+ FreePool(Directory);
+ } // while
} // if
} // static VOID ScanEfiFiles()
if (PartitionIndex < LogicalPartitionIndex)
break; // stop the loop, no need to touch further EMBRs
}
-
+
}
return EFI_SUCCESS;
ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList);
- Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &ErrorInStep);
+ Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &ErrorInStep, TRUE);
if (Status == EFI_NOT_FOUND) {
if (ErrorInStep == 1) {
Print(L"\nPlease make sure that you have the latest firmware update installed.\n");
SubEntry->Volume = Entry->Volume;
SubEntry->LoadOptions = Entry->LoadOptions;
AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
-
+
AddMenuEntry(SubScreen, &MenuEntryReturn);
Entry->me.SubScreen = SubScreen;
AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
Volume->BlockIOOffset == 0 &&
Volume->OSName == NULL)
// this is a whole disk (MBR) entry; hide if we have entries for partitions
- HideIfOthersFound = TRUE;
+ HideIfOthersFound = TRUE;
}
if (HideIfOthersFound) {
// check for other bootable entries on the same disk
static VOID StartTool(IN LOADER_ENTRY *Entry)
{
- BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start <title>" as assigned below
- StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath),
- Basename(Entry->LoaderPath), NULL);
- FinishExternalScreen();
+ BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start <title>" as assigned below
+ StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath),
+ Basename(Entry->LoaderPath), NULL, TRUE);
+ FinishExternalScreen();
} /* static VOID StartTool() */
static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image,
return Entry;
} /* static LOADER_ENTRY * AddToolEntry() */
-// Check the disk for add-on tools -- an EFI shell, the dangerous gptsync.efi, and a rescue Linux
-// installation.
-static VOID ScanTool(VOID)
-{
- CHAR16 *FileName;
- LOADER_ENTRY *Entry;
- UINTN i = 0;
-
- if (GlobalConfig.DisableFlags & DISABLE_FLAG_TOOLS)
- return;
-
- // look for the EFI shell
- while (((FileName = FindCommaDelimited(SHELL_NAMES, i++)) != NULL) && (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SHELL))) {
- if (FileExists(SelfRootDir, FileName)) {
- AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
- }
- FreePool(FileName);
- FileName = NULL;
- } // while
-
- // look for the GPT/MBR sync tool
- 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);
- }
- FreePool(FileName);
- FileName = NULL;
-
- // look for rescue Linux
- MergeStrings(&FileName, L"\\efi\\rescue\\elilo.efi", 0);
- if (SelfVolume != NULL && FileExists(SelfRootDir, FileName)) {
- Entry = AddToolEntry(FileName, L"Rescue Linux", BuiltinIcon(BUILTIN_ICON_TOOL_RESCUE), '0', FALSE);
-
- if (UGAWidth == 1440 && UGAHeight == 900)
- Entry->LoadOptions = L"-d 0 i17";
- else if (UGAWidth == 1680 && UGAHeight == 1050)
- Entry->LoadOptions = L"-d 0 i20";
- else
- Entry->LoadOptions = L"-d 0 mini";
- }
- FreePool(FileName);
-} /* VOID ScanTool() */
-
-
-#ifdef DEBIAN_ENABLE_EFI110
//
// pre-boot driver functions
//
-static VOID ScanDriverDir(IN CHAR16 *Path)
+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, L"*.EFI", &DirEntry)) {
+ 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"", DirEntry->FileName, DirEntry->FileName, NULL);
+ L"", DirEntry->FileName, DirEntry->FileName, NULL, FALSE);
}
Status = DirIterClose(&DirIter);
if (Status != EFI_NOT_FOUND) {
SPrint(FileName, 255, L"while scanning the %s directory", Path);
CheckError(Status, FileName);
}
+ return (NumFound);
}
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;
-
+ 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,
&AllHandleBuffer);
if (EFI_ERROR(Status))
return Status;
-
+
for (Index = 0; Index < AllHandleCount; Index++) {
//
// Scan the handle database
&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);
+ Status = refit_call4_wrapper(BS->ConnectController,
+ AllHandleBuffer[Index],
+ NULL,
+ NULL,
+ TRUE);
}
}
}
-
+
FreePool (HandleBuffer);
FreePool (HandleType);
}
-
+
Done:
FreePool (AllHandleBuffer);
return Status;
-}
+} /* EFI_STATUS ConnectAllDriversToAllControllers() */
+// 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 DirName[256];
-
- // load drivers from /efi/refind/drivers
- SPrint(DirName, 255, L"%s\\drivers", SelfDirPath);
- ScanDriverDir(DirName);
-
- // load drivers from /efi/tools/drivers
- ScanDriverDir(L"\\efi\\tools\\drivers");
+ CHAR16 *Directory;
+ UINTN i = 0, Length, NumFound = 0;
+
+ // load drivers from the "drivers" subdirectory of rEFInd's home directory
+ Directory = StrDuplicate(SelfDirPath);
+ CleanUpPathNameSlashes(Directory);
+ MergeStrings(&Directory, L"drivers", L'\\');
+ NumFound += ScanDriverDir(Directory);
+
+ // Scan additional user-specified driver directories....
+ while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) {
+ CleanUpPathNameSlashes(Directory);
+ Length = StrLen(Directory);
+ if (Length > 0)
+ NumFound += ScanDriverDir(Directory);
+ FreePool(Directory);
+ } // while
// connect all devices
- ConnectAllDriversToAllControllers();
-}
-#endif /* DEBIAN_ENABLE_EFI110 */
+ if (NumFound > 0)
+ ConnectAllDriversToAllControllers();
+} /* static VOID LoadDrivers() */
static VOID ScanForBootloaders(VOID) {
UINTN i;
break;
} // switch()
} // for
- ScanTool();
- // fixed other menu entries
- if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS)) {
- MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
- AddMenuEntry(&MainMenu, &MenuEntryAbout);
- }
- if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS) || MainMenu.EntryCount == 0) {
- MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
- AddMenuEntry(&MainMenu, &MenuEntryShutdown);
- MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
- AddMenuEntry(&MainMenu, &MenuEntryReset);
- }
-
// assign shortcut keys
for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++)
MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i);
-
+
// wait for user ACK when there were errors
FinishTextScreen(FALSE);
} // static VOID ScanForBootloaders()
+// Add the second-row tags containing built-in and external tools (EFI shell,
+// reboot, etc.)
+static VOID ScanForTools(VOID) {
+ CHAR16 *FileName = NULL;
+ UINTN i, j;
+
+ for (i = 0; i < NUM_TOOLS; i++) {
+ switch(GlobalConfig.ShowTools[i]) {
+ case TAG_SHUTDOWN:
+ MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
+ AddMenuEntry(&MainMenu, &MenuEntryShutdown);
+ break;
+ case TAG_REBOOT:
+ MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
+ AddMenuEntry(&MainMenu, &MenuEntryReset);
+ break;
+ case TAG_ABOUT:
+ MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
+ AddMenuEntry(&MainMenu, &MenuEntryAbout);
+ break;
+ case TAG_EXIT:
+ MenuEntryExit.Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT);
+ AddMenuEntry(&MainMenu, &MenuEntryExit);
+ break;
+ case TAG_SHELL:
+ j = 0;
+ while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
+ if (FileExists(SelfRootDir, FileName)) {
+ AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
+ }
+ } // while
+ break;
+ case TAG_GPTSYNC:
+ 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);
+ }
+ break;
+ } // switch()
+ if (FileName != NULL) {
+ FreePool(FileName);
+ FileName = NULL;
+ }
+ } // for
+} // static VOID ScanForTools
+
//
// main entry point
//
// further bootstrap (now with config available)
SetupScreen();
-#ifdef DEBIAN_ENABLE_EFI110
LoadDrivers();
-#endif /* DEBIAN_ENABLE_EFI110 */
ScanForBootloaders();
+ ScanForTools();
while (MainLoopRunning) {
MenuExit = RunMainMenu(&MainMenu, GlobalConfig.DefaultSelection, &ChosenEntry);
-
+
// We don't allow exiting the main menu with the Escape key.
if (MenuExit == MENU_EXIT_ESCAPE) {
// Commented-out below: Was part of an attempt to get rEFInd to
// SetupScreen();
continue;
}
-
+
switch (ChosenEntry->Tag) {
-
- case TAG_RESET: // Restart
+
+ case TAG_REBOOT: // Reboot
TerminateScreen();
refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
MainLoopRunning = FALSE; // just in case we get this far
break;
-
+
case TAG_SHUTDOWN: // Shut Down
TerminateScreen();
refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL);
MainLoopRunning = FALSE; // just in case we get this far
break;
-
+
case TAG_ABOUT: // About rEFInd
AboutrEFInd();
break;
-
+
case TAG_LOADER: // Boot OS via .EFI loader
StartLoader((LOADER_ENTRY *)ChosenEntry);
break;
-
+
case TAG_LEGACY: // Boot legacy OS
StartLegacy((LEGACY_ENTRY *)ChosenEntry);
break;
-
+
case TAG_TOOL: // Start a EFI tool
StartTool((LOADER_ENTRY *)ChosenEntry);
break;
-
+
+ case TAG_EXIT: // Terminate rEFInd
+ BeginTextScreen(L" ");
+ return EFI_SUCCESS;
+ break;
+
}
}
// fails, go into an endless loop.
refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
EndlessIdleLoop();
-
+
return EFI_SUCCESS;
} /* efi_main() */