summaryrefslogtreecommitdiffstats
path: root/src/interface/efi/efi_pci.c
Commit message (Collapse)AuthorAgeFilesLines
* [efi] Do not attempt to drive PCI bridge devicesMichael Brown2023-02-031-0/+10
| | | | | | | | | | | | | | | | | | | | | | | | The "bridge" driver introduced in 3aa6b79 ("[pci] Add minimal PCI bridge driver") is required only for BIOS builds using the ENA driver, where experimentation shows that we cannot rely on the BIOS to fully assign MMIO addresses. Since the driver is a valid PCI driver, it will end up binding to all PCI bridge devices even on a UEFI platform, where the firmware is likely to have completed MMIO address assignment correctly. This has no impact on most systems since there is generally no UEFI driver for PCI bridges: the enumeration of the whole PCI bus is handled by the PciBusDxe driver bound to the root bridge. Experimentation shows that at least one laptop will freeze at the point that iPXE attempts to bind to the bridge device. No deeper investigation has been carried out to find the root cause. Fix by causing efipci_supported() to return an error unless the configuration space header type indicates a non-bridge device. Reported-by: Marcel Petersen <mp@sbe.de> Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Clear DMA-coherent buffers before mappingMichael Brown2022-11-041-0/+3
| | | | | | | | | | | | | | | | | | | The DMA mapping is performed implicitly as part of the call to dma_alloc(). The current implementation creates the IOMMU mapping for the allocated and potentially uninitialised data before returning to the caller (which will immediately zero out or otherwise initialise the buffer). This leaves a small window within which a malicious PCI device could potentially attempt to retrieve firmware-owned secrets present in the uninitialised buffer. (Note that the hypothetically malicious PCI device has no viable way to know the address of the buffer from which to attempt a DMA read, rendering the attack extremely implausible.) Guard against any such hypothetical attacks by zeroing out the allocated buffer prior to creating the coherent DMA mapping. Suggested-by: Mateusz Siwiec <Mateusz.Siwiec@ioactive.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [pci] Generalise pci_num_bus() to pci_discover()Michael Brown2022-09-151-1/+1
| | | | | | | | | | Allow pci_find_next() to discover devices beyond the first PCI segment, by generalising pci_num_bus() (which implicitly assumes that there is only a single PCI segment) with pci_discover() (which has the ability to return an arbitrary contiguous chunk of PCI bus:dev.fn address space). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Show ACPI address space descriptor ranges in debug messagesMichael Brown2021-04-211-0/+3
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Always map full length of coherent DMA buffer allocationMichael Brown2021-04-201-1/+2
| | | | | | | | | | | | | | | The EFI PCI API takes a page count as the input to AllocateBuffer() but a byte count as the input to Map(). There is nothing in the UEFI specification that requires us to map exactly the allocated length, and no systems have yet been observed that will fail if the map length does not exactly match the allocated length. However, it is plausible that some implementations may fail if asked to map a length that does not match the length of the corresponding allocation. Avoid potential future problems by always mapping the full allocated length. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Use segment and bus number to identify PCI root bridge I/O protocolMichael Brown2020-12-311-4/+68
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There may be multiple instances of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL for a single PCI segment. Use the bus number range descriptor from the ACPI resource list to identify the correct protocol instance. There is some discrepancy between the ACPI and UEFI specifications regarding the interpretation of values within the ACPI resource list. The ACPI specification defines the min/max field values to be within the secondary (device-side) address space, and defines the offset field value as "the offset that must be added to the address on the secondary side to obtain the address on the primary side". The UEFI specification states instead that the offset field value is the "offset to apply to the starting address to convert it to a PCI address", helpfully omitting to clarify whether "to apply" in this context means "to add" or "to subtract". The implication of the wording is also that the "starting address" is not already a "PCI address" and must therefore be a host-side address rather than the ACPI-defined device-side address. Code comments in the EDK2 codebase seem to support the latter (non-ACPI) interpretation of these ACPI structures. For example, in the PciHostBridgeDxe driver there can be found the comment Macros to translate device address to host address and vice versa. According to UEFI 2.7, device address = host address + translation offset. along with a pair of macros TO_HOST_ADDRESS() and TO_DEVICE_ADDRESS() which similarly negate the sense of the "translation offset" from the definition found in the ACPI specification. The existing logic in efipci_ioremap() (based on a presumed-working externally contributed patch) applies the non-ACPI interpretation: it assumes that min/max field values are host-side addresses and that the offset field value is negated. Match this existing logic by assuming that min/max field values are host-side bus numbers. (The bus number offset value is therefore not required and so can be ignored.) As noted in commit 9b25f6e ("[efi] Fall back to assuming identity mapping of MMIO address space"), some systems seem to fail to provide MMIO address space descriptors. Assume that some systems may similarly fail to provide bus number range descriptors, and fall back in this situation to assuming that matching on segment number alone is sufficient. Testing any of this is unfortunately impossible without access to esoteric hardware that actually uses non-zero translation offsets. Originally-implemented-by: Thomas Walker <twalker@twosigma.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Provide dma_umalloc() for allocating large DMA-coherent buffersMichael Brown2020-11-291-0/+34
| | | | | | | | | | | | | | Some devices (e.g. xHCI USB host controllers) may require the use of large areas of host memory for private use by the device. These allocations cannot be satisfied from iPXE's limited heap space, and so are currently allocated using umalloc() which will allocate external system memory (and alter the system memory map as needed). Provide dma_umalloc() to provide such allocations as part of the DMA API, since there is otherwise no way to guarantee that the allocated regions are usable for coherent DMA. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Avoid requesting zero-length DMA mappingsMichael Brown2020-11-291-12/+16
| | | | | | | | | The UEFI specification does not prohibit zero-length DMA mappings. However, there is a reasonable chance that at least one implementation will treat it as an invalid parameter. As a precaution, avoid calling EFI_PCI_IO_PROTOCOL.Map() with a length of zero. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Move I/O buffer DMA operations to iobuf.hMichael Brown2020-11-281-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Include a potential DMA mapping within the definition of an I/O buffer, and move all I/O buffer DMA mapping functions from dma.h to iobuf.h. This avoids the need for drivers to maintain a separate list of DMA mappings for each I/O buffer that they may handle. Network device drivers typically do not keep track of transmit I/O buffers, since the network device core already maintains a transmit queue. Drivers will typically call netdev_tx_complete_next() to complete a transmission without first obtaining the relevant I/O buffer pointer (and will rely on the network device core automatically cancelling any pending transmissions when the device is closed). To allow this driver design approach to be retained, update the netdev_tx_complete() family of functions to automatically perform the DMA unmapping operation if required. For symmetry, also update the netdev_rx() family of functions to behave the same way. As a further convenience for drivers, allow the network device core to automatically perform DMA mapping on the transmit datapath before calling the driver's transmit() method. This avoids the need to introduce a mapping error handling code path into the typically error-free transmit methods. With these changes, the modifications required to update a typical network device driver to use the new DMA API are fairly minimal: - Allocate and free descriptor rings and similar coherent structures using dma_alloc()/dma_free() rather than malloc_phys()/free_phys() - Allocate and free receive buffers using alloc_rx_iob()/free_rx_iob() rather than alloc_iob()/free_iob() - Calculate DMA addresses using dma() or iob_dma() rather than virt_to_bus() - Set a 64-bit DMA mask if needed using dma_set_mask_64bit() and thereafter eliminate checks on DMA address ranges - Either record the DMA device in netdev->dma, or call iob_map_tx() as part of the transmit() method - Ensure that debug messages use virt_to_phys() when displaying "hardware" addresses Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Record DMA device as part of DMA mapping if neededMichael Brown2020-11-281-12/+13
| | | | | | | Allow for dma_unmap() to be called by code other than the DMA device driver itself. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [dma] Modify DMA API to simplify calculation of medial addressesMichael Brown2020-11-251-3/+3
| | | | | | | | | | | | | | | | | Redefine the value stored within a DMA mapping to be the offset between physical addresses and DMA addresses within the mapped region. Provide a dma() wrapper function to calculate the DMA address for any pointer within a mapped region, thereby simplifying the use cases when a device needs to be given addresses other than the region start address. On a platform using the "flat" DMA implementation the DMA offset for any mapped region is always zero, with the result that dma_map() can be optimised away completely and dma() reduces to a straightforward call to virt_to_phys(). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Provide DMA operations for EFI PCI devicesMichael Brown2020-11-051-0/+237
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Retain a long-lived reference to the EFI_PCI_IO_PROTOCOL instanceMichael Brown2020-11-041-36/+38
| | | | | | | | | | | | | | | 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>
* [efi] Fall back to assuming identity mapping of MMIO address spaceMichael Brown2020-10-301-4/+2Star
| | | | | | | | | | | | | | 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>
* [efi] Use address offset as reported by EFI_PCI_ROOT_BRIDGE_IO_PROTOCOLMichael Brown2020-09-251-1/+74
| | | | | | | | | 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>
* [pci] Define pci_ioremap() for mapping PCI bus addressesMichael Brown2020-09-241-0/+1
| | | | | | | 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>
* [efi] Provide a single implementation of efipci_root_close()Michael Brown2020-09-241-13/+22
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Standardise PCI debug messagesMichael Brown2017-05-011-29/+31
| | | | | | | | | | | | 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>
* [pci] Support systems with multiple PCI root bridgesMichael Brown2016-06-091-18/+119
| | | | | | | | | Extend the 16-bit PCI bus:dev.fn address to a 32-bit seg:bus: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>
* [efi] Remove raw EFI_HANDLE values from debug messagesMichael Brown2015-08-271-21/+20Star
| | | | | | | | | The raw EFI_HANDLE value is almost never useful to know, and simply adds noise to the already verbose debug messages. Improve the legibility of debug messages by using only the name generated by efi_handle_name(). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [legal] Relicense files under GPL2_OR_LATER_OR_UBDLMichael Brown2015-03-021-1/+5
| | | | | | | Relicense files for which I am the sole author (as identified by util/relicense.pl). Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Make EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL optionalMichael Brown2014-09-041-1/+7
| | | | | | | | | | 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>
* [efi] Provide centralised definitions of commonly-used GUIDsMichael Brown2014-08-061-4/+0Star
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Dump existing openers when we are unable to open a protocolMichael Brown2014-07-311-0/+1
| | | | | | | | 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] Use efi_handle_name() instead of efi_devpath_text() where applicableMichael Brown2014-07-311-6/+5Star
| | | | | | | | | | 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>
* [efi] Use efi_handle_name() instead of efi_handle_devpath_text()Michael Brown2014-07-311-11/+9Star
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Allow network devices to be created on top of arbitrary SNP devicesMichael Brown2014-07-031-242/+99Star
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Restructure EFI driver modelMichael Brown2014-06-251-165/+127Star
| | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* [efi] Allow driver to be unloadedMichael Brown2014-03-101-0/+3
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Perform meaningful error code conversionsMichael Brown2013-04-191-22/+25
| | | | | | | | Exploit the redefinition of iPXE error codes to include a "platform error code" to allow for meaningful conversion of EFI_STATUS values to iPXE errors and vice versa. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [legal] Update FSF mailing address in GPL licence textsMichael Brown2012-07-201-1/+2
| | | | | Suggested-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Work around platforms which choke on EFI_PCI_DEVICE_ENABLEMichael Brown2012-05-161-10/+12
| | | | | | | | | | | | | | | | | | | | | | | | | EFI_PCI_DEVICE_ENABLE is a list of the standard attributes that must be enabled for a PCI device to function: I/O cycles, memory cycles, and bus-mastering. We currently call EFI_PCI_IO_PROTOCOL::Attribute() with the parameter EFI_PCI_DEVICE_ENABLE to enable a PCI device. This should translate to a single write to PCI configuration space. Simplicity is not a virtue within the UEFI world. Some platforms will 'helpfully' report an error if EFI_PCI_DEVICE_ENABLE is used on a device that doesn't actually support all three of the relevant attributes. For example, if a PCI device provides only memory-mapped accesses (and so hardwires the I/O enable bit to zero), then using EFI_PCI_DEVICE_ENABLE on such a platform will result in an EFI_UNSUPPORTED error. There is no plausible use case in which it is useful for the platform to return an error in this way, and doing so makes it impossible to distinguish genuine errors from noise. Work around this broken behaviour by attempting to enable the three attributes individually, and ignoring any errors. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Ensure that all drivers are shut down before the OS bootsMichael Brown2011-03-291-2/+22
| | | | | | Reported-by: Itay Gazit <itayg@mellanox.co.il> Suggested-by: Michael R Turner <mikeyt@us.ibm.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Mark SNP devices as children of EFI PCI deviceMichael Brown2011-03-151-0/+49
| | | | | | | | | | | | | Re-open the EFI_PCI_IO_PROTOCOL specifying an Attributes value of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. This causes the SNP devices to be marked as children of the EFI PCI device (as shown in the "devtree" command). On at least one IBM blade system, this is required in order to have the relevant drivers automatically attach to the SNP controller at device creation time. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [efi] Allow EFI to control PCI bus enumerationMichael Brown2011-02-171-0/+378
| | | | | | | | | | | | | | EFI performs its own PCI bus enumeration. Respect this, and start controlling devices only when instructed to do so by EFI. As a side benefit, we should now correctly create multiple SNP instances for multi-port devices. This should also fix the problem of failing to enumerate devices because the PCI bridges have not yet been enabled at the time the iPXE driver is loaded. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [pci] Replace pci_max_bus() with pci_num_bus()Michael Brown2011-02-171-1/+1
| | | | Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [pci] Use single "busdevfn" field in struct pci_deviceMichael Brown2011-02-171-10/+9Star
| | | | | | | Merge the "bus" and "devfn" fields into a single "busdevfn" field, to match the format used by the majority of external code. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [build] Rename gPXE to iPXEMichael Brown2010-04-201-4/+4
| | | | | | | | | | | Access to the gpxe.org and etherboot.org domains and associated resources has been revoked by the registrant of the domain. Work around this problem by renaming project from gPXE to iPXE, and updating URLs to match. Also update README, LOG and COPYRIGHTS to remove obsolete information. Signed-off-by: Michael Brown <mcb30@ipxe.org>
* [legal] Add a selection of FILE_LICENCE declarationsMichael Brown2009-05-181-0/+2
| | | | | Add FILE_LICENCE declarations to almost all files that make up the various standard builds of gPXE.
* [efi] Add efi_strerror()Michael Brown2008-11-191-4/+4
| | | | | | | | | EFI_STATUS is defined as an INTN, which maps to UINT32 (i.e. unsigned int) on i386 and UINT64 (i.e. unsigned long) on x86_64. This would require a cast each time the error status is printed. Add efi_strerror() to avoid this ickiness and simultaneously enable prettier reporting of EFI status codes.
* [i386] Change [u]int32_t to [unsigned] int, rather than [unsigned] longMichael Brown2008-11-191-2/+2
| | | | | | This brings us in to line with Linux definitions, and also simplifies adding x86_64 support since both platforms have 2-byte shorts, 4-byte ints and 8-byte long longs.
* [efi] Add EFI image format and basic runtime environmentMichael Brown2008-10-131-0/+81
We have EFI APIs for CPU I/O, PCI I/O, timers, console I/O, user access and user memory allocation. EFI executables are created using the vanilla GNU toolchain, with the EXE header handcrafted in assembly and relocations generated by a custom efilink utility.