summaryrefslogtreecommitdiffstats
path: root/src/include
Commit message (Collapse)AuthorAgeFilesLines
* [xen] Support scatter-gather to allow for jumbo framesMichael Brown2021-04-141-3/+4
| | | | | | | | | | | | | | | | | | | The use of jumbo frames for the Xen netfront virtual NIC requires the use of scatter-gather ("feature-sg"), with the receive descriptor ring becoming a list of page-sized buffers and the backend using as many page buffers as required for each packet. Since iPXE's abstraction of an I/O buffer does not include any sort of scatter-gather list, this requires an extra allocation and copy on the receive datapath for any packet that spans more than a single page. This support is required in order to successfully boot an AWS EC2 virtual machine (with non-enhanced networking) via iSCSI if jumbo frames are enabled, since the netback driver used in EC2 seems not to allow "feature-sg" to be renegotiated once the Linux kernel driver takes over. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [netdevice] Ensure driver transmit() and poll() will not be re-enteredMichael Brown2021-04-101-0/+6
| | | | | | | | | | | | | | When CONSOLE_SYSLOG is used, a DBG() from within a network device driver may cause its transmit() or poll() methods to be unexpectedly re-entered. Since these methods are not intended to be re-entrant, this can lead to undefined behaviour. Add an explicit re-entrancy guard to both methods. Note that this must operate at a per-netdevice level, since there are legitimate circumstances under which the netdev_tx() or netdev_poll() functions may be re-entered (e.g. when using VLAN devices). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [pci] Avoid scanning nonexistent buses when using PCIAPI_DIRECTMichael Brown2021-04-101-0/+3
| | | | | | | | | | | | | | There is no method for obtaining the number of PCI buses when using PCIAPI_DIRECT, and we therefore currently scan all possible bus numbers. This can cause a several-second startup delay in some virtualised environments, since PCI configuration space access will necessarily require the involvement of the hypervisor. Ameliorate this situation by defaulting to scanning only a single bus, and expanding the number of PCI buses to accommodate any subordinate buses that are detected during enumeration. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Validate length of ACPI table read from sysfsMichael Brown2021-03-031-0/+1
| | | | | | | | | | | | | Consumers of acpi_find() will assume that returned structures include a valid table header and that the length in the table header is correct. These assumptions are necessary when dealing with raw ACPI tables, since there exists no independent source of length information. Ensure that these assumptions are also valid for ACPI tables read from sysfs. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Use fstat() rather than statx()Michael Brown2021-03-031-3/+1Star
| | | | | | | | | | | | The statx() system call has a clean header file and a consistent layout, but was unfortunately added only in kernel 4.11. Using stat() or fstat() directly is extremely messy since glibc does not necessarily use the kernel native data structures. However, as the only current use case is to obtain the length of an open file, we can merely provide a wrapper that does precisely this. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Use generic sysfs mechanism to read SMBIOS tableMichael Brown2021-03-031-0/+1
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Add a generic function for reading files from sysfsMichael Brown2021-03-033-0/+20
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Add missing pci_num_bus() stubMichael Brown2021-03-021-0/+11
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [slirp] Add libslirp driver for LinuxMichael Brown2021-03-023-0/+175
| | | | | | | | | | | | | | | | | | | Add a driver using libslirp to provide a virtual network interface without requiring root permissions on the host. This simplifies the process of running iPXE as a Linux userspace application with network access. For example: make bin-x86_64-linux/slirp.linux ./bin-x86_64-linux/slirp.linux --net slirp libslirp will provide a built-in emulated DHCP server and NAT router. Settings such as the boot filename may be controlled via command-line options. For example: ./bin-x86_64-linux/slirp.linux \ --net slirp,filename=http://192.168.0.1/boot.ipxe Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Provide ACPI settings via /sys/firmware/acpi/tablesMichael Brown2021-03-012-0/+19
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [acpi] Allow for platforms that provide ACPI tables individuallyMichael Brown2021-03-013-3/+28
| | | | | | | | | | | | | | | | The ACPI API currently expects platforms to provide access to a single contiguous ACPI table. Some platforms (e.g. Linux userspace) do not provide a convenient way to obtain the entire ACPI table, but do provide access to individual tables. All iPXE consumers of the ACPI API require access only to individual tables. Redefine the internal API to make acpi_find() an API method, with all existing implementations delegating to the current RSDT-based implementation. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [linux] Use host glibc system call wrappersMichael Brown2021-03-013-112/+86Star
| | | | | | | | | | | | | | | | | | | | | | When building as a Linux userspace application, iPXE currently implements its own system calls to the host kernel rather than relying on the host's C library. The output binary is statically linked and has no external dependencies. This matches the general philosophy of other platforms on which iPXE runs, since there are no external libraries available on either BIOS or UEFI bare metal. However, it would be useful for the Linux userspace application to be able to link against host libraries such as libslirp. Modify the build process to perform a two-stage link: first picking out the requested objects in the usual way from blib.a but with relocations left present, then linking again with a helper object to create a standard hosted application. The helper object provides the standard main() entry point and wrappers for the Linux system calls required by the iPXE Linux drivers and interface code. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Record cached DHCPACK from loaded image's device handle, if presentMichael Brown2021-02-172-0/+17
| | | | | | | | | | | Record the cached DHCPACK obtained from the EFI_PXE_BASE_CODE_PROTOCOL instance installed on the loaded image's device handle, if present. This allows a chainloaded UEFI iPXE to reuse the IPv4 address and DHCP options previously obtained by the built-in PXE stack, as is already done for a chainloaded BIOS iPXE. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Split out autoexec script portions of efi_autoboot.cMichael Brown2021-02-173-1/+20
| | | | | | | | | | | The "autoboot device" and "autoexec script" functionalities in efi_autoboot.c are unrelated except in that they both need to be invoked by efiprefix.c before device drivers are loaded. Split out the autoexec script portions to a separate file to avoid potential confusion. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [pxe] Split out platform-independent portions of cachedhcp.cMichael Brown2021-02-172-0/+18
| | | | | | | | | Split out the portions of cachedhcp.c that can be shared between BIOS and UEFI (both of which can provide a buffer containing a previously obtained DHCP packet, and neither of which provide a means to determine the length of this DHCP packet). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [build] Use .balign directive instead of .alignMichael Brown2021-02-131-2/+2
| | | | | | | | | | | | | The semantics of the assembler's .align directive vary by CPU architecture. For the ARM builds, it specifies a power of two rather than a number of bytes. This currently leads to the .einfo entries (which do not appear in the final binary) having an alignment of 256 bytes for the ARM builds. Fix by switching to the GNU-specific directive .balign, which is consistent across architectures Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [build] Remove support for building with the Intel C compilerMichael Brown2021-02-122-76/+0Star
| | | | | | | | | | | | | | | | | | | Support for building with the Intel C compiler (icc) was added in 2009 in the expectation that UEFI support would eventually involve compiling iPXE to EFI Byte Code. EFI Byte Code has never found any widespread use: no widely available compilers can emit it, Microsoft refuses to sign EFI Byte Code binaries for UEFI Secure Boot, and I have personally never encountered any examples of EFI Byte Code in the wild. The support for using the Intel C compiler has not been tested in over a decade, and would almost certainly require modification to work with current releases of the compiler. Simplify the build process by removing this old legacy code. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [infiniband] Require drivers to specify the number of portsChristian Iversen2021-01-271-1/+2
| | | | | | | | | | | | Require drivers to report the total number of Infiniband ports. This is necessary to report the correct number of ports on devices with dynamic port types. For example, dual-port Mellanox cards configured for (eth, ib) would be rejected by the subnet manager, because they report using "port 2, out of 1". Signed-off-by: Christian Iversen <ci@iversenit.dk>
* [cmdline] Expose "iflinkwait" as a commandMichael Brown2021-01-261-1/+2
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Automatically load "/autoexec.ipxe" when booted from a filesystemMichael Brown2021-01-251-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When booting iPXE from a filesystem (e.g. a FAT-formatted USB key) it can be useful to have an iPXE script loaded automatically from the same filesystem. Compared to using an embedded script, this has the advantage that the script can be edited without recompiling the iPXE binary. For the BIOS version of iPXE, loading from a filesystem is handled using syslinux (or isolinux) which allows the script to be passed to the iPXE .lkrn image as an initrd. For the UEFI version of iPXE, the platform firmware loads the iPXE .efi image directly and there is currently no equivalent of the BIOS initrd mechanism. Add support for automatically loading a file "autoexec.ipxe" (if present) from the root of the filesystem containing the UEFI iPXE binary. A combined BIOS and UEFI image for a USB key can be created using e.g. ./util/genfsimg -o usbkey.img -s myscript.ipxe \ bin-x86_64-efi/ipxe.efi bin/ipxe.lkrn The file "myscript.ipxe" would appear as "autoexec.ipxe" on the USB key, and would be loaded automatically on both BIOS and UEFI systems. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [image] Provide image_memory()Michael Brown2021-01-252-2/+3
| | | | | | | Consolidate the remaining logic common to initrd_init() and imgmem() into a shared image_memory() function. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [image] Add the "imgmem" commandMichael Brown2021-01-221-0/+2
| | | | | | | Provide the "imgmem" command to create an image from an existing block of memory, for debugging purposes only. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [image] Provide image_set_data()Michael Brown2021-01-221-0/+1
| | | | | | | Extract part of the logic in initrd_init() to a standalone function image_set_data(). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [eap] Treat an EAP Request-Identity as indicating a blocked linkMichael Brown2021-01-193-0/+73
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A switch port using 802.1x authentication will send EAP Request-Identity packets once the physical link is up, and will not be forwarding packets until the port identity has been established. We do not currently support 802.1x authentication. However, a reasonably common configuration involves using a preset list of permitted MAC addresses, with the "authentication" taking place between the switch and a RADIUS server. In this configuration, the end device does not need to perform any authentication step, but does need to be prepared for the switch port to fail to forward packets for a substantial time after physical link-up. This exactly matches the "blocked link" semantics already used when detecting a non-forwarding switch port via LACP or STP. Treat a received EAP Request-Identity as indicating a blocked link. Unlike LACP or STP, there is no way to determine the expected time until the next EAP packet and so we must choose a fixed timeout. Erroneously assuming that the link is blocked is relatively harmless since we will still attempt to transmit and receive data even over a link that is marked as blocked, and so the net effect is merely to prolong DHCP attempts. In contrast, erroneously assuming that the link is unblocked will potentially cause DHCP to time out and give up, resulting in a failed boot. The default EAP Request-Identity interval in Cisco switches (where this is most likely to be encountered in practice) is 30 seconds, so choose 45 seconds as a timeout that is likely to avoid gaps during which we falsely assume that the link is unblocked. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [eapol] Replace EAPoL codeMichael Brown2021-01-191-90/+34Star
| | | | | | | Replace the GPL2+-only EAPoL code (currently used only for WPA) with new code licensed under GPL2+-or-UBDL. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Use segment and bus number to identify PCI root bridge I/O protocolMichael Brown2020-12-311-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There may be multiple instances of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL for a single PCI segment. Use the bus number range descriptor from the ACPI resource list to identify the correct protocol instance. There is some discrepancy between the ACPI and UEFI specifications regarding the interpretation of values within the ACPI resource list. The ACPI specification defines the min/max field values to be within the secondary (device-side) address space, and defines the offset field value as "the offset that must be added to the address on the secondary side to obtain the address on the primary side". The UEFI specification states instead that the offset field value is the "offset to apply to the starting address to convert it to a PCI address", helpfully omitting to clarify whether "to apply" in this context means "to add" or "to subtract". The implication of the wording is also that the "starting address" is not already a "PCI address" and must therefore be a host-side address rather than the ACPI-defined device-side address. Code comments in the EDK2 codebase seem to support the latter (non-ACPI) interpretation of these ACPI structures. For example, in the PciHostBridgeDxe driver there can be found the comment Macros to translate device address to host address and vice versa. According to UEFI 2.7, device address = host address + translation offset. along with a pair of macros TO_HOST_ADDRESS() and TO_DEVICE_ADDRESS() which similarly negate the sense of the "translation offset" from the definition found in the ACPI specification. The existing logic in efipci_ioremap() (based on a presumed-working externally contributed patch) applies the non-ACPI interpretation: it assumes that min/max field values are host-side addresses and that the offset field value is negated. Match this existing logic by assuming that min/max field values are host-side bus numbers. (The bus number offset value is therefore not required and so can be ignored.) As noted in commit 9b25f6e ("[efi] Fall back to assuming identity mapping of MMIO address space"), some systems seem to fail to provide MMIO address space descriptors. Assume that some systems may similarly fail to provide bus number range descriptors, and fall back in this situation to assuming that matching on segment number alone is sufficient. Testing any of this is unfortunately impossible without access to esoteric hardware that actually uses non-zero translation offsets. Originally-implemented-by: Thomas Walker <twalker@twosigma.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [smbios] Add support for the 64-bit SMBIOS3 entry pointMichael Brown2020-12-291-4/+47
| | | | | | | Support UEFI systems that provide only 64-bit versions of the SMBIOS entry point. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Allow EFI_USB_IO_PROTOCOL interfaces to be nullified and leakedMichael Brown2020-12-171-0/+2
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [iphone] Add iPhone tethering driverMichael Brown2020-12-161-0/+1
| | | | | | | | | USB tethering via an iPhone is unreasonably complicated due to the requirement to perform a pairing operation that involves establishing a TLS session over a completely unrelated USB function that speaks a protocol that is almost, but not quite, entirely unlike TCP. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [crypto] Allow private key to be specified as a TLS connection parameterMichael Brown2020-12-153-3/+62
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [tls] Include root of trust within definition of TLS sessionMichael Brown2020-12-151-1/+4
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [x509] Make root of trust a reference-counted structureMichael Brown2020-12-091-1/+26
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [x509] Record root of trust used when validating a certificateMichael Brown2020-12-083-16/+13Star
| | | | | | | | | | | | | Record the root of trust used at the point that a certificate is validated, redefine validation as checking a certificate against a specific root of trust, and pass an explicit root of trust when creating a TLS connection. This allows a custom TLS connection to be used with a custom root of trust, without causing any validated certificates to be treated as valid for normal purposes. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [http] Hide HTTP transport-layer filter implementation detailsMichael Brown2020-12-081-3/+3
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [asn1] Define ASN1_SHORT() for constructing short tagged valuesMichael Brown2020-12-081-0/+5
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [asn1] Rename ASN1_OID_CURSOR to ASN1_CURSORMichael Brown2020-12-081-4/+4
| | | | | | | | There is nothing OID-specific about the ASN1_OID_CURSOR macro. Rename to allow it to be used for constructing ASN.1 cursors with arbitrary contents. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [asn1] Add constant for UTF-8 string tagMichael Brown2020-12-071-0/+3
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [tls] Allow provision of a client certificate chainMichael Brown2020-12-071-2/+2
| | | | | | | Use the existing certificate store to automatically append any available issuing certificates to the selected client certificate. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [tls] Use intf_insert() to add TLS to an interfaceMichael Brown2020-12-072-5/+2Star
| | | | | | | | | | Restructure the use of add_tls() to insert a TLS filter onto an existing interface. This allows for the possibility of using add_tls() to start TLS on an existing connection (as used in several protocols which will negotiate the choice to use TLS before the ClientHello is sent). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [interface] Provide intf_insert() to insert a filter interfaceMichael Brown2020-12-071-0/+2
| | | | | | | | Generalise the filter interface insertion logic from block_translate() and expose as intf_insert(), allowing a filter interface to be inserted on any existing interface. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Allow vetoing of drivers that cannot be unloadedMichael Brown2020-11-301-1/+1
| | | | | | | | | | | | | | | | Some UEFI drivers (observed with the "Usb Xhci Driver" on an HP EliteBook) are particularly badly behaved: they cannot be unloaded and will leave handles opened with BY_DRIVER attributes even after disconnecting the driver, thereby preventing a replacement iPXE driver from opening the handle. Allow such drivers to be vetoed by falling back to a brute-force mechanism that will disconnect the driver from all handles, uninstall the driver binding protocol (to prevent it from attaching to any new handles), and finally close any stray handles that the vetoed driver has left open. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Split out dbg_efi_opener() as a standalone functionMichael Brown2020-11-301-0/+22
| | | | | | | Allow external code to dump the information for an opened protocol information entry via DBG_EFI_OPENER() et al. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [xhci] Update driver to use DMA APIMichael Brown2020-11-291-4/+18
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Provide dma_umalloc() for allocating large DMA-coherent buffersMichael Brown2020-11-291-0/+93
| | | | | | | | | | | | | | Some devices (e.g. xHCI USB host controllers) may require the use of large areas of host memory for private use by the device. These allocations cannot be satisfied from iPXE's limited heap space, and so are currently allocated using umalloc() which will allocate external system memory (and alter the system memory map as needed). Provide dma_umalloc() to provide such allocations as part of the DMA API, since there is otherwise no way to guarantee that the allocated regions are usable for coherent DMA. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Move I/O buffer DMA operations to iobuf.hMichael Brown2020-11-283-22/+61
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Include a potential DMA mapping within the definition of an I/O buffer, and move all I/O buffer DMA mapping functions from dma.h to iobuf.h. This avoids the need for drivers to maintain a separate list of DMA mappings for each I/O buffer that they may handle. Network device drivers typically do not keep track of transmit I/O buffers, since the network device core already maintains a transmit queue. Drivers will typically call netdev_tx_complete_next() to complete a transmission without first obtaining the relevant I/O buffer pointer (and will rely on the network device core automatically cancelling any pending transmissions when the device is closed). To allow this driver design approach to be retained, update the netdev_tx_complete() family of functions to automatically perform the DMA unmapping operation if required. For symmetry, also update the netdev_rx() family of functions to behave the same way. As a further convenience for drivers, allow the network device core to automatically perform DMA mapping on the transmit datapath before calling the driver's transmit() method. This avoids the need to introduce a mapping error handling code path into the typically error-free transmit methods. With these changes, the modifications required to update a typical network device driver to use the new DMA API are fairly minimal: - Allocate and free descriptor rings and similar coherent structures using dma_alloc()/dma_free() rather than malloc_phys()/free_phys() - Allocate and free receive buffers using alloc_rx_iob()/free_rx_iob() rather than alloc_iob()/free_iob() - Calculate DMA addresses using dma() or iob_dma() rather than virt_to_bus() - Set a 64-bit DMA mask if needed using dma_set_mask_64bit() and thereafter eliminate checks on DMA address ranges - Either record the DMA device in netdev->dma, or call iob_map_tx() as part of the transmit() method - Ensure that debug messages use virt_to_phys() when displaying "hardware" addresses Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Record DMA device as part of DMA mapping if neededMichael Brown2020-11-281-51/+70
| | | | | | | Allow for dma_unmap() to be called by code other than the DMA device driver itself. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Modify DMA API to simplify calculation of medial addressesMichael Brown2020-11-251-10/+64
| | | | | | | | | | | | | | | | | Redefine the value stored within a DMA mapping to be the offset between physical addresses and DMA addresses within the mapped region. Provide a dma() wrapper function to calculate the DMA address for any pointer within a mapped region, thereby simplifying the use cases when a device needs to be given addresses other than the region start address. On a platform using the "flat" DMA implementation the DMA offset for any mapped region is always zero, with the result that dma_map() can be optimised away completely and dma() reduces to a straightforward call to virt_to_phys(). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Avoid dropping below TPL as at entry to iPXEMichael Brown2020-11-201-0/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | iPXE will currently drop to TPL_APPLICATION whenever the current system time is obtained via currticks(), since the system time mechanism relies on a timer that can fire only when the TPL is below TPL_CALLBACK. This can cause unexpected behaviour if the system time is obtained in the middle of an API call into iPXE by external code. For example, MnpDxe sets up a 10ms periodic timer running at TPL_CALLBACK to poll the underling EFI_SIMPLE_NETWORK_PROTOCOL device for received packets. If the resulting poll within iPXE happens to hit a code path that requires obtaining the current system time (e.g. due to reception of an STP packet, which affects iPXE's blocked link timer), then iPXE will end up temporarily dropping to TPL_APPLICATION. This can potentially result in retriggering the MnpDxe periodic timer, causing code to be unexpectedly re-entered. Fix by recording the external TPL at any entry point into iPXE and dropping only as far as this external TPL, rather than dropping unconditionally to TPL_APPLICATION. The side effect of this change is that iPXE's view of the current system time will be frozen for the duration of any API calls made into iPXE by external code at TPL_CALLBACK or above. Since any such external code is already responsible for allowing execution at TPL_APPLICATION to occur, then this should not cause a problem in practice. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Rename efi_blacklist to efi_vetoMichael Brown2020-11-083-14/+14
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Provide DMA operations for EFI PCI devicesMichael Brown2020-11-052-0/+5
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>