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>
Consolidate the remaining logic common to initrd_init() and imgmem()
into a shared image_memory() function.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
iPXE currently assumes that DMA-capable devices can directly address
physical memory using host addresses. This assumption fails when
using an IOMMU.
Define an internal DMA API with two implementations: a "flat"
implementation for use in legacy BIOS or other environments in which
flat physical addressing is guaranteed to be used and all allocated
physical addresses are guaranteed to be within a 32-bit address space,
and an "operations-based" implementation for use in UEFI or other
environments in which DMA mapping may require bus-specific handling.
The purpose of the fully inlined "flat" implementation is to allow the
trivial identity DMA mappings to be optimised out at build time,
thereby avoiding an increase in code size for legacy BIOS builds.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The malloc_dma() function allocates memory with specified physical
alignment, and is typically (though not exclusively) used to allocate
memory for DMA.
Rename to malloc_phys() to more closely match the functionality, and
to create name space for functions that specifically allocate and map
DMA-capable buffers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide opened EFI PCI devices with access to the underlying
EFI_PCI_IO_PROTOCOL instance, in order to facilitate the future use of
the DMA mapping methods within the fast data path.
Do not require the use of this stored EFI_PCI_IO_PROTOCOL instance for
memory-mapped I/O (since the entire point of memory-mapped I/O as a
concept is to avoid this kind of unnecessary complexity) or for
slow-path PCI configuration space accesses (since these may be
required for access to PCI bus:dev.fn addresses that do not correspond
to a device bound via our driver binding protocol instance).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit 87e39a9c9 ("[efi] Split efi_usb_path() out to a separate
function") unintentionally introduced an undefined symbol reference
from efi_path.o to usb_depth(), causing the USB subsystem to become a
dependency of all EFI builds.
Fix by converting usb_depth() to a static inline function.
Reported-by: Pico Mitchell <pico@randomapplications.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The UEFI specification allows uninstallation of a protocol interface
to fail. There is no sensible way for code to react to this, since
uninstallation is likely to be taking place on a code path that cannot
itself fail (e.g. a code path that is itself a failure path).
Where the protocol structure exists within a dynamically allocated
block of memory, this leads to possible use-after-free bugs. Work
around this unfortunate design choice by nullifying the protocol
(i.e. overwriting the method pointers with no-ops) and leaking the
memory containing the protocol structure.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The UEFI specification provides a partial definition of an Infiniband
device path structure. Use this structure to construct what may be a
plausible path containing at least some of the information required to
identify an SRP target device.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
There is no standard defined for AoE device paths in the UEFI
specification, and it seems unlikely that any standard will be adopted
in future.
Choose to construct an AoE device path using a concatenation of the
network device path and a SATA device path, treating the AoE major and
minor numbers as the HBA port number and port multiplier port number
respectively.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide efi_netdev_path() as a standalone function, to allow for reuse
when constructing child device paths.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow an interface operation to be declared as unused. This will
perform full type-checking and compilation of the implementing method,
without including any code in the resulting object (other than a NULL
entry in the interface operations table).
The intention is to provide a relatively clean way for interface
operation methods to be omitted in builds for which the operation is
not required (such as an operation to describe an object using an EFI
device path, which would not be required in a non-EFI build).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI BIOSes (observed with at least the Insyde UEFI BIOS on a
Microsoft Surface Go) provide a very broken version of the
UsbMassStorageDxe driver that is incapable of binding to the standard
EFI_USB_IO_PROTOCOL instances and instead relies on an undocumented
proprietary protocol (with GUID c965c76a-d71e-4e66-ab06-c6230d528425)
installed by the platform's custom version of UsbCoreDxe.
The upshot is that USB mass storage devices become inaccessible once
iPXE's native USB host controller drivers are loaded.
One possible workaround is to load a known working version of
UsbMassStorageDxe (e.g. from the EDK2 tree): this driver will
correctly bind to the standard EFI_USB_IO_PROTOCOL instances exposed
by iPXE. This workaround is ugly in practice, since it involves
embedding UsbMassStorageDxe.efi into the iPXE binary and including an
embedded script to perform the required "chain UsbMassStorageDxe.efi".
Provide a native USB mass storage driver for iPXE, allowing USB mass
storage devices to be exposed as iPXE SAN devices.
Signed-off-by: Michael Brown <mcb30@ipxe.org>