diff options
-rw-r--r-- | OvmfPkg/Include/Library/PciCapPciIoLib.h | 58 | ||||
-rw-r--r-- | OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.c | 243 | ||||
-rw-r--r-- | OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.h | 44 | ||||
-rw-r--r-- | OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.inf | 36 | ||||
-rw-r--r-- | OvmfPkg/OvmfPkg.dec | 5 |
5 files changed, 386 insertions, 0 deletions
diff --git a/OvmfPkg/Include/Library/PciCapPciIoLib.h b/OvmfPkg/Include/Library/PciCapPciIoLib.h new file mode 100644 index 0000000000..553715fd50 --- /dev/null +++ b/OvmfPkg/Include/Library/PciCapPciIoLib.h @@ -0,0 +1,58 @@ +/** @file
+ Library class layered on top of PciCapLib that allows clients to plug an
+ EFI_PCI_IO_PROTOCOL 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_IO_LIB_H__
+#define __PCI_CAP_PCI_IO_LIB_H__
+
+#include <Protocol/PciIo.h>
+
+#include <Library/PciCapLib.h>
+
+
+/**
+ Create a PCI_CAP_DEV object from an EFI_PCI_IO_PROTOCOL instance. The config
+ space accessors are based upon EFI_PCI_IO_PROTOCOL.Pci.Read() and
+ EFI_PCI_IO_PROTOCOL.Pci.Write().
+
+ @param[in] PciIo EFI_PCI_IO_PROTOCOL representation of the PCI device.
+
+ @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.
+ PciDevice can be passed to the PciCapLib APIs.
+
+ @retval EFI_SUCCESS PciDevice has been constructed and output.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+PciCapPciIoDeviceInit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT PCI_CAP_DEV **PciDevice
+ );
+
+
+/**
+ Free the resources used by PciDevice.
+
+ @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by
+ PciCapPciIoDeviceInit().
+**/
+VOID
+EFIAPI
+PciCapPciIoDeviceUninit (
+ IN PCI_CAP_DEV *PciDevice
+ );
+
+#endif // __PCI_CAP_PCI_IO_LIB_H__
diff --git a/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.c b/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.c new file mode 100644 index 0000000000..358d87f931 --- /dev/null +++ b/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.c @@ -0,0 +1,243 @@ +/** @file
+ Plug an EFI_PCI_IO_PROTOCOL 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 <Library/MemoryAllocationLib.h>
+
+#include "UefiPciCapPciIoLib.h"
+
+
+/**
+ Transfer bytes between the config space of a given PCI device and a memory
+ buffer.
+
+ ProtoDevTransferConfig() performs as few config space accesses as possible
+ (without attempting 64-bit wide accesses).
+
+ @param[in] PciIo The EFI_PCI_IO_PROTOCOL representation of the
+ PCI device.
+
+ @param[in] TransferFunction The EFI_PCI_IO_PROTOCOL_CONFIG function that
+ implements the transfer. The direction of the
+ transfer is inherent to TransferFunction.
+ TransferFunction() is required to return an
+ unspecified error if any sub-transfer within
+ Size bytes from ConfigOffset exceeds the config
+ space limit of the PCI device.
+
+ @param[in] ConfigOffset The offset in the config space of the PCI device
+ at which the transfer should commence.
+
+ @param[in,out] Buffer The memory buffer where the transfer should
+ occur.
+
+ @param[in] Size The number of bytes to transfer.
+
+ @retval EFI_SUCCESS Size bytes have been transferred between config space
+ and Buffer.
+
+ @return Error codes propagated from TransferFunction(). Fewer
+ than Size bytes may have been transferred.
+**/
+STATIC
+EFI_STATUS
+ProtoDevTransferConfig (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_PCI_IO_PROTOCOL_CONFIG TransferFunction,
+ IN UINT16 ConfigOffset,
+ IN OUT UINT8 *Buffer,
+ IN UINT16 Size
+ )
+{
+ while (Size > 0) {
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+ UINT16 Count;
+ EFI_STATUS Status;
+ UINT16 Progress;
+
+ //
+ // Pick the largest access size that is allowed by the remaining transfer
+ // Size and by the alignment of ConfigOffset.
+ //
+ // When the largest access size is available, transfer as many bytes as
+ // possible in one iteration of the loop. Otherwise, transfer only one
+ // unit, to improve the alignment.
+ //
+ if (Size >= 4 && (ConfigOffset & 3) == 0) {
+ Width = EfiPciIoWidthUint32;
+ Count = Size >> Width;
+ } else if (Size >= 2 && (ConfigOffset & 1) == 0) {
+ Width = EfiPciIoWidthUint16;
+ Count = 1;
+ } else {
+ Width = EfiPciIoWidthUint8;
+ Count = 1;
+ }
+ Status = TransferFunction (PciIo, Width, ConfigOffset, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Progress = Count << Width;
+ ConfigOffset += Progress;
+ Buffer += Progress;
+ Size -= Progress;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read the config space of a given PCI device (both normal and extended).
+
+ ProtoDevReadConfig() performs as few config space accesses as possible
+ (without attempting 64-bit wide accesses).
+
+ ProtoDevReadConfig() returns an unspecified error if accessing Size bytes
+ from SourceOffset exceeds the config space limit of the PCI device. Fewer
+ than Size bytes may have been read in this case.
+
+ @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.
+
+ @return Error codes propagated from
+ EFI_PCI_IO_PROTOCOL.Pci.Read(). Fewer than Size bytes
+ may have been read.
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+ProtoDevReadConfig (
+ IN PCI_CAP_DEV *PciDevice,
+ IN UINT16 SourceOffset,
+ OUT VOID *DestinationBuffer,
+ IN UINT16 Size
+ )
+{
+ PROTO_DEV *ProtoDev;
+
+ ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);
+ return ProtoDevTransferConfig (ProtoDev->PciIo, ProtoDev->PciIo->Pci.Read,
+ SourceOffset, DestinationBuffer, Size);
+}
+
+
+/**
+ Write the config space of a given PCI device (both normal and extended).
+
+ ProtoDevWriteConfig() performs as few config space accesses as possible
+ (without attempting 64-bit wide accesses).
+
+ ProtoDevWriteConfig() returns an unspecified error if accessing Size bytes at
+ DestinationOffset exceeds the config space limit of the PCI device. Fewer
+ than Size bytes may have been written in this case.
+
+ @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.
+
+ @return Error codes propagated from
+ EFI_PCI_IO_PROTOCOL.Pci.Write(). Fewer than Size
+ bytes may have been written.
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+ProtoDevWriteConfig (
+ IN PCI_CAP_DEV *PciDevice,
+ IN UINT16 DestinationOffset,
+ IN VOID *SourceBuffer,
+ IN UINT16 Size
+ )
+{
+ PROTO_DEV *ProtoDev;
+
+ ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);
+ return ProtoDevTransferConfig (ProtoDev->PciIo, ProtoDev->PciIo->Pci.Write,
+ DestinationOffset, SourceBuffer, Size);
+}
+
+
+/**
+ Create a PCI_CAP_DEV object from an EFI_PCI_IO_PROTOCOL instance. The config
+ space accessors are based upon EFI_PCI_IO_PROTOCOL.Pci.Read() and
+ EFI_PCI_IO_PROTOCOL.Pci.Write().
+
+ @param[in] PciIo EFI_PCI_IO_PROTOCOL representation of the PCI device.
+
+ @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.
+ PciDevice can be passed to the PciCapLib APIs.
+
+ @retval EFI_SUCCESS PciDevice has been constructed and output.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+PciCapPciIoDeviceInit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT PCI_CAP_DEV **PciDevice
+ )
+{
+ PROTO_DEV *ProtoDev;
+
+ ProtoDev = AllocatePool (sizeof *ProtoDev);
+ if (ProtoDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ProtoDev->Signature = PROTO_DEV_SIG;
+ ProtoDev->PciIo = PciIo;
+ ProtoDev->BaseDevice.ReadConfig = ProtoDevReadConfig;
+ ProtoDev->BaseDevice.WriteConfig = ProtoDevWriteConfig;
+
+ *PciDevice = &ProtoDev->BaseDevice;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Free the resources used by PciDevice.
+
+ @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by
+ PciCapPciIoDeviceInit().
+**/
+VOID
+EFIAPI
+PciCapPciIoDeviceUninit (
+ IN PCI_CAP_DEV *PciDevice
+ )
+{
+ PROTO_DEV *ProtoDev;
+
+ ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);
+ FreePool (ProtoDev);
+}
diff --git a/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.h b/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.h new file mode 100644 index 0000000000..a94f65e5a4 --- /dev/null +++ b/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.h @@ -0,0 +1,44 @@ +/** @file
+ Plug an EFI_PCI_IO_PROTOCOL 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 __UEFI_PCI_CAP_PCI_IO_LIB_H__
+#define __UEFI_PCI_CAP_PCI_IO_LIB_H__
+
+#include <Library/DebugLib.h>
+
+#include <Library/PciCapPciIoLib.h>
+
+#define PROTO_DEV_SIG SIGNATURE_64 ('P', 'C', 'P', 'I', 'O', 'P', 'R', 'T')
+
+typedef struct {
+ //
+ // Signature identifying the derived class.
+ //
+ UINT64 Signature;
+ //
+ // Members added by the derived class, specific to the use of
+ // EFI_PCI_IO_PROTOCOL.
+ //
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ //
+ // Base class.
+ //
+ PCI_CAP_DEV BaseDevice;
+} PROTO_DEV;
+
+#define PROTO_DEV_FROM_PCI_CAP_DEV(PciDevice) \
+ CR (PciDevice, PROTO_DEV, BaseDevice, PROTO_DEV_SIG)
+
+#endif // __UEFI_PCI_CAP_PCI_IO_LIB_H__
diff --git a/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.inf b/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.inf new file mode 100644 index 0000000000..2e14acb0ab --- /dev/null +++ b/OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.inf @@ -0,0 +1,36 @@ +## @file
+# Plug an EFI_PCI_IO_PROTOCOL 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 = UefiPciCapPciIoLib
+ FILE_GUID = 4102F4FE-DA10-4F0F-AC18-4982ED506154
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciCapPciIoLib
+
+[Sources]
+ UefiPciCapPciIoLib.h
+ UefiPciCapPciIoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## CONSUMES
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index fbec1cfe4a..dc5597db41 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 an
+ # EFI_PCI_IO_PROTOCOL backend into PciCapLib, for config
+ # space access.
+ PciCapPciIoLib|Include/Library/PciCapPciIoLib.h
+
## @libraryclass Layered on top of PciCapLib, allows clients to plug a
# PciSegmentLib backend into PciCapLib, for config space
# access.
|