A successful call to ExitBootServices() will result in the EFI console
becoming unusable. Ensure that the EFI wrapper produces a complete
line of debug output before calling the wrapped ExitBootServices()
method, and attempt subsequent debug output only if the call fails.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit cd3de55 ("[efi] Record cached DHCPACK from loaded image's
device handle, if present") added the ability for a chainloaded UEFI
iPXE to reuse an IPv4 address and DHCP options previously obtained by
a built-in PXE stack, without needing to perform a second DHCP
request.
Extend this to also record the cached ProxyDHCPOFFER and PXEBSACK
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 a boot filename or other
options that were provided via a ProxyDHCP or PXE boot server
mechanism, rather than by standard DHCP.
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The Ip4ConfigDxe driver bug that was observed on Dell systems in
commit 64b4452 ("[efi] Blacklist the Dell Ip4ConfigDxe driver") has
also been observed on systems with a manufacturer name of "Itautec
S.A.". The symptoms of the bug are identical: an attempt to call
DisconnectController() on the LOM device handle will lock up the
system.
Fix by extending the veto to cover the Ip4ConfigDxe driver for this
manufacturer.
Debugged-by: Celso Viana <celso.vianna@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide a file "initrd.magic" via the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
that contains the initrd file as constructed for BIOS bzImage kernels
(including injected files with CPIO headers constructed by iPXE).
This allows BIOS and UEFI kernels to obtain the exact same initramfs
image, by adding "initrd=initrd.magic" to the kernel command line.
For example:
#!ipxe
kernel boot/vmlinuz initrd=initrd.magic
initrd boot/initrd.img
initrd boot/modules/e1000.ko /lib/modules/e1000.ko
initrd boot/modules/af_packet.ko /lib/modules/af_packet.ko
boot
Do not include the "initrd.magic" file within the root directory
listing, since doing so would break software such as wimboot that
processes all files within the root directory.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Restructure the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL implementation to
allow for the existence of virtual files that are not simply backed by
a single underlying image.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EFI PCI API takes a page count as the input to AllocateBuffer()
but a byte count as the input to Map(). There is nothing in the UEFI
specification that requires us to map exactly the allocated length,
and no systems have yet been observed that will fail if the map length
does not exactly match the allocated length. However, it is plausible
that some implementations may fail if asked to map a length that does
not match the length of the corresponding allocation.
Avoid potential future problems by always mapping the full allocated
length.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The iPXE build system is constructed for a standalone codebase with no
external dependencies, and does not have any equivalent of the
standard userspace ./configure script. We currently check for the
ability to include slirp/libslirp.h and conditionalise portions of
linux_api.c on its presence. The actual slirp driver code is built
unconditionally, as with all iPXE drivers.
This currently leads to a silent runtime failure if attempting to use
slirp.linux built on a system that was missing slirp/libslirp.h.
Convert this to a link-time failure by deliberately omitting the
relevant symbols from linux_api.c when slirp/libslirp.h is not
present. This allows other builds (e.g. tap.linux or tests.linux) to
succeed: the link-time failure will occur only if the slirp driver is
included within the build target.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Linux kernel 3.12 and earlier report a zero size via stat() for all
ACPI table files in sysfs. There is no way to determine the file size
other than by reading the file until EOF.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
Versions of gcc prior to 9.1 do not support the single-argument form
of static_assert(). Fix by unconditionally defining a compatibility
macro for the single file that uses this.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
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>
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>
The code to detect the autoboot link-layer address and to load the
autoexec script currently runs before the call to initialise() and so
has to function without a working heap.
This requirement can be relaxed by deferring this code to run via an
initialisation function. This gives the code a normal runtime
environment, but still invokes it early enough to guarantee that the
original loaded image device handle has not yet been invalidated.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
The original EFI_SIMPLE_TEXT_INPUT_PROTOCOL is not technically
required to handle the use of the Ctrl key, and the long-obsolete EFI
1.10 specification lists only backspace, tab, linefeed, and carriage
return as required. Some particularly brain-dead vendor UEFI firmware
implementations dutifully put in the extra effort of ensuring that all
other control characters (such as Ctrl-C) are impossible to type via
EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
Current versions of the UEFI specification mandate that the console
input handle must support both EFI_SIMPLE_TEXT_INPUT_PROTOCOL and
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL, the latter of which at least
provides access to modifier key state.
Unlike EFI_SIMPLE_TEXT_INPUT_PROTOCOL, the pointer to the
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance does not appear within the
EFI system table and must therefore be opened explicitly. The UEFI
specification provides no safe way to do so, since we cannot open the
handle BY_DRIVER or BY_CHILD_CONTROLLER and so nothing guarantees that
this pointer will remain valid for the lifetime of iPXE. We must
simply hope that no UEFI firmware implementation ever discovers a
motivation for reinstalling the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
instance.
Use EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL if available, falling back to
the existing EFI_SIMPLE_TEXT_PROTOCOL otherwise.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
Some UEFI device drivers will react to an asynchronous USB transfer
failure by dubiously terminating the scheduled transfer from within
the completion handler.
We already have code from commit fbb776f ("[efi] Leave USB endpoint
descriptors in existence until device is removed") that avoids freeing
memory in this situation, in order to avoid use-after-free bugs. This
is not sufficient to avoid potential problems, since with an xHCI
controller the act of closing the endpoint requires issuing a command
and awaiting completion via the event ring, which may in turn dispatch
further USB transfer completion events.
Avoid these problems by leaving the USB endpoint open (but with the
refill timer stopped) until the device is finally removed, as is
already done for control and bulk transfers.
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>
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>
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>
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>
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>
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>
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>
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 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
The length as returned by UsbGetSupportedLanguages() should not
include the length of the descriptor header itself.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
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>
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>
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>
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>
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>
The various USB specifications all use one-based numbering for ports.
This scheme is applied consistently across the various relevant
specifications, covering both port numbers that appear on the wire
(i.e. downstream hub port numbers) and port numbers that exist only
logically (i.e. root hub port numbers).
The UEFI specification is ambiguous about the port numbers as used for
the ParentPortNumber field within a USB_DEVICE_PATH structure. As of
UEFI specification version 2.8 errata B:
- section 10.3.4.5 just states "USB Parent Port Number" with no
indication of being zero-based or one-based
- section 17.1.1 notes that for the EFI_USB2_HC_PROTOCOL, references
to PortNumber parameters are zero-based for root hub ports
- section 17.1.1 also mentions a TranslatorPortNumber used by
EFI_USB2_HC_PROTOCOL, with no indication of being zero-based or
one-based
- there are no other mentions of USB port numbering schemes.
Experimentation and inspection of the EDK2 codebase reveals that at
least the EDK2 reference implementation will use zero-based numbering
for both root and non-root hub ports when populating a USB_DEVICE_PATH
structure (though will inconsistently use one-based numbering for the
TranslatorPortNumber parameter).
Use zero-based numbering for both root and non-root hub ports when
constructing a USB_DEVICE_PATH in order to match the behaviour of the
EDK2 implementation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
According to the latest UEFI specification (Version 2.8 Errata B)
p. 7.2:
"Buffer: A pointer to a pointer to the allocated buffer if the call
succeeds; undefined otherwise."
So implementations are obliged neither to return NULL, if the
allocation fails, nor to preserve the contents of the pointer.
Make the logic more reliable by checking the status code from
AllocatePool() instead of checking the returned pointer for NULL
Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Claiming the SNP devices has the side effect of raising the TPL to
iPXE's normal operating level of TPL_CALLBACK (see the commit message
for c89a446 ("[efi] Run at TPL_CALLBACK to protect against UEFI
timers") for details). This must happen before executing any code
that relies upon the TPL having been raised to TPL_CALLBACK.
The call to efi_snp_claim() in efi_download_start() currently happens
only after the call to xfer_open(). Calling xfer_open() will
typically result in a retry timer being started, which will result in
a call to currticks() in order to initialise the timer. The call to
currticks() will drop to TPL_APPLICATION and restore to TPL_CALLBACK
in order to allow a timer tick to occur. Since this call happened
before the call to efi_snp_claim(), the restored TPL is incorrect.
This in turn results in efi_snp_claim() recording the incorrect
original TPL, causing efi_snp_release() to eventually restore the
incorrect TPL, causing the system to lock up when ExitBootServices()
is called at TPL_CALLBACK.
Fix by moving the call to efi_snp_claim() to the start of
efi_download_start().
Debugged-by: Jarrod Johnson <jjohnson2@lenovo.com>
Debugged-by: He He4 Huang <huanghe4@lenovo.com>
Debugged-by: James Wang <jameswang@ami.com.tw>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The NUL byte included within the stack cookie to act as a string
terminator should be placed at the lowest byte address within the
stack cookie, in order to avoid potentially including the stack cookie
value within an accidentally unterminated string.
Suggested-by: Pete Beck <pete.beck@ioactive.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Several of the values used to compute a stack cookie (in the absence
of a viable entropy source) will tend to have either all-zeroes or
all-ones in the higher order bits. Rotate the values in order to
distribute the (minimal) available entropy more evenly.
Suggested-by: Pete Beck <pete.beck@ioactive.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
As per commit c89a446 ("[efi] Run at TPL_CALLBACK to protect against
UEFI timers") we expect to run at TPL_CALLBACK almost all of the time.
Various code paths rely on this assumption. Code paths that need to
temporarily lower the TPL (e.g. for entropy gathering) will restore it
to TPL_CALLBACK.
The entropy gathering code will be run during DRBG initialisation,
which happens during the call to startup(). In the case of iPXE
compiled as an EFI application this code will run within the scope of
efi_snp_claim() and so will execute at TPL_CALLBACK as expected.
In the case of iPXE compiled as an EFI driver the code will
incorrectly run at TPL_APPLICATION since there is nothing within the
EFI driver entry point that raises (and restores) the TPL. The net
effect is that a build that includes the entropy-gathering code
(e.g. a build with HTTPS enabled) will return from the driver entry
point at TPL_CALLBACK, which causes a system lockup.
Fix by raising and restoring the TPL within the EFI driver entry
point.
Debugged-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EFI_RNG_PROTOCOL on the Microsoft Surface Go does not generate
random numbers. Successive calls to GetRNG() without any intervening
I/O operations (such as writing to the console) will produce identical
results. Successive reboots will produce identical results.
It is unclear what the Microsoft Surface Go is attempting to use as an
entropy source, but it is demonstrably producing zero bits of entropy.
The failure is already detected by the ANS-mandated Repetition Count
Test performed as part of our GetEntropy implementation. This
currently results in the entropy source being marked as broken, with
the result that iPXE refuses to perform any operations that require a
working entropy source.
We cannot use the existing EFI driver blacklisting mechanism to unload
the broken driver, since the RngDxe driver is integrated into the
DxeCore image.
Work around the broken driver by checking for consecutive identical
results returned by EFI_RNG_PROTOCOL and falling back to the original
timer-based entropy source.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Enable -fstack-protector for EFI builds, where binary size is less
critical than for BIOS builds.
The stack cookie must be constructed immediately on entry, which
prohibits the use of any viable entropy source. Construct a cookie by
XORing together various mildly random quantities to produce a value
that will at least not be identical on each run.
On detecting a stack corruption, attempt to call Exit() with an
appropriate error. If that fails, then lock up the machine since
there is no other safe action that can be taken.
The old conditional check for support of -fno-stack-protector is
omitted since this flag dates back to GCC 4.1.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some platforms (observed with an AMI BIOS on an Apollo Lake system)
will spuriously fail the call to ConnectController() when the UEFI
network stack is disabled. This appears to be a BIOS bug that also
affects attempts to connect any non-iPXE driver to the NIC controller
handle via the UEFI shell "connect" utility.
Work around this BIOS bug by falling back to calling our
efi_driver_start() directly if the call to ConnectController() fails.
This bypasses any BIOS policy in terms of deciding which driver to
connect but still cooperates with the UEFI driver model in terms of
handle ownership, since the use of EFI_OPEN_PROTOCOL_BY_DRIVER ensures
that the BIOS is aware of our ownership claim.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
As described in the previous commit, work around a UEFI specification
bug that necessitates calling UnloadImage if the return value from
LoadImage is EFI_SECURITY_VIOLATION.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Use '%p' directive, and print handle's address if the address is null
and the handle doesn't have a name. This fixes the following
compilation error:
interface/efi/efi_debug.c:334:3: error: '%s' directive
argument is null [-Werror=format-overflow=]
Signed-off-by: Valentine Barshak <gvaxon@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
efidev_parent() currently assumes that any device with BUS_TYPE_EFI is
part of a struct efi_device. This assumption is not valid, since the
code in efi_device_info() may also create a device with BUS_TYPE_EFI.
Fix by searching through the list of registered EFI devices when
looking for a match, instead of relying on the bus type value.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On a Dell OptiPlex 7010, calling DisconnectController() on the LOM
device handle will lock up the system. Debugging shows that execution
is trapped in an infinite loop that is somehow trying to reconnect
drivers (without going via ConnectController()).
The problem can be reproduced in the UEFI shell with no iPXE code
present, by using the "disconnect" command. Experimentation shows
that the only fix is to unload (rather than just disconnect) the
"Ip4ConfigDxe" driver.
Add the concept of a blacklist of UEFI drivers that will be
automatically unloaded when iPXE runs as an application, and add the
Dell Ip4ConfigDxe driver to this blacklist.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Current (simplified):
1. InstallMultipleProtocolInterfaces
if err goto err_install_protocol_interface;
2. OpenProtocol(efi_nii_protocol_guid)
if err goto err_open_nii;
3. OpenProtocol(efi_nii31_protocol_guid)
if err goto err_open_nii31;
4. efi_child_add
if err goto err_efi_child_add;
...
err_efi_child_add:
CloseProtocol(efi_nii_protocol_guid) <= should be efi_nii31_protocol_guid
err_open_nii: <= should be err_open_nii31
CloseProtocol(efi_nii31_protocol_guid) <= should be efi_nii_protocol_guid
err_open_nii31: <= should be err_open_nii
UninstallMultipleProtocolInterfaces
Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The definition of version_response channel message in Linux doesn't
include version field, so the upcoming VMBus implementation in QEMU
doesn't set it either. Neither Windows nor Linux had any problem with
this.
The check against this field is redundant because the message is the
response to initiate_contact message containing the specific version
requested, so the response with version_supported=true is unambiguous.
Drop this check and don't rely on the field to be present in the
message.
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When booting some versions of the UEFI shell, our driver binding
protocol's Supported() entry point is called at TPL_NOTIFY for no
discernible reason. Attempting to raise to TPL_CALLBACK triggers an
immediate assertion failure in the firmware.
Since our Supported() method can run at any TPL, fix by simply not
attempting to raise the TPL within this method.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Release SNP devices to allow the SAN booted image to use our
EFI_SIMPLE_NETWORK_PROTOCOL instance, and to ensure that the image is
started at TPL_APPLICATION.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit c89a446 ("[efi] Run at TPL_CALLBACK to protect against UEFI
timers") introduced a regression in the EFI entropy gathering code.
When the EFI_RNG_PROTOCOL is not present, we fall back to using timer
interrupts (as for the BIOS build). Since timer interrupts are
disabled at TPL_CALLBACK, WaitForEvent() fails and no entropy can be
gathered.
Fix by dropping to TPL_APPLICATION while entropy gathering is enabled.
Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
As noted in the comments, UEFI manages to combines the all of the
worst aspects of both a polling design (inefficiency and inability to
sleep until something interesting happens) and of an interrupt-driven
design (the complexity of code that could be preempted at any time,
thanks to UEFI timers).
This causes problems in particular for UEFI USB keyboards: the
keyboard driver calls UsbAsyncInterruptTransfer() to set up a periodic
timer which is used to poll the USB bus. This poll may interrupt a
critical section within iPXE, typically resulting in list corruption
and either a hang or reboot.
Work around this problem by mirroring the BIOS design, in which we run
with interrupts disabled almost all of the time.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Xen 4.4 includes the device "device/suspend/event-channel" which does
not have a "backend" key. This currently causes the entire XenBus
device tree probe to fail.
Fix by skipping probe attempts for device types for which there is no
iPXE driver.
Debugged-by: Eytan Heidingsfeld <eytanh@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some HP BIOSes (observed with a Z840) seem to attempt to connect our
drivers in the middle of our call to DisconnectController(). The
precise chain of events is unclear, but the symptom is that we see
several calls to our Supported() and Start() methods, followed by a
system lock-up.
Work around this dubious BIOS behaviour by explicitly failing calls to
our Start() method while we are in the middle of attempting to
disconnect drivers.
Reported-by: Jordan Wright <jordan.m.wright@disney.com>
Debugged-by: Adrian Lucrèce Céleste <adrianlucrececeleste@airmail.cc>
Debugged-by: Christian Nilsson <nikize@gmail.com>
Tested-by: Jordan Wright <jordan.m.wright@disney.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI BIOSes will deliberately break the implementation of
ConnectController() to return errors for devices that have been
"disabled" via the BIOS setup screen. (As an added bonus, such BIOSes
may return garbage EFI_STATUS values such as 0xff.)
Work around these broken UEFI BIOSes by ignoring failures and
continuing to attempt to connect any remaining handles.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The UEFI specification does not state whether or not a return value of
EFI_BUFFER_TOO_SMALL from the SNP Receive() method should follow the
usual EFI API behaviour of allowing the caller to retry the request
with an increased buffer size.
Examination of the SnpDxe driver in EDK2 suggests that Receive() will
just return the truncated packet (complete with any requested
link-layer header fields), so match this behaviour.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We do not currently check the length of the caller's buffer for
received packets. This creates a potential buffer overrun when iPXE
is being used via the SNP or UNDI protocols.
Fix by checking the buffer length and correctly returning the required
length and an EFI_BUFFER_TOO_SMALL error.
Reported-by: Paul McMillan <paul.mcmillan@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Ensure that efi_systab is an undefined symbol in non-EFI builds. In
particular, this prevents users from incorrectly enabling IMAGE_EFI in
a BIOS build of iPXE.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Use the PCI bus:dev.fn address in debug messages, falling back to the
EFI handle name only if we do not yet have enough information to
determine the bus:dev.fn address.
Include the vendor and device IDs in debug messages when no suitable
driver is found, to match the diagnostics available in a BIOS
environment.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
An "enlightened" external bootloader (such as Windows Server 2016's
winload.exe) may take ownership of the Hyper-V connection before all
INT 13 operations have been completed. When this happens, all VMBus
devices are implicitly closed and we are left with a non-functional
network connection.
Detect when our Hyper-V connection has been lost (by checking the
SynIC message page MSR). Reclaim ownership of the Hyper-V connection
and reestablish any VMBus devices, without disrupting any existing
iPXE state (such as IPv4 settings attached to the network device).
Windows Server 2016 will not cleanly take ownership of an active
Hyper-V connection. Experimentation shows that we can quiesce by
resetting only the SynIC message page MSR; this results in a
successful SAN boot (on a Windows 2012 R2 physical host). Choose to
quiesce by resetting (almost) all MSRs, in the hope that this will be
more robust against corner cases such as a stray synthetic interrupt
occurring during the handover.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some older operating systems (e.g. RHEL6) use a non-default filename
on the root disk and rely on setting an EFI variable to point to the
bootloader. This does not work when performing a SAN boot on a
machine where the EFI variable is not present.
Fix by allowing a non-default filename to be specified via the
"sanboot --filename" option or the "san-filename" setting. For
example:
sanboot --filename \efi\redhat\grub.efi \
iscsi:192.168.0.1::::iqn.2010-04.org.ipxe.demo:rhel6
or
option ipxe.san-filename code 188 = string;
option ipxe.san-filename "\\efi\\redhat\\grub.efi";
option root-path "iscsi:192.168.0.1::::iqn.2010-04.org.ipxe.demo:rhel6";
Originally-implemented-by: Vishvananda Ishaya Abrams <vish.ishaya@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Describe all SAN devices via ACPI tables such as the iBFT. For tables
that can describe only a single device (i.e. the aBFT and sBFT), one
table is installed per device. For multi-device tables (i.e. the
iBFT), all devices are described in a single table.
An underlying SAN device connection may be closed at the time that we
need to construct an ACPI table. We therefore introduce the concept
of an "ACPI descriptor" which enables the SAN boot code to maintain an
opaque pointer to the underlying object, and an "ACPI model" which can
build tables from a list of such descriptors. This separates the
lifecycles of ACPI descriptions from the lifecycles of the block
device interfaces, and allows for construction of the ACPI tables even
if the block device interface has been closed.
For a multipath SAN device, iPXE will wait until sufficient
information is available to describe all devices but will not wait for
all paths to connect successfully. For example: with a multipath
iSCSI boot iPXE will wait until at least one path has become available
and name resolution has completed on all other paths. We do this
since the iBFT has to include IP addresses rather than DNS names. We
will commence booting without waiting for the inactive paths to either
become available or close; this avoids unnecessary boot delays.
Note that the Linux kernel will refuse to accept an iBFT with more
than two NIC or target structures. We therefore describe only the
NICs that are actually required in order to reach the described
targets. Any iBFT with at most two targets is therefore guaranteed to
describe at most two NICs.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Add basic support for multipath block devices. The "sanboot" and
"sanhook" commands now accept a list of SAN URIs. We open all URIs
concurrently. The first connection to become available for issuing
block device commands is marked as the active path and used for all
subsequent commands; all other connections are then closed. Whenever
the active path fails, we reopen all URIs and repeat the process.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Our asprintf() implementation guarantees that strp will be NULL on
allocation failure, but this is not standard behaviour. Detect errors
by checking for a negative return value instead of a NULL pointer.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide a basic proof of concept ACPI table description (e.g. iBFT for
iSCSI) for SAN devices in a UEFI environment, using a control flow
that is functionally identical to that used in a BIOS environment.
Originally-implemented-by: Vishvananda Ishaya Abrams <vish.ishaya@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The concept of the SAN drive number is meaningful only in a BIOS
environment, where it represents the INT13 drive number (0x80 for the
first hard disk). We retain this concept in a UEFI environment to
allow for a simple way for iPXE commands to refer to SAN drives.
Centralise the concept of the default drive number, since it is shared
between all supported environments.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow the active timer (providing udelay() and currticks()) to be
selected at runtime based on probing during the INIT_EARLY stage of
initialisation.
TICKS_PER_SEC is now a fixed compile-time constant for all builds, and
is independent of the underlying clock tick rate. We choose the value
1024 to allow multiplications and divisions on seconds to be converted
to bit shifts.
TICKS_PER_MS is defined as 1, allowing multiplications and divisions
on milliseconds to be omitted entirely. The 2% inaccuracy in this
definition is negligible when using the standard BIOS timer (running
at around 18.2Hz).
TIMER_RDTSC now checks for a constant TSC before claiming to be a
usable timer. (This timer can be tested in KVM via the command-line
option "-cpu host,+invtsc".)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
In some high-end Azure instances (e.g. NC6) we may receive an
unsolicited VMBUS_OFFER_CHANNEL message for a PCIe pass-through device
some time after completing the bus enumeration. This currently causes
apparently random failures due to unexpected VMBus message types.
Fix by ignoring any unsolicited VMBus messages.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
EFI provides no clean way for device drivers to shut down in
preparation for handover to a booted operating system. The platform
firmware simply doesn't bother to call the drivers' Stop() methods.
Instead, drivers must register an EVT_SIGNAL_EXIT_BOOT_SERVICES event
to be signalled when ExitBootServices() is called, and clean up
without any reference to the EFI driver model.
Unfortunately, all timers silently stop working when ExitBootServices()
is called. Even more unfortunately, and for no discernible reason,
this happens before any EVT_SIGNAL_EXIT_BOOT_SERVICES events are
signalled. The net effect of this entertaining design choice is that
any timeout loops on the shutdown path (e.g. for gracefully closing
outstanding TCP connections) may wait indefinitely.
There is no way to report failure from currticks(), since the API
lazily assumes that the host system continues to travel through time
in the usual direction. Work around EFI's violation of this
assumption by falling back to a simple free-running monotonic counter.
Debugged-by: Maor Dickman <maord@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The Windows drivers for VMBus devices are enumerated using the
instance UUID rather than the channel number. Include the instance
UUID within the iPXE device name to allow an iPXE network device to be
more easily associated with the corresponding Windows network device
when debugging.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
In edk2, there are several drivers that associate HII forms (and
corresponding config access protocol instances) with each individual
network device. (In this context, "network device" means the EFI
handle on which the SNP protocol is installed, and on which the device
path ending with the MAC() node is installed also.) Such edk2 drivers
are, for example: Ip4Dxe, HttpBootDxe, VlanConfigDxe.
In UEFI, any given handle can carry at most one instance of a specific
protocol (see e.g. the specification of the InstallProtocolInterface()
boot service). This implies that the class of drivers mentioned above
can't install their EFI_HII_CONFIG_ACCESS_PROTOCOL instances on the
SNP handle directly -- they would conflict with each other.
Accordingly, each of those edk2 drivers creates a "private" child
handle under the SNP handle, and installs its config access protocol
(and corresponding HII package list) on its child handle.
The device path for the child handle is traditionally derived by
appending a Hardware Vendor Device Path node after the MAC() node.
The VenHw() nodes in question consist of a GUID (by definition), and
no trailing data (by choice). The purpose of these VenHw() nodes is
only that all the child nodes can be uniquely identified by device
path.
At the moment iPXE does not follow this pattern. It doesn't run into
a conflict when it installs its EFI_HII_CONFIG_ACCESS_PROTOCOL
directly on the SNP handle, but that's only because iPXE is the sole
driver not following the pattern. This behavior seems risky (one
might call it a "latent bug"); better align iPXE with the edk2 custom.
Cc: Michael Brown <mcb30@ipxe.org>
Cc: Gary Lin <glin@suse.com>
Cc: Ladi Prosek <lprosek@redhat.com>
Ref: http://thread.gmane.org/gmane.comp.bios.edk2.devel/13494/focus=13532
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ladi Prosek <lprosek@redhat.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The HII IFR structures are allocated via realloc() rather than
zalloc(), and so are not automatically zeroed. This results in the
presence of uninitialised and invalid data, causing crashes elsewhere
in the UEFI firmware.
Fix by explicitly zeroing the newly allocated portion of any IFR
structure in efi_ifr_op().
Debugged-by: Laszlo Ersek <lersek@redhat.com>
Debugged-by: Gary Lin <glin@suse.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The SNP device path includes the network device's MAC address within
the MAC_ADDR_DEVICE_PATH.MacAddress field. We check that the
link-layer address will fit within this field, and then perform the
copy using the length of the destination buffer.
At 32 bytes, the MacAddress field is actually larger than the current
maximum iPXE link-layer address. The copy therefore overflows the
source buffer, resulting in trailing garbage bytes being appended to
the device path's MacAddress. This is invisible in debug messages,
since the DevicePathToText protocol will render only the length
implied by the interface type.
Fix by copying only the actual length of the link-layer address (which
we have already verified will not overflow the destination buffer).
Debugged-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Extend the 16-bit PCI bus:dev.fn address to a 32-bit seg🚌dev.fn
address, assuming a segment value of zero in contexts where multiple
segments are unsupported by the underlying data structures (e.g. in
the iBFT or BOFM tables).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Mac OS X uses non-standard EFI protocols to obtain the DHCP packets
from the UEFI firmware.
Originally-implemented-by: Michael Kuron <m.kuron@gmx.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently use the EFI_CPU_ARCH_PROTOCOL's GetTimerValue() method to
generate the currticks() timer, calibrated against a 1ms delay from
the boot services Stall() method.
This does not work on ARM platforms, where GetTimerValue() is an empty
stub which just returns EFI_UNSUPPORTED.
Fix by instead creating a periodic timer event, and using this event
to increment a current tick counter.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EFI_HII_CONFIG_ACCESS_PROTOCOL's ExtractConfig() method is passed
a request string which includes the parameters being queried plus an
apparently meaningless blob of information (the ConfigHdr), and is
expected to include this same meaningless blob of information in the
results string.
Neither the specification nor the existing EDK2 code (including the
nominal reference implementation in the DriverSampleDxe driver)
provide any reason for the existence of this meaningless blob of
information. It appears to be consumed in its entirety by the
EFI_HII_CONFIG_ROUTING_PROTOCOL, and to contain zero bits of
information by the time it reaches an EFI_HII_CONFIG_ACCESS_PROTOCOL
instance. It would potentially allow for multiple configuration data
sets to be handled by a single EFI_HII_CONFIG_ACCESS_PROTOCOL
instance, in a style alien to the rest of the UEFI specification
(which implicitly assumes that the instance pointer is always
sufficient to uniquely identify the instance).
iPXE currently handles this by simply copying the ConfigHdr from the
request string to the results string, and otherwise ignoring it. This
approach is also used by some code in EDK2, such as OVMF's PlatformDxe
driver.
As of EDK2 commit 8a45f80 ("MdeModulePkg: Make HII configuration
settings available to OS runtime"), this causes an assertion failure
inside EDK2. The failure arises when iPXE is handled a NULL request
string, and responds (as per the specification) with a results string
including all settings. Since there is no meaningless blob to copy
from the request string, there is no corresponding meaningless blob in
the results string. This now causes an assertion failure in
HiiDatabaseDxe's HiiConfigRoutingExportConfig().
The same failure does not affect the OVMF PlatformDxe driver, which
simply passes the request string to the HII BlockToConfig() utility
function. The BlockToConfig() function returns EFI_INVALID_PARAMETER
when passed a null request string, and PlatformDxe propagates this
error directly to the caller.
Fix by matching the behaviour of OVMF's PlatformDxe driver: explicitly
return EFI_INVALID_PARAMETER if the request string is NULL or empty.
This violates the specification (insofar as it is feasible to
determine what the specification actually requires), but causes
correct behaviour with the EDK2 codebase.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide access to local files via the "file://" URI scheme. There are
three syntaxes:
- An opaque URI with a relative path (e.g. "file:script.ipxe").
This will be interpreted as a path relative to the iPXE binary.
- A hierarchical URI with a non-network absolute path
(e.g. "file:/boot/script.ipxe"). This will be interpreted as a
path relative to the root of the filesystem from which the iPXE
binary was loaded.
- A hierarchical URI with a network path in which the authority is a
volume label (e.g. "file://bootdisk/script.ipxe"). This will be
interpreted as a path relative to the root of the filesystem with
the specified volume label.
Note that the potentially desirable shell mappings (e.g. "fs0:" and
"blk0:") are concepts internal to the UEFI shell binary, and do not
seem to be exposed in any way to external executables. The old
EFI_SHELL_PROTOCOL (which did provide access to these mappings) is no
longer installed by current versions of the UEFI shell.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Several UEFI platforms are known to return EFI_NOT_FOUND when asked to
retrieve the system default font information via GetFontInfo(). Work
around these broken platforms by iterating over the glyphs to find the
maximum height used by a printable character.
Originally-fixed-by: Jonathan Dieter <jdieter@lesbg.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>