]> code.delx.au - refind/commitdiff
rEFInd can now load EFI drivers!
authorsrs5694 <srs5694@users.sourceforge.net>
Thu, 19 Apr 2012 00:49:58 +0000 (20:49 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Thu, 19 Apr 2012 00:49:58 +0000 (20:49 -0400)
docs/refind/installing.html
docs/refind/todo.html
libeg/screen.c
refind.conf-sample
refind/Makefile
refind/config.c
refind/global.h
refind/main.c

index 048807cd199baac3caf46cecd673343439687feb..0009d550c7e915e966ff127c8b6fc9a221ab5f0f 100644 (file)
@@ -14,7 +14,7 @@
   <p class="subhead">by Roderick W. Smith, <a
 href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
 
-  <p>Originally written: 3/14/2012; last Web page update: 4/14/2012, referencing rEFInd 0.2.6</p>
+  <p>Originally written: 3/14/2012; last Web page update: 4/17/2012, referencing rEFInd 0.2.6</p>
 
 
 <p>I'm a technical writer and consultant specializing in Linux technologies. This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!</p>
@@ -127,7 +127,7 @@ Filesystem     1K-blocks  Used Available Use% Mounted on
 
 <li>Rename the configuration file by typing <tt><b>mv refind.conf-sample refind.conf</b></tt>. Consult the <a href="configfile.html">Editing the rEFInd Configuration File</a> page for information on how to adjust your options.</li>
 
-<p class="sidebar"><b>Warning:</b> I've seen reports that Linux's <tt>efibootmgr</tt> utility can damage some Macs' firmware, necessitating re-flashing it. I've also seen some vague suggestions that this problem has been fixed with the 3.0 kernels, but I haven't been able to substantiate this suggestion. Therefore, I recommend using <tt>bless</tt> from OS X to do this job on Apple hardware.</p>
+<p class="sidebar"><b>Warning:</b> I've seen reports that Linux's <tt>efibootmgr</tt> utility can damage some Macs' firmware, necessitating re-flashing it. I've also seen some vague suggestions that this problem has been fixed with the 3.0 kernels, but I haven't been able to substantiate this suggestion. In either event, <tt>efibootmgr</tt> by itself can't completely change the EFI boot loader on Macs. Therefore, I recommend using <tt>bless</tt> from OS X to do this job on Apple hardware. Alternatively, there's a new Linux program, <tt>hfs-bless</tt>, part of the <a href="http://www.codon.org.uk/~mjg59/mactel-boot/"><tt>mactel-boot</tt></a> package, that's supposed to work with <tt>efibootmgr</tt> to make a Mac HFS partition bootable. I've not yet tried it, though.</p>
 
 <a name="efibootmgr">
 <li>On a UEFI-based system, type <tt><b>efibootmgr -c -l \\EFI\\refind\\refind_x64.efi -L rEFInd</b></tt> to add rEFInd to your EFI's list of available boot loaders, which it stores in NVRAM. (Adjust the path to the binary as required if you install somewhere else.) You may need to install this program on some systems; it's a standard part of most distributions' repositories.</li>
@@ -197,9 +197,13 @@ Filesystem     1K-blocks  Used Available Use% Mounted on
 
 <li>Type <b><tt>rename refind.conf-sample refind.conf</tt></b> to rename rEFInd's configuration file.</li>
 
+<li>Type <b><tt>bcdedit /set {bootmgr} path \EFI\refind\refind_x64.efi</tt></b> to set rEFInd as the default EFI boot program. Note that <tt>{bootmgr}</tt> is entered as such; that's not a notation for a variable.</li>
+
+<li>If you like, type <b><tt>bcdedit /set {bootmgr} description "<i>rEFInd description</i>"</tt></b> to set a description (change <tt><i>rEFInd description</i></tt> as you see fit).</li>
+
 </ol>
 
-<p>Unfortunately, I know of no Windows tool that's equivalent to <tt>efibootmgr</tt> under Linux or <tt>bless</tt> under OS X. (Such a tool <i>must</i> exist, but I don't know what it is. If you do, please <a href="mailto:rodsmith@rodsbooks.com">e-mail</a> me a pointer!) This can make adding rEFInd to your system a bit tricky, particularly if your firmware provides few boot options. In the best of all possible worlds, you'll be able to use your firmware's user interface to add rEFInd to your firmware's own boot manager; however, far too many EFI implementations lack even this modest capability. If you're stuck in this boat, you have several options, such as:</p>
+<p>At this point, when you reboot, rEFInd should appear as your new default boot program. One caveat: My only EFI Windows installation uses UEFI DUET, which "forgets" its boot options upon reboot. Thus, I'm unable to test the last two steps (which were provided by a helpful user) myself. If it doesn't work for you, you have several other options, such as:</p>
 
 <ul>
 
index f1a69ecebace73a2f2cbc3c7d0e6342ab823fc30..a55620e8de96b7ea5320899cf8cf521c572e79fb 100644 (file)
@@ -117,6 +117,8 @@ program. I'm not sure what you'd use in Windows to create ICNS files.</li>
 
 <li>The code could be more flexible in its handling of the sizes of various graphical elements, and particularly drawn text. Prior to version 0.2.2, submenu text was invisible on UEFI-based PCs with 800x600 and smaller displays because of an inability to properly crop the graphics fields that hold the text. With version 0.2.2, I've put a band-aid on this problem by reducing the field size so that it now works on 800x600 displays, but smaller displays still suffer from this problem. This is just an example of the inflexibility of certain layout issues within rEFInd.</li>
 
+<li>I'd like to add a configuration option to set the screen resolution. Many computers seem to default to 800x600, even when the hardware can handle much higher resolutions. A higher resolution would enable fitting more OS tags on the screen at once. I haven't yet looked into the system calls that would enable such changes.</li>
+
 <li>Although the ICNS file format used by rEFInd supports multiple image sizes, if a size that rEFInd needs isn't present in the file, rEFInd can't use the icon. The ability to scale images to the desired size would be useful.</li>
 
 <li>I would like to be able to specify the volume on which a boot loader resides using a partition GUID value, but extracting a GUID from the partition data is harder than extracting the volume's label or counting up the filesystem numbers.</li>
index f3a36c49c2d8682eea58d174ee973d87eec329c3..1fa517a82e26675b064e3df701cbef3756d25aa7 100644 (file)
@@ -64,20 +64,20 @@ VOID egInitScreen(VOID)
 {
     EFI_STATUS Status;
     UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate;
-    
+
     // get protocols
     Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl);
     if (EFI_ERROR(Status))
         ConsoleControl = NULL;
-    
+
     Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw);
     if (EFI_ERROR(Status))
         UgaDraw = NULL;
-    
+
     Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
     if (EFI_ERROR(Status))
         GraphicsOutput = NULL;
-    
+
     // get screen size
     egHasGraphics = FALSE;
     if (GraphicsOutput != NULL) {
@@ -142,14 +142,14 @@ VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable)
 {
     EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode;
     EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode;
-    
+
     if (ConsoleControl != NULL) {
         refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL);
-        
+
         NewMode = Enable ? EfiConsoleControlScreenGraphics
                          : EfiConsoleControlScreenText;
         if (CurrentMode != NewMode)
-           refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode);
+           refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode);
     }
 }
 
index 97a01df15f6f0e137858c391c0bc8d6a6d785ce7..bd90b38ba9c44466694e4279988911f352e0b8f5 100644 (file)
@@ -58,6 +58,15 @@ timeout 20
 #
 #showtools shell, about, reboot
 
+# Directories in which to search for EFI drivers. These drivers can
+# provide filesystem support, give access to hard disks on plug-in
+# controllers, etc. In most cases none are needed, but if you add
+# EFI drivers and you want rEFInd to automatically load them, you
+# should specify one or more paths here.
+# Default is to scan no directories for EFI drivers
+#
+#scan_driver_dirs EFI/refind/drivers,drivers
+
 # Which types of boot loaders to search, and in what order to display them:
 #  internal      - internal EFI disk-based boot loaders
 #  external      - external EFI disk-based boot loaders
index 4c40c48277c759e832e55c6620c4628e1b388521..f1bbdb8d84be775da41d4102e2185be44d70252c 100644 (file)
@@ -19,7 +19,7 @@ LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -DDEBI
 LOCAL_LDFLAGS   = -L$(SRCDIR)/../libeg/$(LIBEG)
 LOCAL_LIBS      = -leg
 
-OBJS            = main.o config.o menu.o screen.o icns.o lib.o
+OBJS            = main.o config.o menu.o screen.o icns.o lib.o bootsvcs.o
 TARGET          = refind.efi
 
 all: $(TARGET)
index 7ad8f91b423e8642e7c3611378ff9034c6ae5fbb..6d0ab1667ecfe88d31b67de519182790c85a9142 100644 (file)
@@ -366,7 +366,15 @@ VOID ReadConfig(VOID)
            for (i = 1; i < TokenCount; i++)
               MergeStrings(&GlobalConfig.AlsoScan, TokenList[i], L',');
 
-      } else if (StriCmp(TokenList[0], L"showtools") == 0) {
+        } else if (StriCmp(TokenList[0], L"scan_driver_dirs") == 0) {
+           if (GlobalConfig.DriverDirs != NULL) {
+              FreePool(GlobalConfig.DriverDirs);
+              GlobalConfig.DriverDirs = NULL;
+           } // if
+           for (i = 1; i < TokenCount; i++)
+              MergeStrings(&GlobalConfig.DriverDirs, TokenList[i], L',');
+
+        } else if (StriCmp(TokenList[0], L"showtools") == 0) {
             SetMem(GlobalConfig.ShowTools, NUM_TOOLS * sizeof(UINTN), 0);
             for (i = 1; (i < TokenCount) && (i < NUM_TOOLS); i++) {
                 FlagName = TokenList[i];
@@ -402,9 +410,9 @@ VOID ReadConfig(VOID)
         } else if (StriCmp(TokenList[0], L"textonly") == 0) {
             GlobalConfig.TextOnly = TRUE;
 
-        } else if ((StriCmp(TokenList[0], L"}") == 0) || (StriCmp(TokenList[0], L"loader") == 0) ||
-                   (StriCmp(TokenList[0], L"icon") == 0) || (StriCmp(TokenList[0], L"options") == 0)) {
-           // Do nothing; handled by ScanUserConfigured()
+//         } else if ((StriCmp(TokenList[0], L"}") == 0) || (StriCmp(TokenList[0], L"loader") == 0) ||
+//                    (StriCmp(TokenList[0], L"icon") == 0) || (StriCmp(TokenList[0], L"options") == 0)) {
+//            // Do nothing; handled by ScanUserConfigured()
         } else if ((StriCmp(TokenList[0], L"max_tags") == 0) && (TokenCount > 1)) {
            GlobalConfig.MaxTags = Atoi(TokenList[1]);
         }
index d61676b419b235e160ae688781e80dfbc018a48a..433de0f8994c1e3d072bd4a1e1d182ba23b176c7 100644 (file)
@@ -160,6 +160,7 @@ typedef struct {
    CHAR16      *SelectionBigFileName;
    CHAR16      *DefaultSelection;
    CHAR16      *AlsoScan;
+   CHAR16      *DriverDirs;
    UINTN       ShowTools[NUM_TOOLS];
    CHAR8       ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan
 } REFIT_CONFIG;
index 058728cfa181d0f7a2675e7722d10f222c036dbe..2b2d78cdb29249209c1d123873061883fdc4f6cf 100644 (file)
@@ -49,6 +49,7 @@
 #include "icns.h"
 #include "menu.h"
 #include "refit_call_wrapper.h"
+#include "bootsvcs.h"
 #include "../include/syslinux_mbr.h"
 
 // 
@@ -72,7 +73,7 @@ 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, 20, 0, 0, NULL, NULL, NULL, NULL, NULL,
+REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL,
                               {TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
 
 //
@@ -83,7 +84,7 @@ static VOID AboutrEFInd(VOID)
 {
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.6.1");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.6.2");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
@@ -115,7 +116,8 @@ static VOID AboutrEFInd(VOID)
 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;
@@ -124,7 +126,8 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     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;
 
@@ -160,7 +163,8 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
         // 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
@@ -191,13 +195,14 @@ bailout:
 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() */
 
 //
@@ -210,7 +215,7 @@ static VOID StartLoader(IN LOADER_ENTRY *Entry)
 
     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();
 }
 
@@ -395,7 +400,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
             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";
@@ -939,7 +944,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry)
 
     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");
@@ -1083,7 +1088,7 @@ 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);
+                  Basename(Entry->LoaderPath), NULL, TRUE);
     FinishExternalScreen();
 } /* static VOID StartTool() */
 
@@ -1107,69 +1112,54 @@ static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle
     return Entry;
 } /* static LOADER_ENTRY * AddToolEntry() */
 
-#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];
 
     // look through contents of the directory
     DirIterOpen(SelfRootDir, Path, &DirIter);
-    while (DirIterNext(&DirIter, 2, L"*.EFI", &DirEntry)) {
+    while (DirIterNext(&DirIter, 2, L"*.efi", &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);
 }
-/* EFI_STATUS
-LibScanHandleDatabase (
-     EFI_HANDLE  DriverBindingHandle, OPTIONAL
-     UINT32      *DriverBindingHandleIndex, OPTIONAL
-     EFI_HANDLE  ControllerHandle, OPTIONAL
-     UINT32      *ControllerHandleIndex, OPTIONAL
-     UINTN       *HandleCount,
-     EFI_HANDLE  **HandleBuffer,
-     UINT32      **HandleType
-     );
-#define EFI_HANDLE_TYPE_UNKNOWN                     0x000
-#define EFI_HANDLE_TYPE_IMAGE_HANDLE                0x001
-#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE       0x002
-#define EFI_HANDLE_TYPE_DEVICE_DRIVER               0x004
-#define EFI_HANDLE_TYPE_BUS_DRIVER                  0x008
-#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010
-#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE   0x020
-#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE       0x040
-#define EFI_HANDLE_TYPE_DEVICE_HANDLE               0x080
-#define EFI_HANDLE_TYPE_PARENT_HANDLE               0x100
-#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE           0x200
-#define EFI_HANDLE_TYPE_CHILD_HANDLE                0x400 */
 
 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;
+
+    // GNU EFI's EFI_BOOT_SERVICES data structure is truncated, but all the
+    // items are in memory, so point a more complete data structure to it
+    // so that we can use items not in GNU EFI's implementation....
+    gBS = (MY_BOOT_SERVICES*) BS;
 
     Status = LibLocateHandle(AllHandles,
                              NULL,
@@ -1204,15 +1194,15 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
             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(gBS->ConnectController,
+                                                AllHandleBuffer[Index],
+                                                NULL,
+                                                NULL,
+                                                TRUE);
                 }
             }
         }
@@ -1224,23 +1214,30 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
 Done:
     FreePool (AllHandleBuffer);
     return Status;
-}
+} /* EFI_STATUS ConnectAllDriversToAllControllers() */
 
 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;
+
+    // Scan user-specified driver directories....
+    while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) {
+       Length = StrLen(Directory);
+       // Some EFI implementations won't read a directory if the path ends in
+       // a backslash, so eliminate this character, if it's present....
+       while ((Length > 0) && (Directory[Length - 1] == L'\\')) {
+          Directory[--Length] = 0;
+       } // while
+       if (Length > 0)
+          NumFound += ScanDriverDir(Directory);
+       FreePool(Directory);
+    } // while
 
     // connect all devices
-    ConnectAllDriversToAllControllers();
+    if (NumFound > 0)
+       ConnectAllDriversToAllControllers();
 }
-#endif /* DEBIAN_ENABLE_EFI110 */
 
 static VOID ScanForBootloaders(VOID) {
    UINTN i;
@@ -1370,9 +1367,7 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
 
     // further bootstrap (now with config available)
     SetupScreen();
-#ifdef DEBIAN_ENABLE_EFI110
     LoadDrivers();
-#endif /* DEBIAN_ENABLE_EFI110 */
     ScanForBootloaders();
     ScanForTools();
 
@@ -1432,6 +1427,6 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
     // fails, go into an endless loop.
     refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
     EndlessIdleLoop();
-    
+
     return EFI_SUCCESS;
 } /* efi_main() */