]> code.delx.au - refind/commitdiff
Merge commit 'a1e55b412149a2b2ced44c07ea5c285c04c243fb'
authorsrs5694 <srs5694@users.sourceforge.net>
Mon, 8 Dec 2014 02:41:02 +0000 (21:41 -0500)
committersrs5694 <srs5694@users.sourceforge.net>
Mon, 8 Dec 2014 02:41:02 +0000 (21:41 -0500)
25 files changed:
BUILDING.txt
CREDITS.txt
NEWS.txt
debian/changelog
docs/refind/configfile.html
docs/refind/installing.html
filesystems/fsw_efi.c
gptsync/gptsync.h
icons/os_network.png [new file with mode: 0644]
icons/tool_netboot.png [new file with mode: 0644]
icons/vol_net.png [new file with mode: 0644]
install.sh
net/Makefile [new file with mode: 0644]
net/discovery/Makefile.housekeeping [new file with mode: 0644]
net/discovery/console.h [new file with mode: 0644]
net/discovery/efi_discovery_prefix.c [new file with mode: 0644]
refind.conf-sample
refind.spec
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..26ec59eea6ffb6f0683b0d8cea00f2e57d59af0b 100644 (file)
@@ -46,6 +46,14 @@ 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).
+
+* Rohan Sehgal (rohan.sehgal.su@gmail.com) wrote code to help rEFInd
+  detect network boot options and launch them, with the help of the
+  external ipxe.efi and ipxe_discover.efi programs.
+
 * 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
@@ -73,6 +81,9 @@ Icons and graphics:
   pages correctly, the original creator was David Vignoni (aka
   "deviantdark" on the deviantart site).
 
+* Erik Kemperman provided the rEFInd icon, which is a combination of
+  the common refresh/reload icon and the search/find icon.
+
 * The keys icon for MOK keys management comes from the
   kdeartwork-iconthemes-4.8.5 package on Gentoo.
 
@@ -103,5 +114,9 @@ Icons and graphics:
   (http://en.wikipedia.org/wiki/File:Google_Chrome_icon_and_wordmark_%282011%29.svg),
   which in turn is Google's original work.
 
-* Erik Kemperman provided the rEFInd icon, which is a combination of
-  the common refresh/reload icon and the search/find icon.
+* The icon used (at different sizes) for both the generic network OS and
+  for the network-boot badge is from
+  https://www.iconfinder.com/icons/37048/intranet_network_icon.
+
+* The icon used for the network-boot tool on the second row comes from
+  https://cdn2.iconfinder.com/data/icons/oxygen/48x48/devices/network-wired.png.
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 63df1ba244e4fd20937d31c9610cb20903eae8d1..96c84a7ed342255137e59e6408be61c4e6216003 100644 (file)
@@ -1,8 +1,14 @@
+refind (0.8.4-0ppa1) trusty; urgency=medium
+
+  * Version bump
+
+ -- Rod Smith <rodsmith@rodsbooks.com>  Sun, 07 Dec 2014 12:28:56 -0400
+
 refind (0.8.3-0ppa1) trusty; urgency=medium
 
   * Version bump
 
- -- Rod Smith <rodsmith@vbu1404>  Sun, 06 Jul 2014 12:28:56 -0400
+ -- Rod Smith <rodsmith@rodsbooks.com>  Sun, 06 Jul 2014 12:28:56 -0400
 
 refind (0.8.2-0ppa3) trusty; urgency=medium
 
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 dd5d7c5f1576aa2f4b27fc7ee1d68bc5a6a876ec..f2cb4fe372900871055fc7594711743695e4cb6a 100644 (file)
@@ -78,7 +78,7 @@ EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
 /** Helper macro for stringification. */
 #define FSW_EFI_STRINGIFY(x) #x
 /** Expands to the EFI driver name given the file system type name. */
-#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.8.3 " FSW_EFI_STRINGIFY(t) L" File System Driver"
+#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.8.4 " FSW_EFI_STRINGIFY(t) L" File System Driver"
 
 // function prototypes
 
index 0f9835e2c8d7767ff6aabb25009001f024c1cf66..c35740a766d8ad3de6649f74572a033be04ee1b0 100644 (file)
@@ -35,7 +35,7 @@
  */
 /* Changes copyright (c) 2013 Roderick W. Smith */
 
-#define VERSION L"0.8.3"
+#define VERSION L"0.8.4"
 
 //
 // config
diff --git a/icons/os_network.png b/icons/os_network.png
new file mode 100644 (file)
index 0000000..ca41192
Binary files /dev/null and b/icons/os_network.png differ
diff --git a/icons/tool_netboot.png b/icons/tool_netboot.png
new file mode 100644 (file)
index 0000000..a5070ef
Binary files /dev/null and b/icons/tool_netboot.png differ
diff --git a/icons/vol_net.png b/icons/vol_net.png
new file mode 100644 (file)
index 0000000..614d53c
Binary files /dev/null and b/icons/vol_net.png differ
index 50748d3af88a9b75042a1094be21138548d4683b..f5dae71626c06d0472be0e6cb53dc81bdaf294c7 100755 (executable)
@@ -7,8 +7,8 @@
 # ./install.sh [options]
 #
 # options include:
-#    "--esp" to install to the ESP rather than to the system's root
-#           filesystem. This is the default on Linux.
+#    "--notesp" to install to the OS X root filesystem rather than to the ESP.
+#           This option may not be used under Linux.
 #    "--usedefault {devicefile}" to install as default
 #           (/EFI/BOOT/BOOTX64.EFI and similar) to the specified device
 #           (/dev/sdd1 or whatever) without registering with the NVRAM.
@@ -35,6 +35,7 @@
 #
 # Revision history:
 #
+# 0.8.4   -- OS X default changed to install to ESP under /EFI/BOOT
 # 0.7.9   -- Fixed bug that caused errors if dmraid utility not installed
 # 0.7.7   -- Fixed bug that created mangled refind_linux.conf file; added ability
 #            to locate and mount ESP on Linux, if it's not mounted
@@ -89,18 +90,17 @@ AlwaysYes=0
 #
 
 GetParams() {
-   InstallToEspOnMac=0
-   if [[ $OSName == "Linux" ]] ; then
-      # Install the driver required to read /boot, if it's available
-      InstallDrivers="boot"
-   else
-      InstallDrivers="none"
-   fi
+   InstallToEspOnMac=1
+   # Install the driver required to read Linux /boot, if it's available
+   # Note: Under OS X, this will be installed only if a Linux partition
+   # is detected, in which case the ext4fs driver will be installed.
+   InstallDrivers="boot"
    while [[ $# -gt 0 ]]; do
       case $1 in
-         --esp | --ESP) InstallToEspOnMac=1
+         --notesp) InstallToEspOnMac=0
               ;;
          --ownhfs) OwnHfs=1
+              InstallToEspOnMac=0
               TargetPart="$2"
               TargetDir=/System/Library/CoreServices
               shift
@@ -112,6 +112,7 @@ GetParams() {
               shift
               ;;
          --root) RootDir="$2"
+              InstallToEspOnMac=0
               shift
               ;;
          --localkeys) LocalKeys=1
@@ -126,7 +127,7 @@ GetParams() {
               ;;
          --yes) AlwaysYes=1
               ;;
-         * ) echo "Usage: $0 [--esp | --usedefault {device-file} | --root {directory} |"
+         * ) echo "Usage: $0 [--notesp | --usedefault {device-file} | --root {dir} |"
              echo "                     --ownhfs {device-file} ]"
              echo "                  [--nodrivers | --alldrivers] [--shim {shim-filename}]"
              echo "                  [--localkeys] [--yes]"
@@ -135,18 +136,10 @@ GetParams() {
       shift
    done
 
-   if [[ $InstallToEspOnMac == 1 && "$TargetDir" == '/EFI/BOOT' ]] ; then
-      echo "You may use --esp OR --usedefault, but not both! Aborting!"
-      exit 1
-   fi
    if [[ "$RootDir" != '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
       echo "You may use --usedefault OR --root, but not both! Aborting!"
       exit 1
    fi
-   if [[ "$RootDir" != '/' && $InstallToEspOnMac == 1 ]] ; then
-      echo "You may use --root OR --esp, but not both! Aborting!"
-      exit 1
-   fi
    if [[ "$TargetDir" != '/System/Library/CoreServices' && "$OwnHfs" == '1' ]] ; then
       echo "If you use --ownhfs, you may NOT use --usedefault! Aborting!"
       exit 1
@@ -245,20 +238,43 @@ CopyKeys() {
    fi
 } # CopyKeys()
 
+# Determine (or guess) the filesystem used on the Linux /boot filesystem.
+# Store the result in the BootFS global variable.
+SetBootFS() {
+   local Blkid
+
+   Blkid=`which blkid 2> /dev/null`
+   BootFS=""
+   if [[ $OSName == 'Linux' && -x "$Blkid" ]] ; then
+      BootPart=`df /boot | grep dev | cut -f 1 -d " "`
+      BootFS=`$Blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
+   fi
+   if [[ $OSName == 'Darwin' ]] ; then
+      # 0FC63DAF-8483-4772-8E79-3D69D8477DE4 = Linux filesystem
+      # BC13C2FF-59E6-4262-A352-B275FD6F7172 = Freedesktop $boot partition
+      # 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 = Freedesktop Linux /home
+      # E6D6D379-F507-44C2-A23C-238F2A3DF928 = Linux LVM
+      # A19D880F-05FC-4D3B-A006-743F0F84911E = Linux RAID
+      # 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F = Linux swap
+      Temp=$(diskutil list | grep -i '0FC63DAF-8483-4772-8E79-3D69D8477DE4\|BC13C2FF-59E6-4262-A352-B275FD6F7172\|933AC7E1-2EB4-4F13-B844-0E14E2AEF915\|E6D6D379-F507-44C2-A23C-238F2A3DF928\|A19D880F-05FC-4D3B-A006-743F0F84911E\|0657FD6D-A4AB-43C4-84E5-0933C84B4F4F\|Linux')
+      BootFS=""
+      if [[ -n $Temp ]] ; then
+         echo "Found suspected Linux partition(s); installing ext4fs driver."
+         BootFS="ext4"
+      fi
+   fi
+} # SetBootFS()
+
 # Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1,
 # honoring the $InstallDrivers condition. Must be passed a suitable
 # architecture code (ia32 or x64).
 CopyDrivers() {
-   local Blkid
-
-   Blkid=`which blkid 2> /dev/null`
    if [[ $InstallDrivers == "all" ]] ; then
       mkdir -p "$InstallDir/$TargetDir/drivers_$1"
       cp "$ThisDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
       cp "$RefindDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
-   elif [[ "$InstallDrivers" == "boot" && -x "$Blkid" ]] ; then
-      BootPart=`df /boot | grep dev | cut -f 1 -d " "`
-      BootFS=`$Blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
+   elif [[ "$InstallDrivers" == "boot" ]] ; then
+      SetBootFS
       DriverType=""
       case $BootFS in
          ext2 | ext3) DriverType="ext2"
@@ -282,7 +298,7 @@ CopyDrivers() {
          cp "$RefindDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1"/ 2> /dev/null
       fi
    fi
-}
+} # CopyDrivers()
 
 # Copy tools (currently only gptsync, and that only on Macs) to the EFI/tools
 # directory on the ESP. Must be passed a suitable architecture code (ia32
@@ -318,7 +334,7 @@ CopyRefindFiles() {
       if [[ $InstallDrivers == "all" ]] ; then
          cp -r "$RefindDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
          cp -r "$ThisDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
-      elif [[ $Upgrade == 1 ]] ; then
+      elif [[ $Upgrade == 1 || $InstallToEspOnMac == 1 ]] ; then
          if [[ $Platform == 'EFI64' ]] ; then
             CopyDrivers x64
             CopyTools x64
@@ -328,6 +344,11 @@ CopyRefindFiles() {
          fi
       fi
       Refind=""
+      if [[ $Platform == 'EFI64' ]] ; then
+         Refind='bootx64.efi'
+      elif [[ $Platform == 'EFI32' ]] ; then
+         Refind='bootia32.efi'
+      fi
       CopyKeys
    elif [[ $Platform == 'EFI64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then
       cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64"
@@ -432,7 +453,6 @@ MountDefaultTarget() {
       rmdir "$InstallDir"
       exit 1
    fi
-   echo "UnmountEsp = $UnmountEsp"
 } # MountDefaultTarget()
 
 #
@@ -448,9 +468,7 @@ MountOSXESP() {
    # if the system has multiple disks, this could be wrong!
    Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p")
    if [ $Temp ]; then
-      Temp=$(diskutil list $Temp | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p
-             q
-         }' )
+      Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1)
       if [ -z $Temp ]; then
          echo "Warning: root device doesn't have an EFI partition"
       fi
@@ -514,10 +532,10 @@ ENDOFHERE
 # Sets Problems=1 if problems found during the installation.
 InstallOnOSX() {
    echo "Installing rEFInd on OS X...."
-   if [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then
-      MountDefaultTarget
-   elif [[ "$InstallToEspOnMac" == "1" ]] ; then
+   if [[ "$InstallToEspOnMac" == "1" ]] ; then
       MountOSXESP
+   elif [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then
+      MountDefaultTarget
    else
       InstallDir="$RootDir/"
    fi
@@ -1057,11 +1075,20 @@ if [[ $OSName == 'Darwin' ]] ; then
       echo "The --localkeys option is not supported on OS X! Exiting!"
       exit 1
    fi
+   if [[ $InstallToEspOnMac == 1 ]] ; then
+      TargetDir=/EFI/BOOT
+      TargetX64="bootx64.efi"
+      TargetIA32="bootia32.efi"
+   fi
    InstallOnOSX $1
 elif [[ $OSName == 'Linux' ]] ; then
    InstallOnLinux
 else
    echo "Running on unknown OS; aborting!"
+   if [[ "$InstallToEspOnMac" == 0 ]] ; then
+      echo "The --notesp option is not supported on Linux! Exiting!"
+      exit 1
+   fi
 fi
 
 if [[ $Problems ]] ; then
diff --git a/net/Makefile b/net/Makefile
new file mode 100644 (file)
index 0000000..8be6a61
--- /dev/null
@@ -0,0 +1,24 @@
+IPXE_GIT=git://git.ipxe.org/ipxe.git
+EFI_PREFIX=efi_discovery_prefix.c
+EFI_DISCOVERY_BINARY=ipxe_discovery.efi
+EFI_DISCOVERY_ENTRY=_efi_discovery_start
+IPXE_SRC = ipxe
+
+source:
+       rm -rf $(IPXE_SRC)/
+       git clone $(IPXE_GIT)
+       cp discovery/$(EFI_PREFIX) ipxe/src/arch/x86/prefix/
+       cp discovery/Makefile.housekeeping ipxe/src/Makefile.housekeeping
+netboot:
+       mkdir -p bin
+       cp discovery/console.h ipxe/src/config/local/console.h;\
+       cd ipxe/src;\
+       make bin-x86_64-efi/ipxe.efi TGT_LD_ENTRY=$(EFI_DISCOVERY_ENTRY);\
+       cp bin-x86_64-efi/ipxe.efi ../../bin/$(EFI_DISCOVERY_BINARY);\
+       rm -r bin-x86_64-efi/;\
+       rm config/local/console.h;\
+       make bin-x86_64-efi/ipxe.efi;\
+       cp bin-x86_64-efi/ipxe.efi ../../bin/ipxe.efi;\
+       cd ../../
+clean:
+       rm -r bin/
diff --git a/net/discovery/Makefile.housekeeping b/net/discovery/Makefile.housekeeping
new file mode 100644 (file)
index 0000000..8dad3a1
--- /dev/null
@@ -0,0 +1,1461 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+#
+# This file contains various boring housekeeping functions that would
+# otherwise seriously clutter up the main Makefile.
+
+###############################################################################
+#
+# Find a usable "echo -e" substitute.
+#
+TAB                    := $(shell $(PRINTF) '\t')
+ECHO_E_ECHO            := $(ECHO)
+ECHO_E_ECHO_E          := $(ECHO) -e
+ECHO_E_BIN_ECHO        := /bin/echo
+ECHO_E_BIN_ECHO_E      := /bin/echo -e
+ECHO_E_ECHO_TAB                := $(shell $(ECHO_E_ECHO) '\t' | cat)
+ECHO_E_ECHO_E_TAB      := $(shell $(ECHO_E_ECHO_E) '\t' | cat)
+ECHO_E_BIN_ECHO_TAB    := $(shell $(ECHO_E_BIN_ECHO) '\t')
+ECHO_E_BIN_ECHO_E_TAB  := $(shell $(ECHO_E_BIN_ECHO_E) '\t')
+
+ifeq ($(ECHO_E_ECHO_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_ECHO)
+endif
+ifeq ($(ECHO_E_ECHO_E_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_ECHO_E)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_BIN_ECHO)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_E_TAB),$(TAB))
+ECHO_E         := $(ECHO_E_BIN_ECHO_E)
+endif
+
+.echocheck :
+ifdef ECHO_E
+       @$(TOUCH) $@
+else
+       @$(PRINTF) '%24s : x%sx\n' 'tab' '$(TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO) \t"' \
+                                   '$(ECHO_E_ECHO_TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO_E) \t"' \
+                                   '$(ECHO_E_ECHO_E_TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO) \t"' \
+                                   '$(ECHO_E_BIN_ECHO_TAB)'
+       @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO_E) \t"' \
+                                   '$(ECHO_E_BIN_ECHO_E_TAB)'
+       @$(ECHO) "No usable \"echo -e\" substitute found"
+       @exit 1
+endif
+MAKEDEPS       += .echocheck
+VERYCLEANUP    += .echocheck
+
+echo :
+       @$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\""
+
+###############################################################################
+#
+# Generate a usable "seq" substitute
+#
+define seq
+       $(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }')
+endef
+
+###############################################################################
+#
+# Determine host OS
+#
+HOST_OS                := $(shell uname -s)
+hostos :
+       @$(ECHO) $(HOST_OS)
+
+###############################################################################
+#
+# Determine compiler
+
+CCDEFS         := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2)
+ccdefs:
+       @$(ECHO) $(CCDEFS)
+
+ifeq ($(filter __ICC,$(CCDEFS)),__ICC)
+CCTYPE         := icc
+else
+CCTYPE         := gcc
+endif
+cctype:
+       @$(ECHO) $(CCTYPE)
+
+###############################################################################
+#
+# Check for tools that can cause failed builds
+#
+
+ifeq ($(CCTYPE),gcc)
+GCC_2_96_BANNER := $(shell $(CC) -v 2>&1 | grep -is 'gcc version 2\.96')
+ifneq ($(GCC_2_96_BANNER),)
+$(warning gcc 2.96 is unsuitable for compiling iPXE)
+$(warning Use gcc 2.95 or a newer version instead)
+$(error Unsuitable build environment found)
+endif
+endif
+
+PERL_UNICODE_CHECK := $(shell $(PERL) -e 'use bytes; print chr(255)' | wc -c)
+ifeq ($(PERL_UNICODE_CHECK),2)
+$(warning Your Perl version has a Unicode handling bug)
+$(warning Execute this command before building iPXE:)
+$(warning export LANG=$${LANG%.UTF-8})
+$(error Unsuitable build environment found)
+endif
+
+LD_GOLD_BANNER := $(shell $(LD) -v 2>&1 | grep 'GNU gold')
+ifneq ($(LD_GOLD_BANNER),)
+$(warning GNU gold is unsuitable for building iPXE)
+$(warning Use GNU ld instead)
+$(error Unsuitable build environment found)
+endif
+
+###############################################################################
+#
+# Check if $(eval ...) is available to use
+#
+
+HAVE_EVAL :=
+ifndef NO_EVAL
+$(eval HAVE_EVAL := yes)
+endif
+eval :
+       @$(ECHO) $(HAVE_EVAL)
+
+###############################################################################
+#
+# Check for various tool workarounds
+#
+
+WORKAROUND_CFLAGS :=
+WORKAROUND_ASFLAGS :=
+WORKAROUND_LDFLAGS :=
+
+# Make syntax does not allow use of comma or space in certain places.
+# This ugly workaround is suggested in the manual.
+#
+COMMA  := ,
+EMPTY  :=
+SPACE  := $(EMPTY) $(EMPTY)
+HASH   := \#
+define NEWLINE
+
+
+endef
+
+# Some widespread patched versions of gcc include -fstack-protector by
+# default, even when -ffreestanding is specified.  We therefore need
+# to disable -fstack-protector if the compiler supports it.
+#
+ifeq ($(CCTYPE),gcc)
+SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \
+               -o /dev/null >/dev/null 2>&1
+SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
+WORKAROUND_CFLAGS += $(SP_FLAGS)
+endif
+
+# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
+# default.  Note that gcc will exit *successfully* if it fails to
+# recognise an option that starts with "no", so we have to test for
+# output on stderr instead of checking the exit status.
+#
+ifeq ($(CCTYPE),gcc)
+PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
+PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
+WORKAROUND_CFLAGS += $(PIE_FLAGS)
+endif
+
+# gcc 4.4 generates .eh_frame sections by default, which distort the
+# output of "size".  Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \
+                -fno-asynchronous-unwind-tables -x c -c /dev/null \
+                -o /dev/null >/dev/null 2>&1
+CFI_FLAGS := $(shell $(CFI_TEST) && \
+              $(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \
+                      '-fno-unwind-tables -fno-asynchronous-unwind-tables')
+WORKAROUND_CFLAGS += $(CFI_FLAGS)
+endif
+
+# gcc 4.6 generates spurious warnings if -Waddress is in force.
+# Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+WNA_TEST = $(CC) -Wno-address -x c -c /dev/null -o /dev/null >/dev/null 2>&1
+WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address')
+WORKAROUND_CFLAGS += $(WNA_FLAGS)
+endif
+
+# Some versions of gas choke on division operators, treating them as
+# comment markers.  Specifying --divide will work around this problem,
+# but isn't available on older gas versions.
+#
+DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null
+DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide')
+WORKAROUND_ASFLAGS += $(DIVIDE_FLAGS)
+
+###############################################################################
+#
+# Build verbosity
+#
+ifeq ($(V),1)
+Q :=
+QM := @\#
+else
+Q := @
+QM := @
+endif
+
+###############################################################################
+#
+# Checker
+#
+ifeq ($(C),1)
+export REAL_CC := $(CC)
+CC := cgcc
+CFLAGS += -Wno-decl
+endif
+
+###############################################################################
+#
+# Set BIN according to whatever was specified on the command line as
+# the build target.
+#
+
+# Determine how many different BIN directories are mentioned in the
+# make goals.
+#
+BIN_GOALS      := $(filter bin bin/% bin-%,$(MAKECMDGOALS))
+BIN_GOALS_BINS := $(sort $(foreach BG,$(BIN_GOALS),\
+                                   $(firstword $(subst /, ,$(BG)))))
+NUM_BINS       := $(words $(BIN_GOALS_BINS))
+
+ifeq ($(NUM_BINS),0)
+
+# No BIN directory was specified.  Set BIN to "bin" as a sensible
+# default.
+
+BIN            := bin
+
+else # NUM_BINS == 0
+
+ifeq ($(NUM_BINS),1)
+
+# If exactly one BIN directory was specified, set BIN to match this
+# directory.
+#
+BIN            := $(firstword $(BIN_GOALS_BINS))
+
+else # NUM_BINS == 1
+
+# More than one BIN directory was specified.  We cannot handle the
+# latter case within a single make invocation, so set up recursive
+# targets for each BIN directory.  Use exactly one target for each BIN
+# directory since running multiple make invocations within the same
+# BIN directory is likely to cause problems.
+#
+# Leave $(BIN) undefined.  This has implications for any target that
+# depends on $(BIN); such targets should be made conditional upon the
+# existence of $(BIN).
+#
+BIN_GOALS_FIRST        := $(foreach BGB,$(BIN_GOALS_BINS),\
+                            $(firstword $(filter $(BGB)/%,$(BIN_GOALS))))
+BIN_GOALS_OTHER        := $(filter-out $(BIN_GOALS_FIRST),$(BIN_GOALS))
+
+$(BIN_GOALS_FIRST) : % : BIN_RECURSE
+       $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) \
+           $(filter $(firstword $(subst /, ,$@))/%, $(BIN_GOALS))
+$(BIN_GOALS_OTHER) : % : BIN_RECURSE
+       $(Q)$(TRUE)
+.PHONY : BIN_RECURSE
+
+endif # NUM_BINS == 1
+endif # NUM_BINS == 0
+
+ifdef BIN
+
+# Create $(BIN) directory if it doesn't exist yet
+#
+ifeq ($(wildcard $(BIN)),)
+$(shell $(MKDIR) -p $(BIN))
+endif
+
+# Target to allow e.g. "make bin-efi arch"
+#
+$(BIN) :
+       @# Do nothing, silently
+.PHONY : $(BIN)
+
+# Remove everything in $(BIN) for a "make clean"
+#
+CLEANUP        += $(BIN)/*.* # Avoid picking up directories
+
+endif # defined(BIN)
+
+# Determine whether or not we need to include the dependency files
+#
+NO_DEP_TARGETS := $(BIN) clean veryclean
+ifeq ($(MAKECMDGOALS),)
+NEED_DEPS      := 1
+endif
+ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),)
+NEED_DEPS      := 1
+endif
+
+###############################################################################
+#
+# Select build architecture and platform based on $(BIN)
+#
+# BIN has the form bin[-[arch-]platform]
+
+ARCHS          := $(patsubst arch/%,%,$(wildcard arch/*))
+PLATFORMS      := $(patsubst config/defaults/%.h,%,\
+                    $(wildcard config/defaults/*.h))
+archs :
+       @$(ECHO) $(ARCHS)
+
+platforms :
+       @$(ECHO) $(PLATFORMS)
+
+ifdef BIN
+
+# Determine architecture portion of $(BIN), if present
+BIN_ARCH       := $(strip $(foreach A,$(ARCHS),\
+                            $(patsubst bin-$(A)-%,$(A),\
+                              $(filter bin-$(A)-%,$(BIN)))))
+
+# Determine platform portion of $(BIN), if present
+ifeq ($(BIN_ARCH),)
+BIN_PLATFORM   := $(patsubst bin-%,%,$(filter bin-%,$(BIN)))
+else
+BIN_PLATFORM   := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN))
+endif
+
+# Determine build architecture
+DEFAULT_ARCH   := i386
+ARCH           := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH))
+CFLAGS         += -DARCH=$(ARCH)
+arch :
+       @$(ECHO) $(ARCH)
+.PHONY : arch
+
+# Determine build platform
+DEFAULT_PLATFORM := pcbios
+PLATFORM       := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM))
+CFLAGS         += -DPLATFORM=$(PLATFORM)
+platform :
+       @$(ECHO) $(PLATFORM)
+
+endif # defined(BIN)
+
+# Include architecture-specific Makefile
+ifdef ARCH
+MAKEDEPS       += arch/$(ARCH)/Makefile
+include arch/$(ARCH)/Makefile
+endif
+
+# Include architecture-specific include path
+ifdef ARCH
+INCDIRS                += arch/$(ARCH)/include
+INCDIRS                += arch/$(ARCH)/include/$(PLATFORM)
+endif
+
+###############################################################################
+#
+# Source file handling
+
+# SRCDIRS lists all directories containing source files.
+srcdirs :
+       @$(ECHO) $(SRCDIRS)
+
+# SRCS lists all .c or .S files found in any SRCDIR
+#
+SRCS   += $(wildcard $(patsubst %,%/*.c,$(SRCDIRS)))
+SRCS   += $(wildcard $(patsubst %,%/*.S,$(SRCDIRS)))
+srcs :
+       @$(ECHO) $(SRCS)
+
+# AUTO_SRCS lists all files in SRCS that are not mentioned in
+# NON_AUTO_SRCS.  Files should be added to NON_AUTO_SRCS if they
+# cannot be built using the standard build template.
+#
+AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS))
+autosrcs :
+       @$(ECHO) $(AUTO_SRCS)
+
+# Just about everything else in this section depends upon having
+# $(BIN) set
+
+ifdef BIN
+
+# INCDIRS lists the include path
+incdirs :
+       @$(ECHO) $(INCDIRS)
+
+# Common flags
+#
+CFLAGS         += $(foreach INC,$(INCDIRS),-I$(INC))
+CFLAGS         += -Os
+CFLAGS         += -g
+ifeq ($(CCTYPE),gcc)
+CFLAGS         += -ffreestanding
+CFLAGS         += -Wall -W -Wformat-nonliteral
+HOST_CFLAGS    += -Wall -W -Wformat-nonliteral
+endif
+ifeq ($(CCTYPE),icc)
+CFLAGS         += -fno-builtin
+CFLAGS         += -no-ip
+CFLAGS         += -no-gcc
+CFLAGS         += -diag-disable 111 # Unreachable code
+CFLAGS         += -diag-disable 128 # Unreachable loop
+CFLAGS         += -diag-disable 170 # Array boundary checks
+CFLAGS         += -diag-disable 177 # Unused functions
+CFLAGS         += -diag-disable 181 # printf() format checks
+CFLAGS         += -diag-disable 188 # enum strictness
+CFLAGS         += -diag-disable 193 # Undefined preprocessor identifiers
+CFLAGS         += -diag-disable 280 # switch ( constant )
+CFLAGS         += -diag-disable 310 # K&R parameter lists
+CFLAGS         += -diag-disable 424 # Extra semicolon
+CFLAGS         += -diag-disable 589 # Declarations mid-code
+CFLAGS         += -diag-disable 593 # Unused variables
+CFLAGS         += -diag-disable 810 # Casting ints to smaller ints
+CFLAGS         += -diag-disable 981 # Sequence point violations
+CFLAGS         += -diag-disable 1292 # Ignored attributes
+CFLAGS         += -diag-disable 1338 # void pointer arithmetic
+CFLAGS         += -diag-disable 1361 # Variable-length arrays
+CFLAGS         += -diag-disable 1418 # Missing prototypes
+CFLAGS         += -diag-disable 1419 # Missing prototypes
+CFLAGS         += -diag-disable 1599 # Hidden variables
+CFLAGS         += -Wall -Wmissing-declarations
+endif
+CFLAGS         += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
+ASFLAGS                += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
+LDFLAGS                += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
+HOST_CFLAGS    += -O2 -g
+
+# Inhibit -Werror if NO_WERROR is specified on make command line
+#
+ifneq ($(NO_WERROR),1)
+CFLAGS         += -Werror
+ASFLAGS                += --fatal-warnings
+HOST_CFLAGS    += -Werror
+endif
+
+# Function trace recorder state in the last build.  This is needed
+# in order to correctly rebuild whenever the function recorder is
+# enabled/disabled.
+#
+FNREC_STATE    := $(BIN)/.fnrec.state
+ifeq ($(wildcard $(FNREC_STATE)),)
+FNREC_OLD      := <invalid>
+else
+FNREC_OLD      := $(shell cat $(FNREC_STATE))
+endif
+ifeq ($(FNREC_OLD),$(FNREC))
+$(FNREC_STATE) :
+else
+$(FNREC_STATE) : clean
+$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE))
+endif
+
+VERYCLEANUP    += $(FNREC_STATE)
+MAKEDEPS       += $(FNREC_STATE)
+
+ifeq ($(FNREC),1)
+# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
+# warnings about use of uninitialised variables.
+#
+CFLAGS         += -Wno-uninitialized
+CFLAGS         += -finstrument-functions
+CFLAGS         += -finstrument-functions-exclude-file-list=core/fnrec.c
+endif
+
+# Enable per-item sections and section garbage collection.  Note that
+# some older versions of gcc support -fdata-sections but treat it as
+# implying -fno-common, which would break our build.  Some other older
+# versions issue a spurious and uninhibitable warning if
+# -ffunction-sections is used with -g, which would also break our
+# build since we use -Werror.
+#
+ifeq ($(CCTYPE),gcc)
+DS_TEST                = $(ECHO) 'char x;' | \
+                 $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \
+                 grep -E '\.comm' > /dev/null
+DS_FLAGS       := $(shell $(DS_TEST) && $(ECHO) '-fdata-sections')
+FS_TEST                = $(CC) -ffunction-sections -g -c -x c /dev/null \
+                 -o /dev/null 2>/dev/null
+FS_FLAGS       := $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections')
+CFLAGS         += $(FS_FLAGS) $(DS_FLAGS)
+endif
+LDFLAGS                += --gc-sections
+
+# Force creation of static binaries (required for OpenBSD, does no
+# harm on other platforms).
+#
+LDFLAGS                += -static
+
+# compiler.h is needed for our linking and debugging system
+#
+CFLAGS         += -include include/compiler.h
+
+# CFLAGS for specific object types
+#
+CFLAGS_c       +=
+CFLAGS_S       += -DASSEMBLY
+
+# Base object name of the current target
+#
+OBJECT         = $(firstword $(subst ., ,$(@F)))
+
+# CFLAGS for specific object files.  You can define
+# e.g. CFLAGS_rtl8139, and have those flags automatically used when
+# compiling bin/rtl8139.o.
+#
+OBJ_CFLAGS     = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
+$(BIN)/%.flags :
+       @$(ECHO) $(OBJ_CFLAGS)
+
+# ICC requires postprocessing objects to fix up table alignments
+#
+ifeq ($(CCTYPE),icc)
+POST_O         = && $(ICCFIX) $@
+POST_O_DEPS    := $(ICCFIX)
+else
+POST_O         :=
+POST_O_DEPS    :=
+endif
+
+# Rules for specific object types.
+#
+COMPILE_c      = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
+RULE_c         = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
+RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O)
+RULE_c_to_c    = $(Q)$(COMPILE_c) -E -c $< > $@
+RULE_c_to_s    = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
+
+PREPROCESS_S   = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
+ASSEMBLE_S     = $(AS) $(ASFLAGS)
+RULE_S         = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_s    = $(Q)$(PREPROCESS_S) $< > $@
+
+DEBUG_TARGETS  += dbg%.o c s
+
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBED          := $(EMBEDDED_IMAGE) # Maintain backwards compatibility
+EMBEDDED_LIST  := $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBED_OLD := <invalid>
+else
+EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBED_OLD),$(EMBED))
+$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP    += $(EMBEDDED_LIST)
+
+EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED))
+EMBED_ALL      := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
+                    EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+                            \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
+
+embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
+
+# List of trusted root certificates
+#
+TRUSTED_LIST   := $(BIN)/.trusted.list
+ifeq ($(wildcard $(TRUSTED_LIST)),)
+TRUST_OLD := <invalid>
+else
+TRUST_OLD := $(shell cat $(TRUSTED_LIST))
+endif
+ifneq ($(TRUST_OLD),$(TRUST))
+$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST))
+endif
+
+$(TRUSTED_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP    += $(TRUSTED_LIST)
+
+# Trusted root certificate fingerprints
+#
+TRUSTED_CERTS  := $(subst $(COMMA), ,$(TRUST))
+TRUSTED_FPS    := $(foreach CERT,$(TRUSTED_CERTS),\
+                    0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\
+                        $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \
+                                -fingerprint))))$(COMMA))
+
+rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
+
+CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
+
+# List of embedded certificates
+#
+CERT_LIST := $(BIN)/.certificate.list
+ifeq ($(wildcard $(CERT_LIST)),)
+CERT_OLD := <invalid>
+else
+CERT_OLD := $(shell cat $(CERT_LIST))
+endif
+ifneq ($(CERT_OLD),$(CERT))
+$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
+endif
+
+$(CERT_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(CERT_LIST)
+
+# Embedded certificates concatenated and then split into one file per
+# certificate (even if original files contained certificate chains)
+#
+CERT_FILES := $(subst $(COMMA), ,$(CERT))
+CERT_CONCAT := $(BIN)/.certificates.pem
+
+ifneq ($(CERT),)
+
+CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l)
+
+$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST)
+       $(Q)cat $(CERT_FILES) > $@
+
+# We must use an (otherwise unnecessary) pattern rule here to encode
+# the fact that one "csplit" command generates multiple targets
+CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
+              $(BIN)/.certificate.pem.$(i))
+$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.%
+       $(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \
+               '/BEGIN CERTIFICATE/' '{*}'
+
+CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS))
+$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.%
+       $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
+
+CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
+             CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" ))
+
+endif
+
+certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS)
+
+CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)"
+
+CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.*
+
+# (Single-element) list of private keys
+#
+ifdef KEY
+PRIVKEY        := $(KEY) # Maintain backwards compatibility
+endif
+PRIVKEY_LIST := $(BIN)/.private_key.list
+ifeq ($(wildcard $(PRIVKEY_LIST)),)
+PRIVKEY_OLD := <invalid>
+else
+PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST))
+endif
+ifneq ($(PRIVKEY_OLD),$(PRIVKEY))
+$(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST))
+endif
+
+$(PRIVKEY_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(PRIVKEY_LIST)
+
+# Embedded private key
+#
+PRIVKEY_INC := $(BIN)/.private_key.der
+
+ifdef PRIVKEY
+$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
+       $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
+
+privkey_DEPS += $(PRIVKEY_INC)
+endif
+
+CLEANUP += $(BIN)/.private_key.*
+
+privkey_DEPS += $(PRIVKEY_LIST)
+
+CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
+
+# (Single-element) list of named configurations
+#
+CONFIG_LIST := $(BIN)/.config.list
+ifeq ($(wildcard $(CONFIG_LIST)),)
+CONFIG_OLD := <invalid>
+else
+CONFIG_OLD := $(shell cat $(CONFIG_LIST))
+endif
+ifneq ($(CONFIG_OLD),$(CONFIG))
+$(shell $(ECHO) "$(CONFIG)" > $(CONFIG_LIST))
+endif
+
+$(CONFIG_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(CONFIG_LIST)
+
+# Named configurations
+#
+ifneq ($(CONFIG),)
+ifneq ($(wildcard config/$(CONFIG)),)
+CFLAGS += -DCONFIG=$(CONFIG)
+endif
+CFLAGS += -DLOCAL_CONFIG=$(CONFIG)
+endif
+
+config/named.h : $(CONFIG_LIST)
+       $(Q)$(TOUCH) $@
+
+.PRECIOUS : config/named.h
+
+# These files use .incbin inline assembly to include a binary file.
+# Unfortunately ccache does not detect this dependency and caches
+# builds even when the binary file has changed.
+#
+$(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC)
+$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC)
+$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC)
+
+# Debug message autocolourisation range
+#
+DBGCOL_LIST    := $(BIN)/.dbgcol.list
+ifeq ($(wildcard $(DBGCOL_LIST)),)
+DBGCOL_OLD := <invalid>
+else
+DBGCOL_OLD := $(shell cat $(DBGCOL_LIST))
+endif
+ifneq ($(DBGCOL_OLD),$(DBGCOL))
+$(shell $(ECHO) "$(DBGCOL)" > $(DBGCOL_LIST))
+endif
+
+$(DBGCOL_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(DBGCOL_LIST)
+
+DBGCOL_COLOURS := $(subst -, ,$(DBGCOL))
+DBGCOL_MIN := $(word 1,$(DBGCOL_COLOURS))
+DBGCOL_MAX := $(word 2,$(DBGCOL_COLOURS))
+
+debug_DEPS += $(DBGCOL_LIST)
+
+CFLAGS_debug += $(if $(DBGCOL_MIN),-DDBGCOL_MIN=$(DBGCOL_MIN))
+CFLAGS_debug += $(if $(DBGCOL_MAX),-DDBGCOL_MAX=$(DBGCOL_MAX))
+
+# We automatically generate rules for any file mentioned in AUTO_SRCS
+# using the following set of templates.  We use $(eval ...) if
+# available, otherwise we generate separate Makefile fragments and
+# include them.
+
+# deps_template : generate dependency list for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define deps_template_file
+$(call deps_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1))))
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define deps_template_parts
+       @$(ECHO) "  [DEPS] $(1)"
+       @$(MKDIR) -p $(BIN)/deps/$(dir $(1))
+       $(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
+               -Wno-error -M $(1) -MG -MP | \
+               sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
+       $(Q)$(if $(findstring drivers/,$(1)),\
+          $(PERL) $(PARSEROM) $(1) >> $(BIN)/deps/$(1).d)
+endef
+
+# rules_template : generate rules for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define rules_template
+$(call rules_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1))))
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define rules_template_parts
+$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
+       $$(QM)$(ECHO) "  [BUILD] $$@"
+       $$(RULE_$(2))
+BOBJS += $$(BIN)/$(3).o
+$(foreach TGT,$(DEBUG_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT))))
+$$(BIN)/deps/$(1).d : $$($(3)_DEPS)
+TAGS : $$($(3)_DEPS)
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+# $(4) is the destination type (e.g. "dbg%.o")
+#
+define rules_template_target
+$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
+       $$(QM)$(ECHO) "  [BUILD] $$@"
+       $$(RULE_$(2)_to_$(4))
+$(TGT)_OBJS += $$(BIN)/$(3).$(4)
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define rules_template_file
+       @$(ECHO) "  [RULES] $(1)"
+       @$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+       @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call rules_template,$(1)))' \
+                > $(BIN)/rules/$(1).r
+endef
+
+# Generate the dependency files
+#
+$(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM)
+       $(call deps_template_file,$<)
+
+# Calculate list of dependency files
+#
+AUTO_DEPS      = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
+autodeps :
+       @$(ECHO) $(AUTO_DEPS)
+VERYCLEANUP    += $(BIN)/deps
+
+# Include dependency files
+#
+ifdef NEED_DEPS
+ifneq ($(AUTO_DEPS),)
+-include $(AUTO_DEPS)
+endif
+endif
+
+# Generate the rules files
+#
+$(BIN)/rules/%.r : % $(MAKEDEPS)
+       $(call rules_template_file,$<)
+
+# Calculate list of rules files
+#
+AUTO_RULES     = $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS))
+autorules :
+       @$(ECHO) $(AUTO_RULES)
+VERYCLEANUP    += $(BIN)/rules
+
+# Evaluate rules (or include rules files)
+#
+ifdef NEED_DEPS
+ifneq ($(AUTO_RULES),)
+ifneq ($(HAVE_EVAL),)
+$(foreach SRC,$(AUTO_SRCS),$(eval $(call rules_template,$(SRC))))
+else
+-include $(AUTO_RULES)
+endif
+endif
+endif
+
+# The following variables are created by the rules files
+#
+bobjs :
+       @$(ECHO) $(BOBJS)
+drivers :
+       @$(ECHO) $(DRIVERS)
+.PHONY : drivers
+roms :
+       @$(ECHO) $(ROMS)
+
+# Generate error usage information
+#
+$(BIN)/%.einfo : $(BIN)/%.o
+       $(QM)$(ECHO) "  [EINFO] $@"
+       $(Q)$(OBJCOPY) -O binary -j .einfo --set-section-flags .einfo=alloc \
+               $< $@
+
+EINFOS         := $(patsubst $(BIN)/%.o,$(BIN)/%.einfo,$(BOBJS))
+$(BIN)/errors : $(EINFOS) $(EINFO)
+       $(QM)$(ECHO) "  [EINFO] $@"
+       $(Q)$(EINFO) $(EINFOS) | sort > $@
+CLEANUP                += $(BIN)/errors        # Doesn't match the $(BIN)/*.* pattern
+
+# Generate the NIC file from the parsed source files.  The NIC file is
+# only for rom-o-matic.
+#
+$(BIN)/NIC : $(AUTO_DEPS)
+       @$(ECHO) '# This is an automatically generated file, do not edit' > $@
+       @$(ECHO) '# It does not affect anything in the build, ' \
+            'it is only for rom-o-matic' >> $@
+       @$(ECHO) >> $@
+       @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
+CLEANUP                += $(BIN)/NIC   # Doesn't match the $(BIN)/*.* pattern
+
+# Analyse a target name (e.g. "bin/dfe538--prism2_pci.rom.tmp") and
+# derive the variables:
+# 
+# TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci")
+# TGT_PREFIX   : the prefix type (e.g. "pcirom")
+# TGT_DRIVERS  : the driver for each element (e.g. "rtl8139 prism2_pci")
+# TGT_ROM_NAME : the ROM name (e.g. "dfe538")
+#
+DRIVERS_ipxe   = $(DRIVERS)
+CARD_DRIVER    = $(firstword $(DRIVER_$(1)) $(1))
+TGT_ELEMENTS   = $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
+TGT_ROM_NAME   = $(firstword $(TGT_ELEMENTS))
+TGT_DRIVERS    = $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \
+                              $(DRIVERS_$(TGT_ROM_NAME)), \
+                              $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \
+                                $(call CARD_DRIVER,$(TGT_ELEMENT))) ))
+TGT_PREFIX_NAME        = $(word 2,$(subst ., ,$(notdir $@)))
+TGT_PREFIX     = $(strip $(if $(filter rom,$(TGT_PREFIX_NAME)), \
+                              $(ROM_TYPE_$(TGT_ROM_NAME))rom, \
+                              $(TGT_PREFIX_NAME)))
+
+# Look up ROM IDs for the current target
+# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables:
+#
+# TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186")
+# TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300")
+#
+TGT_PCI_VENDOR = $(PCI_VENDOR_$(TGT_ROM_NAME))
+TGT_PCI_DEVICE = $(PCI_DEVICE_$(TGT_ROM_NAME))
+
+# Calculate link-time options for the current target
+# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables:
+#
+# TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers
+#                 (e.g. "obj_rtl8139 obj_prism2_pci")
+# TGT_LD_IDS :     symbols to define in order to fill in ID structures in the
+#                 ROM header (e.g."pci_vendor_id=0x1186 pci_device_id=0x1300")
+#
+TGT_LD_DRIVERS = $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS)))
+TGT_LD_IDS     = pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \
+                 pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0)
+
+ifndef TGT_LD_ENTRY
+TGT_LD_ENTRY   = _$(TGT_PREFIX)_start
+endif
+
+# Calculate linker flags based on link-time options for the current
+# target type (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the
+# variables:
+#
+# TGT_LD_FLAGS : target-specific flags to pass to linker (e.g.
+#               "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci
+#                --defsym pci_vendor=0x1186 --defsym pci_device=0x1300")
+#
+TGT_LD_FLAGS   = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) obj_config,\
+                   -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \
+                 $(patsubst %,--defsym %,$(TGT_LD_IDS)) \
+                 -e $(TGT_LD_ENTRY)
+
+# Calculate list of debugging versions of objects to be included in
+# the target.
+#
+DEBUG_LIST     = $(subst $(COMMA), ,$(DEBUG))
+DEBUG_OBJ_LEVEL        = $(firstword $(word 2,$(subst :, ,$(1))) 1)
+DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1))
+DEBUG_OBJ      = $(BIN)/$(call DEBUG_OBJ_BASE,$(1)).o
+DEBUG_ORIG_OBJ = $(BIN)/$(word 1,$(subst :, ,$(1))).o
+DEBUG_OBJS     = $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D)))
+DEBUG_ORIG_OBJS        = $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D)))
+BLIB_OBJS      = $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS))
+
+# Print out all derived information for a given target.
+#
+$(BIN)/%.info :
+       @$(ECHO) 'Elements             : $(TGT_ELEMENTS)'
+       @$(ECHO) 'Prefix               : $(TGT_PREFIX)'
+       @$(ECHO) 'Drivers              : $(TGT_DRIVERS)'
+       @$(ECHO) 'ROM name             : $(TGT_ROM_NAME)'
+       @$(ECHO)
+       @$(ECHO) 'PCI vendor           : $(TGT_PCI_VENDOR)'
+       @$(ECHO) 'PCI device           : $(TGT_PCI_DEVICE)'
+       @$(ECHO)
+       @$(ECHO) 'LD driver symbols    : $(TGT_LD_DRIVERS)'
+       @$(ECHO) 'LD ID symbols        : $(TGT_LD_IDS)'
+       @$(ECHO) 'LD entry point       : $(TGT_LD_ENTRY)'
+       @$(ECHO)
+       @$(ECHO) 'LD target flags      : $(TGT_LD_FLAGS)'
+       @$(ECHO)
+       @$(ECHO) 'Debugging objects    : $(DEBUG_OBJS)'
+       @$(ECHO) 'Replaced objects     : $(DEBUG_ORIG_OBJS)'
+
+# List of objects included in the last build of blib.  This is needed
+# in order to correctly rebuild blib whenever the list of objects
+# changes.
+#
+BLIB_LIST      := $(BIN)/.blib.list
+ifeq ($(wildcard $(BLIB_LIST)),)
+BLIB_OBJS_OLD  := <invalid>
+else
+BLIB_OBJS_OLD  := $(shell cat $(BLIB_LIST))
+endif
+ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS))
+$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST))
+endif
+
+$(BLIB_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP    += $(BLIB_LIST)
+
+# Library of all objects
+#
+BLIB           = $(BIN)/blib.a
+$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
+       $(Q)$(RM) $(BLIB)
+       $(QM)$(ECHO) "  [AR] $@"
+       $(Q)$(AR) r $@ $(BLIB_OBJS)
+       $(Q)$(RANLIB) $@
+blib : $(BLIB)
+
+# Command to generate build ID.  Must be unique for each $(BIN)/%.tmp,
+# even within the same build run.
+#
+BUILD_ID_CMD   := perl -e 'printf "0x%08x", int ( rand ( 0xffffffff ) );'
+
+# Build timestamp
+#
+BUILD_TIMESTAMP := $(shell date +%s)
+
+# Build version
+#
+GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
+$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
+       $(QM)$(ECHO) "  [VERSION] $@"
+       $(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
+               -DVERSION_MAJOR=$(VERSION_MAJOR) \
+               -DVERSION_MINOR=$(VERSION_MINOR) \
+               -DVERSION_PATCH=$(VERSION_PATCH) \
+               -DVERSION="\"$(VERSION)\"" \
+               -c $< -o $@
+
+# Build an intermediate object file from the objects required for the
+# specified target.
+#
+$(BIN)/%.tmp : $(BIN)/version.%.o $(BLIB) $(MAKEDEPS) $(LDSCRIPT)
+       $(QM)$(ECHO) "  [LD] $@"
+       $(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $< $(BLIB) -o $@ \
+               --defsym _build_id=`$(BUILD_ID_CMD)` \
+               --defsym _build_timestamp=$(BUILD_TIMESTAMP) \
+               -Map $(BIN)/$*.tmp.map
+       $(Q)$(OBJDUMP) -ht $@ | $(PERL) $(SORTOBJDUMP) >> $(BIN)/$*.tmp.map
+
+# Keep intermediate object file (useful for debugging)
+.PRECIOUS : $(BIN)/%.tmp
+
+# Show a linker map for the specified target
+#
+$(BIN)/%.map : $(BIN)/%.tmp
+       @less $(BIN)/$*.tmp.map
+
+# Get objects list for the specified target
+#
+define objs_list
+       $(sort $(foreach OBJ_SYMBOL,\
+                $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+                $(patsubst obj_%,%,$(OBJ_SYMBOL))))
+endef
+$(BIN)/%.objs : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call objs_list,$<)
+$(BIN)/%.sizes : $(BIN)/%.tmp
+       $(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \
+               sort -g
+
+# Get dependency list for the specified target
+#
+define deps_list
+       $(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS)))
+endef
+$(BIN)/%.deps : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call deps_list,$<)
+
+# Get unneeded source files for the specified target
+#
+define nodeps_list
+       $(sort $(filter-out $(call deps_list,$(1)),\
+                $(foreach BOBJ,$(BOBJS),\
+                  $($(basename $(notdir $(BOBJ)))_DEPS))))
+endef
+$(BIN)/%.nodeps : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call nodeps_list,$<)
+
+# Get licensing verdict for the specified target
+#
+define licensable_deps_list
+       $(filter-out config/local/%.h,\
+         $(filter-out $(BIN)/.%.list,\
+           $(call deps_list,$(1))))
+endef
+define unlicensed_deps_list
+       $(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1)))
+endef
+define licence_list
+       $(sort $(foreach LICENCE,\
+                $(filter __licence__%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+                $(word 2,$(subst __, ,$(LICENCE)))))
+endef
+$(BIN)/%.licence_list : $(BIN)/%.tmp
+       $(Q)$(ECHO) $(call licence_list,$<)
+$(BIN)/%.licence : $(BIN)/%.tmp
+       $(QM)$(ECHO) "  [LICENCE] $@"
+       $(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\
+               echo -n "Unable to determine licence because the following " ;\
+               echo "files are missing a licence declaration:" ;\
+               echo $(call unlicensed_deps_list,$<);\
+               exit 1,\
+               $(PERL) $(LICENCE) $(call licence_list,$<))
+
+# Extract compression information from intermediate object file
+#
+$(BIN)/%.zinfo : $(BIN)/%.tmp
+       $(QM)$(ECHO) "  [ZINFO] $@"
+       $(Q)$(OBJCOPY) -O binary -j .zinfo $< $@
+
+# Build raw binary file from intermediate object file
+#
+$(BIN)/%.bin : $(BIN)/%.tmp
+       $(QM)$(ECHO) "  [BIN] $@"
+       $(Q)$(OBJCOPY) -O binary -R .zinfo $< $@
+
+# Compress raw binary file
+#
+$(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
+       $(QM)$(ECHO) "  [ZBIN] $@"
+       $(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
+
+# Rules for each media format.  These are generated and placed in an
+# external Makefile fragment.  We could do this via $(eval ...), but
+# that would require make >= 3.80.
+# 
+# Note that there's an alternative way to generate most .rom images:
+# they can be copied from their 'master' ROM image using cp and
+# reprocessed with makerom to add the PCI IDs and ident string.  The
+# relevant rule would look something like:
+#
+#   $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom
+#      cat $< $@
+#      $(FINALISE_rom)
+# 
+# You can derive the ROM/driver relationships using the variables
+# DRIVER_<rom> and/or ROMS_<driver>.
+# 
+# We don't currently do this, because (a) it would require generating
+# yet more Makefile fragments (since you need a rule for each ROM in
+# ROMS), and (b) the linker is so fast that it probably wouldn't make
+# much difference to the overall build time.
+
+# Add NON_AUTO_MEDIA to the media list, so that they show up in the
+# output of "make"
+#
+MEDIA          += $(NON_AUTO_MEDIA)
+
+media :
+       @$(ECHO) $(MEDIA)
+
+AUTO_MEDIA     = $(filter-out $(NON_AUTO_MEDIA),$(MEDIA))
+automedia :
+       @$(ECHO) $(AUTO_MEDIA)
+
+# media_template : create media rules
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template
+$(if $(filter $(1),$(AUTO_MEDIA)),$(call auto_media_template,$(1)))
+LIST_$(1) := $$(if $$(LIST_NAME_$(1)),$$($$(LIST_NAME_$(1))),$$(DRIVERS))
+ALL_$(1) = $$(foreach ITEM,$$(LIST_$(1)),$$(BIN)/$$(ITEM).$(1))
+$$(BIN)/all$(1)s : $$(ALL_$(1))
+$$(BIN)/allall : $$(BIN)/all$(1)s
+all$(1)s : $$(BIN)/all$(1)s
+allall : $$(BIN)/allall
+endef
+#
+# $(1) is the media name (e.g. "rom")
+#
+define auto_media_template
+$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin
+       $$(QM)echo "  [FINISH] $$@"
+       $$(Q)$$(CP) $$< $$@
+       $$(Q)$$(if $$(PAD_$(1)),$$(PAD_$(1)) $$@)
+       $$(Q)$$(if $$(FINALISE_$(1)),$$(FINALISE_$(1)) $$@)
+endef
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template_file
+       @$(ECHO) "  [MEDIARULES] $(1)"
+       @$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+       @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call media_template,$(1)))' \
+               > $(BIN)/rules/$(1).media.r
+endef
+
+# Generate media rules files
+#
+$(BIN)/rules/%.media.r : $(MAKEDEPS)
+       $(call media_template_file,$*)
+
+# Calculate list of media rules files
+#
+MEDIA_RULES            = $(patsubst %,$(BIN)/rules/%.media.r,$(MEDIA))
+mediarules :
+       @$(ECHO) $(MEDIA_RULES)
+
+# Evaluate media rules (or include media rules files)
+#
+ifdef NEED_DEPS
+ifneq ($(MEDIA_RULES),)
+ifneq ($(HAVE_EVAL),)
+$(foreach MEDIUM,$(MEDIA),$(eval $(call media_template,$(MEDIUM))))
+else
+-include $(MEDIA_RULES)
+endif
+endif
+endif
+
+# Alias for ipxe.%
+#
+$(BIN)/etherboot.% : $(BIN)/ipxe.%
+       ln -sf $(notdir $<) $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# The compression utilities
+#
+$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \
+                      -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
+CLEANUP        += $(NRV2B)
+
+$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $<
+CLEANUP += $(ZBIN)
+
+###############################################################################
+#
+# The EFI image converter
+#
+ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
+                  -I$(ZLIB_DIR)/include -idirafter include
+ELF2EFI_LDFLAGS        := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
+                  -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch
+
+$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \
+               $(ELF2EFI_LDFLAGS) -o $@
+CLEANUP += $(ELF2EFI32)
+
+$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \
+               $(ELF2EFI_LDFLAGS) -o $@
+CLEANUP += $(ELF2EFI64)
+
+$(EFIROM) : util/efirom.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EFIROM)
+
+$(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EFIFATBIN)
+
+###############################################################################
+#
+# The ICC fixup utility
+#
+$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(ICCFIX)
+
+###############################################################################
+#
+# The error usage information utility
+#
+$(EINFO) : util/einfo.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EINFO)
+
+###############################################################################
+#
+# Local configs
+#
+CONFIG_HEADERS := $(patsubst config/%,%,$(wildcard config/*.h))
+CONFIG_LOCAL_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\
+                                 config/local/$(HEADER))
+
+$(CONFIG_LOCAL_HEADERS) :
+       $(Q)$(TOUCH) $@
+
+.PRECIOUS : $(CONFIG_LOCAL_HEADERS)
+
+ifneq ($(CONFIG),)
+
+CONFIG_LOCAL_NAMED_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\
+                                       config/local/$(CONFIG)/$(HEADER))
+
+$(CONFIG_LOCAL_NAMED_HEADERS) :
+       $(Q)$(MKDIR) -p $(dir $@)
+       $(Q)$(TOUCH) $@
+
+.PRECIOUS : $(CONFIG_LOCAL_NAMED_HEADERS)
+
+endif
+
+###############################################################################
+#
+# Auto-incrementing build serial number.  Append "bs" to your list of
+# build targets to get a serial number printed at the end of the
+# build.  Enable -DBUILD_SERIAL in order to see it when the code runs.
+#
+BUILDSERIAL_H          = config/.buildserial.h
+BUILDSERIAL_NOW                = config/.buildserial.now
+BUILDSERIAL_NEXT       = config/.buildserial.next
+
+$(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) :
+       $(ECHO) 1 > $@
+
+$(BUILDSERIAL_H) : $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT)
+       $(ECHO) '#define BUILD_SERIAL_NUM $(shell cat $<)' > $@
+
+ifeq ($(filter bs,$(MAKECMDGOALS)),bs)
+$(shell diff -q $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) > /dev/null || \
+       cp -f $(BUILDSERIAL_NEXT) $(BUILDSERIAL_NOW))
+endif
+
+bs : $(BUILDSERIAL_NOW)
+       @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT)
+       @$(ECHO) "Build serial number is $(shell cat $<)"
+
+###############################################################################
+#
+# Build the TAGS file(s) for emacs
+#
+TAGS :
+       ctags -e -R -f $@ --exclude=bin
+
+CLEANUP        += TAGS
+
+###############################################################################
+#
+# Force rebuild for any given target
+#
+%.rebuild :
+       rm -f $*
+       $(Q)$(MAKE) $*
+
+###############################################################################
+#
+# Symbol table checks
+#
+
+ifdef BIN
+
+SYMTAB = $(BIN)/symtab
+$(SYMTAB) : $(BLIB)
+       $(OBJDUMP) -w -t $< > $@
+
+CLEANUP        += $(BIN)/symtab
+
+symcheck : $(SYMTAB)
+       $(PERL) $(SYMCHECK) $<
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Build bochs symbol table
+#
+
+ifdef BIN
+
+$(BIN)/%.bxs : $(BIN)/%.tmp
+       $(NM) $< | cut -d" " -f1,3 > $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Documentation
+#
+
+ifdef BIN
+
+$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
+       $(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
+               -e  's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \
+               -e  's{\@BIN\@}{$(BIN)}; ' \
+               -e  's{\@ARCH\@}{$(ARCH)}; ' \
+               $< > $@
+
+$(BIN)/doc : $(BIN)/doxygen.cfg
+       $(Q)$(DOXYGEN) $<
+
+.PHONY : $(BIN)/doc
+
+doc : $(BIN)/doc
+
+doc-clean :
+       $(Q)$(RM) -r $(BIN)/doc
+
+VERYCLEANUP    += $(BIN)/doc
+
+docview :
+       @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc
+       @if [ -n "$$BROWSER" ] ; then \
+               ( $$BROWSER $(BIN)/doc/html/index.html & ) ; \
+       else \
+               $(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \
+       fi
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Keyboard maps
+#
+
+hci/keymap/keymap_%.c :
+       $(Q)$(PERL) $(GENKEYMAP) $* > $@
+
+###############################################################################
+#
+# Force deletion of incomplete targets
+#
+
+.DELETE_ON_ERROR :
+
+###############################################################################
+#
+# Clean-up
+#
+
+ifeq ($(NUM_BINS),0)
+ALLBINS                := bin{,-*}
+CLEANUP                := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(CLEANUP))
+VERYCLEANUP    := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(VERYCLEANUP))
+endif
+
+clean :
+       $(RM) $(CLEANUP)
+
+veryclean : clean
+       $(RM) -r $(VERYCLEANUP)
diff --git a/net/discovery/console.h b/net/discovery/console.h
new file mode 100644 (file)
index 0000000..426ac93
--- /dev/null
@@ -0,0 +1 @@
+#undef CONSOLE_EFI
diff --git a/net/discovery/efi_discovery_prefix.c b/net/discovery/efi_discovery_prefix.c
new file mode 100644 (file)
index 0000000..c799072
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_snp.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/uri.h>
+#include <ipxe/init.h>
+#include <usr/ifmgmt.h>
+#include <usr/route.h>
+#include <usr/autoboot.h>
+
+#define MAX_EXIT_BUFFER_SIZE 256
+
+/**
+ * Close all open net devices
+ *
+ * Called before a fresh boot attempt in order to free up memory.  We
+ * don't just close the device immediately after the boot fails,
+ * because there may still be TCP connections in the process of
+ * closing.
+ */
+static void close_all_netdevs ( void ) {
+       struct net_device *netdev;
+
+       for_each_netdev ( netdev ) {
+               ifclose ( netdev );
+       }
+}
+
+static struct uri* try_getting_next_server ( struct net_device *netdev ) {
+       struct uri *filename;
+
+       /* Close all other network devices */
+       close_all_netdevs();
+
+       /* Open device and display device status */
+       if ( ifopen ( netdev ) != 0 )
+               goto err_ifopen;
+       ifstat ( netdev );
+
+       /* Configure device */
+       if (ifconf ( netdev, NULL )!= 0 )
+               goto err_dhcp;
+       route();
+
+  /* Fetch next server and filename */
+       filename = fetch_next_server_and_filename ( NULL );
+       if ( ! filename )
+               goto err_filename;
+       if ( ! uri_has_path ( filename ) ) {
+               /* Ignore empty filename */
+               uri_put ( filename );
+               filename = NULL;
+       }
+       return filename;
+  err_filename:
+  err_dhcp:
+  err_ifopen:
+    return NULL;
+}
+
+
+static struct uri* efi_discover ( void ) {
+       struct net_device *netdev;
+  
+  struct uri* filename = NULL;
+
+       for_each_netdev ( netdev ) {
+               filename = try_getting_next_server ( netdev );
+       }
+
+       return filename;
+}
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle     Image handle
+ * @v systab           System table
+ * @ret efirc          EFI return status code
+ */
+EFI_STATUS EFIAPI _efi_discovery_start ( EFI_HANDLE image_handle,
+                              EFI_SYSTEM_TABLE *systab ) {
+       EFI_STATUS efirc;
+  struct uri* filename;
+  userptr_t user_buf;
+  wchar_t* exit_buf;
+
+       /* Initialise EFI environment */
+       if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+               goto err_init;
+
+  if ( ( user_buf = umalloc(MAX_EXIT_BUFFER_SIZE*2) ) == 0)
+  {
+     efirc = EFI_OUT_OF_RESOURCES;
+     goto err_init;
+  }
+  
+  exit_buf = (wchar_t *)user_to_phys(user_buf,0);
+
+  initialise();
+  startup();
+
+  if ( ( filename = efi_discover() ) == NULL)
+  {
+     efirc = EFI_NOT_FOUND;
+     goto err_filename;
+  }
+  
+       efi_snp_release();
+       efi_loaded_image->Unload ( image_handle );
+       efi_driver_reconnect_all();
+  efi_snprintf(exit_buf,MAX_EXIT_BUFFER_SIZE,"%s - %s", filename->host, filename->path);
+  uri_put(filename);
+
+  systab->BootServices->Exit(image_handle, efirc, MAX_EXIT_BUFFER_SIZE, (CHAR16 *) exit_buf);
+
+ err_filename:
+ err_init:
+       systab->BootServices->Exit(image_handle, efirc, 0, NULL);
+       return efirc;
+}
+
+/**
+ * Probe EFI root bus
+ *
+ * @v rootdev          EFI root device
+ */
+static int efi_probe ( struct root_device *rootdev __unused ) {
+
+       return efi_driver_connect_all();
+}
+
+/**
+ * Remove EFI root bus
+ *
+ * @v rootdev          EFI root device
+ */
+static void efi_remove ( struct root_device *rootdev __unused ) {
+
+       efi_driver_disconnect_all();
+}
+
+/** EFI root device driver */
+static struct root_driver efi_root_driver = {
+       .probe = efi_probe,
+       .remove = efi_remove,
+};
+
+/** EFI root device */
+struct root_device efi_root_device __root_device = {
+       .dev = { .name = "EFI" },
+       .driver = &efi_root_driver,
+};
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 6bbb945e5dc226955ae950a521754d951fd493cd..4abdb999a09cf00721aca196c6465f16ad503b52 100644 (file)
@@ -1,6 +1,6 @@
 Summary: EFI boot manager software
 Name: refind
-Version: 0.8.3
+Version: 0.8.4
 Release: 1%{?dist}
 Summary: EFI boot manager software
 License: GPLv3
@@ -159,6 +159,8 @@ fi
 # wiping out the just-updated files.
 
 %changelog
+* Sun Dec 7 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.4
+- Updated spec file for 0.8.4
 * Sun Jul 6 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.3
 - Updated spec file for 0.8.3
 * Sun Jun 8 2014 R Smith <rodsmith@rodsbooks.com> - 0.8.2
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 4feba412593c764e43c9912df6a86aca11cb04c2..e58ac56e6b9719a20bddbf48e61218f1e526855f 100644 (file)
@@ -82,6 +82,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"
@@ -91,6 +92,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
@@ -144,7 +150,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;
@@ -170,7 +176,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.90");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2014 Roderick W. Smith");
@@ -452,7 +458,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)
 {
@@ -477,7 +483,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) {
@@ -913,61 +919,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',');
@@ -982,33 +994,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
@@ -1021,7 +1039,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo
 // 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;
+   LOADER_ENTRY  *Entry;
 
    CleanUpPathNameSlashes(LoaderPath);
    Entry = InitializeLoaderEntry(NULL);
@@ -1030,7 +1048,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'\\')) {
@@ -1346,6 +1368,53 @@ 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 = NULL;
+   UINTN            boot_info_size = 0;
+
+   FilePath = FileDevicePath (Volume, IPXE_DISCOVER_NAME);
+   Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, FilePath,
+                                NULL, 0, &iPXEHandle);
+   if (Status != 0)
+      return NULL;
+
+   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));
+         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;
@@ -2257,6 +2326,9 @@ static VOID ScanForBootloaders(VOID) {
          case 'o': case 'O':
             ScanOptical();
             break;
+         case 'n': case 'N':
+            ScanNetboot();
+            break;
       } // switch()
    } // for
 
@@ -2377,6 +2449,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");