]> code.delx.au - refind/commitdiff
Support for iPXE (booting from a network server from rEFInd).
authorsrs5694 <srs5694@users.sourceforge.net>
Sat, 6 Dec 2014 23:34:31 +0000 (18:34 -0500)
committersrs5694 <srs5694@users.sourceforge.net>
Sat, 6 Dec 2014 23:34:31 +0000 (18:34 -0500)
13 files changed:
BUILDING.txt
CREDITS.txt
NEWS.txt
docs/refind/configfile.html
docs/refind/installing.html
refind.conf-sample
refind/config.c
refind/global.h
refind/icns.c
refind/icns.h
refind/lib.c
refind/lib.h
refind/main.c

index df00b427e9cc8f2b9366492654fb4e905e9127ce..f9d889ce7a52b15253454b8f85d801c4855f7598 100644 (file)
@@ -297,3 +297,25 @@ Christoph Pfisterer. Most of the drivers seem to have passed through
 Oracle's VirtualBox project (https://www.virtualbox.org) and the Clover
 boot loader project (https://sourceforge.net/projects/cloverefiboot/),
 which I used as the source for this build.
+
+Adding Support for Network Boot
+===============================
+
+rEFInd provides EXPERIMENTAL support for booting over the network using
+iPXE (http://ipxe.org) as a means to receive the payload. In order to
+enable this feature you'll want to follow these instructions:
+
+* cd net/
+* make source
+* make netboot
+* copy bin/ipxe.efi and bin/ipxe_discover.efi to the EFI volume at EFI/tools/
+
+Note that you may need to install additional development packages, such as
+libiberty-dev and binutils-dev, in addition to those needed to build rEFInd
+itself.
+
+My own tests show this support to work under optimal conditions; however,
+architecture (EFI vs. BIOS) detection may not work, and some computers will
+hang or won't retrieve boot files from the network. For these reasons, this
+support is disabled by default in rEFInd, and I do not provide iPXE
+binaries.
index 301cace1788e35d0f0738147935c545de217a9ea..a04d1abaf1093544b9d39eee99a7cfaa03bfb66c 100644 (file)
@@ -46,6 +46,10 @@ Program (C source code) files:
 * Samuel Liao ported the GRUB 2 Btrfs code into an EFI driver and
   contributed it to this project.
 
+* Emerson Barcelos (emerson_freitas@yahoo.com.br) wrote the code for
+  enabling Intel VMX support (the enable_and_lock_vmx token in
+  refind.conf).
+
 * Matthew J. Garrett (mjg@redhat.com) wrote the shim boot loader upon which
   rEFInd relies for its Secure Boot functionality. I took a few shim
   functions to help out on the rEFInd side, too; see the mok/mok.c source
index 5ef467f11247b51666df84f2cb3f9dad36addab5..0fb703154fdd0c3f612ac067c1ff4cd512b453dd 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
   work. Most EFIs enable setting this feature in their own setup utilities,
   but some (such as most Macs) don't.
 
+- If rEFInd can't locate an icons directory (either the default or one
+  specified by the icons_dir token), the program switches to text-only
+  mode.
+
+- If a loader contains the string "grub" and no other clue to the loader's
+  OS association exists, search for os_grub.{png|icns} (which is not
+  provided with rEFInd) or os_linux.{png|icns}. (Previous versions provided
+  a generic loader icon for GRUB.)
+
 0.8.3 (7/6/2014):
 -----------------
 
index 5d47e93c921df76c64afd7f693a2af2f5d5507e9..a39174aaf4b720124ce3546f698ea1667876ed21 100644 (file)
@@ -240,7 +240,7 @@ timeout 20
 <tr>
    <td><tt>icons_dir</tt></td>
    <td>directory name</td>
-   <td>Specifies a directory in which custom icons may be found. This directory should contain files with the same names as the files in the standard <tt>icons</tt> directory. The directory name is specified relative to the directory in which the rEFInd binary resides. The standard <tt>icons</tt> directory is searched if an icon can't be found in the one specified by <tt>icons_dir</tt>, so you can use this location to redefine just some icons.</td>
+   <td>Specifies a directory in which custom icons may be found. This directory should contain files with the same names as the files in the standard <tt>icons</tt> directory. The directory name is specified relative to the directory in which the rEFInd binary resides. The standard <tt>icons</tt> directory is searched if an icon can't be found in the one specified by <tt>icons_dir</tt>, so you can use this location to redefine just some icons. Note that if no icons directory is found (either <tt>icons</tt> or one specified by <tt>icons_dir</tt>), rEFInd switches to text-only mode, as if <tt>textonly</tt> had been specified.</td>
 </tr>
 <tr>
    <td><tt>banner</tt></td>
@@ -274,8 +274,8 @@ timeout 20
 </tr>
 <tr>
    <td><tt>showtools</tt></td>
-   <td><tt>shell</tt>, <tt>memtest</tt>, <tt>gdisk</tt>, <tt>gptsync</tt>, <tt>apple_recovery</tt>, <tt>mok_tool</tt>, <tt>about</tt>, <tt>exit</tt>, <tt>shutdown</tt>, <tt>reboot</tt>, and <tt>firmware</tt></td>
-   <td>Specifies which tool tags to display on the second row. <tt>shell</tt> launches an EFI shell, <tt>memtest</tt> (or <tt>memtest86</tt>) launches the <a href="http://www.memtest86.com/download.htm">Memtest86</a> program, <tt>gdisk</tt> launches the partitioning tool of the same name, <tt>gptsync</tt> launches a tool that creates a hybrid MBR, <tt>apple_recovery</tt> boots the OS X Recovery HD, <tt>windows_recovery</tt> boots a Windows recovery tool, <tt>mok_tool</tt> launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, <tt>about</tt> displays information about the program, <tt>exit</tt> terminates rEFInd, <tt>shutdown</tt> shuts down the computer (or reboots it, on some UEFI PCs), <tt>reboot</tt> reboots the computer, and <tt>firmware</tt> reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is <tt>shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware</tt>. Note that the <tt>shell</tt>, <tt>memtest</tt>, <tt>apple_recovery</tt>, and <tt>mok_tool</tt> options all require the presence of programs not included with rEFInd. The <tt>gptsync</tt> option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the <a href="installing.html#addons">"Installing Additional Components"</a> section of the <a href="installing.html">Installing rEFInd</a> page for pointers to the shell, Memtest86, and <tt>gptsync</tt> programs. The <tt>apple_recovery</tt> option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called <tt>com.apple.recovery.boot/boot.efi</tt>). The <tt>firmware</tt> option works only on computers that support this option; on other computers, the option is quietly ignored. See the <a href="secureboot.html">Secure Boot</a> page for information on Secure Boot and MOK management.</td>
+   <td><tt>shell</tt>, <tt>memtest</tt>, <tt>gdisk</tt>, <tt>gptsync</tt>, <tt>apple_recovery</tt>, <tt>mok_tool</tt>, <tt>netboot</tt>, <tt>about</tt>, <tt>exit</tt>, <tt>shutdown</tt>, <tt>reboot</tt>, and <tt>firmware</tt></td>
+   <td>Specifies which tool tags to display on the second row. <tt>shell</tt> launches an EFI shell, <tt>memtest</tt> (or <tt>memtest86</tt>) launches the <a href="http://www.memtest86.com/download.htm">Memtest86</a> program, <tt>gdisk</tt> launches the partitioning tool of the same name, <tt>gptsync</tt> launches a tool that creates a hybrid MBR, <tt>apple_recovery</tt> boots the OS X Recovery HD, <tt>windows_recovery</tt> boots a Windows recovery tool, <tt>mok_tool</tt> launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, <tt>netboot</tt> launches the network boot tool (iPXE), <tt>about</tt> displays information about rEFInd, <tt>exit</tt> terminates rEFInd, <tt>shutdown</tt> shuts down the computer (or reboots it, on some UEFI PCs), <tt>reboot</tt> reboots the computer, and <tt>firmware</tt> reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is <tt>shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware</tt>. Note that the <tt>shell</tt>, <tt>memtest</tt>, <tt>apple_recovery</tt>, and <tt>mok_tool</tt> options all require the presence of programs not included with rEFInd. The <tt>gptsync</tt> option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the <a href="installing.html#addons">"Installing Additional Components"</a> section of the <a href="installing.html">Installing rEFInd</a> page for pointers to the shell, Memtest86, and <tt>gptsync</tt> programs. The <tt>apple_recovery</tt> option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called <tt>com.apple.recovery.boot/boot.efi</tt>). The <tt>firmware</tt> option works only on computers that support this option; on other computers, the option is quietly ignored. See the <a href="secureboot.html">Secure Boot</a> page for information on Secure Boot and MOK management.</td>
 </tr>
 <tr>
    <td><tt>font</tt></td>
@@ -285,7 +285,7 @@ timeout 20
 <tr>
    <td><tt>textonly</tt></td>
    <td>none or one of <tt>true</tt>, <tt>on</tt>, <tt>1</tt>, <tt>false</tt>, <tt>off</tt>, or <tt>0</tt></td>
-   <td>rEFInd defaults to a graphical mode; however, if you prefer to do without the flashy graphics, you can run it in text mode by including this option (alone or with <tt>true</tt>, <tt>on</tt>, or <tt>1</tt>). Passing <tt>false</tt>, <tt>off</tt>, or <tt>0</tt> causes graphics mode to be used. (This could be useful if you want to override a text-mode setting in an included secondary configuration file.)</td>
+   <td>rEFInd defaults to a graphical mode; however, if you prefer to do without the flashy graphics, you can run it in text mode by including this option (alone or with <tt>true</tt>, <tt>on</tt>, or <tt>1</tt>). Passing <tt>false</tt>, <tt>off</tt>, or <tt>0</tt> causes graphics mode to be used. (This could be useful if you want to override a text-mode setting in an included secondary configuration file.) Text-only mode is implicitly set if rEFInd cannot find either a subdirectory called <tt>icons</tt> or a subdirectory named by <tt>icons_dir</tt>.</td>
 </tr>
 <tr>
    <td><tt>textmode</tt></td>
@@ -309,8 +309,8 @@ timeout 20
 </tr>
 <tr>
    <td><tt>scanfor</tt></td>
-   <td><tt>internal</tt>, <tt>external</tt>, <tt>optical</tt>, <tt>hdbios</tt>, <tt>biosexternal</tt>, <tt>cd</tt>, and <tt>manual</tt></td>
-   <td>Tells rEFInd what methods to use to locate boot loaders. The <tt>internal</tt>, <tt>external</tt>, and <tt>optical</tt> parameters tell rEFInd to scan for EFI boot loaders on internal, external, and optical (CD, DVD, and Blu-ray) devices, respectively. The <tt>hdbios</tt>, <tt>biosexternal</tt>, and <tt>cd</tt> parameters are similar, but scan for BIOS boot loaders. (Note that the BIOS options scan more thoroughly and actively on Macs than on UEFI-based PCs; for the latter, only options in the firmware's boot list are scanned, as described on the <a href="using.html">Using rEFInd</a> page.) The <tt>manual</tt> parameter tells rEFInd to scan the configuration file for manual settings. You can specify multiple parameters to have the program scan for multiple boot loader types. When you do so, the order determines the order in which the boot loaders appear in the menu. The default is <tt>internal, external, optical, manual</tt> on most systems, but <tt>internal, hdbios, external, biosexternal, optical, cd, manual</tt> on Macs.</td>
+   <td><tt>internal</tt>, <tt>external</tt>, <tt>optical</tt>, <tt>netboot</tt>, <tt>hdbios</tt>, <tt>biosexternal</tt>, <tt>cd</tt>, and <tt>manual</tt></td>
+   <td>Tells rEFInd what methods to use to locate boot loaders. The <tt>internal</tt>, <tt>external</tt>, and <tt>optical</tt> parameters tell rEFInd to scan for EFI boot loaders on internal, external, and optical (CD, DVD, and Blu-ray) devices, respectively. The <tt>netboot</tt> option relies on the presence of the <tt>ipxe.efi</tt> and <tt>ipxe_discover.efi</tt> program files in the <tt>EFI/tools</tt> directory to assist with network (Preboot Execution Environment, or PXE) booting. Note that <tt>netboot</tt> is experimental. See the <tt>BUILDING.txt</tt> file for information on building the necessary binaries. The <tt>hdbios</tt>, <tt>biosexternal</tt>, and <tt>cd</tt> parameters are similar, but scan for BIOS boot loaders. (Note that the BIOS options scan more thoroughly and actively on Macs than on UEFI-based PCs; for the latter, only options in the firmware's boot list are scanned, as described on the <a href="using.html">Using rEFInd</a> page.) The <tt>manual</tt> parameter tells rEFInd to scan the configuration file for manual settings. You can specify multiple parameters to have the program scan for multiple boot loader types. When you do so, the order determines the order in which the boot loaders appear in the menu. The default is <tt>internal, external, optical, manual</tt> on most systems, but <tt>internal, hdbios, external, biosexternal, optical, cd, manual</tt> on Macs.</td>
 </tr>
 <tr>
    <td><tt>uefi_deep_legacy_scan</tt></td>
index ec81622523b7601f2e0addded8e199dc9c8ef9e2..f85f939e6e0c8b139efd13b482fc8729641e11a7 100644 (file)
@@ -198,6 +198,8 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
 
    </ul></li>
 
+<li class="tight"><a href="#winprob">Fixing Windows Boot Problems</a></li>
+
 <li class="tight"><a href="#uninstalling">Uninstalling rEFInd</a></li>
 
 </ul>
@@ -1003,6 +1005,38 @@ $ <b>ioreg -l -p IODeviceTree | grep firmware-abi</b>
 
 <p>Unfortunately, I lack a recent Mac and so can't investigate these issues myself, so I'm dependent upon others (mostly non-programmers) to offer workarounds. This is the type of problem that really requires hands-on interactive debugging sessions with the code to stand any chance of finding a better solution.</p>
 
+<a name="winprob">
+<h2>Fixing Windows Boot Problems</h2>
+</a>
+
+<p>Most Windows boot problems are best addressed on Windows-specific sites, so I recommend you make the rounds of Windows forums to solve such problems. There is one that deserves mention here, though: If you accidentally erase the Windows boot loader file, <tt>EFI/Microsoft/Boot/bootmgfw.efi</tt>, you won't be able to boot Windows. The simplest solution is to restore this file from a backup you prepared ahead of time. If you don't have such a backup, though, you can restore it as follows:</p>
+
+<ol>
+
+<li>Boot from an emergency Windows recovery disk. If you don't have one, you can prepare one from a working Windows system as described <a href="http://windows.microsoft.com/en-us/windows7/create-a-system-repair-disc">here.</a></li>
+
+<li>Type <tt class="userinput">diskpart</tt> to enter the Windows disk-partitioning tool.</li>
+
+<li>In <tt>diskpart</tt>, type <tt class="userinput">sel disk 0</tt> followed by <tt>list vol</tt>. You should see a set of partitions. This step is intended to help you identify your ESP, which will probably be the only FAT32 partition on the disk. (If you have multiple disks, you may need to try again with <tt class="userinput">sel disk 1</tt> or higher.) Note the volume number of your ESP.</li>
+
+<li>Type <tt class="userinput">sel vol 1</tt>, changing <tt>1</tt> to whatever the ESP's volume number is.</li>
+
+<li>Type <tt class="userinput">assign letter=S:</tt> to assign the ESP a Windows disk identifier of <tt>S:</tt>. (You can use another letter if you prefer.)</li>
+
+<li>Type <tt class="userinput">exit</tt> to exit from <tt>diskutil</tt>.</li>
+
+<li>Type <tt class="userinput">cd /d s:\EFI\Microsoft\Boot\</tt> to change into the Windows boot loader directory. (If this directory doesn't exist, you may need to create it first with <tt>mkdir</tt>. If rEFInd or some other boot loader occupies this directory, back it up first.</li>
+
+<li>Type <tt class="userinput">bootrec /fixboot</tt>.</li>
+
+<li>Type <tt class="userinput">bcdboot c:\Windows /s s: /f ALL</tt>. Note that this command should set the Windows boot loader as the default. Omit <tt>/f ALL</tt> if you don't want to adjust the EFI's default boot program.</li>
+
+<li>Reboot and hope it works! If the computer boots straight to Windows and you want to use rEFInd, use <tt>bcdedit</tt> in Windows, as described in step 9 of the <a href="#windows">Installing rEFInd Manually Using Windows</a> section of this page.</li>
+
+</ol>
+
+<p>For more information, see <a href="http://superuser.com/questions/460762/how-can-i-repair-the-windows-8-efi-bootloader">this SuperUser question and answer.</a></p>
+
 <a name="uninstalling">
 <h2>Uninstalling rEFInd</h2>
 </a>
index ab7cd665ab93e0ef1999591a1d816ad1fab2a505..193a75d05360afaa5597182861254914a8afe68b 100644 (file)
@@ -174,6 +174,7 @@ timeout 20
 #  reboot           - a tag to reboot the computer
 #  firmware         - a tag to reboot the computer into the firmware's
 #                     user interface (ignored on older computers)
+#  netboot          - launch the ipxe.efi tool for network (PXE) booting
 # Default is shell,memtest,gdisk,apple_recovery,windows_recovery,mok_tool,about,shutdown,reboot,firmware
 #
 #showtools shell, gdisk, memtest, mok_tool, about, reboot, exit, firmware
@@ -200,12 +201,15 @@ timeout 20
 #  internal      - internal EFI disk-based boot loaders
 #  external      - external EFI disk-based boot loaders
 #  optical       - EFI optical discs (CD, DVD, etc.)
+#  netboot       - EFI network (PXE) boot options
 #  hdbios        - BIOS disk-based boot loaders
 #  biosexternal  - BIOS external boot loaders (USB, eSATA, etc.)
 #  cd            - BIOS optical-disc boot loaders
 #  manual        - use stanzas later in this configuration file
 # Note that the legacy BIOS options require firmware support, which is
 # not present on all computers.
+# The netboot option is experimental and relies on the ipxe.efi and
+# ipxe_discover.efi program files.
 # On UEFI PCs, default is internal,external,optical,manual
 # On Macs, default is internal,hdbios,external,biosexternal,optical,cd,manual
 #
index ba0c06b3b171ab54cc27ce9af94af5ac2915ac53..9e5016b0f9022fbb9c3a398e797fb24bf6ea0a6f 100644 (file)
@@ -475,8 +475,12 @@ VOID ReadConfig(CHAR16 *FileName)
     } // if
 
     if (!FileExists(SelfDir, FileName)) {
-        Print(L"Configuration file '%s' missing!\n", FileName);
-        return;
+       Print(L"Configuration file '%s' missing!\n", FileName);
+       if (!FileExists(SelfDir, L"icons")) {
+          Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n");
+          GlobalConfig.TextOnly = TRUE;
+       }
+       return;
     }
 
     Status = ReadFile(SelfDir, FileName, &File, &i);
@@ -585,6 +589,8 @@ VOID ReadConfig(CHAR16 *FileName)
                    GlobalConfig.ShowTools[i - 1] = TAG_FIRMWARE;
                 } else if ((StriCmp(FlagName, L"memtest86") == 0) || (StriCmp(FlagName, L"memtest") == 0)) {
                    GlobalConfig.ShowTools[i - 1] = TAG_MEMTEST;
+                } else if (StriCmp(FlagName, L"netboot") == 0) {
+                   GlobalConfig.ShowTools[i - 1] = TAG_NETBOOT;
                 } else {
                    Print(L" unknown showtools flag: '%s'\n", FlagName);
                 }
@@ -685,6 +691,11 @@ VOID ReadConfig(CHAR16 *FileName)
     if ((GlobalConfig.DontScanFiles) && (GlobalConfig.WindowsRecoveryFiles))
        MergeStrings(&(GlobalConfig.DontScanFiles), GlobalConfig.WindowsRecoveryFiles, L',');
     MyFreePool(File.Buffer);
+
+    if (!FileExists(SelfDir, L"icons") && !FileExists(SelfDir, GlobalConfig.IconsDir)) {
+       Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n");
+       GlobalConfig.TextOnly = TRUE;
+    }
 } /* VOID ReadConfig() */
 
 // Finds a volume with the specified Identifier (a filesystem label, a
index fc43038bb284d56d4bd2ed74e80f3d8795f5477c..ea1f71f194e48a252da35fe389f5bdc483ccaccb 100644 (file)
@@ -74,7 +74,8 @@
 #define TAG_FIRMWARE         (14)
 #define TAG_MEMTEST          (15)
 #define TAG_GDISK            (16)
-#define NUM_TOOLS            (17)
+#define TAG_NETBOOT          (17)
+#define NUM_TOOLS            (18)
 
 #define NUM_SCAN_OPTIONS 10
 
index 53a94ef4753b39d0ba07024a5529d57ee3b8d030..5438afdc49908b3517cca3cdfd26e59b770b307a 100644 (file)
@@ -63,9 +63,11 @@ BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = {
    { NULL, L"tool_windows_rescue", ICON_SIZE_SMALL },
    { NULL, L"tool_mok_tool", ICON_SIZE_SMALL },
    { NULL, L"tool_memtest", ICON_SIZE_SMALL },
+   { NULL, L"tool_netboot", ICON_SIZE_SMALL },
    { NULL, L"vol_internal", ICON_SIZE_BADGE },
    { NULL, L"vol_external", ICON_SIZE_BADGE },
    { NULL, L"vol_optical", ICON_SIZE_BADGE },
+   { NULL, L"vol_net", ICON_SIZE_BADGE },
 };
 
 EG_IMAGE * BuiltinIcon(IN UINTN Id)
index 25b545ee8be3adea502c1a74e78b8524995cdcf8..b1c8fdbac1be6ac3d7c2f969f82f398a7d8b3a92 100644 (file)
@@ -67,10 +67,12 @@ EG_IMAGE * BuiltinIcon(IN UINTN Id);
 #define BUILTIN_ICON_TOOL_WINDOWS_RESCUE   (9)
 #define BUILTIN_ICON_TOOL_MOK_TOOL         (10)
 #define BUILTIN_ICON_TOOL_MEMTEST          (11)
-#define BUILTIN_ICON_VOL_INTERNAL          (12)
-#define BUILTIN_ICON_VOL_EXTERNAL          (13)
-#define BUILTIN_ICON_VOL_OPTICAL           (14)
-#define BUILTIN_ICON_COUNT                 (15)
+#define BUILTIN_ICON_TOOL_NETBOOT          (12)
+#define BUILTIN_ICON_VOL_INTERNAL          (13)
+#define BUILTIN_ICON_VOL_EXTERNAL          (14)
+#define BUILTIN_ICON_VOL_OPTICAL           (15)
+#define BUILTIN_ICON_VOL_NET               (16)
+#define BUILTIN_ICON_COUNT                 (17)
 
 #endif
 
index 893f62c35b53a93919436175cb5f0eab22a4acf6..1a7bb811466be342cb4641c0034ff388755714ba 100644 (file)
@@ -713,6 +713,9 @@ VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume)
           case DISK_KIND_OPTICAL:
              Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL);
              break;
+          case DISK_KIND_NET:
+             Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET);
+             break;
       } // switch()
    }
 } // VOID SetVolumeBadgeIcon()
index e6a8c3026ef330a5318a675f31a27a912e33a329..6a106ee8f51726a04c71667098cccf959ec5dbe6 100644 (file)
@@ -73,6 +73,7 @@ typedef struct {
 #define DISK_KIND_INTERNAL  (0)
 #define DISK_KIND_EXTERNAL  (1)
 #define DISK_KIND_OPTICAL   (2)
+#define DISK_KIND_NET       (3)
 
 #define VOL_UNREADABLE 999
 
@@ -95,10 +96,10 @@ VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount);
 
 VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList);
 
+VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume);
 VOID ScanVolumes(VOID);
 
 BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath);
-BOOLEAN DirectoryExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath);
 
 EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode);
 
index e83940bcea6c1a281f6f4426a393b6e2cc0984a9..e3e009d0a512edb52cca97fe0b2383344e9b2d9c 100644 (file)
@@ -81,6 +81,7 @@
 #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 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"
@@ -90,6 +91,7 @@
 #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 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 SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\shell.efi"
 #define GPTSYNC_NAMES           L"\\EFI\\tools\\gptsync.efi"
 #define GDISK_NAMES             L"\\EFI\\tools\\gdisk.efi"
+#define NETBOOT_NAMES           L"\\EFI\\tools\\ipxe.efi"
 #define MEMTEST_NAMES           L"memtest86.efi"
 #define DRIVER_DIRS             L"drivers"
 #define FALLBACK_FULLNAME       L"EFI\\BOOT\\boot.efi" /* Not really correct */
 #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
@@ -143,7 +149,7 @@ REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TE
                               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_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL,
-                                TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, 0, 0, 0, 0, 0, 0 }
+                                TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, 0, 0, 0, 0, 0, 0, 0, 0 }
                             };
 
 EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE;
@@ -169,7 +175,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.3.2");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.3.4");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2014 Roderick W. Smith");
@@ -451,7 +457,7 @@ static VOID DoEnableAndLockVMX(VOID)
         msr = 0x3a;
         __asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits));
     } 
-} // VOID DoEnableAndLockVMX
+} // VOID DoEnableAndLockVMX()
 
 static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName)
 {
@@ -476,7 +482,7 @@ static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName)
 // '\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
+// finds.) Thus, care should be taken to avoid placing duplicate matching files in
 // the kernel's directory.
 // If no matching init file can be found, returns NULL.
 static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
@@ -912,61 +918,67 @@ static VOID GuessLinuxDistribution(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CH
 // code and shortcut letter. For Linux EFI stub loaders, also sets kernel options
 // that will (with luck) work fairly automatically.
 VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Volume) {
-   CHAR16      *FileName, *PathOnly, *NoExtension, *OSIconName = NULL, *Temp, *SubString;
+   CHAR16      *NameClues, *PathOnly, *NoExtension, *OSIconName = NULL, *Temp, *SubString;
    CHAR16      ShortcutLetter = 0;
    UINTN       i = 0, Length;
 
-   FileName = Basename(LoaderPath);
+   NameClues = Basename(LoaderPath);
    PathOnly = FindPath(LoaderPath);
-   NoExtension = StripEfiExtension(FileName);
+   NoExtension = StripEfiExtension(NameClues);
 
-   // 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, GlobalConfig.IconSizes[ICON_SIZE_BIG]);
-   }
-   if (!Entry->me.Image) {
-      Entry->me.Image = egCopyImage(Volume->VolIconImage);
-   }
+   if (Volume->DiskKind == DISK_KIND_NET) {
+      MergeStrings(&NameClues, Entry->me.Title, L' ');
+   } else {
+      // 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, GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+      }
+      if (!Entry->me.Image) {
+         Entry->me.Image = egCopyImage(Volume->VolIconImage);
+      }
 
-   // Begin creating icon "hints" by using last part of directory path leading
-   // to the loader
-   Temp = FindLastDirName(LoaderPath);
-   MergeStrings(&OSIconName, Temp, L',');
-   MyFreePool(Temp);
-   Temp = NULL;
-   if (OSIconName != NULL) {
-      ShortcutLetter = OSIconName[0];
-   }
+      // Begin creating icon "hints" by using last part of directory path leading
+      // to the loader
+      Temp = FindLastDirName(LoaderPath);
+      MergeStrings(&OSIconName, Temp, L',');
+      MyFreePool(Temp);
+      Temp = NULL;
+      if (OSIconName != NULL) {
+         ShortcutLetter = OSIconName[0];
+      }
 
-   // Add every "word" in the volume label, delimited by spaces, dashes (-), or
-   // underscores (_), to the list of hints to be used in searching for OS
-   // icons.
-   if ((Volume->VolName) && (StrLen(Volume->VolName) > 0)) {
-      Temp = SubString = StrDuplicate(Volume->VolName);
-      if (Temp != NULL) {
-         Length = StrLen(Temp);
-         for (i = 0; i < Length; i++) {
-            if ((Temp[i] == L' ') || (Temp[i] == L'_') || (Temp[i] == L'-')) {
-               Temp[i] = 0;
-               if (StrLen(SubString) > 0)
-                  MergeStrings(&OSIconName, SubString, L',');
-               SubString = Temp + i + 1;
-            } // if
-         } // for
-         MergeStrings(&OSIconName, SubString, L',');
-         MyFreePool(Temp);
+      // Add every "word" in the volume label, delimited by spaces, dashes (-), or
+      // underscores (_), to the list of hints to be used in searching for OS
+      // icons.
+      if ((Volume->VolName) && (StrLen(Volume->VolName) > 0)) {
+         Temp = SubString = StrDuplicate(Volume->VolName);
+         if (Temp != NULL) {
+            Length = StrLen(Temp);
+            for (i = 0; i < Length; i++) {
+               if ((Temp[i] == L' ') || (Temp[i] == L'_') || (Temp[i] == L'-')) {
+                  Temp[i] = 0;
+                  if (StrLen(SubString) > 0)
+                     MergeStrings(&OSIconName, SubString, L',');
+                  SubString = Temp + i + 1;
+               } // if
+            } // for
+            MergeStrings(&OSIconName, SubString, L',');
+            MyFreePool(Temp);
+         } // if
       } // if
-   } // if
+   } // if/else network boot
 
    // detect specific loaders
-   if (StriSubCmp(L"bzImage", FileName) || StriSubCmp(L"vmlinuz", FileName)) {
-      GuessLinuxDistribution(&OSIconName, Volume, LoaderPath);
+   if (StriSubCmp(L"bzImage", NameClues) || StriSubCmp(L"vmlinuz", NameClues)) {
+      if (Volume->DiskKind != DISK_KIND_NET) {
+         GuessLinuxDistribution(&OSIconName, Volume, LoaderPath);
+         Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume);
+      }
       MergeStrings(&OSIconName, L"linux", L',');
       Entry->OSType = 'L';
       if (ShortcutLetter == 0)
          ShortcutLetter = 'L';
-      Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume);
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX;
    } else if (StriSubCmp(L"refit", LoaderPath)) {
       MergeStrings(&OSIconName, L"refit", L',');
@@ -981,33 +993,39 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo
       Entry->OSType = 'M';
       ShortcutLetter = 'M';
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX;
-   } else if (StriCmp(FileName, L"diags.efi") == 0) {
+   } else if (StriCmp(NameClues, L"diags.efi") == 0) {
       MergeStrings(&OSIconName, L"hwtest", L',');
-   } else if (StriCmp(FileName, L"e.efi") == 0 || StriCmp(FileName, L"elilo.efi") == 0 || StriSubCmp(L"elilo", FileName)) {
+   } else if (StriCmp(NameClues, L"e.efi") == 0 || StriCmp(NameClues, L"elilo.efi") == 0 || StriSubCmp(L"elilo", NameClues)) {
       MergeStrings(&OSIconName, L"elilo,linux", L',');
       Entry->OSType = 'E';
       if (ShortcutLetter == 0)
          ShortcutLetter = 'L';
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO;
-   } else if (StriSubCmp(L"grub", FileName)) {
+   } else if (StriSubCmp(L"grub", NameClues)) {
+      MergeStrings(&OSIconName, L"grub,linux", L',');
       Entry->OSType = 'G';
       ShortcutLetter = 'G';
       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"bkpbootmgfw.efi") == 0) {
+   } else if (StriCmp(NameClues, L"cdboot.efi") == 0 ||
+              StriCmp(NameClues, L"bootmgr.efi") == 0 ||
+              StriCmp(NameClues, L"bootmgfw.efi") == 0 ||
+              StriCmp(NameClues, L"bkpbootmgfw.efi") == 0) {
       MergeStrings(&OSIconName, L"win", L',');
       Entry->OSType = 'W';
       ShortcutLetter = 'W';
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
-   } else if (StriCmp(FileName, L"xom.efi") == 0) {
+   } else if (StriCmp(NameClues, L"xom.efi") == 0) {
       MergeStrings(&OSIconName, L"xom,win", L',');
       Entry->UseGraphicsMode = TRUE;
       Entry->OSType = 'X';
       ShortcutLetter = 'W';
       Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS;
    }
+   else if (StriSubCmp(L"ipxe", NameClues)) {
+      Entry->OSType = 'N';
+      ShortcutLetter = 'N';
+      MergeStrings(&OSIconName, L"network", L',');
+   } 
 
    if ((ShortcutLetter >= 'a') && (ShortcutLetter <= 'z'))
       ShortcutLetter = ShortcutLetter - 'a' + 'A'; // convert lowercase to uppercase
@@ -1017,6 +1035,38 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo
    MyFreePool(PathOnly);
 } // VOID SetLoaderDefaults()
 
+// // Add a network (PXE) EFI boot loader to the list, using automatic settings
+// // for icons, options, etc.
+// LOADER_ENTRY * AddNetbootLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) {
+//    LOADER_ENTRY      *Entry;
+// 
+//    Print(L"Adding iPXE entry for '%s'\n", LoaderTitle);
+//    PauseForKey();
+//    CleanUpPathNameSlashes(LoaderPath);
+//    Entry = InitializeLoaderEntry(NULL);
+//    if (Entry != NULL) {
+//       Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath);
+//       Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256);
+//       // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume
+//       // name is identical except for something added to the end (e.g., VolB1 vs. VolB12).
+//       SPrint(Entry->me.Title, 255, L"NetBoot %s", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath);
+//       Entry->me.Row = 0;
+//       if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) {
+//          Entry->LoaderPath = StrDuplicate(L"\\");
+//       } else {
+//          Entry->LoaderPath = NULL;
+//       }
+//       MergeStrings(&(Entry->LoaderPath), LoaderPath, 0);
+//       Entry->VolName = Volume->VolName;
+//       Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath);
+//       SetLoaderDefaults(Entry, LoaderPath, Volume);
+//       GenerateSubScreen(Entry, Volume);
+//       AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+//    }
+// 
+//    return(Entry);
+// } // LOADER_ENTRY * AddLoaderEntry()
+
 // 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) {
@@ -1029,7 +1079,11 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN
       Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256);
       // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume
       // name is identical except for something added to the end (e.g., VolB1 vs. VolB12).
-      SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName);
+      // Note: Volume->VolName will be NULL for network boot programs.
+      if (Volume->VolName)
+         SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName);
+      else
+         SPrint(Entry->me.Title, 255, L"Boot %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath);
       Entry->me.Row = 0;
       Entry->me.BadgeImage = Volume->VolBadgeImage;
       if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) {
@@ -1345,6 +1399,55 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
     return FoundFallbackDuplicate;
 } /* static VOID ScanLoaderDir() */
 
+// Run the IPXE_DISCOVER_NAME program, which obtains the IP address of the boot
+// server and the name of the boot file it delivers.
+CHAR16* RuniPXEDiscover(EFI_HANDLE Volume)
+{
+   EFI_STATUS       Status;
+   EFI_DEVICE_PATH  *FilePath;
+   EFI_HANDLE       iPXEHandle;
+   CHAR16           *boot_info;
+   UINTN            boot_info_size = 256 * sizeof(CHAR16);
+
+   FilePath = FileDevicePath (Volume, IPXE_DISCOVER_NAME);
+   Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, FilePath,
+                                NULL, 0, &iPXEHandle);
+   if (Status != 0) {
+      return NULL;
+   } // if
+
+   boot_info = AllocatePool(256 * sizeof(CHAR16));
+   Status = refit_call3_wrapper(BS->StartImage, iPXEHandle, &boot_info_size, &boot_info);
+
+   return boot_info;
+} // RuniPXEDiscover()
+
+// Scan for network (PXE) boot servers. This function relies on the presence
+// of the IPXE_DISCOVER_NAME and IPXE_NAME program files on the volume from
+// which rEFInd launched. As of December 6, 2014, these tools aren't entirely
+// reliable. See BUILDING.txt for information on building them.
+static VOID ScanNetboot() {
+   CHAR16        *iPXEFileName = IPXE_NAME;
+   CHAR16        *Location;
+   REFIT_VOLUME  *NetVolume;
+
+   if (FileExists(SelfVolume->RootDir, IPXE_DISCOVER_NAME) &&
+       FileExists(SelfVolume->RootDir, IPXE_NAME) &&
+       IsValidLoader(SelfVolume->RootDir, IPXE_DISCOVER_NAME) &&
+       IsValidLoader(SelfVolume->RootDir, IPXE_NAME)) {
+      Location = RuniPXEDiscover(SelfVolume->DeviceHandle);
+      if (Location != NULL && FileExists(SelfVolume->RootDir, iPXEFileName)) {
+         NetVolume = AllocatePool(sizeof(REFIT_VOLUME));
+         NetVolume = CopyMem(NetVolume, SelfVolume, sizeof(REFIT_VOLUME));
+         NetVolume->DiskKind = DISK_KIND_NET;
+         NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET);
+         NetVolume->PartName = NetVolume->VolName = NULL;
+         AddLoaderEntry(iPXEFileName, Location, NetVolume);
+         MyFreePool(NetVolume);
+      } // if support files exist and are valid
+   } 
+} // VOID ScanNetBoot()
+
 static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    EFI_STATUS              Status;
    REFIT_DIR_ITER          EfiDirIter;
@@ -2256,6 +2359,9 @@ static VOID ScanForBootloaders(VOID) {
          case 'o': case 'O':
             ScanOptical();
             break;
+         case 'n': case 'N':
+            ScanNetboot();
+            break;
       } // switch()
    } // for
 
@@ -2376,6 +2482,18 @@ static VOID ScanForTools(VOID) {
             } // while
             FileName = NULL;
             break;
+         
+         case TAG_NETBOOT:
+            j = 0;
+            while ((FileName = FindCommaDelimited(NETBOOT_NAMES, j++)) != NULL) {
+               if (FileExists(SelfRootDir, FileName)) {
+                  AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Netboot",
+                               BuiltinIcon(BUILTIN_ICON_TOOL_NETBOOT), 'N', FALSE);
+               } // if
+               MyFreePool(FileName);
+            } // while
+            FileName = NULL;
+            break;
 
          case TAG_APPLE_RECOVERY:
             FileName = StrDuplicate(L"\\com.apple.recovery.boot\\boot.efi");