diff options
Diffstat (limited to 'OvmfPkg')
5 files changed, 395 insertions, 0 deletions
diff --git a/OvmfPkg/Include/Library/PciCapPciSegmentLib.h b/OvmfPkg/Include/Library/PciCapPciSegmentLib.h new file mode 100644 index 0000000..6b69302 --- /dev/null +++ b/OvmfPkg/Include/Library/PciCapPciSegmentLib.h @@ -0,0 +1,82 @@ +/** @file
+ Library class layered on top of PciCapLib that allows clients to plug a
+ PciSegmentLib backend into PciCapLib, for config space access.
+
+ Copyright (C) 2018, Red Hat, Inc.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#ifndef __PCI_CAP_PCI_SEGMENT_LIB_H__
+#define __PCI_CAP_PCI_SEGMENT_LIB_H__
+
+#include <Library/PciCapLib.h>
+
+
+/**
+ Create a PCI_CAP_DEV object from the PCI Segment:Bus:Device.Function
+ quadruplet. The config space accessors are based upon PciSegmentLib.
+
+ @param[in] MaxDomain If MaxDomain is PciCapExtended, then
+ PciDevice->ReadConfig() and PciDevice->WriteConfig()
+ will delegate extended config space accesses too to
+ PciSegmentReadBuffer() and PciSegmentWriteBuffer(),
+ respectively. Otherwise, PciDevice->ReadConfig() and
+ PciDevice->WriteConfig() will reject accesses to
+ extended config space with RETURN_UNSUPPORTED, without
+ calling PciSegmentReadBuffer() or
+ PciSegmentWriteBuffer(). By setting MaxDomain to
+ PciCapNormal, the platform can prevent undefined
+ PciSegmentLib behavior when the PCI root bridge under
+ the PCI device at Segment:Bus:Device.Function doesn't
+ support extended config space.
+
+ @param[in] Segment 16-bit wide segment number.
+
+ @param[in] Bus 8-bit wide bus number.
+
+ @param[in] Device 5-bit wide device number.
+
+ @param[in] Function 3-bit wide function number.
+
+ @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.
+ PciDevice can be passed to the PciCapLib APIs.
+
+ @retval RETURN_SUCCESS PciDevice has been constructed and output.
+
+ @retval RETURN_INVALID_PARAMETER Device or Function does not fit in the
+ permitted number of bits.
+
+ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
+**/
+RETURN_STATUS
+EFIAPI
+PciCapPciSegmentDeviceInit (
+ IN PCI_CAP_DOMAIN MaxDomain,
+ IN UINT16 Segment,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ OUT PCI_CAP_DEV **PciDevice
+ );
+
+
+/**
+ Free the resources used by PciDevice.
+
+ @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by
+ PciCapPciSegmentDeviceInit().
+**/
+VOID
+EFIAPI
+PciCapPciSegmentDeviceUninit (
+ IN PCI_CAP_DEV *PciDevice
+ );
+
+#endif // __PCI_CAP_PCI_SEGMENT_LIB_H__
diff --git a/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.c b/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.c new file mode 100644 index 0000000..57eb6b6 --- /dev/null +++ b/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.c @@ -0,0 +1,226 @@ +/** @file
+ Plug a PciSegmentLib backend into PciCapLib, for config space access.
+
+ Copyright (C) 2018, Red Hat, Inc.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <IndustryStandard/Pci23.h>
+
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciSegmentLib.h>
+
+#include "BasePciCapPciSegmentLib.h"
+
+
+/**
+ Read the config space of a given PCI device (both normal and extended).
+
+ SegmentDevReadConfig() performs as few config space accesses as possible
+ (without attempting 64-bit wide accesses).
+
+ @param[in] PciDevice Implementation-specific unique representation
+ of the PCI device in the PCI hierarchy.
+
+ @param[in] SourceOffset Source offset in the config space of the PCI
+ device to start reading from.
+
+ @param[out] DestinationBuffer Buffer to store the read data to.
+
+ @param[in] Size The number of bytes to transfer.
+
+ @retval RETURN_SUCCESS Size bytes have been transferred from config
+ space to DestinationBuffer.
+
+ @retval RETURN_UNSUPPORTED Accessing Size bytes from SourceOffset exceeds
+ the config space limit of the PCI device.
+ Although PCI_CAP_DEV_READ_CONFIG allows reading
+ fewer than Size bytes in this case,
+ SegmentDevReadConfig() will read none.
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+SegmentDevReadConfig (
+ IN PCI_CAP_DEV *PciDevice,
+ IN UINT16 SourceOffset,
+ OUT VOID *DestinationBuffer,
+ IN UINT16 Size
+ )
+{
+ SEGMENT_DEV *SegmentDev;
+ UINT16 ConfigSpaceSize;
+ UINT64 SourceAddress;
+
+ SegmentDev = SEGMENT_DEV_FROM_PCI_CAP_DEV (PciDevice);
+ ConfigSpaceSize = (SegmentDev->MaxDomain == PciCapNormal ?
+ PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET);
+ //
+ // Note that all UINT16 variables below are promoted to INT32, and the
+ // addition and the comparison is carried out in INT32.
+ //
+ if (SourceOffset + Size > ConfigSpaceSize) {
+ return RETURN_UNSUPPORTED;
+ }
+ SourceAddress = PCI_SEGMENT_LIB_ADDRESS (SegmentDev->SegmentNr,
+ SegmentDev->BusNr, SegmentDev->DeviceNr,
+ SegmentDev->FunctionNr, SourceOffset);
+ PciSegmentReadBuffer (SourceAddress, Size, DestinationBuffer);
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Write the config space of a given PCI device (both normal and extended).
+
+ SegmentDevWriteConfig() performs as few config space accesses as possible
+ (without attempting 64-bit wide accesses).
+
+ @param[in] PciDevice Implementation-specific unique representation
+ of the PCI device in the PCI hierarchy.
+
+ @param[in] DestinationOffset Destination offset in the config space of the
+ PCI device to start writing at.
+
+ @param[in] SourceBuffer Buffer to read the data to be stored from.
+
+ @param[in] Size The number of bytes to transfer.
+
+ @retval RETURN_SUCCESS Size bytes have been transferred from
+ SourceBuffer to config space.
+
+ @retval RETURN_UNSUPPORTED Accessing Size bytes at DestinationOffset exceeds
+ the config space limit of the PCI device.
+ Although PCI_CAP_DEV_WRITE_CONFIG allows writing
+ fewer than Size bytes in this case,
+ SegmentDevWriteConfig() will write none.
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+SegmentDevWriteConfig (
+ IN PCI_CAP_DEV *PciDevice,
+ IN UINT16 DestinationOffset,
+ IN VOID *SourceBuffer,
+ IN UINT16 Size
+ )
+{
+ SEGMENT_DEV *SegmentDev;
+ UINT16 ConfigSpaceSize;
+ UINT64 DestinationAddress;
+
+ SegmentDev = SEGMENT_DEV_FROM_PCI_CAP_DEV (PciDevice);
+ ConfigSpaceSize = (SegmentDev->MaxDomain == PciCapNormal ?
+ PCI_MAX_CONFIG_OFFSET : PCI_EXP_MAX_CONFIG_OFFSET);
+ //
+ // Note that all UINT16 variables below are promoted to INT32, and the
+ // addition and the comparison is carried out in INT32.
+ //
+ if (DestinationOffset + Size > ConfigSpaceSize) {
+ return RETURN_UNSUPPORTED;
+ }
+ DestinationAddress = PCI_SEGMENT_LIB_ADDRESS (SegmentDev->SegmentNr,
+ SegmentDev->BusNr, SegmentDev->DeviceNr,
+ SegmentDev->FunctionNr, DestinationOffset);
+ PciSegmentWriteBuffer (DestinationAddress, Size, SourceBuffer);
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Create a PCI_CAP_DEV object from the PCI Segment:Bus:Device.Function
+ quadruplet. The config space accessors are based upon PciSegmentLib.
+
+ @param[in] MaxDomain If MaxDomain is PciCapExtended, then
+ PciDevice->ReadConfig() and PciDevice->WriteConfig()
+ will delegate extended config space accesses too to
+ PciSegmentReadBuffer() and PciSegmentWriteBuffer(),
+ respectively. Otherwise, PciDevice->ReadConfig() and
+ PciDevice->WriteConfig() will reject accesses to
+ extended config space with RETURN_UNSUPPORTED, without
+ calling PciSegmentReadBuffer() or
+ PciSegmentWriteBuffer(). By setting MaxDomain to
+ PciCapNormal, the platform can prevent undefined
+ PciSegmentLib behavior when the PCI root bridge under
+ the PCI device at Segment:Bus:Device.Function doesn't
+ support extended config space.
+
+ @param[in] Segment 16-bit wide segment number.
+
+ @param[in] Bus 8-bit wide bus number.
+
+ @param[in] Device 5-bit wide device number.
+
+ @param[in] Function 3-bit wide function number.
+
+ @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.
+ PciDevice can be passed to the PciCapLib APIs.
+
+ @retval RETURN_SUCCESS PciDevice has been constructed and output.
+
+ @retval RETURN_INVALID_PARAMETER Device or Function does not fit in the
+ permitted number of bits.
+
+ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
+**/
+RETURN_STATUS
+EFIAPI
+PciCapPciSegmentDeviceInit (
+ IN PCI_CAP_DOMAIN MaxDomain,
+ IN UINT16 Segment,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ OUT PCI_CAP_DEV **PciDevice
+ )
+{
+ SEGMENT_DEV *SegmentDev;
+
+ if (Device > PCI_MAX_DEVICE || Function > PCI_MAX_FUNC) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ SegmentDev = AllocatePool (sizeof *SegmentDev);
+ if (SegmentDev == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ SegmentDev->Signature = SEGMENT_DEV_SIG;
+ SegmentDev->MaxDomain = MaxDomain;
+ SegmentDev->SegmentNr = Segment;
+ SegmentDev->BusNr = Bus;
+ SegmentDev->DeviceNr = Device;
+ SegmentDev->FunctionNr = Function;
+ SegmentDev->BaseDevice.ReadConfig = SegmentDevReadConfig;
+ SegmentDev->BaseDevice.WriteConfig = SegmentDevWriteConfig;
+
+ *PciDevice = &SegmentDev->BaseDevice;
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Free the resources used by PciDevice.
+
+ @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by
+ PciCapPciSegmentDeviceInit().
+**/
+VOID
+EFIAPI
+PciCapPciSegmentDeviceUninit (
+ IN PCI_CAP_DEV *PciDevice
+ )
+{
+ SEGMENT_DEV *SegmentDev;
+
+ SegmentDev = SEGMENT_DEV_FROM_PCI_CAP_DEV (PciDevice);
+ FreePool (SegmentDev);
+}
diff --git a/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.h b/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.h new file mode 100644 index 0000000..3ce15fe --- /dev/null +++ b/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.h @@ -0,0 +1,47 @@ +/** @file
+ Plug a PciSegmentLib backend into PciCapLib, for config space access --
+ internal macro and type definitions.
+
+ Copyright (C) 2018, Red Hat, Inc.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#ifndef __BASE_PCI_CAP_PCI_SEGMENT_LIB_H__
+#define __BASE_PCI_CAP_PCI_SEGMENT_LIB_H__
+
+#include <Library/DebugLib.h>
+
+#include <Library/PciCapPciSegmentLib.h>
+
+#define SEGMENT_DEV_SIG SIGNATURE_64 ('P', 'C', 'P', 'S', 'G', 'M', 'N', 'T')
+
+typedef struct {
+ //
+ // Signature identifying the derived class.
+ //
+ UINT64 Signature;
+ //
+ // Members added by the derived class, specific to the use of PciSegmentLib.
+ //
+ PCI_CAP_DOMAIN MaxDomain;
+ UINT16 SegmentNr;
+ UINT8 BusNr;
+ UINT8 DeviceNr;
+ UINT8 FunctionNr;
+ //
+ // Base class.
+ //
+ PCI_CAP_DEV BaseDevice;
+} SEGMENT_DEV;
+
+#define SEGMENT_DEV_FROM_PCI_CAP_DEV(PciDevice) \
+ CR (PciDevice, SEGMENT_DEV, BaseDevice, SEGMENT_DEV_SIG)
+
+#endif // __BASE_PCI_CAP_PCI_SEGMENT_LIB_H__
diff --git a/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.inf b/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.inf new file mode 100644 index 0000000..e3cf5de --- /dev/null +++ b/OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.inf @@ -0,0 +1,35 @@ +## @file
+# Plug a PciSegmentLib backend into PciCapLib, for config space access.
+#
+# Copyright (C) 2018, Red Hat, Inc.
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+##
+
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = BasePciCapPciSegmentLib
+ FILE_GUID = ED011855-AA31-43B9-ACC0-BF45A05C5985
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciCapPciSegmentLib
+
+[Sources]
+ BasePciCapPciSegmentLib.h
+ BasePciCapPciSegmentLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ MemoryAllocationLib
+ PciSegmentLib
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 74818a2..fbec1cf 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -35,6 +35,11 @@ # config space.
PciCapLib|Include/Library/PciCapLib.h
+ ## @libraryclass Layered on top of PciCapLib, allows clients to plug a
+ # PciSegmentLib backend into PciCapLib, for config space
+ # access.
+ PciCapPciSegmentLib|Include/Library/PciCapPciSegmentLib.h
+
## @libraryclass Access QEMU's firmware configuration interface
#
QemuFwCfgLib|Include/Library/QemuFwCfgLib.h
|