Michael Brown [Mon, 20 Oct 2025 11:35:36 +0000 (12:35 +0100)]
[cloud] Display build architecture in AWS EC2
On some newer (7th and 8th generation) instance types, the 32-bit
build of iPXE cannot access PCI configuration space since the ECAM is
placed outside of the 32-bit address space. The visible symptom is
that iPXE fails to detect any network devices.
The public AMIs are all now built as 64-bit binaries, but there is
nothing that prevents the building and importing of a 32-bit AMI.
There are still potentially valid use cases for 32-bit AMIs (e.g. if
planning to use the AMI only for older instance types), and so we
cannot sensibly prevent this error at build time.
Display the build architecture as part of the AWS EC2 embedded script,
to at least allow for easy identification of this particular failure
mode at run time.
Michael Brown [Fri, 17 Oct 2025 11:35:11 +0000 (12:35 +0100)]
[ena] Limit receive queue size to work around hardware bugs
Commit a801244 ("[ena] Increase receive ring size to 128 entries")
increased the receive ring size to 128 entries (while leaving the fill
level at 16), since using a smaller receive ring caused unexplained
failures on some instance types.
The original hardware bug that resulted in that commit seems to have
been fixed: experiments suggest that the original failure (observed on
a c6i.large instance in eu-west-2) will no longer reproduce when using
a receive ring containing only 16 entries (as was the case prior to
that commit).
Newer generations of the ENA hardware (observed on an m8i.large
instance in eu-south-2) seem to have a new and exciting hardware bug:
these instance types appear to use a hash of the received packet
header to determine which portion of the (out-of-order) receive ring
to use. If that portion of the ring happens to be empty (e.g. because
only 32 entries of the 128-entry ring are filled at any one time),
then the packet will be silently dropped.
Work around this new hardware bug by reducing the receive ring size
down to the current fill level of 32 entries. This appears to work on
all current instance types (but has not been exhaustively tested).
Michael Brown [Thu, 16 Oct 2025 15:33:38 +0000 (16:33 +0100)]
[ena] Increase receive fill level
Experiments suggest that at least some instance types (observed with
c6i.large in eu-west-2) experience high packet drop rates with only 16
receive buffers allocated. Increase the fill level to 32 buffers.
Michael Brown [Thu, 16 Oct 2025 14:58:23 +0000 (15:58 +0100)]
[ena] Add support for low latency transmit queues
Newer generations of the ENA hardware require the use of low latency
transmit queues, where the submission queues and the initial portion
of the transmitted packet are written to on-device memory via BAR2
instead of being read from host memory.
Detect support for low latency queues and set the placement policy
appropriately. We attempt the use of low latency queues only if the
device reports that it supports inline headers, 128-byte entries, and
two descriptors prior to the inlined header, on the basis that we
don't care about using low latency queues on older versions of the
hardware since those versions will support normal host memory
submission queues anyway.
We reuse the redundant memory allocated for the submission queue as
the bounce buffer for constructing the descriptors and inlined packet
data, since this avoids needing a separate allocation just for the
bounce buffer.
We construct a metadata submission queue entry prior to the actual
submission queue entry, since experimentation suggests that newer
generations of the hardware require this to be present even though it
conveys no information beyond its own existence.
Michael Brown [Wed, 15 Oct 2025 14:27:03 +0000 (15:27 +0100)]
[ena] Map the on-device memory, if present
Newer generations of the ENA hardware require the use of low latency
transmit queues, where the submission queues and the initial portion
of the transmitted packet are written to on-device memory via BAR2
instead of being read from host memory.
Prepare for this by mapping the on-device memory BAR. As with the
register BAR, we may need to steal a base address from the upstream
PCI bridge since the BIOS on some instance types (observed with an
m8i.metal-48xl instance in eu-south-2) will fail to assign an address
to the device.
Michael Brown [Tue, 14 Oct 2025 13:44:56 +0000 (14:44 +0100)]
[ena] Use pci_bar_set() to place device within bridge memory window
Use pci_bar_set() when we need to set a device base address (on
instance types such as c6i.metal where the BIOS fails to do so), so
that 64-bit BARs will be handled automatically.
This particular issue has so far been observed only on 6th generation
instances. These use 32-bit BARs, and so the lack of support for
handling 64-bit BARs has not caused any observable issue.
Michael Brown [Tue, 14 Oct 2025 12:46:54 +0000 (13:46 +0100)]
[pci] Handle sizing of 64-bit BARs
Provide pci_bar_set() to handle setting the base address for a
potentially 64-bit BAR, and rewrite pci_bar_size() to correctly handle
sizing of 64-bit BARs.
Michael Brown [Sun, 12 Oct 2025 21:37:49 +0000 (22:37 +0100)]
[tls] Disable renegotiation unless extended master secret is used
RFC 7627 states that renegotiation becomes no longer secure under
various circumstances when the non-extended master secret is used.
The description of the precise set of circumstances is spread across
various points within the document and is not entirely clear.
Avoid a superset of the circumstances in which renegotiation
apparently becomes insecure by refusing renegotiation completely
unless the extended master secret is used.
Michael Brown [Sun, 12 Oct 2025 21:29:33 +0000 (22:29 +0100)]
[tls] Refuse to resume sessions with mismatched master secret methods
RFC 7627 section 5.3 states that the client must abort the handshake
if the server attempts to resume a session where the master secret
calculation method stored in the session does not match the method
used for the connection being resumed.
Michael Brown [Sun, 12 Oct 2025 21:26:49 +0000 (22:26 +0100)]
[tls] Add support for the Extended Master Secret
RFC 7627 defines the Extended Master Secret (EMS) as an alternative
calculation that uses the digest of all handshake messages rather than
just the client and server random bytes.
Add support for negotiating the Extended Master Secret extension and
performing the relevant calculation of the master secret.
Michael Brown [Sun, 12 Oct 2025 21:20:13 +0000 (22:20 +0100)]
[tls] Generate master secret only after sending Client Key Exchange
The calculation for the extended master secret as defined in RFC 7627
relies upon the digest of all handshake messages up to and including
the Client Key Exchange.
Facilitate this calculation by generating the master secret only after
sending the Client Key Exchange message.
Michael Brown [Fri, 10 Oct 2025 12:07:05 +0000 (13:07 +0100)]
[gve] Rearm interrupts unconditionally on every poll
Experimentation suggests that rearming the interrupt once per observed
completion is not sufficient: we still see occasional delays during
which the hardware fails to write out completions.
As described in commit d2e1e59 ("[gve] Use dummy interrupt to trigger
completion writeback in DQO mode"), there is no documentation around
the precise semantics of the interrupt rearming mechanism, and so
experimentation is the only available guide. Switch to rearming both
TX and RX interrupts unconditionally on every poll, since this
produces better experimental results.
Michael Brown [Fri, 10 Oct 2025 11:44:01 +0000 (12:44 +0100)]
[gve] Use raw DMA addresses in descriptors in DQO-QPL mode
The DQO-QPL operating mode uses registered queue page lists but still
requires the raw DMA address (rather than the linear offset within the
QPL) to be provided in transmit and receive descriptors.
Set the queue page list base device address appropriately.
Michael Brown [Thu, 9 Oct 2025 16:25:25 +0000 (17:25 +0100)]
[gve] Report only packet completions for the transmit ring
The hardware reports descriptor and packet completions separately for
the transmit ring. We currently ignore descriptor completions (since
we cannot free up the transmit buffers in the queue page list and
advance the consumer counter until the packet has also completed).
Now that transmit completions are written out immediately (instead of
being delayed until 128 bytes of completions are available), there is
no value in retaining the descriptor completions.
Omit descriptor completions entirely, and reduce the transmit fill
level back down to its original value.
Michael Brown [Thu, 9 Oct 2025 16:12:20 +0000 (17:12 +0100)]
[gve] Use dummy interrupt to trigger completion writeback in DQO mode
When operating in the DQO operating mode, the device will defer
writing transmit and receive completions until an entire internal
cacheline (128 bytes) is full, or until an associated interrupt is
asserted. Since each receive descriptor is 32 bytes, this will cause
received packets to be effectively delayed until up to three further
packets have arrived. When network traffic volumes are very low (such
as during DHCP, DNS lookups, or TCP handshakes), this typically
induces delays of up to 30 seconds and results in a very poor user
experience.
Work around this hardware problem in the same way as for the Intel
40GbE and 100GbE NICs: by enabling dummy MSI-X interrupts to trick the
hardware into believing that it needs to write out completions to host
memory.
There is no documentation around the interrupt rearming mechanism.
The value written to the interrupt doorbell does not include a
consumer counter value, and so must be relying on some undocumented
ordering constraints. Comments in the Linux driver source suggest
that the authors believe that the device will automatically and
atomically mask an MSI-X interrupt at the point of asserting it, that
any further interrupts arriving before the doorbell is written will be
recorded in the pending bit array, and that writing the doorbell will
therefore immediately assert a new interrupt if needed.
In the absence of any documentation, choose to rearm the interrupt
once per observed completion. This is overkill, but is less impactful
than the alternative of rearming the interrupt unconditionally on
every poll.
Michael Brown [Thu, 9 Oct 2025 15:01:51 +0000 (16:01 +0100)]
[pci] Map all MSI-X interrupts to a dummy target address by default
Interrupts as such are not used in iPXE, which operates in polling
mode. However, some network cards (such as the Intel 40GbE and 100GbE
NICs) will defer writing out completions until the point of asserting
an MSI-X interrupt.
From the point of view of the PCI device, asserting an MSI-X interrupt
is just a 32-bit DMA write of an opaque value to an opaque target
address. The PCI device has no know to know whether or not the target
address corresponds to a real APIC.
We can therefore trick the PCI device into believing that it is
asserting an MSI-X interrupt, by configuring it to write an opaque
32-bit value to a dummy target address in host memory. This is
sufficient to trigger the associated write of the completions to host
memory.
Allocate a dummy target address when enabling MSI-X on a PCI device,
and map all interrupts to this target address by default.
Michael Brown [Mon, 6 Oct 2025 13:04:18 +0000 (14:04 +0100)]
[gve] Select preferred operating mode
Select a preferred operating mode from those advertised as supported
by the device, falling back to the oldest known mode (GQI-QPL) if
no modes are advertised.
Since there are devices in existence that support only QPL addressing,
and since we want to minimise code size, we choose to always use a
single fixed ring buffer even when using raw DMA addressing. Having
paid this penalty, we therefore choose to prefer QPL over RDA since
this allows the (virtual) hardware to minimise the number of page
table manipulations required. We similarly prefer GQI over DQO since
this minimises the amount of work we have to do: in particular, the RX
descriptor ring contents can remain untouched for the lifetime of the
device and refills require only a doorbell write.
Michael Brown [Mon, 6 Oct 2025 13:04:11 +0000 (14:04 +0100)]
[gve] Add support for out-of-order queues
Add support for the "DQO" out-of-order transmit and receive queue
formats. These are almost entirely different in format and usage (and
even endianness) from the original "GQI" in-order transmit and receive
queues, and arguably should belong to a completely different device
with a different PCI ID. However, Google chose to essentially crowbar
two unrelated device models into the same virtual hardware, and so we
must handle both of these device models within the same driver.
Most of the new code exists solely to handle the differences in
descriptor sizes and formats. Out-of-order completions are handled
via a buffer ID ring (as with other devices supporting out-of-order
completions, such as the Xen, Hyper-V, and Amazon virtual NICs). A
slight twist is that on the transmit datapath (but not the receive
datapath) the Google NIC provides only one completion per packet
instead of one completion per descriptor, and so we must record the
list of chained buffer IDs in a separate array at the time of
transmission.
Michael Brown [Mon, 6 Oct 2025 12:06:06 +0000 (13:06 +0100)]
[gve] Cancel pending transmissions when closing device
We cancel any pending transmissions when (re)starting the device since
any transmissions that were initiated before the admin queue reset
will not complete.
The network device core will also cancel any pending transmissions
after the device is closed. If the device is closed with some
transmissions still pending and is then reopened, this will therefore
result in a stale I/O buffer being passed to netdev_tx_complete_err()
when the device is restarted.
This error has not been observed in practice since transmissions
generally complete almost immediately and it is therefore unlikely
that the device will ever be closed with transmissions still pending.
With out-of-order queues, the device seems to delay transmit
completions (with no upper time limit) until a complete batch is
available to be written out as a block of 128 bytes. It is therefore
very likely that the device will be closed with transmissions still
pending.
Fix by ensuring that we have dropped all references to transmit I/O
buffers before returning from gve_close().
Michael Brown [Mon, 29 Sep 2025 14:00:11 +0000 (15:00 +0100)]
[gve] Allow for descriptor and completion lengths to vary by mode
The descriptors and completions in the DQO operating mode are not the
same sizes as the equivalent structures in the GQI operating mode.
Allow the queue stride size to vary by operating mode (and therefore
to be known only after reading the device descriptor and selecting the
operating mode).
Michael Brown [Mon, 29 Sep 2025 11:41:06 +0000 (12:41 +0100)]
[gve] Allow for out-of-order buffer consumption
We currently assume that the buffer index is equal to the descriptor
ring index, which is correct only for in-order queues.
Out-of-order queues will include a buffer tag value that is copied
from the descriptor to the completion. Redefine the data buffers as
being indexed by this tag value (rather than by the descriptor ring
index), and add a circular ring buffer to allow for tags to be reused
in whatever order they are released by the hardware.
Michael Brown [Fri, 26 Sep 2025 11:33:19 +0000 (12:33 +0100)]
[gve] Add support for raw DMA addressing
Raw DMA addressing allows the transmit and receive descriptors to
provide the DMA address of the data buffer directly, without requiring
the use of a pre-registered queue page list. It is modelled in the
device as a magic "raw DMA" queue page list (with QPL ID 0xffffffff)
covering the whole of the DMA address space.
When using raw DMA addressing, the transmit and receive datapaths
could use the normal pattern of mapping I/O buffers directly, and
avoid copying packet data into and out of the fixed queue page list
ring buffer. However, since we must retain support for queue page
list addressing (which requires this additional copying), we choose to
minimise code size by continuing to use the fixed ring buffer even
when using raw DMA addressing.
Add support for using raw DMA addressing by setting the queue page
list base device address appropriately, omitting the commands to
register and unregister the queue page lists, and specifying the raw
DMA QPL ID when creating the TX and RX queues.
Michael Brown [Mon, 29 Sep 2025 11:04:13 +0000 (12:04 +0100)]
[gve] Add concept of a queue page list base device address
Allow for the existence of a queue page list where the base device
address is non-zero, as will be the case for the raw DMA addressing
(RDA) operating mode.
Michael Brown [Mon, 29 Sep 2025 11:37:25 +0000 (12:37 +0100)]
[gve] Set descriptor and completion ring sizes when creating queues
The "create TX queue" and "create RX queue" commands have fields for
the descriptor and completion ring sizes, which are currently left
unpopulated since they are not required for the original GQI-QPL
operating mode.
Populate these fields, and allow for the possibility that a transmit
completion ring exists (which will be the case when using the DQO
operating mode).
* QPL: pre-registered queue page list addressing
* RDA: raw DMA addressing
All four combinations (GQI-QPL, GQI-RDA, DQO-QPL, and DQO-RDA) are
theoretically supported by the Linux driver, which is essentially the
only public reference provided by Google. The original versions of
the GVE NIC supported only GQI-QPL mode, and so the iPXE driver is
written to target this mode, on the assumption that it would continue
to be supported by all models of the GVE NIC.
This assumption turns out to be incorrect: Google does not deem it
necessary to retain backwards compatibility. Some newer machine types
(such as a4-highgpu-8g) support only the DQO-RDA operating mode.
Add a definition of operating mode, and pass this as an explicit
parameter to the "configure device resources" admin queue command. We
choose a representation that subtracts one from the value passed in
this command, since this happens to allow us to decompose the mode
into two independent bits (one representing the use of DQO descriptor
format, one representing the use of QPL addressing).
Michael Brown [Mon, 29 Sep 2025 13:45:32 +0000 (14:45 +0100)]
[gve] Remove separate concept of "packet descriptor"
The Linux driver occasionally uses the terminology "packet descriptor"
to refer to the portion of the descriptor excluding the buffer
address. This is not a helpful separation, and merely adds
complexity.
Simplify the code by removing this artifical separation.
Michael Brown [Thu, 25 Sep 2025 13:42:19 +0000 (14:42 +0100)]
[gve] Parse option list returned in device descriptor
Provide space for the device to return its list of supported options.
Parse the option list and record the existence of each option in a
support bitmask.
Joseph Wong [Fri, 29 Aug 2025 10:02:00 +0000 (10:02 +0000)]
[bnxt] Add error recovery support
Add support to advertise adapter error recovery support to the
firmware. Implement error recovery operations if adapter fault is
detected. Refactor memory allocation to better align with probe and
open functions.
Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
Michael Brown [Thu, 28 Aug 2025 14:35:00 +0000 (15:35 +0100)]
[efi] Use current boot option as a fallback for obtaining the boot URI
Some systems (observed with a Lenovo X1) fail to populate the loaded
image device path with a Uri() component when performing a UEFI HTTP
boot, instead creating a broken loaded image device path that
represents a DHCP+TFTP boot that has not actually taken place.
If no URI is found within the loaded image device path, then fall back
to looking for a URI within the current boot option.
Michael Brown [Thu, 28 Aug 2025 14:34:32 +0000 (15:34 +0100)]
[efi] Add ability to extract device path from an EFI load option
An EFI boot option (stored in a BootXXXX variable) comprises an
EFI_LOAD_OPTION structure, which includes some undefined number of EFI
device paths. (The structure is extremely messy and awkward to parse
in C, but that's par for the course with EFI.)
Add a function to extract the first device path from an EFI load
option, along with wrapper functions to read and extract the first
device path from an EFI boot variable.
Michael Brown [Wed, 27 Aug 2025 12:12:11 +0000 (13:12 +0100)]
[efi] Drag in MNP driver whenever SNP driver is present
The chainloaded-device-only "snponly" driver already drags in support
for driving SNP, NII, and MNP devices, on the basis that the user
generally doesn't care which UEFI API is used and just wants to boot
from the same network device that was used to load iPXE.
The multi-device "snp" driver already drags in support for driving SNP
and NII devices, but does not drag in support for MNP devices.
There is essentially zero code size overhead to dragging in support
for MNP devices, since this support is always present in any iPXE
application build anyway (as part of the code to download
"autoexec.ipxe" prior to installing our own drivers).
Minimise surprise by dragging in support for MNP devices whenever
using the "snp" driver, following the same reasoning used for the
"snponly" driver.
Michael Brown [Thu, 7 Aug 2025 14:43:58 +0000 (15:43 +0100)]
[dwgpio] Use fdt_reg() to get GPIO port numbers
DesignWare GPIO port numbers are represented as unsized single-entry
regions. Use fdt_reg() to obtain the GPIO port number, rather than
requiring access to a region cell size specification stored in the
port group structure.
This allows the field name "regs" in the port group structure to be
repurposed to hold the I/O register base address, which then matches
the common usage in other drivers.
Michael Brown [Thu, 7 Aug 2025 14:41:42 +0000 (15:41 +0100)]
[fdt] Provide fdt_reg() for unsized single-entry regions
Many region types (e.g. I2C bus addresses) can only ever contain a
single region with no size cells specified. Provide fdt_reg() to
reduce boilerplate in this common use case.
Michael Brown [Wed, 6 Aug 2025 15:29:32 +0000 (16:29 +0100)]
[cmdline] Show commands in alphabetical order
Commands were originally ordered by functional group (e.g. keeping the
image management commands together), with arrays used to impose a
functionally meaningful order within the group.
As the number of commands and functional groups has expanded over the
years, this has become essentially useless as an organising principle.
Switch to sorting commands alphabetically (using the linker table
mechanism).
Michael Brown [Wed, 6 Aug 2025 13:54:30 +0000 (14:54 +0100)]
[digest] Treat inability to acquire an image as a fatal error
The "md5sum" and "sha1sum" commands were originally intended solely as
debugging utilities, and would return success (with a warning message)
even if the specified images did not exist.
To minimise surprise and to be consistent with other commands, treat
the inability to acquire an image as a fatal error.
Note that digest verification alone cannot be used to set the trusted
execution status of an image. The only way to mark an image as
trusted is to use the "imgverify" command.
Michael Brown [Wed, 6 Aug 2025 12:31:00 +0000 (13:31 +0100)]
[github] Extend sponsorship link
Add Christian Nilsson <nikize@gmail.com> as a project sponsorship
recipient, to reflect the enormous amount of time invested in
responding to issues and pull requests.
Michael Brown [Wed, 6 Aug 2025 12:05:26 +0000 (13:05 +0100)]
[digest] Add commands for all enabled digest algorithms
Add "sha256sum", "sha512sum", and similar commands. Include these new
commands only when DIGEST_CMD is enabled in config/general.h and the
corresponding algorithm is enabled in config/crypto.h.
Leave "mdsum" and "sha1sum" included whenever only DIGEST_CMD is
enabled, to avoid potentially breaking backwards compatibility with
builds that disabled MD5 or SHA-1 as a TLS or X.509 digest algorithm,
but would still have expected those commands to be present.
Michael Brown [Mon, 4 Aug 2025 13:52:00 +0000 (14:52 +0100)]
[fdt] Use phandle as device location
Consumption of phandles will be in the form of locating a functional
device (e.g. a GPIO device, or an I2C device, or a reset controller)
by phandle, rather than locating the device tree node to which the
phandle refers.
Repurpose fdt_phandle() to obtain the phandle value (instead of
searching by phandle), and record this value as the bus location
within the generic device structure.
Michael Brown [Wed, 30 Jul 2025 14:59:38 +0000 (15:59 +0100)]
[dwmac] Show core version in debug messages
Read and display the core version immediately after mapping the MMIO
registers, to provide a basic sanity check that the registers have
been correctly mapped and the core is not held in reset.
Michael Brown [Wed, 30 Jul 2025 12:40:36 +0000 (13:40 +0100)]
[serial] Explicitly initialise serial console UART to NULL
When debugging is enabled for the device tree or memory map parsing
code, the active serial console UART variable will be accessed during
early initialisation, before the .bss section has been zeroed.
Place this variable in the .data section (by providing an explicit
initialiser), so that reading this variable is well defined even
during early initialisation.
Michael Brown [Wed, 30 Jul 2025 12:14:21 +0000 (13:14 +0100)]
[riscv] Place explicitly zero-initialised variables in the .data section
Variables in the .bss section cannot be relied upon to have zero
values during early initialisation, before we have relocated ourselves
to somewhere suitable in RAM and zeroed the .bss section.
Place any explicitly zero-initialised variables in the .data section
rather than in .bss, so that we can rely on their values even during
this early initialisation stage.
Michael Brown [Wed, 30 Jul 2025 10:11:00 +0000 (11:11 +0100)]
[riscv] Allow for poisoning .bss section before early initialisation
On startup, we may be running from read-only memory, and therefore
cannot zero the .bss section (or write to the .data section) until we
have parsed the system memory map and relocated ourselves to somewhere
suitable in RAM. The code that runs during this early initialisation
stage must be carefully written to avoid writing to the .data section
and to avoid reading from or writing to the .bss section.
Detecting code that erroneously writes to the .data or .bss sections
is relatively easy since running from read-only memory (e.g. via
QEMU's -pflash option) will immediately reveal the bug. Detecting
code that erroneously reads from the .bss section is harder, since in
a freshly powered-on machine (or in a virtual machine) there is a high
probability that the contents of the memory will be zero even before
we explicitly zero out the section.
Add the ability to fill the .bss section with an invalid non-zero
value to expose bugs in early initialisation code that erroneously
relies upon variables in .bss before the section has been zeroed. We
use the value 0xeb55eb55eb55eb55 ("EBSS") since this is immediately
recognisable as a value in a crash dump, and will trigger a page fault
if dereferenced since the address is in a non-canonical form.
Poisoning the .bss can be done only when the image is known to already
reside in writable memory. It will overwrite the relocation records,
and so can be done only on a system where relocation is known to be
unnecessary (e.g. because paging is supported). We therefore do not
enable this behaviour by default, but leave it as a configurable
option via the config/fault.h header.
Michael Brown [Thu, 24 Jul 2025 12:59:42 +0000 (13:59 +0100)]
[undi] Assume that legacy interrupts are broken for any PCIe device
PCI Express devices do not have physical INTx output signals, and on
modern motherboards there is unlikely to be any interrupt controller
with physical interrupt input signals. There are multiple levels of
abstraction involved in emulating the legacy INTx interrupt mechanism:
the PCIe device sends Assert_INTx and Deassert_INTx messages, PCIe
bridges and switches must collate these virtual wires, and the root
complex must map the virtual wires into messages that can be
understood by the host's emulated 8259 PIC.
This complex chain of emulations is rarely tested on modern hardware,
since operating systems will invariably use MSI-X for PCI devices and
the I/O APIC for non-PCI devices such as the real-time clock. Since
the legacy interrupt emulation mechanism is rarely tested, it is
frequently unreliable. We have encountered many issues over the years
in which legacy interrupts are simply not raised as expected, even
when inspection shows that the device believes it is asserting an
interrupt and the controller believes that the interrupt is enabled.
We already maintain a list of devices that are known to fail to
generate legacy interrupts correctly. This list is based on the PCI
vendor and device IDs, which is not necessarily a fair test since the
root cause may be a board-level misconfiguration rather than a
device-level fault.
Assume that any PCI Express device has a high chance of not being able
to raise legacy interrupts reliably. This is a relatively intrusive
change since it will affect essentially all modern network devices,
but should hopefully fix all future issues with non-functional legacy
interrupts, without needing to constantly grow the list of known
broken devices.
If some PCI Express devices are found to fail when operated in polling
mode, then this change will need to be revisited.
Michael Brown [Wed, 23 Jul 2025 15:11:09 +0000 (16:11 +0100)]
[pxeprefix] Display PCI vendor and device ID in PXE startup banner
In the case of a misbehaving PXE stack, it is often useful to know the
PCI vendor and device IDs (e.g. for adding the device to the list of
devices with known broken support for generating interrupts).
The PCI vendor and device ID is already available to the prefix code,
and so can trivially be printed out. Add this information to the PXE
prefix startup banner.
Michael Brown [Mon, 21 Jul 2025 12:44:38 +0000 (13:44 +0100)]
[dwusb] Add driver for DesignWare USB3 host controller
Add a basic driver for the DesignWare USB3 host controller as found in
the Lichee Pi 4A.
This driver covers only the DesignWare host controller hardware. On
the Lichee Pi 4A, this is sufficient to get the single USB root hub
port (exposed internally via the SODIMM connector) up and running.
The driver does not yet handle the various GPIOs that control power
and signal routing for the Lichee Pi 4A's onboard VL817 USB hub and
the four physical USB-A ports. This therefore leaves the USB hub and
the USB-A ports unpowered, and the USB2 root hub port routed to the
physical USB-C port. Devices plugged in to the USB-A ports will not
be powered up, and a device plugged in to the USB-C port will
enumerate as a USB2 device.
Michael Brown [Fri, 18 Jul 2025 13:24:23 +0000 (14:24 +0100)]
[xhci] Use root hub port number to determine slot type
We currently use the downstream hub's port number to determine the
xHCI slot type for a newly connected USB device. The downstream hub
port number is irrelevant to the xHCI controller's supported protocols
table: the relevant value is the number of the root hub port through
which the device is attached.
Fix by using the root hub port number instead of the immediate parent
hub's port number.
This bug has not previously been detected since the slot type for the
first N root hub ports will invariably be zero to indicate that these
are USB ports. For any xHCI controller with a sufficiently large
number of root hub ports, the code would therefore end up happening to
calculate the correct slot type value despite using an incorrect port
number.
Michael Brown [Tue, 15 Jul 2025 15:56:11 +0000 (16:56 +0100)]
[efi] Check only the non-extended WaitForKey event
The WaitForKeyEx event in EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL is
redundant: by definition it has to signal under exactly the same
conditions as the WaitForKey event in EFI_SIMPLE_TEXT_INPUT_PROTOCOL
and cannot provide any "extended" information since EFI events do not
convey any information beyond their own occurrence.
UEFI keyboard drivers such as Ps2KeyboardDxe and UsbKbDxe invariably
use a single notification function to implement both events. The
console multiplexer driver ConSplitterDxe uses a single notification
function for both events, which ends up checking only the WaitForKey
event on the underlying console devices. (Since all console input is
routed through the console multiplexer, this means that in practice
nothing will ever check the underlying devices' WaitForKeyEx events.)
UEFI console consumers such as the UEFI shell tend to use only the
EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance provided as ConIn in the EFI
system table. With the exception of the UEFI text editor (the "edit"
command in the UEFI shell), almost nothing bothers to open the
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance on the same handle.
The Lenovo ThinkPad T14s Gen 5 has a very peculiar firmware bug.
Enabling the "UEFI Wi-Fi Network Boot" feature in the BIOS setup will
cause the completely unrelated WaitForKeyEx event pointer to be
overwritten with a pointer to a FAT_DIRENT structure representing the
"BOOT" directory in the EFI system partition. This happens with 100%
repeatability. It is not necessary to attempt to boot from Wi-Fi: it
is only necessary to have the feature enabled. The root cause is
unknown, but is presumably an uninitialised pointer or similar
memory-related bug in Lenovo's UEFI Wi-Fi driver.
Work around this Lenovo firmware bug by checking only the WaitForKey
event, ignoring the WaitForKeyEx event even if we will subsequently
use ReadKeyStrokeEx() to read the keypress. Since almost all other
UEFI console consumers use only WaitForKey, this ensures that we will
be using code paths that the firmware vendor is likely to have tested
at least once.
Michael Brown [Tue, 15 Jul 2025 15:51:05 +0000 (16:51 +0100)]
[efi] Allow compiler to perform type checks on EFI_EVENT
As with EFI_HANDLE, the EFI headers define EFI_EVENT as a void
pointer, rendering EFI_EVENT compatible with a pointer to itself and
hence guaranteeing that pointer type bugs will be introduced.
Redefine EFI_EVENT as a pointer to an anonymous structure (as we
already do for EFI_HANDLE) to allow the compiler to perform type
checking as expected.
Michael Brown [Tue, 15 Jul 2025 08:12:54 +0000 (09:12 +0100)]
[efi] Assume that vendor wireless drivers are unusable via SNP
The UEFI model for wireless network boot cannot sensibly be described
without cursing. Commit 758a504 ("[efi] Inhibit calls to Shutdown()
for wireless SNP devices") attempts to work around some of the known
issues.
Experimentation shows that on at least some platforms (observed with a
Lenovo ThinkPad T14s Gen 5) the vendor SNP driver is broken to the
point of being unusable in anything other than the single use case
envisioned by the firwmare authors. Doing almost anything directly
via the SNP protocol interface has a greater than 50% chance of
locking up the system.
Assume, in the absence of any evidence to the contrary so far, that
vendor SNP drivers for wireless network devices are so badly written
as to be unusable. Refuse to even attempt to interact with these
drivers via the SNP or NII protocol interfaces.
Michael Brown [Mon, 14 Jul 2025 11:17:11 +0000 (12:17 +0100)]
[efi] Drop to external TPL for calls to ConnectController()
There is nothing in the current versions of the UEFI specification
that limits the TPL at which we may call ConnectController() or
DisconnectController(). However, at least some platforms (observed
with a Lenovo ThinkPad T14s Gen 5) will occasionally and unpredictably
lock up before returning from ConnectController() if called at a TPL
higher than TPL_APPLICATION.
Work around whatever defect is present on these systems by dropping to
the current external TPL for all calls to ConnectController() or
DisconnectController().
Michael Brown [Fri, 11 Jul 2025 11:24:02 +0000 (12:24 +0100)]
[riscv] Support the standard Svpbmt extension for page-based memory types
Set the appropriate Svpbmt type bits within page table entries if the
extension is supported. Tested only in QEMU so far, due to the lack
of availability of real hardware supporting Svpbmt.
Michael Brown [Fri, 11 Jul 2025 11:00:10 +0000 (12:00 +0100)]
[riscv] Create coherent DMA mapping of 32-bit address space on demand
Reuse the code that creates I/O device page mappings to create the
coherent DMA mapping of the 32-bit address space on demand, instead of
constructing this mapping as part of the initial page table.
Michael Brown [Fri, 11 Jul 2025 10:30:57 +0000 (11:30 +0100)]
[riscv] Use 1GB pages for I/O device mappings
All 64-bit paging schemes support at least 1GB "gigapages". Use these
to map I/O devices instead of 2MB "megapages". This reduces the
number of consumed page table entries, increases the visual similarity
of I/O remapped addresses to the underlying physical addresses, and
opens up the possibility of reusing the code to create the coherent
DMA map of the 32-bit address space.
Michael Brown [Thu, 10 Jul 2025 13:33:34 +0000 (14:33 +0100)]
[riscv] Invalidate data cache on completed RX DMA buffers
The data cache must be invalidated twice for RX DMA buffers: once
before passing ownership to the DMA device (in case the cache happens
to contain dirty data that will be written back at an undefined future
point), and once after receiving ownership from the DMA device (in
case the CPU happens to have speculatively accessed data in the buffer
while it was owned by the hardware).
Only the used portion of the buffer needs to be invalidated after
completion, since we do not care about data within the unused portion.
Update the DMA API to include the used length as an additional
parameter to dma_unmap(), and add the necessary second cache
invalidation pass to the RISC-V DMA API implementation.
Michael Brown [Thu, 10 Jul 2025 11:50:00 +0000 (12:50 +0100)]
[riscv] Add optimised TCP/IP checksumming
Add a RISC-V assembly language implementation of TCP/IP checksumming,
which is around 50x faster than the generic algorithm. The main loop
checksums aligned xlen-bit words, using almost entirely compressible
instructions and accumulating carries in a separate register to allow
folding to be deferred until after all loops have completed.
Experimentation on a C910 CPU suggests that this achieves around four
bytes per clock cycle, which is comparable to the x86 implementation.
Michael Brown [Tue, 8 Jul 2025 13:56:47 +0000 (14:56 +0100)]
[riscv] Provide a DMA API implementation for RISC-V bare-metal systems
Provide an implementation of dma_map() that performs cache clean or
invalidation as required, and an implementation of dma_alloc() that
returns virtual addresses within the coherent mapping of the 32-bit
physical address space.
Michael Brown [Mon, 7 Jul 2025 12:11:33 +0000 (13:11 +0100)]
[riscv] Support explicit cache management operations on I/O buffers
On platforms where DMA devices are not in the same coherency domain as
the CPU cache, it is necessary to be able to explicitly clean the
cache (i.e. force data to be written back to main memory) and
invalidate the cache (i.e. discard any cached data and force a
subsequent read from main memory).
Add support for cache management via the standard Zicbom extension or
the T-Head cache management operations extension, with the supported
extension detected on first use.
Support cache management operations only on I/O buffers, since these
are guaranteed to not share cachelines with other data.
Michael Brown [Mon, 7 Jul 2025 12:21:24 +0000 (13:21 +0100)]
[iobuf] Ensure I/O buffer data sits within unshared cachelines
On platforms where DMA devices are not in the same coherency domain as
the CPU cache, we must ensure that DMA I/O buffers do not share
cachelines with other data.
Align the start and end of I/O buffers to IOB_ZLEN, which is larger
than any cacheline size we expect to encounter.
Michael Brown [Fri, 4 Jul 2025 12:29:44 +0000 (13:29 +0100)]
[uaccess] Allow for coherent DMA mapping of the 32-bit address space
On platforms where DMA devices are not in the same coherency domain as
the CPU cache, it is necessary to create page table entries where the
translations are marked as uncacheable.
We choose to place iPXE within the low 4GB of memory (since 32-bit DMA
devices are still reasonably common even on systems with 64-bit CPUs).
We therefore need to cover only the low 4GB of memory with these page
table entries.
Update virt_to_phys() to allow for the existence of such a mapping,
assuming that iPXE itself will always reside within the top 4GB of the
64-bit virtual address space (and therefore that the DMA mapping must
lie somewhere below this in the negative virtual address space).
Michael Brown [Fri, 4 Jul 2025 13:37:31 +0000 (14:37 +0100)]
[riscv] Construct invariant portions of page table outside the loop
The page table entries for the identity map vary according to the
paging level in use, and so must be constructed within the loop used
to detect the maximum supported paging level. Other page table
entries are invariant between paging levels, and so may be constructed
just once before entering the loop.
Joseph Wong [Thu, 26 Jun 2025 22:37:05 +0000 (15:37 -0700)]
[bnxt] Remove VLAN stripping logic
Remove logic that programs the hardware to strip out VLAN from RX
packets. Do not drop packets due to VLAN mismatch and allow the upper
layer to decide whether to discard the packets.
Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
Michael Brown [Thu, 26 Jun 2025 15:24:01 +0000 (16:24 +0100)]
[github] Add sponsorship link
iPXE is released under the GNU GPL and is 100% open source software.
There are no "premium editions", no in-app advertisements, and no
hidden costs. The fully public version published to GitHub is and
always will be the definitive and only version of iPXE.
Many large features in iPXE have been commercially funded within this
open source model, with features being published upstream as soon as
they are complete and made available for the whole world to use, not
restricted for use only by the customer funding that particular piece
of development work.
There has not to date been any funding model for smaller pieces of
work, such as occasional code review or guaranteed attention to bug
reports. The overhead of establishing a commercial relationship is
usually too high to be worthwhile for very small units of work.
The GitHub sponsorship mechanism provides a framework for efficiently
handling small commercial requests (or individual tokens of thanks).
Add a FUNDING.yml file to provide a convenient way for anyone who
wants to support the ongoing open source development of iPXE to do so.
Michael Brown [Tue, 24 Jun 2025 12:32:49 +0000 (13:32 +0100)]
[build] Disable use of common symbols
We no longer have any requirement for common symbols. Disable common
symbols via the -fno-common compiler option, and simplify the test for
support of -fdata-sections (which can return a false negative when
common symbols are enabled).
Michael Brown [Tue, 24 Jun 2025 12:17:19 +0000 (13:17 +0100)]
[legacy] Allocate legacy driver .bss-like segments at probe time
Some legacy drivers use large static allocations for transmit and
receive buffers. To avoid bloating the .bss segment, we currently
implement these as a single common symbol named "_shared_bss" (which
is permissible since only one legacy driver may be active at any one
time).
Switch to dynamic allocation of these .bss-like segments, to avoid the
requirement for using common symbols.
Michael Brown [Tue, 24 Jun 2025 12:10:53 +0000 (13:10 +0100)]
[legacy] Rename the global legacy NIC to "legacy_nic"
We currently have contexts in which the local variable "nic" is a
pointer to the global variable also called "nic". This complicates
the creation of macros.
Rename the global variable to "legacy_nic" to reduce pollution of the
global namespace and to allow for the creation of macros referring to
fields within this global variable.