Provide a generic framework for allocating, refilling, and optionally
recycling I/O buffers used by bulk IN and interrupt endpoints.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Hardened versions of gcc default to building position-independent
code, which breaks our i386 build. Our build process therefore
detects such platforms and automatically adds "-fno-PIE -nopie" to the
gcc command line.
On x86_64, we choose to build position-independent code (in order to
reduce the final binary size and, in particular, the number of
relocations required for UEFI binaries). The workaround therefore
breaks the build process for x86_64 binaries on such platforms.
Fix by moving the workaround to the i386-specific portion of the
Makefile.
Reported-by: Jan Kundrát <jkt@kde.org>
Debugged-by: Jan Kundrát <jkt@kde.org>
Debugged-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
UEFI binaries may be relocated to any location within the 64-bit
address space. We compile as position-independent code with hidden
visibility, which should force all relocation records to be either
PC-relative (in which case no PE relocations are required) or full
64-bit relocations. There should be no R_X86_64_32 relocation
records, since that would imply an invalid assumption that code could
not be relocated above 4GB.
Remove support for R_X86_64_32 relocation records from util/elf2efi.c,
so that any such records result in a build failure rather than a
potential runtime failure.
Reported-by: Jan Kundrát <jkt@kde.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When building hvmloader for Xen tools the iPXE objects are also linked
into the binary. Unfortunately the linker will place them in the
order found in the archive. Since this order is random the resulting
hvmloader binary differs when it was built from identical sources but
on different build hosts. To help with creating a reproducible binary
the elements in blib.a must simply be sorted before passing them to
$(AR).
Signed-off-by: Olaf Hering <olaf@aepfle.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit a60f2dd ("[usb] Try multiple USB device configurations")
changed the behaviour of register_usb() such that if no drivers are
found then the device will be closed and the memory used will be
freed.
If a port status change subsequently occurs while the device is still
physically attached, then usb_hotplug() will see this as a new device
having been attached, since there is no device recorded as being
currently attached to the port. This can lead to spurious hotplug
events (or even endless loops of hotplug events, if the process of
opening and closing the device happens to generate a port status
change).
Fix by using a separate flag to indicate that a device is physically
attached (even if we have no corresponding struct usb_device).
Reported-by: Dan Ellis <Dan.Ellis@displaylink.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Use PRODUCT_SHORT_NAME instead of a hardcoded "iPXE" for strings which
are typically shown in the user interface.
Note that this only allows for customisation of the user interface.
Where the "iPXE" string serves a technical purpose (such as in the
HTTP User-Agent), the string cannot be customised.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some xHCI controllers (observed with a Renesas Electronics PCIe USB3
card) seem to require a delay after forcing the link state of USB3
ports to RxDetect. Omitting this delay causes strange behaviour
including system lockups.
Add an unconditional 20ms delay after writing the port link states.
This seems to be sufficient to avoid the problem.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some USB endpoints require that a short packet be used to terminate
transfers, since they have no other way to determine message
boundaries. If the message length happens to be an exact multiple of
the USB packet size, then this requires the use of an additional
zero-length packet.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
USB Communications Device Class devices may use a union functional
descriptor to group several interfaces into a function.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Iterate over a USB device's available configurations until we find one
for which we have working drivers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some protocols (such as ARP) may modify the received packet and re-use
the same I/O buffer for transmission of a reply. To allow this,
reserve sufficient headroom at the start of each received packet
buffer for our transmit datapath headers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some devices return multiple packets in a single poll. Handle such
devices gracefully by enqueueing received PXE UDP packets (along with
a pseudo-header to hold the IPv4 addresses and port numbers) and
dequeueing them on subsequent calls to PXENV_UDP_READ.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Fetching the TFTP file size is currently implemented via a custom
"tftpsize://" protocol hack. Generalise this approach to instead
close the TFTP connection whenever the parent data-transfer interface
is closed.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some devices have a very small number of internal buffers, and rely on
being able to pack multiple packets into each buffer. Using 2048-byte
buffers on such devices produces throughput of around 100Mbps. Using
a small number of much larger buffers (e.g. 32kB) increases the
throughput to around 780Mbps. (The full 1Gbps is not reached because
the high RTT induced by the use of multi-packet buffers causes us to
saturate our 256kB TCP window.)
Since allocation of large buffers is very likely to fail, allocate the
buffer set only once when the device is opened and recycle buffers
immediately after use. Received data is now always copied to
per-packet buffers.
If allocation of large buffers fails, fall back to allocating a larger
number of smaller buffers. This will give reduced performance, but
the device will at least still be functional.
Share code between the interrupt and bulk IN endpoint handlers, since
the buffer handling is now very similar.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow drivers to specify a supported PCI class code. To save space in
the final binary, make this an attribute of the driver rather than an
attribute of a PCI device ID list entry.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We require the ability to disconnect from and reconnect to VMBus; if
we don't have this then there is no (viable) way for a loaded
operating system to continue to use any VMBus devices. (There is also
a small but non-zero risk that the host will continue to write to our
interrupt and monitor pages, since the VMBUS_UNLOAD message in earlier
versions is essentially a no-op.)
This requires us to ensure that the host supports protocol version 3.0
(VMBUS_VERSION_WIN8_1). However, we can't actually _use_ protocol
version 3.0, since doing so causes an iSCSI-booted Windows Server 2012
R2 VM to crash due to a NULL pointer dereference in vmbus.sys.
To work around this problem, we first ensure that we can connect using
protocol v3.0, then disconnect and reconnect using the oldest known
protocol.
This deliberately prevents the use of the iPXE native Hyper-V drivers
on older versions of Hyper-V, where we could use our drivers but in so
doing would break the loaded operating system.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Windows Server 2012 R2 generates an RNDIS_INDICATE_STATUS_MSG with a
status code of 0x4002006. This status code does not appear to be
documented anywhere within the sphere of human knowledge.
Explicitly ignore this status code in order to avoid unnecessarily
cluttering the display when RNDIS debugging is enabled.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The (undocumented) VMBus protocol seems to allow for transfer
page-based packets where the data payload is split into an arbitrary
set of ranges within the transfer page set.
The RNDIS protocol includes a length field within the header of each
message, and it is known from observation that multiple RNDIS messages
can be concatenated into a single VMBus message.
iPXE currently assumes that the transfer page range boundaries are
entirely arbitrary, and uses the RNDIS header length to determine the
RNDIS message boundaries.
Windows Server 2012 R2 generates an RNDIS_INDICATE_STATUS_MSG for an
undocumented and unknown status code (0x40020006) with a malformed
RNDIS header length: the length does not cover the StatusBuffer
portion of the message. This causes iPXE to report a malformed RNDIS
message and to discard any further RNDIS messages within the same
VMBus message.
The Linux Hyper-V driver assumes that the transfer page range
boundaries correspond to RNDIS message boundaries, and so does not
notice the malformed length field in the RNDIS header.
Match the behaviour of the Linux Hyper-V driver: assume that the
transfer page range boundaries correspond to the RNDIS message
boundaries and ignore the RNDIS header length. This avoids triggering
the "malformed packet" error and also avoids unnecessary data copying:
since we now have one I/O buffer per RNDIS message, there is no longer
any need to use iob_split().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Empirical observation suggests that 32 is a sensible size to minimise
the number of deferred packet transmissions without overflowing the
VMBus transmit ring buffer.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow for elision of transmitted TCP ACKs by handling all received
VMBus messages in each network device poll operation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On Windows Server 2012 R2, closing and reopening the device will
sometimes result in a non-functional RX datapath. The root cause is
unknown. Clearing the receive filter before closing the device seems
to fix the problem.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On Windows Server 2012 R2, the receive buffer teardown completion
message seems to occasionally be deferred until after the VMBus
channel has been closed. This happens even if there are no packets
currently in the receive buffer.
Work around this problem by separating the revocation and teardown of
the receive buffer, and deferring the teardown until after the VMBus
channel has been closed.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The Hyper-V RNDIS implementation on Windows Server 2012 R2 requires
that we send an explicit RNDIS initialisation message in order to get
a working RX datapath.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
RNDIS devices may provide multiple packets encapsulated into a single
message. Provide an API to allow the RNDIS driver to split an I/O
buffer into smaller portions.
The current implementation will always copy the underlying data,
rather than splitting the buffer in situ.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Check the integrity of the free memory block list before and after any
modifications to the list. We check that certain invariants are
preserved:
- the list is a well-formed doubly linked list
- all blocks are at least MIN_MEMBLOCK_SIZE
- no block extends beyond the end of our address space
- blocks remain sorted in ascending order of address
- no blocks are adjacent (i.e. any adjacent blocks have been merged)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently compare the entirety of the KeyHash object (including the
ASN.1 tag and length byte) against the raw SHA-1 hash of the
certificate's public key. This causes OCSP validation to fail for any
responses which identify the responder by key hash rather than by
name, and hence prevents the use of X.509 certificates where any
certificate in the chain has an OCSP responder which chooses to
identify itself via its key hash.
Fix by adding the missing asn1_enter() required to enter the ASN.1
octet string containing the key hash.
Also add a corresponding test case including an OCSP response where
the responder is identified by key hash, to ensure that this
functionality cannot be broken in future.
Debugged-by: Brian Rak <brak@gameservers.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The i350 (and possibly other Intel NICs) have a non-trivial
correspondence between the PCI function number and the external
physical port number. For example, the i350 has a "LAN Function Sel"
bit within the EEPROM which can invert the mapping so that function 0
becomes port 3, function 1 becomes port 2, etc.
Unfortunately the MAC addresses within the EEPROM are indexed by
physical port number rather than PCI function number. The end result
is that when anything other than the default mapping is used, iPXE
will use the wrong address as the base MAC address.
Fix by using the autoloaded MAC address if it is valid, and falling
back to reading the MAC address directly from the EEPROM only if no
autoloaded address is available.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Add the "-c <count>" option to the "ping" command, allowing for
automatic termination after a specified number of packets.
When a number of packets is specified:
- if a serious error (i.e. length mismatch or content mismatch)
occurs, then the ping will be immediately terminated with the relevant
status code;
- if at least one response is received successfully, and all errors
are non-serious (i.e. timeouts or out-of-sequence responses), then
the ping will be terminated after the final response (or timeout)
with a success status;
- if no responses are received successfully, then the ping will be
terminated after the final timeout with ETIMEDOUT.
If no number of packets is specified, then the ping will continue
until manually interrupted.
Originally-implemented-by: Cedric Levasseur <cyr-ius@ipocus.net>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
End users almost certainly don't care whether the underlying interface
is SNP or NII/UNDI. Try to minimise surprise and unnecessary
documentation by including the NII driver whenever the SNP driver is
requested.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
iPXE itself exposes a dummy NII protocol with no UNDI. Avoid
potentially dereferencing a NULL pointer by checking for a non-zero
UNDI address.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI network drivers provide a software UNDI interface which is
exposed via the Network Interface Identifier Protocol (NII), rather
than providing a Simple Network Protocol (SNP).
The UEFI platform firmware will usually include the SnpDxe driver,
which attaches to NII and provides an SNP interface. The SNP
interface is usually provided on the same handle as the underlying NII
device. This causes problems for our EFI driver model: when
efi_driver_connect() detaches existing drivers from the handle it will
cause the SNP interface to be uninstalled, and so our SNP driver will
not be able to attach to the handle. The platform firmware will
eventually reattach the SnpDxe driver and may attach us to the SNP
handle, but we have no way to prevent other drivers from attaching
first.
Fix by providing a driver which can attach directly to the NII
protocol, using the software UNDI interface to drive the network
device.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The snpnet driver uses netdev_tx_defer() and so must ensure that space
in the (single-entry) transmit descriptor ring is freed up before
calling netdev_tx_complete().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EDK2 codebase uses -malign-double for 32-bit builds, which causes
64-bit integers to be naturally aligned. This affects the layout of
some structures (including EFI_BLOCK_IO_MEDIA).
This mirrors wimboot commit 7b8f39d ("[build] Fix building of 32-bit
UEFI version").
Signed-off-by: Michael Brown <mcb30@ipxe.org>
As of commit 03f0c23 ("[ipoib] Expose Ethernet-compatible eIPoIB
link-layer addresses and headers"), all link layers have used
addresses which fit within the DHCP chaddr field. The dhcp_chaddr()
function was therefore made obsolete by this commit, but was
accidentally left present (though unused) in the source code.
Remove the dhcp_chaddr() function and the only remaining use of it,
unnecessarily introduced in commit 08bcc0f ("[dhcp] Check for matching
chaddr in received DHCP packets").
Reported-by: Wissam Shoukair <wissams@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On large networks a DHCP XID collision is possible. Fix by explicitly
checking the chaddr in received DHCP packets.
Originally-fixed-by: Wissam Shoukair <wissams@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI platforms will fail the call to LoadImage() with
EFI_INVALID_PARAMETER if we do not provide a device path (even though
we are providing a non-NULL SourceBuffer).
Fix by providing an empty device path for the call to LoadImage() in
efi_image_probe().
The call to LoadImage() in efi_image_exec() already constructs and
provides a device path (based on the most recently opened SNP device),
and so does not require this fix.
Reported-by: NICOLAS CATTIE <nicolas.cattie@mpsa.com>
Tested-by: NICOLAS CATTIE <nicolas.cattie@mpsa.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Add the ID for the LM variant and differentiate it from the I217-V.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Add utility for constructing EFI fat binaries (dual 32/64-bit
binaries, usable only on Apple EFI systems).
This utility is not part of the standard build process. To use it:
make util/efifatbin bin-i386-efi/ipxe.efi bin-x86_64-efi/ipxe.efi
and then
./util/efifatbin bin-*-efi/ipxe.efi fat-ipxe.efi
Requested-by: Brandon Penglase <bpenglase-ipxe@spaceservices.net>
Tested-by: Brandon Penglase <bpenglase-ipxe@spaceservices.net>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow a straightforward "make clean" or "make veryclean" to apply to
all binary directories (using the shell pattern "bin{,-*}").
Individual binary directories can be cleaned using e.g.
make bin clean
make bin-x86_64-efi clean
Reported-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently require information about the underlying PCI device to
populate the snpnet device's name and description. If the underlying
device is not a PCI device, this will fail and prevent the device from
being registered.
Fix by falling back to populating the device description with
information based on the EFI handle, if no PCI device information is
available.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI systems (observed with a Hyper-V virtual machine) do not
provide EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. Make this an optional
protocol (and fail any attempts to access PCI configuration space via
the root bridge if the protocol is missing).
Reported-by: Colin Blacker <Colin.Blacker@computerplanet.co.uk>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Under UEFI, reads from PCI configuration space may fail. If this
happens, we should return all-ones (which will mimic the behaviour of
an absent PCI device).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some systems will install a child of the SNP device and use this as
our loaded image's device handle, duplicating the installation of the
underlying SNP protocol onto the child device handle. On such
systems, we want to end up driving the parent device (and
disconnecting any other drivers, such as MNP, which may be attached to
the parent device).
Fix by recording the SNP protocol instance at initialisation time, and
using this to match against device handles (rather than simply
comparing the handles themselves).
Reported-by: Jarrod Johnson <jarrod.b.johnson@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Propagate our modified EFI system table to any images loaded by the
image that we wrap, thereby allowing us to observe boot services calls
made by all subsequent EFI images.
Also show details of intercepted ExitBootServices() calls. When
wrapping is used, exiting boot services will almost certainly fail,
but this at least allows us to see when it happens.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The .mrom payload has a code type of 0xff and so the initialisation
length field (single byte at offset 0x02) does not need to be
present. Use only the PCI header's image length field, which allows
the .mrom payload to be up to 32MB in size.
Inspired-by: Swift Geek <swiftgeek@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
mromprefix.S currently uses the initialisation length field (single
byte at offset 0x02) to determine the length of a ROM image within a
multi-image ROM BAR. For PCI ROM images with a code type other than
0, the initialisation length field may not be present.
Fix by using the PCI header's image length field instead.
Inspired-by: Swift Geek <swiftgeek@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Option::ROM currently uses the initialisation length field (single
byte at offset 0x02) to determine the length of a ROM image within a
multi-image ROM file. For PCI ROM images with a code type other than
0, the initialisation length field may not be present.
Fix by using the PCI header's image length field instead. Note that
this does not prevent us from correctly handling ISA ROMs, since ISA
ROMs do not support multiple images within a single ROM BAR anyway.
Inspired-by: Swift Geek <swiftgeek@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
With extremely unlucky timing, it is possible to interrupt a build and
cause make to delete config/named.h (and possibly any local
configuration headers).
Mark config/named.h and all local configuration headers as .PRECIOUS
to prevent make from ever deleting them.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The build process has for a long time assumed that every ROM is a PCI
ROM, and will always include the PCI header and PCI-related
functionality (such as checking the PCI BIOS version, including the
PCI bus:dev.fn address within the ROM product name string, etc.).
While real ISA cards are no longer in use, some virtualisation
environments (notably VirtualBox) have support only for ISA ROMs.
This can cause problems: in particular, VirtualBox will call our
initialisation entry point with random garbage in %ax, which we then
treat as the PCI bus:dev.fn address of the autoboot device: this
generally prevents the default boot sequence from using any network
devices.
Create .isarom and .pcirom prefixes which can be used to explicitly
specify the type of ROM to be created. (Note that the .mrom prefix
always implies a PCI ROM, since the .mrom mechanism relies on
reconfiguring PCI BARs.)
Make .rom a magic prefix which will automatically select the
appropriate PCI or ISA ROM prefix for ROMs defined via a PCI_ROM() or
ISA_ROM() macro. To maintain backwards compatibility, we default to
building a PCI ROM for anything which is not directly derived from a
PCI_ROM() or ISA_ROM() macro (e.g. bin/intel.rom).
Add a selection of targets to "make everything" to ensure that the
(relatively obscure) ISA ROM build process is included within the
per-commit QA checks.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Since some PnP BIOSes fail to set %es:di to point to the PnP signature
on entry, we identify a PnP BIOS by scanning through the top 64kB of
base memory looking for the PnP structure. We therefore don't
actually use the values of %es:di provided to the initialisation entry
point, and so there is no need to preserve them.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
ICH8 devices have an errata which requires us to reconfigure the
packet buffer size (PBS) register, and correspondingly adjust the
packet buffer allocation (PBA) register. The "Intel I/O Controller
Hub ICH8/9/10 and 82566/82567/82562V Software Developer's Manual"
notes for the PBS register that:
10.4.20 Packet Buffer Size - PBS (01008h; R/W)
Note: The default setting of this register is 20 KB and is
incorrect. This register must be programmed to 16 KB.
Initial value: 0014h
0018h (ICH9/ICH10)
It is unclear from this comment precisely which devices require the
workaround to be applied. We currently attempt to err on the side of
caution: if we detect an initial value of either 0x14 or 0x18 then the
workaround will be applied. If the workaround is applied
unnecessarily, then the effect should be just that we use less than
the full amount of the available packet buffer memory.
Unfortunately this approach does not play nicely with other device
drivers. For example, the Linux e1000e driver will rewrite PBA while
assuming that PBS still contains the default value, which can result
in inconsistent values between the two registers, and a corresponding
inability to transmit or receive packets. Even more unfortunately,
the contents of PBS and PBA are not reset by anything less than a
power cycle, meaning that this error condition will survive a hardware
reset.
The Linux driver (written and maintained by Intel) applies the PBS/PBA
errata workaround only for devices in the ICH8 family, identified via
the PCI device ID. Adopt a similar approach, using the PCI_ROM()
driver data field to indicate when the workaround is required.
Reported-by: Donald Bindner <dbindner@truman.edu>
Debugged-by: Donald Bindner <dbindner@truman.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow named configurations to be specified via the CONFIG=... build
parameter. For headers in config/*.h which support named
configurations, the following files will be included when building
with CONFIG=<name>:
- config/defaults/<platform>.h (e.g. config/defaults/pcbios.h)
- config/<header>.h
- config/<name>/<header>.h (only if the directory config/<name> exists)
- config/local/<header>.h (autocreated if necessary)
- config/local/<name>/<header>.h (autocreated if necessary)
This mechanism allows for predefined named configurations to be
checked in to the source tree, as a directory config/<name> containing
all of the required header files.
The mechanism also allows for users to define multiple local
configurations, by creating header files in the directory
config/local/<name>.
Note that the config/*.h files which are used only to configure
internal iPXE APIs (e.g. config/ioapi.h) cannot be modified via a
named configuration. This avoids rebuilding the entire iPXE codebase
whenever switching to a different named configuration.
Inspired-by: Robin Smidsrød <robin@smidsrod.no>
Tested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Under some circumstances (e.g. if iPXE itself is booted via iSCSI, or
after an unclean reboot), the backend may not be in the expected
InitWait state when iPXE starts up.
There is no generic reset mechanism for Xenbus devices. Recent
versions of xen-netback will gracefully perform all of the required
steps if the frontend sets its state to Initialising. Older versions
(such as that found in XenServer 6.2.0) require the frontend to
transition through Closed before reaching Initialising.
Add a reset mechanism for netfront devices which does the following:
- read current backend state
- if backend state is anything other than InitWait, then set the
frontend state to Closed and wait for the backend to also reach
Closed
- set the frontend state to Initialising and wait for the backend to
reach InitWait.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Using version 1 grant tables limits guests to using 16TB of grantable
RAM, and prevents the use of subpage grants. Some versions of the Xen
hypervisor refuse to allow the grant table version to be set after the
first grant references have been created, so the loaded operating
system may be stuck with whatever choice we make here. We therefore
currently use version 2 grant tables, since they give the most
flexibility to the loaded OS.
Current versions (7.2.0) of the Windows PV drivers have no support for
version 2 grant tables, and will merrily create version 1 entries in
what the hypervisor believes to be a version 2 table. This causes
some confusion.
Avoid this problem by attempting to use version 1 tables, since
otherwise we may render Windows unable to boot.
Play nicely with other potential bootloaders by accepting either
version 1 or version 2 grant tables (if we are unable to set our
requested version).
Note that the use of version 1 tables on a 64-bit system introduces a
possible failure path in which a frame number cannot fit into the
32-bit field within the v1 structure. This in turn introduces
additional failure paths into netfront_transmit() and
netfront_refill_rx().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
At some point during XenServer development history, the Windows PV
drivers changed to using a PCI device ID of 5853:0002 rather than
5853:0001. Current (7.2.0) drivers will bind to either 5853:0001 or
5853:0002, and the general approach taken by the world at large
(including Amazon EC2) seems to be to use only 5853:0001.
However, the current version of XenServer (6.2.0) will create the
platform device as 5853:0002 (via the platform:device_id VM parameter)
for any VMs created using the built-in templates for Windows Vista or
later.
Accept either PCI ID, since the underlying device is identical.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The behavior observed in the Apple EFI (1.10) RecieveFilters() call
is:
- failure if any of the PROMISCUOUS or MULTICAST filters are
included
- success if only UNICAST is included, however the result is
UNICAST|BROADCAST
- success if only UNICAST and BROADCAST are included
- if UNICAST, or UNICAST|BROADCAST are used, but the previous call
tried (and failed) to set UNICAST|BROADCAST|MULTICAST, then the
result is UNICAST|BROADCAST|MULTICAST
Work around this apparently broken SNP implementation by trying
RecieveFilterMask, then falling back to UNICAST|BROADCAST|MULTICAST,
then UNICAST|BROADCAST, and finally UNICAST.
Modified-by: Michael Brown <mcb30@ipxe.org>
Tested-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some EFI 1.10 systems (observed on an Apple iMac) do not allow us to
open the device path protocol with an attribute of
EFI_OPEN_PROTOCOL_BY_DRIVER and so we cannot maintain a safe,
long-lived pointer to the device path. Work around this by instead
opening the device path protocol with an attribute of
EFI_OPEN_PROTOCOL_GET_PROTOCOL whenever we need to use it.
Debugged-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
According to the UEFI specification, the MCastFilter parameter (which
we currently pass as NULL, along with a zero MCastFilterCnt) is
optional only if ResetMCastFilter is true.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The ComponentName and ComponentName2 protocols differ only in the
standard which is used for language name codes.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Try very hard to avoid ever doing something invalid while attempting
to generate a debug message.
Debugged-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Dump the existing openers of a protocol whenever we are unable to open
a protocol using attributes of BY_DEVICE, EXCLUSIVE, or
BY_CHILD_CONTROLLER.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
efi_file_install() and efi_download_install() are both used to install
onto existing handles. There is therefore no need to allow for each
of their calls to InstallMultipleProtocolInterfaces() to create a new
handle.
By passing the handle directly (rather than a pointer to the handle),
we avoid potential confusion (and erroneous debug message colours).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EFI headers define EFI_HANDLE as a void pointer, which renders
type checking on anything dealing with EFI handles somewhat useless.
Work around this bizarre sabotage attempt by redefining EFI_HANDLE as
a pointer to an anonymous structure.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Using efi_devpath_text() is marginally more efficient if we already
have the device path protocol available, but the mild increase in
efficiency is not worth compromising the clarity of the pattern:
DBGC ( device, "THING %p %s ...", device, efi_handle_name ( device ) );
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide a function efi_handle_name() (as a generalisation of
efi_handle_devpath_text()) which tries various methods to produce a
human-readable name for an EFI handle.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
HII seems to fail on several systems. Since it is non-essential,
treat HII problems as non-fatal.
Debugged-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Reject network devices which appear to be duplicates of those already
available via a different underlying hardware device. On a Xen PV-HVM
system, this allows us to filter out the emulated PCI NICs (which
would otherwise appear alongside the netfront NICs).
Note that we cannot use the Xen facility to "unplug" the emulated PCI
NICs, since there is no guarantee that the OS we subsequently load
will have a native netfront driver.
We permit devices with the same MAC address if they are attached to
the same underlying hardware device (e.g. VLAN devices).
Inspired-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some EFI 1.10 implementations (observed with a mid-2011 iMac) seem to
fail to fill in the DeviceHandle for our loaded images. It is
plausible that these implementations fill in the DeviceHandle only if
loading the image from a device path (rather than directly from a
memory buffer).
Work around this problem by filling in DeviceHandle if the firmware
leaves it empty.
We cannot sensibly fill in FilePath, because we have no way of knowing
whether or not the firmware will treat this as a pointer to be freed
when the image returns.
Reported-by: Curtis Larsen <larsen@dixie.edu>
Tested-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
If the StartImage() call returns with no error, then the image must
have been started and returned successfully. It either unloaded
itself, or it intended to remain loaded (e.g. it was a driver). We
therefore do not unload successful images.
If there was an error, we attempt to unload the image. This may not
work. In particular, there is no way to tell whether an error
returned from StartImage() was due to being unable to start the image
(in which case we probably should call UnloadImage()), or due to the
image itself returning an error (in which case we probably should not
call UnloadImage()). We therefore ignore any failures from the
UnloadImage() call itself.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently treat network devices as available for use via the SNP
API only if RX queue processing has been frozen. (This is similar in
spirit to the way that RX queue processing is frozen for the network
device currently exposed via the PXE API.)
The default state of a freshly created network device is for the RX
queue to not be frozen, and thus to be unavailable for use via SNP.
This causes problems when devices are added through code paths other
than _efidrv_start() (which explicitly releases devices for use via
SNP).
We don't actually need to freeze RX queue processing, since calls via
the SNP API will always use netdev_poll() rather than net_poll(), and
so will never trigger the RX queue processing code path anyway.
We can therefore simplify the code to use a single global flag to
indicate whether network devices are claimed for use by iPXE or
available for use via SNP. Using a global flag allows the default
state for dynamically created network devices to behave sensibly.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Add basic support for Xen PV-HVM domains (detected via the Xen
platform PCI device with IDs 5853:0001), including support for
accessing configuration via XenStore and enumerating devices via
XenBus.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Import selected headers from the xen/include/public directory of the
Xen repository at git://xenbits.xen.org/xen.git
The script ./include/xen/import.pl can be used to automatically import
any required headers and their dependencies (in a similar fashion to
./include/ipxe/efi/import.pl). Trailing whitespace is stripped and an
appropriate FILE_LICENCE declaration is added to each header file.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit 24bbaf6 ("[lotest] Allow loopback testing on shared networks")
introduced a regression in which loopback testing packets would be
accepted from any network device. This produces unexpected results,
such as VLAN loopback testing succeeding even when incorrectly using
the underlying trunk device as either transmitter or receiver.
Fix by discarding any loopback testing packets which arrive on a
network device other than the current loopback testing receiver.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The $(BIN)/version.%.o target will fail if iPXE is built within a
non-git repository, e.g. when the user downloaded and extracted an
archive containing iPXE sources, *and* if any parent directory of the
iPXE sources is a git repository (or even contains a directory named
".git"). This is because git will by default ascend the directory
tree and look for ".git".
The problem typically manifests on source based distributions, see for
example https://bugs.gentoo.org/show_bug.cgi?id=482804
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some switches do not allow an individual link (as defined in IEEE Std
802.3ad-2000 section 43.3.5) to work alone in a link aggregation group
as described in section 43.3.6. This is verified on Dell's
PowerConnect M6220, based on the Broadcom Strata XGS-IV chipset.
Set the LACP_STATE_AGGREGATABLE flag in the actor.state field to
announce link aggregation in the response LACPDU, which will have the
switch enable the link aggregation group and allow frames to pass.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When a 32-bit iPXE binary is running on a system which allocates PCI
memory BARs above 4GB, our PCI subsystem will return the base address
for any such BARs as zero (with a warning message if DEBUG=pci is
enabled). Currently, ioremap() will happily map an address pointing
to the start of physical memory, providing no sensible indication of
failure.
Fix by always returning NULL if we are asked to ioremap() a zero bus
address.
With a totally flat memory model (e.g. under EFI), this provides an
accurate failure indication since no PCI peripheral will be mapped to
the zero bus address.
With the librm memory model, there is the possibility of a spurious
NULL return from ioremap() if the bus address happens to be equal to
virt_offset. Under the current virtual memory map, the NULL virtual
address will always be the start of .textdata, and so this problem
cannot occur; a NULL return from ioremap() will always be an accurate
failure indication.
Debugged-by: Anton D. Kachalov <mouse@yandex-team.ru>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On some older EFI 1.10 implementations (observed with an old iMac), we
must use the (now obsolete) EFI_CONSOLE_CONTROL_PROTOCOL to switch the
console into text mode.
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EFI_CONSOLE_CONTROL_PROTOCOL does not exist in the current UEFI
specification, but is required to enable text output on some older EFI
1.10 implementations (observed on an old iMac).
The header is not present in any of the standard include directories,
but can still be found in the EDK2 codebase as part of
EdkCompatibilityPkg.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When building with DEBUG=efi_wrap, print details of calls made by the
loaded image to selected boot services functions.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The EFI FAT filesystem driver has a bug: if a block device contains no
FAT filesystem but does have an EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
instance, the FAT driver will assume that it must have previously
installed the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. This causes the FAT
driver to claim control of our device, and to refuse to stop driving
it, which prevents us from later uninstalling correctly.
Work around this bug by opening the disk I/O protocol ourselves,
thereby preventing the FAT driver from opening it.
Note that the alternative approach of opening the block I/O protocol
(and thereby in theory preventing DiskIo from attaching to the block
I/O protocol) causes an endless loop of calls to our DRIVER_STOP
method when starting the EFI shell. I have no idea why this is.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When functioning as an EFI driver, drivers can be disconnected and
reconnected multiple times (e.g. via the EFI shell "connect" command,
or by running an executable such as ipxe.efi which will temporarily
disconnect existing drivers).
Minimise surprise by resetting the network device index to zero
whenever the last device is unregistered. This is not foolproof, but
it does handle the common case of having all devices unregistered and
then reregistered in the original order.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Rewrite the SNP NIC driver to use non-blocking and deferrable
transmissions, to provide link status detection, to provide
information about the underlying (PCI) hardware device, and to avoid
unnecessary I/O buffer allocations during receive polling.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit 8290a95 ("[build] Expose build timestamp, build name, and
product names") introduced a regression in the build process which
resulted in broken final binaries which had names based on object
files (e.g. "undionly.kpxe" or "intel.rom") rather than on device IDs
(e.g. "8086100e.mrom").
The underlying problem is the -DOBJECT=<name> macro which is used to
generate the obj_<name> symbols used to select objects required for
the final binary. The macro definition is derived from the initial
portion (up to the first dot) of the object being built. In the case
of e.g. undionly.kpxe.version.o, this gives -DOBJECT=undionly. This
results in undionly.kpxe.version.o claiming to be the "undionly"
object; the real "undionly" object will therefore never get dragged in
to the build.
Fix by renaming $(BIN)/%.version.o to $(BIN)/version.%.o, so that the
object is always built with -DOBJECT=version (as might be expected,
since it is built from core/version.c).
Final binaries which have names based on device IDs (such as
"8086100e.mrom") are not affected by this problem, since the object
name "8086100e" will not conflict with that of the underlying "intel"
object.
This problem was not detected by the per-commit smoke testing
procedure, which happens to use the binary bin/8086100e.mrom.
Reported-by: Christian Hesse <list@eworm.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Provide a single instance of EFI_DRIVER_BINDING_PROTOCOL (attached to
our image handle); this matches the expectations scattered throughout
the EFI specification.
Open the underlying hardware device using EFI_OPEN_PROTOCOL_BY_DRIVER
and EFI_OPEN_PROTOCOL_EXCLUSIVE, to prevent other drivers from
attaching to the same device.
Do not automatically connect to devices when being loaded as a driver;
leave this task to the platform firmware (or to the user, if loading
directly from the EFI shell).
When running as an application, forcibly disconnect any existing
drivers from devices that we want to control, and reconnect them on
exit.
Provide a meaningful driver version number (based on the build
timestamp), to allow platform firmware to automatically load newer
versions of iPXE drivers if multiple drivers are present.
Include device paths within debug messages where possible, to aid in
debugging.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Expose the build timestamp (measured in seconds since the Epoch) and
the build name (e.g. "rtl8139.rom" or "ipxe.efi"), and provide the
product name and product short name in a single centralised location.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When multiple iPXE binaries are running concurrently (e.g. in the case
of undionly.kpxe using an underlying iPXE driver via the UNDI
interface) it would be helpful to be able to visually distinguish
debug messages from each binary.
Allow the range of debug colours used to be customised via the
DBGCOL=... build parameter. For example:
# Restrict to colours 31-33 (red, green, yellow)
make DBGCOL=31-33
# Restrict to colours 34-36 (blue, magenta, cyan)
make DBGCOL=34-36
Signed-off-by: Michael Brown <mcb30@ipxe.org>
If iPXE is used as a git submodule then the ../.git/index file will
not exist, and the build will fail. Fix by checking that the git
index file exists before adding it as a build dependency.
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
With blade servers, the chassis serial number (exposed via ${serial})
may not be unique. Expose ${board-serial} as a named setting to
provide easy access to a more meaningful serial number.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The VF might not have assigned a MAC address upon startup, and will
end up with a random MAC address during probe(). With this patch the
MAC address can be changed later on.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
If the VF doesn't have a MAC address assigned we should create a
random MAC address.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The iBFT includes an "origin" field to indicate the source of the IP
address. We use the heuristic of assuming that the source should be
"manual" if the IP address originates directly from the network device
settings block, and "DHCP" otherwise. This is an imperfect guess, but
is likely to be correct in most common situations.
Originally-implemented-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Parse the sense data to extract the reponse code, the sense key, the
additional sense code, and the additional sense code qualifier.
Originally-implemented-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
iPXE currently calls cpu_nap() while performing DHCP, in order to
reduce CPU utilisation on virtual machines. Under mild broadcast load
(~100 packets per second), this can cause received packets to be
dropped because the receive descriptor ring is overrun before the next
18Hz timer interrupt wakes up the CPU. The result is that DHCP is
likely to intermittently fail on networks with appreciable amounts of
broadcast (or multicast) traffic.
This behaviour was introduced in the series of commits which
generalised the "dhcp" command to the "ifconf" command. The earlier
code (which did not handle IPv6 configuration) had no call to
cpu_nap() and so did not suffer from this problem.
Fix by removing the call to cpu_nap() in ifpoller_progress(). This
has the undesirable side effect that CPU utilisation will remain at
100% while waiting for DHCP to complete (which can take several
seconds, if we have to wait around for potential ProxyDHCP offers to
arrive).
Reported-by: Alex Davies <adavies@jumptrading.com>
Reported-by: Christoffer Stokbæk <christoffers@easyspeedy.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some external code (observed with FreeBSD's bootloader) will continue
to make INT 13 calls after reconfiguring the 8259 PIC to change the
vector offsets for IRQs. If an IRQ (e.g. the timer IRQ) subsequently
occurs while iPXE is in protected mode, this will cause a general
protection fault since the corresponding IDT entry is empty.
A general protection fault is INT 0x0d, which happens to overlap with
the original IRQ5. We therefore do have an ISR set up to handle a
general protection fault, but this ISR simply reflects the interrupt
down to the real-mode INT 0x0d and then attempts to return. Since our
ISR is expecting a hardware interrupt rather than a general protection
fault, it doesn't remove the error code from the stack before issuing
the iret instruction; it therefore attempts to return to a garbage
address. Since the segment part of this address is likely to be
invalid, a second general protection fault occurs. This cycle
continues until we run out of stack space and triple fault.
Fix by reflecting all INTs down to real mode. This actually reduces
the code size by four bytes (but increases the bss size by almost
2kB).
Reported-by: Brian Rak <dn@devicenull.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
If ipv6_tx() is called with a non-NULL network device, a NULL or
unspecified source address, and a destination address which does not
match any routing table entry, then it will attempt to copy the source
address from a NULL pointer.
I don't think that there is currently any code path which could
trigger this behaviour, but we should probably ensure that it can
never happen.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Destination multicast addresses require a sin6_scope_id, which should
therefore be transcribed to a network device name by ipv6_sock_ntoa().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The transmitting network device is specified via the destination
address, not the source address. There is no reason to set
sin6_scope_id on the source address.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Setting sin6_scope_id to a non-zero value will cause the check against
the "empty socket address" in udp_demux() to fail, and incoming DHCPv6
responses on interfaces other than net0 will be rejected with a
spurious "No UDP connection listening on port 546" error.
The transmitting network device is specified via the destination
address, not the source address. Fix by simply not setting
sin6_scope_id on the client socket address.
Reported-by: Anton D. Kachalov <mouse@yandex-team.ru>
Tested-by: Anton D. Kachalov <mouse@yandex-team.ru>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Fix an erroneous htonl() in the definition of IN6_IS_ADDR_LINKLOCAL(),
and add self-tests for the IN6_IS_ADDR_xxx() family of macros.
Reported-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI systems (observed with a Mac Pro) do not provide a loaded
image device path protocol. We don't currently use the loaded image
device path protocol for anything beyond printing a debug message, so
simply remove the code which attempts to fetch it.
Reported-by: Matt Woodward <pxematt@woodwardcc.com>
Tested-by: Matt Woodward <pxematt@woodwardcc.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI systems (observed with a Mac Pro) do not provide
EFI_HII_DATABASE_PROTOCOL. We can continue to function without
providing access to network device settings via HII, so make this
protocol optional and fall back to simply not providing any HII
protocols.
Reported-by: Matt Woodward <pxematt@woodwardcc.com>
Tested-by: Matt Woodward <pxematt@woodwardcc.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some UEFI systems (observed with a Mac Pro) do not provide
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. Since we use this protocol only for
debug messages, make it optional and fall back to printing the raw
device path bytes.
Reported-by: Matt Woodward <pxematt@woodwardcc.com>
Tested-by: Matt Woodward <pxematt@woodwardcc.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Get the NFS URI manipulation code out of nfs_open.c. The resulting
code is now much more readable.
Signed-off-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
strndup() may be called on a string which is not NUL-terminated. Use
strnlen() instead of strlen() to ensure that we do not read beyond the
end of such a string.
Add self-tests for strndup(), including a test case with an
unterminated string.
Originally-fixed-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Avoid generating syntactically invalid log messages by ensuring that
invalid characters are not present in the hostname. In particular,
ensure that any whitespace is stripped, since whitespace functions as
a field separator for syslog messages.
Reported-by: Alex Davies <adavies@jumptrading.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
As of commit d28bb51 ("[tcp] Defer sending ACKs until all received
packets have been processed"), increasing the RX ring size will
increase the number of received packets per transmitted ACK (since
each poll will process up to one complete receive ring). Under KVM,
this can make a substantial (up to ~200%) difference to the overall
download speed, since transmissions are very expensive.
Increase the ring fill level from four to eight packets: this
increases the download speed by around 50% at a cost of around 8kB of
heap space. Further speedups are possible by increasing the ring size
further, but it would be preferable to find alternative methods which
do not use noticeable amounts of heap space.
Tested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
An invalid free() was ironically introduced by fixing another invalid
free in commit 7aa69c4 ("[nfs] Fix an invalid free() when loading a
symlink").
Signed-off-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The bzImage boot protocol allows the real-mode code to be loaded at
any segment within base memory. (The fact that both iPXE and recent
versions of Syslinux will load the real-mode code at 1000:0000 is a
coincidence; it is not guaranteed by the specification.)
Fix by making the code relocatable.
Reported-by: Andrew Stuart <andrew@shopcusa.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Rework geniso and genliso to provide a single merged utility for
generating ISO images.
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The .lkrn prefix currently provides a zImage kernel with unused setup
sectors and the whole iPXE binary placed within the "protected mode
kernel" portion of the zImage.
The work carried out years ago to create the .mrom format provides a
mechanism allowing the iPXE binary to be split into a small real-mode
header and a larger payload. This neatly matches the way that a
bzImage is loaded: the "setup sectors" can contain the header and the
"protected mode kernel" can contain the payload.
This removes the size restrictions on an iPXE .lkrn image (and hence
on derived image formats such as .iso).
Also remove obsolete copyright information, since none of the original
code or functionality now remains.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When running inside a virtual machine (or when using the UNDI driver),
transmitting packets can be expensive. When we receive several
packets in one poll (e.g. because a slow BIOS timer interrupt routine
has caused us to fall behind in processing), we can safely send just a
single ACK to cover all of the received packets. This reduces the
time spent transmitting and allows us to clear the backlog much
faster.
Various RFCs (starting with RFC1122) state that there should be an ACK
for at least every second segment. We choose not to enforce this
rule. Under normal operation each poll should find at most one
received packet, and we will then not delay any ACKs. We delay
(i.e. omit) ACKs only when under sufficiently heavy load that we are
finding multiple packets per poll; under these conditions it is
important to clear the backlog quickly since any delay may lead to
dropped packets.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit 8540300 ("[build] Disable ccache for all relevant build
targets") attempted to generalise the rule for $(BIN)/version.o to
$(BIN)/version.% in order to apply the dependency to all relevant
build targets (debug objects, assembly listings, etc).
This generalisation appears to work for the ccache override
directives, but seems to cause make (at least, GNU make 4.0) to simply
ignore the dependency upon the git index.
Since version.c contains only some string constants, there is unlikely
to be a substantive need for its debug objects, assembly listings,
etc. Restore the previous form of the dependency and accept that
hypothetical builds with e.g. DEBUG=version will not be handled
correctly.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When profiling, exclude any time spent inside the hypervisor
responding to our MMIO accesses. This substantially reduces the
variance accumulated on many other profilers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Interrupt processing adds noise to profiling results. Allow
interrupts (from within protected mode) to be profiled separately,
with time spent within the interrupt handler being excluded from any
other profiling currently in progress.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
PXENV_UNDI_ISR calls may implicitly refill the underlying receive
ring, and so could continue to retrieve packets indefinitely. Place
an upper limit on the number of calls to PXENV_UNDI_ISR per call to
undinet_poll().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When making a call from real mode to protected mode, we save and
restore the global and interrupt descriptor table registers. The
restore currently takes place after returning to real mode, which
generates two EXCEPTION_NMIs and corresponding VM exits when running
under KVM on an Intel CPU.
Avoid the VM exits by restoring the descriptor table registers inside
prot_to_real, while still running in protected mode.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Ensure that all segment registers have zero in the low two bits before
transitioning to protected mode. This allows the CPU state to
immediately be deemed to be "valid", and eliminates the need for any
further emulated instructions.
Load the protected-mode interrupt descriptor table after switching to
protected mode, since this avoids triggering an EXCEPTION_NMI and
corresponding VM exit.
This reduces the time taken by real_to_prot under KVM by around 50%.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On an Intel CPU supporting VMX, KVM will emulate instructions while
the CPU state remains "invalid". In real mode, the CPU state is
defined to be "invalid" if any segment register has a base which is
not equal to (sreg<<4) or a limit which is not equal to 64kB.
We don't actually use the base stored in the REAL_DS descriptor for
any significant purpose. Change the base stored in this descriptor to
be equal to (REAL_DS<<4). A segment register loaded with REAL_DS is
then automatically valid in both real and protected modes. This
allows KVM to stop emulating instructions much sooner.
The only use of REAL_DS for memory accesses currently occurs in the
indirect ljmp within prot_to_real. Change this to a direct ljmp,
storing rm_cs in .text16 as part of the ljmp instruction. This
removes the only memory access via REAL_DS (thereby allowing for the
above descriptor base address hack), and also simplifies the ljmp
instruction (which will still have to be emulated).
Load the real-mode interrupt descriptor table register before
switching to real mode, since this avoids triggering an EXCEPTION_NMI
and corresponding VM exit.
This reduces the time taken by prot_to_real under KVM by around 65%.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The mode-transition code involves paths which switch back and forth
between the .text and .text16 sections. At present, only the start of
each function is labelled, which makes it difficult to decode
addresses within the parts of the function existing in a different
section.
Add explicit labels at the start of each section change, so that
addresses can be meaningfully decoded to the nearest label.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Now that we can handle interrupts while in protected mode, there is no
need to switch to real mode just to halt the CPU.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The currticks() function is called at least once per TCP packet, and
so is performance-critical. Switching to real mode just to allow the
timer interrupt to fire is expensive when running inside a virtual
machine, and imposes a significant performance cost.
Fix by enabling interrupts without switching to real mode. This
results in an approximately 100% increase in download speed when
running under KVM.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We now have the ability to handle interrupts while in protected mode,
and so no longer need to set up a dedicated interrupt descriptor table
while running COM32 executables.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
When running in a virtual machine, switching to real mode may be
expensive. Allow interrupts to be enabled while in protected mode and
reflected down to the real-mode interrupt handlers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Allow for an explicit debug level of zero, which will enable
assertions and profiling (i.e. anything controlled by NDEBUG) without
generating any debug messages.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently use flat real mode wherever real mode is required. This
guarantees that we will not surprise some unsuspecting external caller
which has carefully set up flat real mode by suddenly reducing the
segment limits to 64kB.
However, operating in flat real mode imposes a severe performance
penalty in some virtualisation environments, since some CPUs cannot
fully virtualise flat real mode and so the hypervisor must fall back
to emulation. In particular, operating under KVM on a pre-Westmere
Intel CPU will be at least an order of magnitude slower, to the point
that there is a visible teletype effect when printing anything to the
BIOS console. (Older versions of KVM used to cheat and ignore the
"flat" part of flat real mode, which masked the problem.)
Switch (back) to using genuine real mode with 64kB segment limits
instead of flat real mode. Hopefully this won't break anything.
Add an explicit switch to flat real mode before returning to the BIOS
from the ROM prefix, since we know that a PMM BIOS will call the ROM
initialisation point (and potentially the BEV) in flat real mode.
As noted in previous commit messages, it is not possible to restore
the real-mode segment limits after a transition to protected mode,
since there is no way to know which protected-mode segment descriptor
was originally used to initialise the limit portion of the segment
register.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Inside a virtual machine, writing the RX ring tail pointer may incur a
substantial overhead of processing inside the hypervisor. Minimise
this overhead by writing the tail pointer once per batch of
descriptors, rather than once per descriptor.
Profiling under qemu-kvm (version 1.6.2) shows that this reduces the
amount of time taken to refill the RX descriptor ring by around 90%.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Operations which are negligible on physical hardware (such as issuing
a posted write to the transmit ring tail register) may involve
substantial amounts of processing within the hypervisor if running in
a virtual machine.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
As observed in commit 082cedb ("[build] Fix __libgcc attribute for
recent gcc versions"), recent versions of gcc have changed the
semantics of -mrtd as applied to the implicit arithmetic functions.
It is possible for tests to succeed even if our assumptions about
gcc's interpretation of -mrtd are incorrect. In particular, if gcc
chooses to utilise a frame pointer in the calling function, then it
can tolerate a temporarily incorrect stack pointer (since the stack
pointer will shortly afterwards be restored from the frame pointer
anyway).
Add tests designed specifically to check that our implementations of
the implicit arithmetic functions manipulate the stack pointer as
expected by gcc.
The effect of these tests can be observed by temporarily reverting
commit 082cedb ("[build] Fix __libgcc attribute for recent gcc
versions"): without this fix in place, the tests will fail on gcc 4.7
and later.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We observed some time ago (in commit 4ce8d61 "Import various libgcc
functions from syslinux") that gcc seems to treat calls to the
implicit arithmetic functions (e.g. __udivdi3()) as being affected by
-mregparm but unaffected by -mrtd.
This seems to be no longer the case with current gcc versions, which
treat calls to these functions as being affected by both -mregparm and
-mrtd, as expected.
There is nothing obvious in the gcc changelogs to indicate precisely
when this happened. From experimentation with available gcc versions,
the change occurred sometime between v4.6.3 and v4.7.2. We assume
that only versions up to v4.6.x require the special treatment.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
On a 32-bit system, 64-bit division is implemented using the libgcc
functions provided in __udivmoddi4.c etc. Calls to these functions
are generated automatically by gcc, with a calling convention that is
somewhat empirical in nature. Add these self-tests primarily as a
check that we are using the correct calling convention.
Signed-off-by: Michael Brown <mcb30@ipxe.org>