Commit Graph

434 Commits (3f5b4ba6a55b8028274bf5bcee748a556caf3cc9)

Author SHA1 Message Date
Michael Brown 1295b4acff [efi] Allow initialisation via SNP interface even while claimed
iPXE will currently fail all SNP interface methods with EFI_NOT_READY
while the network devices are claimed for use by iPXE's own network
stack.

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

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

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

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

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

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

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

Debugged-by: Aaron Heusser <aaron_heusser@hotmail.com>
Debugged-by: Pico Mitchell <pico@randomapplications.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-23 22:30:04 +00:00
Michael Brown e10a40d41f [efi] Avoid dropping below TPL as at entry to iPXE
iPXE will currently drop to TPL_APPLICATION whenever the current
system time is obtained via currticks(), since the system time
mechanism relies on a timer that can fire only when the TPL is below
TPL_CALLBACK.

This can cause unexpected behaviour if the system time is obtained in
the middle of an API call into iPXE by external code.  For example,
MnpDxe sets up a 10ms periodic timer running at TPL_CALLBACK to poll
the underling EFI_SIMPLE_NETWORK_PROTOCOL device for received packets.
If the resulting poll within iPXE happens to hit a code path that
requires obtaining the current system time (e.g. due to reception of
an STP packet, which affects iPXE's blocked link timer), then iPXE
will end up temporarily dropping to TPL_APPLICATION.  This can
potentially result in retriggering the MnpDxe periodic timer, causing
code to be unexpectedly re-entered.

Fix by recording the external TPL at any entry point into iPXE and
dropping only as far as this external TPL, rather than dropping
unconditionally to TPL_APPLICATION.

The side effect of this change is that iPXE's view of the current
system time will be frozen for the duration of any API calls made into
iPXE by external code at TPL_CALLBACK or above.  Since any such
external code is already responsible for allowing execution at
TPL_APPLICATION to occur, then this should not cause a problem in
practice.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-20 16:57:50 +00:00
Michael Brown 0e26220902 [efi] Rename efi_blacklist to efi_veto
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-07 23:30:56 +00:00
Michael Brown 38a54bd3b1 [efi] Provide DMA operations for EFI PCI devices
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-05 20:18:27 +00:00
Michael Brown be1c87b722 [malloc] Rename malloc_dma() to malloc_phys()
The malloc_dma() function allocates memory with specified physical
alignment, and is typically (though not exclusively) used to allocate
memory for DMA.

Rename to malloc_phys() to more closely match the functionality, and
to create name space for functions that specifically allocate and map
DMA-capable buffers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-05 19:13:52 +00:00
Michael Brown 36dde9b0bf [efi] Retain a long-lived reference to the EFI_PCI_IO_PROTOCOL instance
Provide opened EFI PCI devices with access to the underlying
EFI_PCI_IO_PROTOCOL instance, in order to facilitate the future use of
the DMA mapping methods within the fast data path.

Do not require the use of this stored EFI_PCI_IO_PROTOCOL instance for
memory-mapped I/O (since the entire point of memory-mapped I/O as a
concept is to avoid this kind of unnecessary complexity) or for
slow-path PCI configuration space accesses (since these may be
required for access to PCI bus:dev.fn addresses that do not correspond
to a device bound via our driver binding protocol instance).

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

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

Debugged-by: Tore Anderson <tore@fud.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-30 14:25:41 +00:00
Michael Brown e5e2f3fba8 [efi] Fix memory copy length used in efi_nullify_name2()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-27 11:43:08 +00:00
Michael Brown 5b41b9a80f [efi] Nullify interfaces and leak memory on uninstallation failure
The UEFI specification allows uninstallation of a protocol interface
to fail.  There is no sensible way for code to react to this, since
uninstallation is likely to be taking place on a code path that cannot
itself fail (e.g. a code path that is itself a failure path).

Where the protocol structure exists within a dynamically allocated
block of memory, this leads to possible use-after-free bugs.  Work
around this unfortunate design choice by nullifying the protocol
(i.e. overwriting the method pointers with no-ops) and leaking the
memory containing the protocol structure.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-26 15:24:00 +00:00
Michael Brown 86c6c79fcd [efi] Allow block devices to provide their own EFI device paths
Use the device path constructed via efi_describe() for the installed
EFI_BLOCK_IO_PROTOCOL device handle.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-23 15:34:35 +01:00
Michael Brown a2e44077cd [infiniband] Allow SRP device to be described using an EFI device path
The UEFI specification provides a partial definition of an Infiniband
device path structure.  Use this structure to construct what may be a
plausible path containing at least some of the information required to
identify an SRP target device.

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

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-20 15:05:37 +01:00
Michael Brown 04cb17de50 [aoe] Allow AoE device to be described using an EFI device path
There is no standard defined for AoE device paths in the UEFI
specification, and it seems unlikely that any standard will be adopted
in future.

Choose to construct an AoE device path using a concatenation of the
network device path and a SATA device path, treating the AoE major and
minor numbers as the HBA port number and port multiplier port number
respectively.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 14:45:49 +01:00
Michael Brown 2d49ce6f08 [efi] Provide utility function to concatenate device paths
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 14:45:49 +01:00
Michael Brown 6154b1fb20 [efi] Split efi_netdev_path() out to a separate function
Provide efi_netdev_path() as a standalone function, to allow for reuse
when constructing child device paths.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 14:45:49 +01:00
Michael Brown f2c826179a [efi] Provide efi_uri_path() to construct a URI device path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-19 13:07:40 +01:00
Michael Brown 87e39a9c93 [efi] Split efi_usb_path() out to a separate function
Provide efi_usb_path() as a standalone function, to allow for reuse by
the USB mass storage driver.

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

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:37:03 +01:00
Michael Brown 2bf0fd39ca [efi] Split device path functions out to efi_path.c
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-10-16 15:36:37 +01:00
Michael Brown 02748d0a58 [efi] Defer local download process until file has been opened
When iPXE is downloading a file from an EFI_FILE_PROTOCOL instance
backed by an EFI_BLOCK_IO_PROTOCOL instance provided by the same iPXE
binary (e.g. via a hooked SAN device), then it is possible for step()
to be invoked as a result of the calls into the EFI_BLOCK_IO_PROTOCOL
methods.  This can potentially result in efi_local_step() being run
prematurely, before the file has been opened and before the parent
interface has been attached.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-24 21:45:56 +01:00
Michael Brown ccfffc797a [efi] Provide a single implementation of efipci_root_close()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-24 21:45:56 +01:00
Michael Brown fe69934191 [efi] Show memory map returned by wrapped calls to GetMemoryMap
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-22 13:59:37 +01:00
Michael Brown e08ad61bf7 [efi] Add debug wrappers for all boot services functions of interest
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-09-18 23:16:46 +01:00
Michael Brown c63e61df75 [efi] Use device path to locate filesystem from which we were loaded
The file:/ URI syntax may be used to refer to local files on the
filesystem from which the iPXE binary was loaded.  This is currently
implemented by directly using the DeviceHandle recorded in our
EFI_LOADED_IMAGE_PROTOCOL.

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

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

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-08-03 15:41:30 +01:00
Michael Brown fd47fa8fe1 [efi] Match EDK2 numbering for USB ports
The various USB specifications all use one-based numbering for ports.
This scheme is applied consistently across the various relevant
specifications, covering both port numbers that appear on the wire
(i.e. downstream hub port numbers) and port numbers that exist only
logically (i.e. root hub port numbers).

The UEFI specification is ambiguous about the port numbers as used for
the ParentPortNumber field within a USB_DEVICE_PATH structure.  As of
UEFI specification version 2.8 errata B:

- section 10.3.4.5 just states "USB Parent Port Number" with no
  indication of being zero-based or one-based

- section 17.1.1 notes that for the EFI_USB2_HC_PROTOCOL, references
  to PortNumber parameters are zero-based for root hub ports

- section 17.1.1 also mentions a TranslatorPortNumber used by
  EFI_USB2_HC_PROTOCOL, with no indication of being zero-based or
  one-based

- there are no other mentions of USB port numbering schemes.

Experimentation and inspection of the EDK2 codebase reveals that at
least the EDK2 reference implementation will use zero-based numbering
for both root and non-root hub ports when populating a USB_DEVICE_PATH
structure (though will inconsistently use one-based numbering for the
TranslatorPortNumber parameter).

Use zero-based numbering for both root and non-root hub ports when
constructing a USB_DEVICE_PATH in order to match the behaviour of the
EDK2 implementation.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-08-03 15:12:43 +01:00
Ignat Korchagin b760523357 [efi] Check the status code from AllocatePool()
According to the latest UEFI specification (Version 2.8 Errata B)
p. 7.2:

  "Buffer: A pointer to a pointer to the allocated buffer if the call
   succeeds; undefined otherwise."

So implementations are obliged neither to return NULL, if the
allocation fails, nor to preserve the contents of the pointer.

Make the logic more reliable by checking the status code from
AllocatePool() instead of checking the returned pointer for NULL

Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-07-22 12:54:18 +01:00
Michael Brown 1832f8a9b0 [efi] Claim SNP devices early in efi_download_start()
Claiming the SNP devices has the side effect of raising the TPL to
iPXE's normal operating level of TPL_CALLBACK (see the commit message
for c89a446 ("[efi] Run at TPL_CALLBACK to protect against UEFI
timers") for details).  This must happen before executing any code
that relies upon the TPL having been raised to TPL_CALLBACK.

The call to efi_snp_claim() in efi_download_start() currently happens
only after the call to xfer_open().  Calling xfer_open() will
typically result in a retry timer being started, which will result in
a call to currticks() in order to initialise the timer.  The call to
currticks() will drop to TPL_APPLICATION and restore to TPL_CALLBACK
in order to allow a timer tick to occur.  Since this call happened
before the call to efi_snp_claim(), the restored TPL is incorrect.

This in turn results in efi_snp_claim() recording the incorrect
original TPL, causing efi_snp_release() to eventually restore the
incorrect TPL, causing the system to lock up when ExitBootServices()
is called at TPL_CALLBACK.

Fix by moving the call to efi_snp_claim() to the start of
efi_download_start().

Debugged-by: Jarrod Johnson <jjohnson2@lenovo.com>
Debugged-by: He He4 Huang <huanghe4@lenovo.com>
Debugged-by: James Wang <jameswang@ami.com.tw>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-07-15 10:09:46 +01:00
Michael Brown b6eecb182e [efi] Ensure NUL byte is at lowest address within stack cookie
The NUL byte included within the stack cookie to act as a string
terminator should be placed at the lowest byte address within the
stack cookie, in order to avoid potentially including the stack cookie
value within an accidentally unterminated string.

Suggested-by: Pete Beck <pete.beck@ioactive.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-07-09 14:20:53 +01:00
Michael Brown fcdd9c0982 [efi] Distribute available entropy within stack cookie
Several of the values used to compute a stack cookie (in the absence
of a viable entropy source) will tend to have either all-zeroes or
all-ones in the higher order bits.  Rotate the values in order to
distribute the (minimal) available entropy more evenly.

Suggested-by: Pete Beck <pete.beck@ioactive.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-07-09 13:56:50 +01:00
Michael Brown 2ae5d43386 [efi] Raise TPL during driver entry point
As per commit c89a446 ("[efi] Run at TPL_CALLBACK to protect against
UEFI timers") we expect to run at TPL_CALLBACK almost all of the time.
Various code paths rely on this assumption.  Code paths that need to
temporarily lower the TPL (e.g. for entropy gathering) will restore it
to TPL_CALLBACK.

The entropy gathering code will be run during DRBG initialisation,
which happens during the call to startup().  In the case of iPXE
compiled as an EFI application this code will run within the scope of
efi_snp_claim() and so will execute at TPL_CALLBACK as expected.

In the case of iPXE compiled as an EFI driver the code will
incorrectly run at TPL_APPLICATION since there is nothing within the
EFI driver entry point that raises (and restores) the TPL.  The net
effect is that a build that includes the entropy-gathering code
(e.g. a build with HTTPS enabled) will return from the driver entry
point at TPL_CALLBACK, which causes a system lockup.

Fix by raising and restoring the TPL within the EFI driver entry
point.

Debugged-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-06-30 16:45:48 +01:00
Michael Brown a87537d44c [efi] Detect and disable seriously broken EFI_RNG_PROTOCOL implementations
The EFI_RNG_PROTOCOL on the Microsoft Surface Go does not generate
random numbers.  Successive calls to GetRNG() without any intervening
I/O operations (such as writing to the console) will produce identical
results.  Successive reboots will produce identical results.

It is unclear what the Microsoft Surface Go is attempting to use as an
entropy source, but it is demonstrably producing zero bits of entropy.

The failure is already detected by the ANS-mandated Repetition Count
Test performed as part of our GetEntropy implementation.  This
currently results in the entropy source being marked as broken, with
the result that iPXE refuses to perform any operations that require a
working entropy source.

We cannot use the existing EFI driver blacklisting mechanism to unload
the broken driver, since the RngDxe driver is integrated into the
DxeCore image.

Work around the broken driver by checking for consecutive identical
results returned by EFI_RNG_PROTOCOL and falling back to the original
timer-based entropy source.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-06-28 19:58:48 +01:00
Michael Brown a61b27b97f [efi] Enable stack protection where possible
Enable -fstack-protector for EFI builds, where binary size is less
critical than for BIOS builds.

The stack cookie must be constructed immediately on entry, which
prohibits the use of any viable entropy source.  Construct a cookie by
XORing together various mildly random quantities to produce a value
that will at least not be identical on each run.

On detecting a stack corruption, attempt to call Exit() with an
appropriate error.  If that fails, then lock up the machine since
there is no other safe action that can be taken.

The old conditional check for support of -fno-stack-protector is
omitted since this flag dates back to GCC 4.1.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-06-24 16:23:21 +01:00
Michael Brown 9ee70fb95b [efi] Attempt to connect our driver directly if ConnectController fails
Some platforms (observed with an AMI BIOS on an Apollo Lake system)
will spuriously fail the call to ConnectController() when the UEFI
network stack is disabled.  This appears to be a BIOS bug that also
affects attempts to connect any non-iPXE driver to the NIC controller
handle via the UEFI shell "connect" utility.

Work around this BIOS bug by falling back to calling our
efi_driver_start() directly if the call to ConnectController() fails.
This bypasses any BIOS policy in terms of deciding which driver to
connect but still cooperates with the UEFI driver model in terms of
handle ownership, since the use of EFI_OPEN_PROTOCOL_BY_DRIVER ensures
that the BIOS is aware of our ownership claim.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-06-10 23:01:23 +01:00
Michael Brown ac28bbb7ea [efi] Work around UEFI specification bug in LoadImage for SAN boot
As described in the previous commit, work around a UEFI specification
bug that necessitates calling UnloadImage if the return value from
LoadImage is EFI_SECURITY_VIOLATION.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-06-05 09:44:22 +01:00
Michael Brown bdf0e029ae [efi] Disambiguate errors returned by ConnectController
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-03-14 09:49:49 +00:00
Valentine Barshak 412acd7854 [build] Fix "'%s' directive argument is null" error
Use '%p' directive, and print handle's address if the address is null
and the handle doesn't have a name.  This fixes the following
compilation error:

  interface/efi/efi_debug.c:334:3: error: '%s' directive
  argument is null [-Werror=format-overflow=]

Signed-off-by: Valentine Barshak <gvaxon@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2019-07-22 11:07:13 +01:00
Michael Brown 6dde0f60bf [efi] Register a device tree if provided by the platform firmware
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2019-07-19 17:43:02 +01:00
Michael Brown a385e23768 [efi] Return only registered EFI devices from efidev_parent()
efidev_parent() currently assumes that any device with BUS_TYPE_EFI is
part of a struct efi_device.  This assumption is not valid, since the
code in efi_device_info() may also create a device with BUS_TYPE_EFI.

Fix by searching through the list of registered EFI devices when
looking for a match, instead of relying on the bus type value.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2019-07-15 12:49:47 +01:00
Michael Brown 64b4452bca [efi] Blacklist the Dell Ip4ConfigDxe driver
On a Dell OptiPlex 7010, calling DisconnectController() on the LOM
device handle will lock up the system.  Debugging shows that execution
is trapped in an infinite loop that is somehow trying to reconnect
drivers (without going via ConnectController()).

The problem can be reproduced in the UEFI shell with no iPXE code
present, by using the "disconnect" command.  Experimentation shows
that the only fix is to unload (rather than just disconnect) the
"Ip4ConfigDxe" driver.

Add the concept of a blacklist of UEFI drivers that will be
automatically unloaded when iPXE runs as an application, and add the
Dell Ip4ConfigDxe driver to this blacklist.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2019-02-19 19:02:11 +00:00
Michael Brown 36a4c85f91 [init] Show startup and shutdown function names in debug messages
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2019-01-25 14:53:43 +00:00
Ignat Korchagin e226fecd1b [efi] Fix error handling path in efi_snp_probe
Current (simplified):

1. InstallMultipleProtocolInterfaces
       if err goto err_install_protocol_interface;
2. OpenProtocol(efi_nii_protocol_guid)
       if err goto err_open_nii;
3. OpenProtocol(efi_nii31_protocol_guid)
       if err goto err_open_nii31;
4. efi_child_add
       if err goto err_efi_child_add;
...
err_efi_child_add:
   CloseProtocol(efi_nii_protocol_guid) <= should be efi_nii31_protocol_guid
err_open_nii: <= should be err_open_nii31
   CloseProtocol(efi_nii31_protocol_guid) <= should be efi_nii_protocol_guid
err_open_nii31: <= should be err_open_nii
   UninstallMultipleProtocolInterfaces

Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2019-01-15 14:01:17 +00:00
Roman Kagan 40956545e2 [vmbus] Do not expect version in version_response
The definition of version_response channel message in Linux doesn't
include version field, so the upcoming VMBus implementation in QEMU
doesn't set it either.  Neither Windows nor Linux had any problem with
this.

The check against this field is redundant because the message is the
response to initiate_contact message containing the specific version
requested, so the response with version_supported=true is unambiguous.

Drop this check and don't rely on the field to be present in the
message.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-07-08 00:45:47 +01:00
Rob Taglang 88ac1d3fe4 [efi] Exclude link-layer header length from MaxPacketSize
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-07-07 20:12:10 +01:00
Michael Brown 4f362a032b [efi] Do not raise TPL within EFI_DRIVER_BINDING_PROTOCOL.Supported()
When booting some versions of the UEFI shell, our driver binding
protocol's Supported() entry point is called at TPL_NOTIFY for no
discernible reason.  Attempting to raise to TPL_CALLBACK triggers an
immediate assertion failure in the firmware.

Since our Supported() method can run at any TPL, fix by simply not
attempting to raise the TPL within this method.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-03-26 12:10:09 +01:00
Michael Brown 331ac451e7 [efi] Release SNP devices before starting SAN boot image
Release SNP devices to allow the SAN booted image to use our
EFI_SIMPLE_NETWORK_PROTOCOL instance, and to ensure that the image is
started at TPL_APPLICATION.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-03-26 11:31:41 +01:00
Michael Brown 10d083ffa9 [efi] Raise TPL within EFI_DRIVER_BINDING_PROTOCOL entry points
Debugged-by: Rob Taglang <rob@privatemachines.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-03-14 23:55:28 +00:00
Michael Brown d8c500b794 [efi] Drop to TPL_APPLICATION when gathering entropy
Commit c89a446 ("[efi] Run at TPL_CALLBACK to protect against UEFI
timers") introduced a regression in the EFI entropy gathering code.
When the EFI_RNG_PROTOCOL is not present, we fall back to using timer
interrupts (as for the BIOS build).  Since timer interrupts are
disabled at TPL_CALLBACK, WaitForEvent() fails and no entropy can be
gathered.

Fix by dropping to TPL_APPLICATION while entropy gathering is enabled.

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-03-12 11:02:19 +00:00
Michael Brown f672a27b34 [efi] Raise TPL within EFI_USB_IO_PROTOCOL entry points
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-02-20 11:19:39 +00:00
Michael Brown a272b7ce57 [efi] Raise TPL within EFI_SIMPLE_NETWORK_PROTOCOL entry points
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-02-20 11:19:21 +00:00
Michael Brown c89a446cf0 [efi] Run at TPL_CALLBACK to protect against UEFI timers
As noted in the comments, UEFI manages to combines the all of the
worst aspects of both a polling design (inefficiency and inability to
sleep until something interesting happens) and of an interrupt-driven
design (the complexity of code that could be preempted at any time,
thanks to UEFI timers).

This causes problems in particular for UEFI USB keyboards: the
keyboard driver calls UsbAsyncInterruptTransfer() to set up a periodic
timer which is used to poll the USB bus.  This poll may interrupt a
critical section within iPXE, typically resulting in list corruption
and either a hang or reboot.

Work around this problem by mirroring the BIOS design, in which we run
with interrupts disabled almost all of the time.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2018-02-20 10:56:31 +00:00
Michael Brown e4461f65d8 [xen] Skip probing of any unsupported device types
Xen 4.4 includes the device "device/suspend/event-channel" which does
not have a "backend" key.  This currently causes the entire XenBus
device tree probe to fail.

Fix by skipping probe attempts for device types for which there is no
iPXE driver.

Debugged-by: Eytan Heidingsfeld <eytanh@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-12-28 12:09:27 +00:00
Michael Brown 74d90b33f8 [efi] Inhibit our driver Start() method during disconnection attempts
Some HP BIOSes (observed with a Z840) seem to attempt to connect our
drivers in the middle of our call to DisconnectController().  The
precise chain of events is unclear, but the symptom is that we see
several calls to our Supported() and Start() methods, followed by a
system lock-up.

Work around this dubious BIOS behaviour by explicitly failing calls to
our Start() method while we are in the middle of attempting to
disconnect drivers.

Reported-by: Jordan Wright <jordan.m.wright@disney.com>
Debugged-by: Adrian Lucrèce Céleste <adrianlucrececeleste@airmail.cc>
Debugged-by: Christian Nilsson <nikize@gmail.com>
Tested-by: Jordan Wright <jordan.m.wright@disney.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-09-22 18:39:04 +01:00
Michael Brown d46c53cfc6 [efi] Continue to connect remaining handles after connection errors
Some UEFI BIOSes will deliberately break the implementation of
ConnectController() to return errors for devices that have been
"disabled" via the BIOS setup screen.  (As an added bonus, such BIOSes
may return garbage EFI_STATUS values such as 0xff.)

Work around these broken UEFI BIOSes by ignoring failures and
continuing to attempt to connect any remaining handles.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-09-13 10:07:55 +03:00
Michael Brown e8f30571a3 [efi] Match behaviour of SnpDxe for truncated received packets
The UEFI specification does not state whether or not a return value of
EFI_BUFFER_TOO_SMALL from the SNP Receive() method should follow the
usual EFI API behaviour of allowing the caller to retry the request
with an increased buffer size.

Examination of the SnpDxe driver in EDK2 suggests that Receive() will
just return the truncated packet (complete with any requested
link-layer header fields), so match this behaviour.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-09-06 23:56:22 +01:00
Michael Brown 3f429bdcfe [efi] Check buffer length for packets retrieved via our SNP protocol
We do not currently check the length of the caller's buffer for
received packets.  This creates a potential buffer overrun when iPXE
is being used via the SNP or UNDI protocols.

Fix by checking the buffer length and correctly returning the required
length and an EFI_BUFFER_TOO_SMALL error.

Reported-by: Paul McMillan <paul.mcmillan@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-09-06 23:28:21 +01:00
Michael Brown 993fd2b451 [efi] Provide access to ACPI tables
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-05-23 18:48:02 +01:00
Michael Brown de37652044 [efi] Prevent EFI code from being linked in to non-EFI builds
Ensure that efi_systab is an undefined symbol in non-EFI builds.  In
particular, this prevents users from incorrectly enabling IMAGE_EFI in
a BIOS build of iPXE.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-05-19 12:21:18 +01:00
Michael Brown 17887f87b7 [efi] Standardise PCI debug messages
Use the PCI bus:dev.fn address in debug messages, falling back to the
EFI handle name only if we do not yet have enough information to
determine the bus:dev.fn address.

Include the vendor and device IDs in debug messages when no suitable
driver is found, to match the diagnostics available in a BIOS
environment.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-05-01 14:01:54 +01:00
Michael Brown b91cc983da [hyperv] Cope with Windows Server 2016 enlightenments
An "enlightened" external bootloader (such as Windows Server 2016's
winload.exe) may take ownership of the Hyper-V connection before all
INT 13 operations have been completed.  When this happens, all VMBus
devices are implicitly closed and we are left with a non-functional
network connection.

Detect when our Hyper-V connection has been lost (by checking the
SynIC message page MSR).  Reclaim ownership of the Hyper-V connection
and reestablish any VMBus devices, without disrupting any existing
iPXE state (such as IPv4 settings attached to the network device).

Windows Server 2016 will not cleanly take ownership of an active
Hyper-V connection.  Experimentation shows that we can quiesce by
resetting only the SynIC message page MSR; this results in a
successful SAN boot (on a Windows 2012 R2 physical host).  Choose to
quiesce by resetting (almost) all MSRs, in the hope that this will be
more robust against corner cases such as a stray synthetic interrupt
occurring during the handover.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-04-28 16:20:47 +01:00
Michael Brown dd976cb50d [block] Provide sandev_read() and sandev_write() as global symbols
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-04-26 20:15:39 +01:00
Michael Brown 84d406ccf4 [block] Allow use of a non-default EFI SAN boot filename
Some older operating systems (e.g. RHEL6) use a non-default filename
on the root disk and rely on setting an EFI variable to point to the
bootloader.  This does not work when performing a SAN boot on a
machine where the EFI variable is not present.

Fix by allowing a non-default filename to be specified via the
"sanboot --filename" option or the "san-filename" setting.  For
example:

  sanboot --filename \efi\redhat\grub.efi \
          iscsi:192.168.0.1::::iqn.2010-04.org.ipxe.demo:rhel6

or

  option ipxe.san-filename code 188 = string;
  option ipxe.san-filename "\\efi\\redhat\\grub.efi";
  option root-path "iscsi:192.168.0.1::::iqn.2010-04.org.ipxe.demo:rhel6";

Originally-implemented-by: Vishvananda Ishaya Abrams <vish.ishaya@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-04-12 15:58:05 +01:00
Michael Brown 6c7487d00d [efi] Fix typo in efi_acpi_table_protocol_guid
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-04-10 16:46:11 +01:00
Michael Brown 7cfdd769aa [block] Describe all SAN devices via ACPI tables
Describe all SAN devices via ACPI tables such as the iBFT.  For tables
that can describe only a single device (i.e. the aBFT and sBFT), one
table is installed per device.  For multi-device tables (i.e. the
iBFT), all devices are described in a single table.

An underlying SAN device connection may be closed at the time that we
need to construct an ACPI table.  We therefore introduce the concept
of an "ACPI descriptor" which enables the SAN boot code to maintain an
opaque pointer to the underlying object, and an "ACPI model" which can
build tables from a list of such descriptors.  This separates the
lifecycles of ACPI descriptions from the lifecycles of the block
device interfaces, and allows for construction of the ACPI tables even
if the block device interface has been closed.

For a multipath SAN device, iPXE will wait until sufficient
information is available to describe all devices but will not wait for
all paths to connect successfully.  For example: with a multipath
iSCSI boot iPXE will wait until at least one path has become available
and name resolution has completed on all other paths.  We do this
since the iBFT has to include IP addresses rather than DNS names.  We
will commence booting without waiting for the inactive paths to either
become available or close; this avoids unnecessary boot delays.

Note that the Linux kernel will refuse to accept an iBFT with more
than two NIC or target structures.  We therefore describe only the
NICs that are actually required in order to reach the described
targets.  Any iBFT with at most two targets is therefore guaranteed to
describe at most two NICs.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-28 19:12:48 +03:00
Michael Brown bb5a54b79a [block] Add basic multipath support
Add basic support for multipath block devices.  The "sanboot" and
"sanhook" commands now accept a list of SAN URIs.  We open all URIs
concurrently.  The first connection to become available for issuing
block device commands is marked as the active path and used for all
subsequent commands; all other connections are then closed.  Whenever
the active path fails, we reopen all URIs and repeat the process.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-26 16:06:02 +03:00
Michael Brown 01496a5028 [xen] Use standard calling pattern for asprintf()
Our asprintf() implementation guarantees that strp will be NULL on
allocation failure, but this is not standard behaviour.  Detect errors
by checking for a negative return value instead of a NULL pointer.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-22 14:41:01 +02:00
Michael Brown 8963193cda [hyperv] Fix resource leaks on error path
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-21 14:51:03 +02:00
Michael Brown fdcdc5203b [efi] Provide ACPI table description for SAN devices
Provide a basic proof of concept ACPI table description (e.g. iBFT for
iSCSI) for SAN devices in a UEFI environment, using a control flow
that is functionally identical to that used in a BIOS environment.

Originally-implemented-by: Vishvananda Ishaya Abrams <vish.ishaya@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-13 12:18:46 +00:00
Michael Brown 553f485734 [efi] Add EFI_ACPI_TABLE_PROTOCOL header and GUID definition
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-10 21:58:05 +00:00
Michael Brown 23d388418e [efi] Refactor to use centralised SAN device abstraction
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-07 13:40:35 +00:00
Michael Brown e7ee2eda4b [block] Centralise "san-drive" setting
The concept of the SAN drive number is meaningful only in a BIOS
environment, where it represents the INT13 drive number (0x80 for the
first hard disk).  We retain this concept in a UEFI environment to
allow for a simple way for iPXE commands to refer to SAN drives.

Centralise the concept of the default drive number, since it is shared
between all supported environments.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-03-07 13:40:35 +00:00
Michael Brown 302f1eeb80 [time] Allow timer to be selected at runtime
Allow the active timer (providing udelay() and currticks()) to be
selected at runtime based on probing during the INIT_EARLY stage of
initialisation.

TICKS_PER_SEC is now a fixed compile-time constant for all builds, and
is independent of the underlying clock tick rate.  We choose the value
1024 to allow multiplications and divisions on seconds to be converted
to bit shifts.

TICKS_PER_MS is defined as 1, allowing multiplications and divisions
on milliseconds to be omitted entirely.  The 2% inaccuracy in this
definition is negligible when using the standard BIOS timer (running
at around 18.2Hz).

TIMER_RDTSC now checks for a constant TSC before claiming to be a
usable timer.  (This timer can be tested in KVM via the command-line
option "-cpu host,+invtsc".)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-01-26 08:17:37 +00:00
Michael Brown 321af68b72 [hyperv] Ignore unsolicited VMBus messages
In some high-end Azure instances (e.g. NC6) we may receive an
unsolicited VMBUS_OFFER_CHANNEL message for a PCIe pass-through device
some time after completing the bus enumeration.  This currently causes
apparently random failures due to unexpected VMBus message types.

Fix by ignoring any unsolicited VMBus messages.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2017-01-24 15:03:10 +00:00
Michael Brown 5cf5ffea28 [efi] Work around temporal anomaly encountered during ExitBootServices()
EFI provides no clean way for device drivers to shut down in
preparation for handover to a booted operating system.  The platform
firmware simply doesn't bother to call the drivers' Stop() methods.
Instead, drivers must register an EVT_SIGNAL_EXIT_BOOT_SERVICES event
to be signalled when ExitBootServices() is called, and clean up
without any reference to the EFI driver model.

Unfortunately, all timers silently stop working when ExitBootServices()
is called.  Even more unfortunately, and for no discernible reason,
this happens before any EVT_SIGNAL_EXIT_BOOT_SERVICES events are
signalled.  The net effect of this entertaining design choice is that
any timeout loops on the shutdown path (e.g. for gracefully closing
outstanding TCP connections) may wait indefinitely.

There is no way to report failure from currticks(), since the API
lazily assumes that the host system continues to travel through time
in the usual direction.  Work around EFI's violation of this
assumption by falling back to a simple free-running monotonic counter.

Debugged-by: Maor Dickman <maord@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-12-07 13:46:37 +00:00
Michael Brown fd95c780b6 [efi] Add basic EFI SAN booting capability
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-11-16 23:03:37 +00:00
Michael Brown 0be77e959e [efi] Add EFI_BLOCK_IO2_PROTOCOL header and GUID definition
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-10-16 23:27:50 +01:00
Michael Brown 145aae3998 [hyperv] Use instance UUID in device name
The Windows drivers for VMBus devices are enumerated using the
instance UUID rather than the channel number.  Include the instance
UUID within the iPXE device name to allow an iPXE network device to be
more easily associated with the corresponding Windows network device
when debugging.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-07-26 16:27:12 +01:00
Laszlo Ersek d6817943d1 [efi] Install the HII config access protocol on a child of the SNP handle
In edk2, there are several drivers that associate HII forms (and
corresponding config access protocol instances) with each individual
network device.  (In this context, "network device" means the EFI
handle on which the SNP protocol is installed, and on which the device
path ending with the MAC() node is installed also.)  Such edk2 drivers
are, for example: Ip4Dxe, HttpBootDxe, VlanConfigDxe.

In UEFI, any given handle can carry at most one instance of a specific
protocol (see e.g. the specification of the InstallProtocolInterface()
boot service).  This implies that the class of drivers mentioned above
can't install their EFI_HII_CONFIG_ACCESS_PROTOCOL instances on the
SNP handle directly -- they would conflict with each other.
Accordingly, each of those edk2 drivers creates a "private" child
handle under the SNP handle, and installs its config access protocol
(and corresponding HII package list) on its child handle.

The device path for the child handle is traditionally derived by
appending a Hardware Vendor Device Path node after the MAC() node.
The VenHw() nodes in question consist of a GUID (by definition), and
no trailing data (by choice).  The purpose of these VenHw() nodes is
only that all the child nodes can be uniquely identified by device
path.

At the moment iPXE does not follow this pattern.  It doesn't run into
a conflict when it installs its EFI_HII_CONFIG_ACCESS_PROTOCOL
directly on the SNP handle, but that's only because iPXE is the sole
driver not following the pattern.  This behavior seems risky (one
might call it a "latent bug"); better align iPXE with the edk2 custom.

Cc: Michael Brown <mcb30@ipxe.org>
Cc: Gary Lin <glin@suse.com>
Cc: Ladi Prosek <lprosek@redhat.com>
Ref: http://thread.gmane.org/gmane.comp.bios.edk2.devel/13494/focus=13532
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ladi Prosek <lprosek@redhat.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-07-08 14:16:32 +01:00
Michael Brown c9f6a86059 [efi] Fix uninitialised data in HII IFR structures
The HII IFR structures are allocated via realloc() rather than
zalloc(), and so are not automatically zeroed.  This results in the
presence of uninitialised and invalid data, causing crashes elsewhere
in the UEFI firmware.

Fix by explicitly zeroing the newly allocated portion of any IFR
structure in efi_ifr_op().

Debugged-by: Laszlo Ersek <lersek@redhat.com>
Debugged-by: Gary Lin <glin@suse.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-06-29 15:17:12 +01:00
Michael Brown 632e57f0f3 [efi] Do not copy garbage bytes into SNP device path MAC address
The SNP device path includes the network device's MAC address within
the MAC_ADDR_DEVICE_PATH.MacAddress field.  We check that the
link-layer address will fit within this field, and then perform the
copy using the length of the destination buffer.

At 32 bytes, the MacAddress field is actually larger than the current
maximum iPXE link-layer address.  The copy therefore overflows the
source buffer, resulting in trailing garbage bytes being appended to
the device path's MacAddress.  This is invisible in debug messages,
since the DevicePathToText protocol will render only the length
implied by the interface type.

Fix by copying only the actual length of the link-layer address (which
we have already verified will not overflow the destination buffer).

Debugged-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-06-22 09:07:20 +01:00
Michael Brown 694c18addc [efi] Report failures to stop the EFI timer tick event
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-06-20 16:08:17 +01:00
Michael Brown 8f0bec4346 [efi] Include VLAN in SNP device path if applicable
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-06-18 18:45:18 +01:00
Michael Brown f76210961c [pci] Support systems with multiple PCI root bridges
Extend the 16-bit PCI bus:dev.fn address to a 32-bit seg🚌dev.fn
address, assuming a segment value of zero in contexts where multiple
segments are unsupported by the underlying data structures (e.g. in
the iBFT or BOFM tables).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-06-09 09:36:28 +01:00
Michael Brown aa4b038c70 [efi] Expose DHCP packets via the Apple NetBoot protocol
Mac OS X uses non-standard EFI protocols to obtain the DHCP packets
from the UEFI firmware.

Originally-implemented-by: Michael Kuron <m.kuron@gmx.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-05-29 13:10:14 +01:00
Michael Brown 57d0ea7c46 [efi] Generalise EFI entropy generation to non-x86 CPUs
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-05-04 14:34:24 +01:00
Michael Brown 757ab98381 [efi] Use a timer event to generate the currticks() timer
We currently use the EFI_CPU_ARCH_PROTOCOL's GetTimerValue() method to
generate the currticks() timer, calibrated against a 1ms delay from
the boot services Stall() method.

This does not work on ARM platforms, where GetTimerValue() is an empty
stub which just returns EFI_UNSUPPORTED.

Fix by instead creating a periodic timer event, and using this event
to increment a current tick counter.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-05-04 13:38:33 +01:00
Michael Brown 5238c85b62 [efi] Work around broken EFI HII specification
The EFI_HII_CONFIG_ACCESS_PROTOCOL's ExtractConfig() method is passed
a request string which includes the parameters being queried plus an
apparently meaningless blob of information (the ConfigHdr), and is
expected to include this same meaningless blob of information in the
results string.

Neither the specification nor the existing EDK2 code (including the
nominal reference implementation in the DriverSampleDxe driver)
provide any reason for the existence of this meaningless blob of
information.  It appears to be consumed in its entirety by the
EFI_HII_CONFIG_ROUTING_PROTOCOL, and to contain zero bits of
information by the time it reaches an EFI_HII_CONFIG_ACCESS_PROTOCOL
instance.  It would potentially allow for multiple configuration data
sets to be handled by a single EFI_HII_CONFIG_ACCESS_PROTOCOL
instance, in a style alien to the rest of the UEFI specification
(which implicitly assumes that the instance pointer is always
sufficient to uniquely identify the instance).

iPXE currently handles this by simply copying the ConfigHdr from the
request string to the results string, and otherwise ignoring it.  This
approach is also used by some code in EDK2, such as OVMF's PlatformDxe
driver.

As of EDK2 commit 8a45f80 ("MdeModulePkg: Make HII configuration
settings available to OS runtime"), this causes an assertion failure
inside EDK2.  The failure arises when iPXE is handled a NULL request
string, and responds (as per the specification) with a results string
including all settings.  Since there is no meaningless blob to copy
from the request string, there is no corresponding meaningless blob in
the results string.  This now causes an assertion failure in
HiiDatabaseDxe's HiiConfigRoutingExportConfig().

The same failure does not affect the OVMF PlatformDxe driver, which
simply passes the request string to the HII BlockToConfig() utility
function.  The BlockToConfig() function returns EFI_INVALID_PARAMETER
when passed a null request string, and PlatformDxe propagates this
error directly to the caller.

Fix by matching the behaviour of OVMF's PlatformDxe driver: explicitly
return EFI_INVALID_PARAMETER if the request string is NULL or empty.
This violates the specification (insofar as it is feasible to
determine what the specification actually requires), but causes
correct behaviour with the EDK2 codebase.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-04-12 12:24:14 +01:00
Michael Brown 04ef198d2f [efi] Move architecture-independent EFI prefixes to interface/efi
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-03-17 14:51:14 +00:00
Michael Brown 9bab13a772 [hyperv] Use generic set_bit() function
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2016-03-16 22:33:41 +00:00