Commit Graph

6059 Commits (699b9f1d1b0338272dc4871ec3348ff3281784a3)

Author SHA1 Message Date
Michael Brown 6769a7c3c6 [efi] Skip interface uninstallation during shutdown
iPXE seems to be almost alone in the UEFI world in attempting to shut
down cleanly, free resources, and leave hardware in a well-defined
reset state before handing over to the booted operating system.

The UEFI driver model does allow for graceful shutdown via
uninstallation of protocol interfaces.  However, virtually no other
UEFI drivers do this, and the external code paths that react to
uninstallation are consequently poorly tested.  This leads to a
proliferation of bugs found in UEFI implementations in the wild, as
described in commits such as 1295b4a ("[efi] Allow initialisation via
SNP interface even while claimed") or b6e2ea0 ("[efi] Veto the HP
XhciDxe Driver").

Try to avoid triggering such bugs by unconditionally skipping the
protocol interface uninstallation during UEFI boot services shutdown,
leaving the interfaces present but nullified and deliberately leaking
the containing memory.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-17 21:32:49 +00:00
Michael Brown fb91542f2a [efi] Nullify interfaces unconditionally on error and shutdown paths
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-17 19:52:41 +00:00
Michael Brown f47a45ea2d [iphone] Add iPhone tethering driver
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>
2020-12-16 13:29:06 +00:00
Michael Brown f43a8f8b9f [crypto] Allow private key to be specified as a TLS connection parameter
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-15 16:54:06 +00:00
Michael Brown 6a8664d9ec [tls] Include root of trust within definition of TLS session
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-15 16:28:33 +00:00
Michael Brown 3475f9162b [x509] Make root of trust a reference-counted structure
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-09 16:45:50 +00:00
Michael Brown e3eedb0be5 [efi] Avoid using potentially uninitialised driver name in veto checks
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-08 15:52:25 +00:00
Michael Brown 39f5293492 [x509] Record root of trust used when validating a certificate
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>
2020-12-08 15:04:28 +00:00
Michael Brown 6e92d6213d [ocsp] Remove dummy OCSP certificate root
OCSP currently calls x509_validate() with an empty root certificate
list, on the basis that the OCSP signer certificate (if existent) must
be signed directly by the issuer certificate.

Using an empty root certificate list is not required to achieve this
goal, since x509_validate() already accepts an explicit issuer
certificate parameter.  The explicit empty root certificate list
merely prevents the signer certificate from being evaluated as a
potential trusted root certificate.

Remove the dummy OCSP root certificate list and use the default root
certificate list when calling x509_validate().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-08 15:04:28 +00:00
Michael Brown be47c2c72c [http] Hide HTTP transport-layer filter implementation details
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-08 15:04:28 +00:00
Michael Brown 1b112e9d18 [asn1] Define ASN1_SHORT() for constructing short tagged values
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-08 12:38:45 +00:00
Michael Brown e4b6328c84 [asn1] Rename ASN1_OID_CURSOR to ASN1_CURSOR
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>
2020-12-08 12:38:45 +00:00
Michael Brown e33f521081 [asn1] Add constant for UTF-8 string tag
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-07 13:55:12 +00:00
Michael Brown 25b53afa5b [tls] Allow provision of a client certificate chain
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>
2020-12-07 13:53:48 +00:00
Michael Brown 2b6b02ee7e [tls] Use intf_insert() to add TLS to an interface
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>
2020-12-07 13:51:46 +00:00
Michael Brown 09fe2bbd34 [interface] Provide intf_insert() to insert a filter interface
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>
2020-12-07 13:50:24 +00:00
Michael Brown cb0ba2f825 [interface] Ignore any attempts to plug in the null interface
Allow intf_plug() and intf_plug_plug() to be called safely on
interfaces that may be the null interface.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-12-07 13:48:35 +00:00
Michael Brown b6e2ea03b0 [efi] Veto the HP XhciDxe Driver
The HP XhciDxe driver (observed on an HP EliteBook 840 G6) does not
respond correctly to driver disconnection, and will leave the PciIo
protocol instance opened with BY_DRIVER attributes even after
returning successfully from its Stop() method.  This prevents iPXE
from subsequently connecting to the PCI device handle.

Veto this driver if the iPXE build includes a native xHCI driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-30 19:34:57 +00:00
Michael Brown 63625b43e9 [efi] Allow vetoing of drivers that cannot be unloaded
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>
2020-11-30 19:34:57 +00:00
Michael Brown 354c252ee1 [efi] Provide manufacturer and driver names to all veto checking methods
Most veto checks are likely to use the manufacturer name and driver
name, so pass these as parameters to minimise code duplication.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-30 17:54:22 +00:00
Michael Brown be49380f55 [efi] Split out dbg_efi_opener() as a standalone function
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>
2020-11-30 16:36:08 +00:00
Michael Brown 13a6d17296 [xhci] Update driver to use DMA API
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-29 11:25:40 +00:00
Michael Brown 6e01b74a8a [dma] Provide dma_umalloc() for allocating large DMA-coherent buffers
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>
2020-11-29 11:25:40 +00:00
Michael Brown a8442750e6 [efi] Avoid requesting zero-length DMA mappings
The UEFI specification does not prohibit zero-length DMA mappings.
However, there is a reasonable chance that at least one implementation
will treat it as an invalid parameter.  As a precaution, avoid calling
EFI_PCI_IO_PROTOCOL.Map() with a length of zero.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-29 11:25:40 +00:00
Michael Brown a2e5cf1a3f [netdevice] Fix misleading comment on netdev_rx()
Unlike netdev_rx_err(), there is no valid circumstance under which
netdev_rx() may be called with a null I/O buffer, since a call to
netdev_rx() represents the successful reception of a packet.  Fix the
code comment to reflect this.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-29 11:25:40 +00:00
Michael Brown 9ff61ab28d [netdevice] Do not attempt to unmap a null I/O buffer
netdev_tx_err() may be called with a null I/O buffer (e.g. to record a
transmit error with no associated buffer).  Avoid a potential null
pointer dereference in the DMA unmapping code path.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-29 11:25:40 +00:00
Michael Brown 8d337ecdae [dma] Move I/O buffer DMA operations to iobuf.h
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>
2020-11-28 20:26:28 +00:00
Michael Brown 70e6e83243 [dma] Record DMA device as part of DMA mapping if needed
Allow for dma_unmap() to be called by code other than the DMA device
driver itself.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-28 18:56:50 +00:00
Michael Brown cf12a41703 [dma] Modify DMA API to simplify calculation of medial addresses
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>
2020-11-25 16:15:55 +00:00
Michael Brown 24ef743778 [intelxl] Configure DMA mask as 64-bit
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-24 17:47:42 +00:00
Michael Brown 9e280aecb7 [intel] Configure DMA mask as 64-bit
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-24 17:46:39 +00:00
Michael Brown 0b5467b658 [efi] Report correct error when failing to unload a vetoed driver
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-24 15:42:43 +00:00
Michael Brown 1295b4acff [efi] Allow initialisation via SNP interface even while claimed
iPXE will currently fail all SNP interface methods with EFI_NOT_READY
while the network devices are claimed for use by iPXE's own network
stack.

As of commit c70b3e0 ("[efi] Always enable recursion when calling
ConnectController()"), this exposes latent UEFI firmware bugs on some
systems at the point of calling ExitBootServices().

With recursion enabled, the MnpDxe driver will immediately attempt to
consume the SNP protocol instance provided by iPXE.  Since the network
devices are claimed by iPXE at this point, the calls by MnpDxe to
Start() and Initialize() will both fail with EFI_NOT_READY.

This unfortunately triggers a broken error-handling code path in the
Ip6Dxe driver.  Specifically: Ip6DriverBindingStart() will call
Ip6CreateService(), which will call Ip6ServiceConfigMnp(), which will
return an error.  The subsequent error handling code path in
Ip6CreateService() simply calls Ip6CleanService().  The code in
Ip6CleanService() will attempt to leave the all-nodes multicast group,
which will fail since the group was never joined.  This will result in
Ip6CleanService() returning an error and omitting most of the required
clean-up operations.  In particular, the MNP protocol instance will
remain opened with BY_DRIVER attributes even though the Ip6Dxe driver
start method has failed.

When ExitBootServices() is eventually called, iPXE will attempt to
uninstall the SNP protocol instance.  This results in the UEFI core
calling Ip6DriverBindingStop(), which will fail since there is no
EFI_IP6_SERVICE_BINDING_PROTOCOL instance installed on the handle.

A failure during a call to UninstallMultipleProtocolInterfaces() will
result in the UEFI core attempting to reinstall any successfully
uninstalled protocols.  This is an intrinsically unsafe operation, and
represents a fundamental design flaw in UEFI.  Failure code paths
cannot be required to themselves handle failures, since there is no
well-defined correct outcome of such a situation.

With a current build of OVMF, this results in some unexpected debug
messages occurring at the time that the loaded operating system calls
ExitBootServices().  With the UEFI firmware in Hyper-V, the result is
an immediate reboot.

Work around these UEFI design and implementation flaws by allowing the
calls to our EFI_SIMPLE_NETWORK_PROTOCOL instance's Start() and
Initialize() methods to return success even when the network devices
are claimed for exclusive use by iPXE.  This is sufficient to allow
MnpDxe to believe that it has successfully initialised the device, and
thereby avoids the problematic failure code paths in Ip6Dxe.

Debugged-by: Aaron Heusser <aaron_heusser@hotmail.com>
Debugged-by: Pico Mitchell <pico@randomapplications.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-23 22:30:04 +00:00
Michael Brown 03314e8da9 [intelxl] Update driver to use DMA API
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-21 13:35:11 +00:00
Michael Brown 76a7bfe939 [intelxl] Read PCI bus:dev.fn number from PFFUNC_RID register
For the physical function driver, the transmit queue needs to be
configured to be associated with the relevant physical function
number.  This is currently obtained from the bus:dev.fn address of the
underlying PCI device.

In the case of a virtual machine using the physical function via PCI
passthrough, the PCI bus:dev.fn address within the virtual machine is
unrelated to the real physical function number.  Such a function will
typically be presented to the virtual machine as a single-function
device.  The function number extracted from the PCI bus:dev.fn address
will therefore always be zero.

Fix by reading from the Function Requester ID Information Register,
which always returns the real PCI bus:dev.fn address as used by the
physical host.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-21 13:35:11 +00:00
Michael Brown b6eb17cbd7 [intelxl] Read MAC address from PRTPM_SA[HL] instead of PRTGL_SA[HL]
The datasheet is fairly incomprehensible in terms of identifying the
appropriate MAC address for use by the physical function driver.
Choose to read the MAC address from PRTPM_SAH and PRTPM_SAL, which at
least matches the MAC address as selected by the Linux i40e driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-20 19:15:30 +00:00
Michael Brown e10a40d41f [efi] Avoid dropping below TPL as at entry to iPXE
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>
2020-11-20 16:57:50 +00:00
Michael Brown 062711f1cf [intel] Use physical addresses in debug messages
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-16 15:07:03 +00:00
Michael Brown 810dc5d6c3 [realtek] Use physical addresses in debug messages
Physical addresses in debug messages are more meaningful from an
end-user perspective than potentially IOMMU-mapped I/O virtual
addresses, and have the advantage of being calculable without access
to the original DMA mapping entry (e.g. when displaying an address for
a single failed completion within a descriptor ring).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-16 14:58:57 +00:00
Michael Brown fc5cf18dab [efi] Use casts rather than virt_to_bus() for UNDI buffer addresses
For a software UNDI, the addresses in PXE_CPB_TRANSMIT.FrameAddr and
PXE_CPB_RECEIVE.BufferAddr are host addresses, not bus addresses.

Remove the spurious (and no-op) use of virt_to_bus() and replace with
a cast via intptr_t.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-15 23:36:17 +00:00
Michael Brown 83b8c0e211 [efi] Do not populate media header length in PXE transmit CPB
The UEFI specification defines PXE_CPB_TRANSMIT.DataLen as excluding
the length of the media header.  iPXE currently fills in DataLen as
the whole frame length (including the media header), along with
placing the media header length separately in MediaheaderLen.  On some
UNDI implementations (observed using a VMware ESXi 7.0b virtual
machine), this causes transmitted packets to include 14 bytes of
trailing garbage.

Match the behaviour of the EDK2 SnpDxe driver, which fills in DataLen
as the whole frame length (including the media header) and leaves
MediaheaderLen as zero.  This behaviour also violates the UEFI
specification, but is likely to work in practice since EDK2 is the
reference implementation.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-15 23:17:17 +00:00
Michael Brown 5439329c99 [intel] Update driver to use DMA API
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-13 19:55:22 +00:00
Michael Brown 0e26220902 [efi] Rename efi_blacklist to efi_veto
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-07 23:30:56 +00:00
Michael Brown 580d9b00da [realtek] Update driver to use DMA API
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-05 20:18:29 +00:00
Michael Brown 38a54bd3b1 [efi] Provide DMA operations for EFI PCI devices
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-05 20:18:27 +00:00
Michael Brown dda03c884d [dma] Define a DMA API to allow for non-flat device address spaces
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>
2020-11-05 20:03:50 +00:00
Michael Brown be1c87b722 [malloc] Rename malloc_dma() to malloc_phys()
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>
2020-11-05 19:13:52 +00:00
Michael Brown 36dde9b0bf [efi] Retain a long-lived reference to the EFI_PCI_IO_PROTOCOL instance
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>
2020-11-04 15:16:22 +00:00
Michael Brown f560e7b70b [realtek] Reset NIC when closing interface if using legacy mode
The legacy transmit descriptor index is not reset by anything short of
a full device reset.  This can cause the legacy transmit ring to stall
after closing and reopening the device, since the hardware and
software indices will be out of sync.

Fix by performing a reset after closing the interface.  Do this only
if operating in legacy mode, since in C+ mode the reset is not
required and would undesirably clear additional state (such as the C+
command register itself).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-04 14:35:19 +00:00
Michael Brown 9b25f6e5cf [efi] Fall back to assuming identity mapping of MMIO address space
Some UEFI systems (observed with a Supermicro X11SPG-TF motherboard)
seem to fail to provide a valid ACPI address space descriptor for the
MMIO address space associated with a PCI root bridge.

If no valid descriptor can be found, fall back to assuming that the
MMIO address space is identity mapped, thereby matching the behaviour
prior to commit 27e886c ("[efi] Use address offset as reported by
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL").

Debugged-by: Tore Anderson <tore@fud.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-30 14:25:41 +00:00
Michael Brown 16873703dd [efi] Avoid dragging in USB subsystem via efi_usb_path()
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>
2020-10-30 13:54:55 +00:00
Michael Brown e5e2f3fba8 [efi] Fix memory copy length used in efi_nullify_name2()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-27 11:43:08 +00:00
Michael Brown 5b41b9a80f [efi] Nullify interfaces and leak memory on uninstallation failure
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>
2020-10-26 15:24:00 +00:00
Michael Brown 86c6c79fcd [efi] Allow block devices to provide their own EFI device paths
Use the device path constructed via efi_describe() for the installed
EFI_BLOCK_IO_PROTOCOL device handle.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-23 15:34:35 +01:00
Michael Brown a2e44077cd [infiniband] Allow SRP device to be described using an EFI device path
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>
2020-10-23 15:34:35 +01:00
Michael Brown bf051a76ee [fcp] Allow Fibre Channel device to be described using an EFI device path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-22 14:16:55 +01:00
Michael Brown e6f9054d13 [iscsi] Allow iSCSI device to be described using an EFI device path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-20 15:05:37 +01:00
Michael Brown 334f0074b1 [efi] Show block device ACPI table contents only at DBGLVL_EXTRA
The ACPI table contents are typically large and are likely to cause
any preceding error messages to scroll off-screen.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-20 15:05:37 +01:00
Michael Brown 04cb17de50 [aoe] Allow AoE device to be described using an EFI device path
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>
2020-10-19 14:45:49 +01:00
Michael Brown 2d49ce6f08 [efi] Provide utility function to concatenate device paths
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 14:45:49 +01:00
Michael Brown 6154b1fb20 [efi] Split efi_netdev_path() out to a separate function
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>
2020-10-19 14:45:49 +01:00
Michael Brown b50ad5f09a [http] Allow HTTP connection to be described using an EFI device path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 13:07:40 +01:00
Michael Brown f2c826179a [efi] Provide efi_uri_path() to construct a URI device path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 13:07:40 +01:00
Michael Brown 1e8648f611 [usbblk] Allow USB block device to be described using an EFI device path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:38:20 +01:00
Michael Brown 87e39a9c93 [efi] Split efi_usb_path() out to a separate function
Provide efi_usb_path() as a standalone function, to allow for reuse by
the USB mass storage driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:38:18 +01:00
Michael Brown 2091288eaa [efi] Define an interface operation to describe using an EFI device path
Allow arbitrary objects to support describing themselves using an EFI
device path.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:37:03 +01:00
Michael Brown 2bf0fd39ca [efi] Split device path functions out to efi_path.c
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:36:37 +01:00
Michael Brown bcf858c56d [efi] Provide EFI_INTF_OP for EFI-only interface operations
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:16:00 +01:00
Michael Brown c504c1d693 [interface] Allow for the definition of an unused interface operation
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>
2020-10-16 15:16:00 +01:00
Michael Brown 49fd66a8c9 [build] Provide a testable platform macro alongside -DPLATFORM
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:16:00 +01:00
Michael Brown 6ccd5239b1 [ipv6] Reduce time spent waiting for router discovery
Now that IPv6 is enabled by default for UEFI builds, it is important
that iPXE does not delay unnecessarily in the (still relatively
common) case of a network that lacks IPv6 routers.

Apply the timeout values used for neighbour discovery to the router
discovery process.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-14 14:57:27 +01:00
Tore Anderson 0c25daad38 [efi] Enable NET_PROTO_IPV6 by default
IPv6 PXE was included in the UEFI specification over eight years ago,
specifically in version 2.3 (Errata D).

http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_3_D.pdf

When iPXE is being chainloaded from a UEFI firmware performing a PXE
boot in an IPv6 network, it is essential that iPXE supports IPv6 as
well.

I understand that the reason for NET_PROTO_IPV6 being disabled by
default (in src/config/general.h) is that it would cause certain
space-constrained build targets to become too large.  However, this
should not be an issue for EFI builds.

It is also worth noting that RFC 6540 makes a clear recommendation
that IPv6 support should not be considered optional.

https://tools.ietf.org/html/rfc6540

Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Tore Anderson <tore@fud.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-14 14:51:29 +01:00
Michael Brown 388d657080 [lacp] Ignore (and do not echo) trailing padding on received packets
The LACP responder reuses the received I/O buffer to construct the
response LACP (or marker) packet.  Any received padding will therefore
be unintentionally included within the response.

Truncate the received I/O buffer to the expected length (which is
already defined in a way to allow for future protocol expansion)
before reusing it to construct the response.

Reported-by: Tore Anderson <tore@fud.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-14 14:18:49 +01:00
Michael Brown 3d43789914 [lacp] Detect and ignore erroneously looped back LACP packets
Some external drivers (observed with the UEFI NII driver provided by
an HPE-branded Mellanox ConnectX-3 Pro) seem to cause LACP packets
transmitted by iPXE to be looped back as received packets.  Since
iPXE's trivial LACP responder will send one response per received
packet, this results in an immediate LACP packet storm.

Detect looped back LACP packets (based on the received LACP actor MAC
address), and refuse to respond to such packets.

Reported-by: Tore Anderson <tore@fud.no>
Tested-by: Tore Anderson <tore@fud.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-14 13:36:17 +01:00
Michael Brown 02748d0a58 [efi] Defer local download process until file has been opened
When iPXE is downloading a file from an EFI_FILE_PROTOCOL instance
backed by an EFI_BLOCK_IO_PROTOCOL instance provided by the same iPXE
binary (e.g. via a hooked SAN device), then it is possible for step()
to be invoked as a result of the calls into the EFI_BLOCK_IO_PROTOCOL
methods.  This can potentially result in efi_local_step() being run
prematurely, before the file has been opened and before the parent
interface has been attached.

Fix by deferring starting the download process until immediately prior
to returning from efi_local_open().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-13 19:18:41 +01:00
Michael Brown 6d680bdec5 [usbblk] Add support for USB mass storage devices
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>
2020-10-13 15:56:38 +01:00
Michael Brown 88288407af [usb] Move usbio driver to end of USB driver list
iPXE will often have multiple drivers available for a USB device.  For
example: some USB network devices will support both RNDIS and CDC-ECM,
and any device may be consumed by the fallback "usbio" driver under
UEFI in order to expose an EFI_USB_IO_PROTOCOL instance.

The driver scoring mechanism is used to select a device configuration
based on the availability of drivers for the interfaces exposed in
each configuration.

For the case of RNDIS versus CDC-ECM, this mechanism will always
produce the correct result since RNDIS and CDC-ECM will not exist
within the same configuration and so each configuration will receive a
score based on the relevant driver.

This guarantee does not hold for the "usbio" driver, which will match
against any device.  It is a surprising coincidence that the "usbio"
driver seems to usually end up at the tail end of the USB drivers
list, thereby resulting in the expected behaviour.

Guarantee the expected behaviour by explicitly placing the "usbio"
driver at the end of the USB drivers list.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-13 15:56:38 +01:00
Michael Brown e30c26d01c [usb] Allow endpoints to be refilled to a specified upper limit
For USB mass storage devices, we do not want to submit more bulk IN
packets than are required for the inbound data, since this will waste
memory.

Allow an upper limit to be specified on each refill attempt.  The
endpoint will be refilled to the lower of this limit or the limit
specified by usb_refill_init().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-12 15:28:26 +01:00
Michael Brown ebf0166081 [usb] Allow device halt to be cleared independently of host controller
Closing and reopening a USB endpoint will clear any halt status
recorded by the host controller, but may leave the endpoint halted at
the device.  This will cause the first packet submitted to the
reopened endpoint to be lost, before the automatic stall recovery
mechanism detects the halt and resets the endpoint.

This is relatively harmless for USB network or HID devices, since the
wire protocols will recover gracefully from dropped packets.  Some
protocols (e.g. for USB mass storage devices) assume zero packet loss
and so would be adversely affected.

Fix by allowing any device endpoint halt status to be cleared on a
freshly opened endpoint.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-12 15:21:25 +01:00
Michael Brown c70b3e04e8 [efi] Always enable recursion when calling ConnectController()
There appears to be no reason for avoiding recursion when calling
ConnectController(), and recursion provides the least surprising
behaviour.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-02 00:36:33 +01:00
Michael Brown fbb5989fd9 [efi] Connect controllers after loading an EFI driver
iPXE is already capable of loading EFI drivers on demand (via
e.g. "chain UsbMassStorageDxe.efi") but there is currently no way to
trigger connection of the driver to any preexisting handles.

Add an explicit call to (re)connect all drivers after successfully
loading an image with a code type that indicates a boot services
driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-02 00:36:33 +01:00
Michael Brown eede697ece [ncm] Treat a zero divisor as indicating no alignment requirements
A zero divisor will currently lead to a 16-bit integer overflow when
calculating the transmit padding, and a potential division by zero if
assertions are enabled.

Avoid these problems by treating a divisor value of zero as equivalent
to a divisor value of one (i.e. no alignment requirements).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-02 00:04:26 +01:00
Michael Brown 0220141710 [efi] Fix reporting of USB supported languages array
The length as returned by UsbGetSupportedLanguages() should not
include the length of the descriptor header itself.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-01 23:27:53 +01:00
Michael Brown 02280dc642 [efi] Avoid integer underflow on malformed USB string descriptors
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-01 23:27:53 +01:00
Michael Brown 7c6fdf57ea [usb] Avoid integer underflow on malformed string descriptors
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-01 23:27:53 +01:00
Michael Brown 7151fa3ffa [efi] Allow DEBUG=efi_wrap to be used independently of a loaded image
Allow temporary debugging code to call efi_wrap_systab() to obtain a
pointer to the wrapper EFI system table.  This can then be used to
e.g. forcibly overwrite the boot services table pointer used by an
already loaded and running UEFI driver, in order to trace calls made
by that driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-01 15:44:05 +01:00
Michael Brown 8344803c93 [efi] Disconnect controllers before uninstalling EFI_USB_IO_PROTOCOL
The call to UninstallMultipleProtocolInterfaces() will implicitly
disconnect any relevant controllers, and there is no specified
requirement to explicitly call DisconnectController() prior to
callling UninstallMultipleProtocolInterfaces().

However, some UEFI implementations (observed with the USB keyboard
driver on a Microsoft Surface Go) will fail to implicitly disconnect
the controller and will consequently fail to uninstall the protocols.

The net effect is that unplugging and replugging a USB keyboard may
leave the keyboard in a non-functional state.

Work around these broken UEFI implementations by including an
unnecessary call to DisconnectController() before the call to
UninstallMultipleProtocolInterfaces().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-29 21:21:04 +01:00
Michael Brown 8eb19a178a [usb] Show debug message on device removal
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-29 14:39:54 +01:00
Michael Brown 627b0ba2a0 [efi] Report any USB errors as EFI_USB_ERR_SYSTEM
Some UEFI USB drivers (e.g. the UsbKbDxe driver in EDK2) will react to
a reported EFI_USB_ERR_STALL by attempting to clear the endpoint halt.
This is redundant with iPXE's EFI_USB_IO_PROTOCOL implementation,
since endpoint stalls are cleared automatically by the USB core as
needed.

The UEFI USB driver's attempt to clear the endpoint halt can introduce
an unwanted 5 second delay per endpoint if the USB error was the
result of a device being physically removed, since the control
transfer will always time out.

Fix by reporting all USB errors as EFI_USB_ERR_SYSTEM instead of
EFI_USB_ERR_STALL.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-29 14:32:57 +01:00
Michael Brown fbb776f2f2 [efi] Leave USB endpoint descriptors in existence until device is removed
Some UEFI USB drivers (observed with the keyboard driver on a
Microsoft Surface Go) will react to an asynchronous USB transfer
failure by terminating the transfer from within the completion
handler.  This closes the USB endpoint and, in the current
implementation, frees the containing structure.

This can lead to use-after-free bugs after the UEFI USB driver's
completion handler returns, since the calling code in iPXE expects
that a completion handler will not perform a control-flow action such
as terminating the transfer.

Fix by leaving the USB endpoint structure allocated until the device
is finally removed, as is already done (as an optimisation) for
control and bulk transfers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-29 14:26:54 +01:00
Michael Brown f42ba772c8 [usb] Reset control endpoints immediately after failure
The current error handling mechanism defers the endpoint reset until
the next use of the endpoint, on the basis that errors are detected
during completions and completion handling should not recursively call
usb_poll().

In the case of usb_control(), we are already at the level that calls
usb_poll() and can therefore safely perform the endpoint reset
immediately.  This has no impact on functionality, but does make
debugging traces easier to read since the reset will appear
immediately after the causative error.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-29 10:16:14 +01:00
Michael Brown 27e886c67b [efi] Use address offset as reported by EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
Retrieve the address windows and translation offsets for the
appropriate PCI root bridge and use them to adjust the PCI BAR address
prior to calling ioremap().

Originally-implemented-by: Pankaj Bansal <pankaj.bansal@nxp.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-25 14:20:18 +01:00
Michael Brown eecb75ba48 [pci] Update drivers to use pci_ioremap()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-25 14:17:07 +01:00
Michael Brown 371af4eef2 [pci] Define pci_ioremap() for mapping PCI bus addresses
Define pci_ioremap() as a wrapper around ioremap() that could allow
for a non-zero address translation offset.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-24 21:45:56 +01:00
Michael Brown ccfffc797a [efi] Provide a single implementation of efipci_root_close()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-24 21:45:56 +01:00
Michael Brown fe69934191 [efi] Show memory map returned by wrapped calls to GetMemoryMap
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-22 13:59:37 +01:00
Michael Brown e08ad61bf7 [efi] Add debug wrappers for all boot services functions of interest
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-18 23:16:46 +01:00
Michael Brown 4bd064de23 [build] Fix building on older versions of gcc
Older versions of gcc (observed with gcc 4.5.3) require attributes to
be specified on the first declaration of a symbol, and will silently
ignore attributes specified after the initial declaration.  This
causes the ASN.1 OID-identified algorithms to end up misaligned.

Fix by adding __asn1_algorithm to the initial declarations in asn1.h.

Debugged-by: Dentcho Bankov <dbankov@vmware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-08-23 17:52:41 +01:00
Michael Brown ef2c844d01 [efi] Attempt NII initialisation both with and without cable detection
We currently use a heuristic to determine whether or not to request
cable detection in PXE_OPCODE_INITIALIZE, based on the need to work
around a known Emulex driver bug (see commit c0b61ba "[efi] Work
around bugs in Emulex NII driver") and the need to accommodate links
that are legitimately slow to come up (see commit 6324227 "[efi] Skip
cable detection at initialisation where possible").

This heuristic appears to fail with newer Emulex drivers.  Attempt to
support all known drivers (past and present) by first attempting
initialisation with cable detection, then falling back to attempting
initialisation without cable detection.

Reported-by: Kwang Woo Lee <kwleeyh@gmail.com>
Tested-by: Kwang Woo Lee <kwleeyh@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-08-17 14:28:21 +01:00
Michael Brown c63e61df75 [efi] Use device path to locate filesystem from which we were loaded
The file:/ URI syntax may be used to refer to local files on the
filesystem from which the iPXE binary was loaded.  This is currently
implemented by directly using the DeviceHandle recorded in our
EFI_LOADED_IMAGE_PROTOCOL.

This mechanism will fail when a USB-enabled build of iPXE is loaded
from USB storage and subsequently installs its own USB host controller
drivers, since doing so will disconnect and reconnect the existing USB
storage drivers and thereby invalidate the original storage device
handle.

Fix by recording the device path for the loaded image's DeviceHandle
at initialisation time and later using the recorded device path to
locate the appropriate device handle.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-08-03 15:41:30 +01:00