[edk2] [PATCH v2 4/5] MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib

Ruiyu Ni posted 5 patches 7 years, 4 months ago
[edk2] [PATCH v2 4/5] MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib
Posted by Ruiyu Ni 7 years, 4 months ago
The patch adds two PciSegmentLib instances that consumes
PciSegmentInfoLib to provide multiple segments PCI configuration
access.

BasePciSegmentLibSegmentInfo instance is a BASE library.
DxeRuntimePciSegmentLibSegmentInfo instance is to be linked with
runtime drivers to provide not only boot time but also runtime
PCI configuration access.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
---
 .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c   |   71 +
 .../BasePciSegmentLibSegmentInfo.inf               |   46 +
 .../BasePciSegmentLibSegmentInfo.uni               |   21 +
 .../DxeRuntimePciSegmentLib.c                      |  321 +++++
 .../DxeRuntimePciSegmentLibSegmentInfo.inf         |   55 +
 .../DxeRuntimePciSegmentLibSegmentInfo.uni         |   21 +
 .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++
 .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h |   57 +
 MdePkg/MdePkg.dsc                                  |    2 +
 9 files changed, 1969 insertions(+)
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
 create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h

diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
new file mode 100644
index 0000000000..e71624d4ba
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
@@ -0,0 +1,71 @@
+/** @file
+  Instance of Base PCI Segment Library that support multi-segment PCI configuration access.
+
+  PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+   support multi-segment PCI configuration access through enhanced configuration access mechanism.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  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 "PciSegmentLibCommon.h"
+
+/**
+  Return the virtual address for the physical address.
+
+  @param  Address  The physical address.
+
+  @retval The virtual address.
+**/
+UINTN
+PciSegmentLibVirtualAddress (
+  IN UINTN                     Address
+  )
+{
+  return Address;
+}
+
+/**
+  Register a PCI device so PCI configuration registers may be accessed after
+  SetVirtualAddressMap().
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address The address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @retval RETURN_SUCCESS           The PCI device was registered for runtime access.
+  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
+                                   after ExitBootServices().
+  @retval RETURN_UNSUPPORTED       The resources required to access the PCI device
+                                   at runtime could not be mapped.
+  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
+                                   complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+  IN UINTN  Address
+  )
+{
+  //
+  // Use PciSegmentLibGetEcamAddress() to validate the Address.
+  //
+  DEBUG_CODE (
+    UINTN                        Count;
+    PCI_SEGMENT_INFO             *SegmentInfo;
+
+    SegmentInfo = GetPciSegmentInfo (&Count);
+    PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count);
+  );
+  return RETURN_SUCCESS;
+}
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
new file mode 100644
index 0000000000..9cd60764dc
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
@@ -0,0 +1,46 @@
+## @file
+# Instance of Base PCI Segment Library that support multi-segment PCI configuration access.
+#
+# PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+#  support multi-segment PCI configuration access through enhanced configuration access mechanism.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+#  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                    = 0x00010005
+  BASE_NAME                      = BasePciSegmentLibSegmentInfo
+  MODULE_UNI_FILE                = BasePciSegmentLibSegmentInfo.uni
+  FILE_GUID                      = 3427D883-E093-4CC9-BE85-6BD4058E96E2
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciSegmentLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  PciSegmentLibCommon.h
+  PciSegmentLibCommon.c
+  BasePciSegmentLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  PciSegmentInfoLib
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
new file mode 100644
index 0000000000..ad33a5fdad
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Instance of Base PCI Segment Library that support multi-segment PCI configuration access.
+
+// PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+//  support multi-segment PCI configuration access through enhanced configuration access mechanism.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Instance of Base PCI Segment Library that support multi-segment PCI configuration access."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to support multi-segment PCI configuration access through enhanced configuration access mechanism."
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
new file mode 100644
index 0000000000..9c86608677
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
@@ -0,0 +1,321 @@
+/** @file
+  Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
+
+  PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+   support multi-segment PCI configuration access through enhanced configuration access mechanism.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  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 "PciSegmentLibCommon.h"
+#include <PiDxe.h>
+#include <Guid/EventGroup.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciSegmentInfoLib.h>
+
+///
+/// Define table for mapping PCI Segment MMIO physical addresses to virtual addresses at OS runtime
+///
+typedef struct {
+  UINTN  PhysicalAddress;
+  UINTN  VirtualAddress;
+} PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE;
+
+///
+/// Set Virtual Address Map Event
+///
+EFI_EVENT                               mDxeRuntimePciSegmentLibVirtualNotifyEvent = NULL;
+
+///
+/// The number of PCI devices that have been registered for runtime access.
+///
+UINTN                                   mDxeRuntimePciSegmentLibNumberOfRuntimeRanges = 0;
+
+///
+/// The table of PCI devices that have been registered for runtime access.
+///
+PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE  *mDxeRuntimePciSegmentLibRegistrationTable = NULL;
+
+///
+/// The table index of the most recent virtual address lookup.
+///
+UINTN                                   mDxeRuntimePciSegmentLibLastRuntimeRange = 0;
+
+/**
+  Convert the physical PCI Express MMIO addresses for all registered PCI devices
+  to virtual addresses.
+
+  @param[in]    Event   The event that is being processed.
+  @param[in]    Context The Event Context.
+**/
+VOID
+EFIAPI
+DxeRuntimePciSegmentLibVirtualNotify (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  UINTN         Index;
+  EFI_STATUS    Status;
+
+  //
+  // If there have been no runtime registrations, then just return
+  //
+  if (mDxeRuntimePciSegmentLibRegistrationTable == NULL) {
+    return;
+  }
+
+  //
+  // Convert physical addresses associated with the set of registered PCI devices to
+  // virtual addresses.
+  //
+  for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
+    Status = EfiConvertPointer (0, (VOID **) &(mDxeRuntimePciSegmentLibRegistrationTable[Index].VirtualAddress));
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Convert table pointer that is allocated from EfiRuntimeServicesData to a virtual address.
+  //
+  Status = EfiConvertPointer (0, (VOID **) &mDxeRuntimePciSegmentLibRegistrationTable);
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  The constructor function caches the PCI Express Base Address and creates a
+  Set Virtual Address Map event to convert physical address to virtual addresses.
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor completed successfully.
+  @retval Other value   The constructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimePciSegmentLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Register SetVirtualAddressMap () notify function
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  DxeRuntimePciSegmentLibVirtualNotify,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &mDxeRuntimePciSegmentLibVirtualNotifyEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  The destructor function frees any allocated buffers and closes the Set Virtual
+  Address Map event.
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The destructor completed successfully.
+  @retval Other value   The destructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimePciSegmentLibDestructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // If one or more PCI devices have been registered for runtime access, then
+  // free the registration table.
+  //
+  if (mDxeRuntimePciSegmentLibRegistrationTable != NULL) {
+    FreePool (mDxeRuntimePciSegmentLibRegistrationTable);
+  }
+
+  //
+  // Close the Set Virtual Address Map event
+  //
+  Status = gBS->CloseEvent (mDxeRuntimePciSegmentLibVirtualNotifyEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Register a PCI device so PCI configuration registers may be accessed after
+  SetVirtualAddressMap().
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address The address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @retval RETURN_SUCCESS           The PCI device was registered for runtime access.
+  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
+                                   after ExitBootServices().
+  @retval RETURN_UNSUPPORTED       The resources required to access the PCI device
+                                   at runtime could not be mapped.
+  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
+                                   complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+  IN UINTN  Address
+  )
+{
+  RETURN_STATUS                    Status;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  Descriptor;
+  UINTN                            Index;
+  VOID                             *NewTable;
+  UINTN                            Count;
+  PCI_SEGMENT_INFO                 *SegmentInfo;
+  UINT64                           EcamAddress;
+
+  //
+  // Convert Address to a ECAM address at the beginning of the PCI Configuration
+  // header for the specified PCI Bus/Dev/Func
+  //
+  Address &= ~(UINTN)EFI_PAGE_MASK;
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  EcamAddress = PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count);
+
+  //
+  // Return an error if this function is called after ExitBootServices().
+  //
+  if (EfiAtRuntime ()) {
+    return RETURN_UNSUPPORTED;
+  }
+  if (sizeof (UINTN) == sizeof (UINT32)) {
+    ASSERT (EcamAddress < BASE_4GB);
+  }
+  Address = (UINTN)EcamAddress;
+
+  //
+  // See if Address has already been registerd for runtime access
+  //
+  for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
+    if (mDxeRuntimePciSegmentLibRegistrationTable[Index].PhysicalAddress == Address) {
+      return RETURN_SUCCESS;
+    }
+  }
+
+  //
+  // Get the GCD Memory Descriptor for the ECAM Address
+  //
+  Status = gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
+  if (EFI_ERROR (Status)) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  //
+  // Mark the 4KB region for the PCI Express Bus/Dev/Func as EFI_RUNTIME_MEMORY so the OS
+  // will allocate a virtual address range for the 4KB PCI Configuration Header.
+  //
+  Status = gDS->SetMemorySpaceAttributes (Address, EFI_PAGE_SIZE, Descriptor.Attributes | EFI_MEMORY_RUNTIME);
+  if (EFI_ERROR (Status)) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  //
+  // Grow the size of the registration table
+  //
+  NewTable = ReallocateRuntimePool (
+               (mDxeRuntimePciSegmentLibNumberOfRuntimeRanges + 0) * sizeof (PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE),
+               (mDxeRuntimePciSegmentLibNumberOfRuntimeRanges + 1) * sizeof (PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE),
+               mDxeRuntimePciSegmentLibRegistrationTable
+               );
+  if (NewTable == NULL) {
+    return RETURN_OUT_OF_RESOURCES;
+  }
+  mDxeRuntimePciSegmentLibRegistrationTable = NewTable;
+  mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibNumberOfRuntimeRanges].PhysicalAddress = Address;
+  mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibNumberOfRuntimeRanges].VirtualAddress  = Address;
+  mDxeRuntimePciSegmentLibNumberOfRuntimeRanges++;
+
+  return RETURN_SUCCESS;
+}
+
+/**
+  Return the linear address for the physical address.
+
+  @param  Address  The physical address.
+
+  @retval The linear address.
+**/
+UINTN
+PciSegmentLibVirtualAddress (
+  IN UINTN                     Address
+  )
+{
+  UINTN                        Index;
+  //
+  // If SetVirtualAddressMap() has not been called, then just return the physical address
+  //
+  if (!EfiGoneVirtual ()) {
+    return Address;
+  }
+
+  //
+  // See if there is a physical address match at the exact same index as the last address match
+  //
+  if (mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibLastRuntimeRange].PhysicalAddress == (Address & (~(UINTN)EFI_PAGE_MASK))) {
+    //
+    // Convert the physical address to a virtual address and return the virtual address
+    //
+    return (Address & EFI_PAGE_MASK) + mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibLastRuntimeRange].VirtualAddress;
+  }
+
+  //
+  // Search the entire table for a physical address match
+  //
+  for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
+    if (mDxeRuntimePciSegmentLibRegistrationTable[Index].PhysicalAddress == (Address & (~(UINTN)EFI_PAGE_MASK))) {
+      //
+      // Cache the matching index value
+      //
+      mDxeRuntimePciSegmentLibLastRuntimeRange = Index;
+      //
+      // Convert the physical address to a virtual address and return the virtual address
+      //
+      return (Address & EFI_PAGE_MASK) + mDxeRuntimePciSegmentLibRegistrationTable[Index].VirtualAddress;
+    }
+  }
+
+  //
+  // No match was found.  This is a critical error at OS runtime, so ASSERT() and force a breakpoint.
+  //
+  ASSERT (FALSE);
+  CpuBreakpoint ();
+
+  //
+  // Return the physical address
+  //
+  return Address;
+}
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
new file mode 100644
index 0000000000..e484af5b06
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
@@ -0,0 +1,55 @@
+## @file
+# Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
+#
+# PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+#  support multi-segment PCI configuration access through enhanced configuration access mechanism.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+#  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                    = 0x00010005
+  BASE_NAME                      = DxeRuntimePciSegmentLibSegmentInfo
+  MODULE_UNI_FILE                = DxeRuntimePciSegmentLibSegmentInfo.uni
+  FILE_GUID                      = F73EB3DE-F4E3-47CB-9F18-97796AE06314
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciSegmentLib|DXE_RUNTIME_DRIVER
+  CONSTRUCTOR                    = DxeRuntimePciSegmentLibConstructor
+  DESTRUCTOR                     = DxeRuntimePciSegmentLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  PciSegmentLibCommon.h
+  PciSegmentLibCommon.c
+  DxeRuntimePciSegmentLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  PciSegmentInfoLib
+  UefiRuntimeLib
+  MemoryAllocationLib
+  DxeServicesTableLib
+  UefiBootServicesTableLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid         ## CONSUMES ## Event
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
new file mode 100644
index 0000000000..171fc7d16c
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
+
+// PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+//  support multi-segment PCI configuration access through enhanced configuration access mechanism.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to support multi-segment PCI configuration access through enhanced configuration access mechanism."
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
new file mode 100644
index 0000000000..7b7324d673
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
@@ -0,0 +1,1375 @@
+/** @file
+  Provide common routines used by BasePciSegmentLibSegmentInfo and
+  DxeRuntimePciSegmentLibSegmentInfo libraries.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  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 "PciSegmentLibCommon.h"
+
+typedef struct {
+  UINT64  Register : 12;
+  UINT64  Function : 3;
+  UINT64  Device : 5;
+  UINT64  Bus : 8;
+  UINT64  Reserved1 : 4;
+  UINT64  Segment : 16;
+  UINT64  Reserved2 : 16;
+} PCI_SEGMENT_LIB_ADDRESS_STRUCTURE;
+
+/**
+  Internal function that converts PciSegmentLib format address that encodes the PCI Bus, Device,
+  Function and Register to ECAM (Enhanced Configuration Access Mechanism) address.
+
+  @param Address     The address that encodes the PCI Bus, Device, Function and
+                     Register.
+  @param SegmentInfo An array of PCI_SEGMENT_INFO holding the segment information.
+  @param Count       Number of segments.
+
+  @retval ECAM address.
+**/
+UINTN
+PciSegmentLibGetEcamAddress (
+  IN UINT64                    Address,
+  IN CONST PCI_SEGMENT_INFO    *SegmentInfo,
+  IN UINTN                     Count
+  )
+{
+  while (Count != 0) {
+    if (SegmentInfo->SegmentNumber == ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Segment) {
+      break;
+    }
+    SegmentInfo++;
+    Count--;
+  }
+  ASSERT (Count != 0);
+  ASSERT (
+    (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Reserved1 == 0) &&
+    (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Reserved2 == 0)
+  );
+  ASSERT (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus >= SegmentInfo->StartBusNumber);
+  ASSERT (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus <= SegmentInfo->EndBusNumber);
+
+  Address = SegmentInfo->BaseAddress + PCI_ECAM_ADDRESS (
+    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus,
+    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Device,
+    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Function,
+    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Register);
+
+  if (sizeof (UINTN) == sizeof (UINT32)) {
+    ASSERT (Address < BASE_4GB);
+  }
+
+  return PciSegmentLibVirtualAddress ((UINTN)Address);
+}
+
+/**
+  Reads an 8-bit PCI configuration register.
+
+  Reads and returns the 8-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+  @return The 8-bit PCI configuration register specified by Address.
+
+**/
+UINT8
+EFIAPI
+PciSegmentRead8 (
+  IN UINT64                    Address
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioRead8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
+}
+
+/**
+  Writes an 8-bit PCI configuration register.
+
+  Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address     Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  Value       The value to write.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentWrite8 (
+  IN UINT64                    Address,
+  IN UINT8                     Value
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioWrite8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
+}
+
+/**
+  Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address,
+  performs a bitwise OR between the read result and the value specified by OrData,
+  and writes the result to the 8-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentOr8 (
+  IN UINT64                    Address,
+  IN UINT8                     OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
+}
+
+/**
+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  and writes the result to the 8-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAnd8 (
+  IN UINT64                    Address,
+  IN UINT8                     AndData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioAnd8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
+}
+
+/**
+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
+  followed a  bitwise OR with another 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 8-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAndThenOr8 (
+  IN UINT64                    Address,
+  IN UINT8                     AndData,
+  IN UINT8                     OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioAndThenOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in an 8-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldRead8 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldRead8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  8-bit register is returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldWrite8 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT8                     Value
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldWrite8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 8-bit port.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 8-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldOr8 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT8                     OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 8-bit register.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 8-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized. Extra left bits in AndData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAnd8 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT8                     AndData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
+}
+
+/**
+  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the 8-bit port.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 8-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAndThenOr8 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT8                     AndData,
+  IN UINT8                     OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldAndThenOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
+}
+
+/**
+  Reads a 16-bit PCI configuration register.
+
+  Reads and returns the 16-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+  @return The 16-bit PCI configuration register specified by Address.
+
+**/
+UINT16
+EFIAPI
+PciSegmentRead16 (
+  IN UINT64                    Address
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioRead16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
+}
+
+/**
+  Writes a 16-bit PCI configuration register.
+
+  Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address     Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  Value       The value to write.
+
+  @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+PciSegmentWrite16 (
+  IN UINT64                    Address,
+  IN UINT16                    Value
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioWrite16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
+}
+
+/**
+  Performs a bitwise OR of a 16-bit PCI configuration register with
+  a 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by OrData, and
+  writes the result to the 16-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned. This function
+  must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Segment, Bus, Device, Function and
+                  Register.
+  @param  OrData  The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentOr16 (
+  IN UINT64                    Address,
+  IN UINT16                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
+}
+
+/**
+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  and writes the result to the 16-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAnd16 (
+  IN UINT64                    Address,
+  IN UINT16                    AndData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioAnd16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
+}
+
+/**
+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
+  followed a  bitwise OR with another 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 16-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAndThenOr16 (
+  IN UINT64                    Address,
+  IN UINT16                    AndData,
+  IN UINT16                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioAndThenOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in a 16-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldRead16 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldRead16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  16-bit register is returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldWrite16 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT16                    Value
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldWrite16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
+}
+
+/**
+  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, writes
+  the result back to the bit field in the 16-bit port.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 16-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldOr16 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT16                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
+}
+
+/**
+  Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
+  AND, writes the result back to the bit field in the 16-bit register.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 16-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized. Extra left bits in AndData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAnd16 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT16                    AndData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
+}
+
+/**
+  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  16-bit port.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 16-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAndThenOr16 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT16                    AndData,
+  IN UINT16                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldAndThenOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
+}
+
+/**
+  Reads a 32-bit PCI configuration register.
+
+  Reads and returns the 32-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+  @return The 32-bit PCI configuration register specified by Address.
+
+**/
+UINT32
+EFIAPI
+PciSegmentRead32 (
+  IN UINT64                    Address
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioRead32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
+}
+
+/**
+  Writes a 32-bit PCI configuration register.
+
+  Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address     Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  Value       The value to write.
+
+  @return The parameter of Value.
+
+**/
+UINT32
+EFIAPI
+PciSegmentWrite32 (
+  IN UINT64                    Address,
+  IN UINT32                    Value
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioWrite32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
+}
+
+/**
+  Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address,
+  performs a bitwise OR between the read result and the value specified by OrData,
+  and writes the result to the 32-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentOr32 (
+  IN UINT64                    Address,
+  IN UINT32                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
+}
+
+/**
+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  and writes the result to the 32-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAnd32 (
+  IN UINT64                    Address,
+  IN UINT32                    AndData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioAnd32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
+}
+
+/**
+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
+  followed a  bitwise OR with another 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 32-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAndThenOr32 (
+  IN UINT64                    Address,
+  IN UINT32                    AndData,
+  IN UINT32                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioAndThenOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in a 32-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldRead32 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldRead32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  32-bit register is returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldWrite32 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT32                    Value
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldWrite32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 32-bit port.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 32-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldOr32 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT32                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 32-bit register.
+
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
+  AND between the read result and the value specified by AndData, and writes the result
+  to the 32-bit PCI configuration register specified by Address. The value written to
+  the PCI configuration register is returned.  This function must guarantee that all PCI
+  read and write operations are serialized.  Extra left bits in AndData are stripped.
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAnd32 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT32                    AndData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
+}
+
+/**
+  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  32-bit port.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 32-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAndThenOr32 (
+  IN UINT64                    Address,
+  IN UINTN                     StartBit,
+  IN UINTN                     EndBit,
+  IN UINT32                    AndData,
+  IN UINT32                    OrData
+  )
+{
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  return MmioBitFieldAndThenOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
+}
+
+/**
+  Reads a range of PCI configuration registers into a caller supplied buffer.
+
+  Reads the range of PCI configuration registers specified by StartAddress and
+  Size into the buffer specified by Buffer. This function only allows the PCI
+  configuration registers from a single PCI function to be read. Size is
+  returned. When possible 32-bit PCI configuration read cycles are used to read
+  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
+  and 16-bit PCI configuration read cycles may be used at the beginning and the
+  end of the range.
+
+  If any reserved bits in StartAddress are set, then ASSERT().
+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+  If Size > 0 and Buffer is NULL, then ASSERT().
+
+  @param  StartAddress  Starting address that encodes the PCI Segment, Bus, Device,
+                        Function and Register.
+  @param  Size          Size in bytes of the transfer.
+  @param  Buffer        Pointer to a buffer receiving the data read.
+
+  @return Size
+
+**/
+UINTN
+EFIAPI
+PciSegmentReadBuffer (
+  IN  UINT64                   StartAddress,
+  IN  UINTN                    Size,
+  OUT VOID                     *Buffer
+  )
+{
+  UINTN                        ReturnValue;
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+  UINTN                        Address;
+
+  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  Address = PciSegmentLibGetEcamAddress (StartAddress, SegmentInfo, Count);
+
+  if (Size == 0) {
+    return 0;
+  }
+
+  ASSERT (Buffer != NULL);
+
+  //
+  // Save Size for return
+  //
+  ReturnValue = Size;
+
+  if ((Address & BIT0) != 0) {
+    //
+    // Read a byte if StartAddress is byte aligned
+    //
+    *(volatile UINT8 *)Buffer = MmioRead8 (Address);
+    Address += sizeof (UINT8);
+    Size -= sizeof (UINT8);
+    Buffer = (UINT8*)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT16) && (Address & BIT1) != 0) {
+    //
+    // Read a word if StartAddress is word aligned
+    //
+    WriteUnaligned16 (Buffer, MmioRead16 (Address));
+    Address += sizeof (UINT16);
+    Size -= sizeof (UINT16);
+    Buffer = (UINT16*)Buffer + 1;
+  }
+
+  while (Size >= sizeof (UINT32)) {
+    //
+    // Read as many double words as possible
+    //
+    WriteUnaligned32 (Buffer, MmioRead32 (Address));
+    Address += sizeof (UINT32);
+    Size -= sizeof (UINT32);
+    Buffer = (UINT32*)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT16)) {
+    //
+    // Read the last remaining word if exist
+    //
+    WriteUnaligned16 (Buffer, MmioRead16 (Address));
+    Address += sizeof (UINT16);
+    Size -= sizeof (UINT16);
+    Buffer = (UINT16*)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT8)) {
+    //
+    // Read the last remaining byte if exist
+    //
+    *(volatile UINT8 *)Buffer = MmioRead8 (Address);
+  }
+
+  return ReturnValue;
+}
+
+/**
+  Copies the data in a caller supplied buffer to a specified range of PCI
+  configuration space.
+
+  Writes the range of PCI configuration registers specified by StartAddress and
+  Size from the buffer specified by Buffer. This function only allows the PCI
+  configuration registers from a single PCI function to be written. Size is
+  returned. When possible 32-bit PCI configuration write cycles are used to
+  write from StartAdress to StartAddress + Size. Due to alignment restrictions,
+  8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+  and the end of the range.
+
+  If any reserved bits in StartAddress are set, then ASSERT().
+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+  If Size > 0 and Buffer is NULL, then ASSERT().
+
+  @param  StartAddress  Starting address that encodes the PCI Segment, Bus, Device,
+                        Function and Register.
+  @param  Size          Size in bytes of the transfer.
+  @param  Buffer        Pointer to a buffer containing the data to write.
+
+  @return The parameter of Size.
+
+**/
+UINTN
+EFIAPI
+PciSegmentWriteBuffer (
+  IN UINT64                    StartAddress,
+  IN UINTN                     Size,
+  IN VOID                      *Buffer
+  )
+{
+  UINTN                        ReturnValue;
+  UINTN                        Count;
+  PCI_SEGMENT_INFO             *SegmentInfo;
+  UINTN                        Address;
+
+  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+  SegmentInfo = GetPciSegmentInfo (&Count);
+  Address = PciSegmentLibGetEcamAddress (StartAddress, SegmentInfo, Count);
+
+  if (Size == 0) {
+    return 0;
+  }
+
+  ASSERT (Buffer != NULL);
+
+  //
+  // Save Size for return
+  //
+  ReturnValue = Size;
+
+  if ((Address & BIT0) != 0) {
+    //
+    // Write a byte if StartAddress is byte aligned
+    //
+    MmioWrite8 (Address, *(UINT8*)Buffer);
+    Address += sizeof (UINT8);
+    Size -= sizeof (UINT8);
+    Buffer = (UINT8*)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT16) && (Address & BIT1) != 0) {
+    //
+    // Write a word if StartAddress is word aligned
+    //
+    MmioWrite16 (Address, ReadUnaligned16 (Buffer));
+    Address += sizeof (UINT16);
+    Size -= sizeof (UINT16);
+    Buffer = (UINT16*)Buffer + 1;
+  }
+
+  while (Size >= sizeof (UINT32)) {
+    //
+    // Write as many double words as possible
+    //
+    MmioWrite32 (Address, ReadUnaligned32 (Buffer));
+    Address += sizeof (UINT32);
+    Size -= sizeof (UINT32);
+    Buffer = (UINT32*)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT16)) {
+    //
+    // Write the last remaining word if exist
+    //
+    MmioWrite16 (Address, ReadUnaligned16 (Buffer));
+    Address += sizeof (UINT16);
+    Size -= sizeof (UINT16);
+    Buffer = (UINT16*)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT8)) {
+    //
+    // Write the last remaining byte if exist
+    //
+    MmioWrite8 (Address, *(UINT8*)Buffer);
+  }
+
+  return ReturnValue;
+}
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
new file mode 100644
index 0000000000..4e1f523098
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
@@ -0,0 +1,57 @@
+/** @file
+  Provide common routines used by BasePciSegmentLibSegmentInfo and
+  DxeRuntimePciSegmentLibSegmentInfo libraries.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  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_SEGMENT_LIB_COMMON_H_
+#define _PCI_SEGMENT_LIB_COMMON_H_
+
+#include <Base.h>
+#include <IndustryStandard/PciExpress21.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/PciSegmentInfoLib.h>
+
+/**
+  Return the linear address for the physical address.
+
+  @param  Address  The physical address.
+
+  @retval The linear address.
+**/
+UINTN
+PciSegmentLibVirtualAddress (
+  IN UINTN                     Address
+  );
+
+/**
+  Internal function that converts PciSegmentLib format address that encodes the PCI Bus, Device,
+  Function and Register to ECAM (Enhanced Configuration Access Mechanism) address.
+
+  @param Address     The address that encodes the PCI Bus, Device, Function and
+                     Register.
+  @param SegmentInfo An array of PCI_SEGMENT_INFO holding the segment information.
+  @param Count       Number of segments.
+
+  @retval ECAM address.
+**/
+UINTN
+PciSegmentLibGetEcamAddress (
+  IN UINT64                    Address,
+  IN CONST PCI_SEGMENT_INFO    *SegmentInfo,
+  IN UINTN                     Count
+  );
+
+#endif
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index e553a702a3..19545aa398 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -70,6 +70,8 @@ [Components]
   MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
   MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
   MdePkg/Library/BasePciSegmentInfoLibNull/BasePciSegmentInfoLibNull.inf
+  MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
+  MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
   MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
   MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
   MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
-- 
2.12.2.windows.2

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH v2 4/5] MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib
Posted by Ard Biesheuvel 7 years, 3 months ago
Hi,

Some comments below.

On 25 August 2017 at 09:57, Ruiyu Ni <ruiyu.ni@intel.com> wrote:
> The patch adds two PciSegmentLib instances that consumes
> PciSegmentInfoLib to provide multiple segments PCI configuration
> access.
>
> BasePciSegmentLibSegmentInfo instance is a BASE library.
> DxeRuntimePciSegmentLibSegmentInfo instance is to be linked with
> runtime drivers to provide not only boot time but also runtime
> PCI configuration access.
>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
> Cc: Liming Gao <liming.gao@intel.com>
> ---
>  .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c   |   71 +
>  .../BasePciSegmentLibSegmentInfo.inf               |   46 +
>  .../BasePciSegmentLibSegmentInfo.uni               |   21 +
>  .../DxeRuntimePciSegmentLib.c                      |  321 +++++
>  .../DxeRuntimePciSegmentLibSegmentInfo.inf         |   55 +
>  .../DxeRuntimePciSegmentLibSegmentInfo.uni         |   21 +
>  .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++
>  .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h |   57 +
>  MdePkg/MdePkg.dsc                                  |    2 +
>  9 files changed, 1969 insertions(+)
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
>
[...]
> diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
> new file mode 100644
> index 0000000000..7b7324d673
> --- /dev/null
> +++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
> @@ -0,0 +1,1375 @@
> +/** @file
> +  Provide common routines used by BasePciSegmentLibSegmentInfo and
> +  DxeRuntimePciSegmentLibSegmentInfo libraries.
> +
> +  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +  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 "PciSegmentLibCommon.h"
> +
> +typedef struct {
> +  UINT64  Register : 12;
> +  UINT64  Function : 3;
> +  UINT64  Device : 5;
> +  UINT64  Bus : 8;
> +  UINT64  Reserved1 : 4;
> +  UINT64  Segment : 16;
> +  UINT64  Reserved2 : 16;
> +} PCI_SEGMENT_LIB_ADDRESS_STRUCTURE;
> +

Is this guaranteed to work as expected by the C spec?

> +/**
> +  Internal function that converts PciSegmentLib format address that encodes the PCI Bus, Device,
> +  Function and Register to ECAM (Enhanced Configuration Access Mechanism) address.
> +
> +  @param Address     The address that encodes the PCI Bus, Device, Function and
> +                     Register.
> +  @param SegmentInfo An array of PCI_SEGMENT_INFO holding the segment information.
> +  @param Count       Number of segments.
> +
> +  @retval ECAM address.
> +**/
> +UINTN
> +PciSegmentLibGetEcamAddress (
> +  IN UINT64                    Address,
> +  IN CONST PCI_SEGMENT_INFO    *SegmentInfo,
> +  IN UINTN                     Count
> +  )
> +{
> +  while (Count != 0) {
> +    if (SegmentInfo->SegmentNumber == ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Segment) {
> +      break;
> +    }
> +    SegmentInfo++;
> +    Count--;
> +  }
> +  ASSERT (Count != 0);
> +  ASSERT (
> +    (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Reserved1 == 0) &&
> +    (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Reserved2 == 0)
> +  );
> +  ASSERT (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus >= SegmentInfo->StartBusNumber);
> +  ASSERT (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus <= SegmentInfo->EndBusNumber);
> +
> +  Address = SegmentInfo->BaseAddress + PCI_ECAM_ADDRESS (
> +    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus,
> +    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Device,
> +    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Function,
> +    ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Register);
> +
> +  if (sizeof (UINTN) == sizeof (UINT32)) {
> +    ASSERT (Address < BASE_4GB);
> +  }
> +
> +  return PciSegmentLibVirtualAddress ((UINTN)Address);
> +}
> +
> +/**
> +  Reads an 8-bit PCI configuration register.
> +
> +  Reads and returns the 8-bit PCI configuration register specified by Address.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +
> +  @return The 8-bit PCI configuration register specified by Address.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentRead8 (
> +  IN UINT64                    Address
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioRead8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
> +}
> +
> +/**
> +  Writes an 8-bit PCI configuration register.
> +
> +  Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
> +  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +
> +  @param  Address     Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  Value       The value to write.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentWrite8 (
> +  IN UINT64                    Address,
> +  IN UINT8                     Value
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioWrite8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
> +}
> +
> +/**
> +  Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
> +
> +  Reads the 8-bit PCI configuration register specified by Address,
> +  performs a bitwise OR between the read result and the value specified by OrData,
> +  and writes the result to the 8-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentOr8 (
> +  IN UINT64                    Address,
> +  IN UINT8                     OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
> +}
> +
> +/**
> +  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
> +
> +  Reads the 8-bit PCI configuration register specified by Address,
> +  performs a bitwise AND between the read result and the value specified by AndData,
> +  and writes the result to the 8-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +  If any reserved bits in Address are set, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentAnd8 (
> +  IN UINT64                    Address,
> +  IN UINT8                     AndData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioAnd8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
> +}
> +
> +/**
> +  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
> +  followed a  bitwise OR with another 8-bit value.
> +
> +  Reads the 8-bit PCI configuration register specified by Address,
> +  performs a bitwise AND between the read result and the value specified by AndData,
> +  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
> +  and writes the result to the 8-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentAndThenOr8 (
> +  IN UINT64                    Address,
> +  IN UINT8                     AndData,
> +  IN UINT8                     OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioAndThenOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in an 8-bit PCI configuration register. The bit field is
> +  specified by the StartBit and the EndBit. The value of the bit field is
> +  returned.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to read.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +
> +  @return The value of the bit field read from the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentBitFieldRead8 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldRead8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI configuration register. The bit
> +  field is specified by the StartBit and the EndBit. All other bits in the
> +  destination PCI configuration register are preserved. The new value of the
> +  8-bit register is returned.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentBitFieldWrite8 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT8                     Value
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldWrite8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
> +  writes the result back to the bit field in the 8-bit port.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 8-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized. Extra left bits in OrData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentBitFieldOr8 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT8                     OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
> +  AND, and writes the result back to the bit field in the 8-bit register.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 8-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentBitFieldAnd8 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT8                     AndData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
> +}

MmioBitFieldAnd8

> +
> +/**
> +  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit field in the 8-bit port.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the read result and
> +  the value specified by AndData, and writes the result to the 8-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized. Extra left bits in both AndData and
> +  OrData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciSegmentBitFieldAndThenOr8 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT8                     AndData,
> +  IN UINT8                     OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldAndThenOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
> +}
> +
> +/**
> +  Reads a 16-bit PCI configuration register.
> +
> +  Reads and returns the 16-bit PCI configuration register specified by Address.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +
> +  @return The 16-bit PCI configuration register specified by Address.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentRead16 (
> +  IN UINT64                    Address
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioRead16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
> +}
> +
> +/**
> +  Writes a 16-bit PCI configuration register.
> +
> +  Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
> +  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address     Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  Value       The value to write.
> +
> +  @return The parameter of Value.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentWrite16 (
> +  IN UINT64                    Address,
> +  IN UINT16                    Value
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioWrite16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
> +}
> +
> +/**
> +  Performs a bitwise OR of a 16-bit PCI configuration register with
> +  a 16-bit value.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by OrData, and
> +  writes the result to the 16-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned. This function
> +  must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Segment, Bus, Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentOr16 (
> +  IN UINT64                    Address,
> +  IN UINT16                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
> +}
> +
> +/**
> +  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
> +
> +  Reads the 16-bit PCI configuration register specified by Address,
> +  performs a bitwise AND between the read result and the value specified by AndData,
> +  and writes the result to the 16-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentAnd16 (
> +  IN UINT64                    Address,
> +  IN UINT16                    AndData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioAnd16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
> +}
> +
> +/**
> +  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
> +  followed a  bitwise OR with another 16-bit value.
> +
> +  Reads the 16-bit PCI configuration register specified by Address,
> +  performs a bitwise AND between the read result and the value specified by AndData,
> +  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
> +  and writes the result to the 16-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentAndThenOr16 (
> +  IN UINT64                    Address,
> +  IN UINT16                    AndData,
> +  IN UINT16                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioAndThenOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in a 16-bit PCI configuration register. The bit field is
> +  specified by the StartBit and the EndBit. The value of the bit field is
> +  returned.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to read.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +
> +  @return The value of the bit field read from the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentBitFieldRead16 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldRead16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI configuration register. The bit
> +  field is specified by the StartBit and the EndBit. All other bits in the
> +  destination PCI configuration register are preserved. The new value of the
> +  16-bit register is returned.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentBitFieldWrite16 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT16                    Value
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldWrite16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, writes
> +  the result back to the bit field in the 16-bit port.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 16-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized. Extra left bits in OrData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentBitFieldOr16 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT16                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
> +  AND, writes the result back to the bit field in the 16-bit register.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 16-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentBitFieldAnd16 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT16                    AndData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
> +}

MmioBitFieldAnd16

> +
> +/**
> +  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit field in the
> +  16-bit port.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the read result and
> +  the value specified by AndData, and writes the result to the 16-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized. Extra left bits in both AndData and
> +  OrData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciSegmentBitFieldAndThenOr16 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT16                    AndData,
> +  IN UINT16                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldAndThenOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
> +}
> +
> +/**
> +  Reads a 32-bit PCI configuration register.
> +
> +  Reads and returns the 32-bit PCI configuration register specified by Address.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +
> +  @return The 32-bit PCI configuration register specified by Address.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentRead32 (
> +  IN UINT64                    Address
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioRead32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
> +}
> +
> +/**
> +  Writes a 32-bit PCI configuration register.
> +
> +  Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
> +  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address     Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  Value       The value to write.
> +
> +  @return The parameter of Value.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentWrite32 (
> +  IN UINT64                    Address,
> +  IN UINT32                    Value
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioWrite32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
> +}
> +
> +/**
> +  Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
> +
> +  Reads the 32-bit PCI configuration register specified by Address,
> +  performs a bitwise OR between the read result and the value specified by OrData,
> +  and writes the result to the 32-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentOr32 (
> +  IN UINT64                    Address,
> +  IN UINT32                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
> +}
> +
> +/**
> +  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
> +
> +  Reads the 32-bit PCI configuration register specified by Address,
> +  performs a bitwise AND between the read result and the value specified by AndData,
> +  and writes the result to the 32-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentAnd32 (
> +  IN UINT64                    Address,
> +  IN UINT32                    AndData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioAnd32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
> +}
> +
> +/**
> +  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
> +  followed a  bitwise OR with another 32-bit value.
> +
> +  Reads the 32-bit PCI configuration register specified by Address,
> +  performs a bitwise AND between the read result and the value specified by AndData,
> +  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
> +  and writes the result to the 32-bit PCI configuration register specified by Address.
> +  The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are serialized.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentAndThenOr32 (
> +  IN UINT64                    Address,
> +  IN UINT32                    AndData,
> +  IN UINT32                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioAndThenOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in a 32-bit PCI configuration register. The bit field is
> +  specified by the StartBit and the EndBit. The value of the bit field is
> +  returned.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to read.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +
> +  @return The value of the bit field read from the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentBitFieldRead32 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldRead32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI configuration register. The bit
> +  field is specified by the StartBit and the EndBit. All other bits in the
> +  destination PCI configuration register are preserved. The new value of the
> +  32-bit register is returned.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentBitFieldWrite32 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT32                    Value
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldWrite32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
> +  writes the result back to the bit field in the 32-bit port.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 32-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized. Extra left bits in OrData are stripped.
> +
> +  If any reserved bits in Address are set, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentBitFieldOr32 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT32                    OrData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
> +  AND, and writes the result back to the bit field in the 32-bit register.
> +
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
> +  AND between the read result and the value specified by AndData, and writes the result
> +  to the 32-bit PCI configuration register specified by Address. The value written to
> +  the PCI configuration register is returned.  This function must guarantee that all PCI
> +  read and write operations are serialized.  Extra left bits in AndData are stripped.
> +  If any reserved bits in Address are set, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   Address that encodes the PCI Segment, Bus, Device, Function, and Register.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciSegmentBitFieldAnd32 (
> +  IN UINT64                    Address,
> +  IN UINTN                     StartBit,
> +  IN UINTN                     EndBit,
> +  IN UINT32                    AndData
> +  )
> +{
> +  UINTN                        Count;
> +  PCI_SEGMENT_INFO             *SegmentInfo;
> +
> +  SegmentInfo = GetPciSegmentInfo (&Count);
> +  return MmioBitFieldOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
> +}

MmioBitFieldAnd32

-- 
Ard.
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH v2 4/5] MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib
Posted by Laszlo Ersek 7 years, 3 months ago
On 08/29/17 20:51, Ard Biesheuvel wrote:
> Hi,
> 
> Some comments below.
> 
> On 25 August 2017 at 09:57, Ruiyu Ni <ruiyu.ni@intel.com> wrote:
>> The patch adds two PciSegmentLib instances that consumes
>> PciSegmentInfoLib to provide multiple segments PCI configuration
>> access.
>>
>> BasePciSegmentLibSegmentInfo instance is a BASE library.
>> DxeRuntimePciSegmentLibSegmentInfo instance is to be linked with
>> runtime drivers to provide not only boot time but also runtime
>> PCI configuration access.
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
>> Cc: Liming Gao <liming.gao@intel.com>
>> ---
>>  .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c   |   71 +
>>  .../BasePciSegmentLibSegmentInfo.inf               |   46 +
>>  .../BasePciSegmentLibSegmentInfo.uni               |   21 +
>>  .../DxeRuntimePciSegmentLib.c                      |  321 +++++
>>  .../DxeRuntimePciSegmentLibSegmentInfo.inf         |   55 +
>>  .../DxeRuntimePciSegmentLibSegmentInfo.uni         |   21 +
>>  .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++
>>  .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h |   57 +
>>  MdePkg/MdePkg.dsc                                  |    2 +
>>  9 files changed, 1969 insertions(+)
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>>  create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
>>
> [...]
>> diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>> new file mode 100644
>> index 0000000000..7b7324d673
>> --- /dev/null
>> +++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>> @@ -0,0 +1,1375 @@
>> +/** @file
>> +  Provide common routines used by BasePciSegmentLibSegmentInfo and
>> +  DxeRuntimePciSegmentLibSegmentInfo libraries.
>> +
>> +  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
>> +  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 "PciSegmentLibCommon.h"
>> +
>> +typedef struct {
>> +  UINT64  Register : 12;
>> +  UINT64  Function : 3;
>> +  UINT64  Device : 5;
>> +  UINT64  Bus : 8;
>> +  UINT64  Reserved1 : 4;
>> +  UINT64  Segment : 16;
>> +  UINT64  Reserved2 : 16;
>> +} PCI_SEGMENT_LIB_ADDRESS_STRUCTURE;
>> +
> 
> Is this guaranteed to work as expected by the C spec?

From C99, "6.7.2.1 Structure and union specifiers", paragraph 10:

"An implementation may allocate any addressable storage unit large
enough to hold a bit-field. If enough space remains, a bit-field that
immediately follows another bit-field in a structure shall be packed
into adjacent bits of the same unit. If insufficient space remains,
whether a bit-field that does not fit is put into the next unit or
overlaps adjacent units is implementation-defined. The order of
allocation of bit-fields within a unit (high-order to low-order or
low-order to high-order) is implementation-defined. The alignment of the
addressable storage unit is unspecified."

Due to the above, I consider bit-fields totally nonportable, and avoid
introducing bit-fields in any code I write.

However, "implementation-defined" means the compiler docs have to
describe how bit-fields are laid out. If you know your toolchain (...all
of your toolchains...), I guess you can make them work. FWIW, edk2 is
chock-full of bit-fields.

... For example, the clang build options contain "-mms-bitfields":

https://clang.llvm.org/docs/ClangCommandLineReference.html

--> "Set the default structure layout to be compatible with the
Microsoft compiler standard".

The GCC docs are here:

https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html

--> "Determined by ABI."

These structures make me shudder, but if they work, I just close my eyes
and move on. :/

Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH v2 4/5] MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib
Posted by Andrew Fish 7 years, 3 months ago
> On Aug 29, 2017, at 1:39 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 08/29/17 20:51, Ard Biesheuvel wrote:
>> Hi,
>> 
>> Some comments below.
>> 
>> On 25 August 2017 at 09:57, Ruiyu Ni <ruiyu.ni@intel.com> wrote:
>>> The patch adds two PciSegmentLib instances that consumes
>>> PciSegmentInfoLib to provide multiple segments PCI configuration
>>> access.
>>> 
>>> BasePciSegmentLibSegmentInfo instance is a BASE library.
>>> DxeRuntimePciSegmentLibSegmentInfo instance is to be linked with
>>> runtime drivers to provide not only boot time but also runtime
>>> PCI configuration access.
>>> 
>>> Contributed-under: TianoCore Contribution Agreement 1.0
>>> Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
>>> Cc: Liming Gao <liming.gao@intel.com>
>>> ---
>>> .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c   |   71 +
>>> .../BasePciSegmentLibSegmentInfo.inf               |   46 +
>>> .../BasePciSegmentLibSegmentInfo.uni               |   21 +
>>> .../DxeRuntimePciSegmentLib.c                      |  321 +++++
>>> .../DxeRuntimePciSegmentLibSegmentInfo.inf         |   55 +
>>> .../DxeRuntimePciSegmentLibSegmentInfo.uni         |   21 +
>>> .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++
>>> .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h |   57 +
>>> MdePkg/MdePkg.dsc                                  |    2 +
>>> 9 files changed, 1969 insertions(+)
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
>>> 
>> [...]
>>> diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>>> new file mode 100644
>>> index 0000000000..7b7324d673
>>> --- /dev/null
>>> +++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
>>> @@ -0,0 +1,1375 @@
>>> +/** @file
>>> +  Provide common routines used by BasePciSegmentLibSegmentInfo and
>>> +  DxeRuntimePciSegmentLibSegmentInfo libraries.
>>> +
>>> +  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
>>> +  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 "PciSegmentLibCommon.h"
>>> +
>>> +typedef struct {
>>> +  UINT64  Register : 12;
>>> +  UINT64  Function : 3;
>>> +  UINT64  Device : 5;
>>> +  UINT64  Bus : 8;
>>> +  UINT64  Reserved1 : 4;
>>> +  UINT64  Segment : 16;
>>> +  UINT64  Reserved2 : 16;
>>> +} PCI_SEGMENT_LIB_ADDRESS_STRUCTURE;
>>> +
>> 
>> Is this guaranteed to work as expected by the C spec?
> 
> From C99, "6.7.2.1 Structure and union specifiers", paragraph 10:
> 
> "An implementation may allocate any addressable storage unit large
> enough to hold a bit-field. If enough space remains, a bit-field that
> immediately follows another bit-field in a structure shall be packed
> into adjacent bits of the same unit. If insufficient space remains,
> whether a bit-field that does not fit is put into the next unit or
> overlaps adjacent units is implementation-defined. The order of
> allocation of bit-fields within a unit (high-order to low-order or
> low-order to high-order) is implementation-defined. The alignment of the
> addressable storage unit is unspecified."
> 
> Due to the above, I consider bit-fields totally nonportable, and avoid
> introducing bit-fields in any code I write.
> 
> However, "implementation-defined" means the compiler docs have to
> describe how bit-fields are laid out. If you know your toolchain (...all
> of your toolchains...), I guess you can make them work. FWIW, edk2 is
> chock-full of bit-fields.
> 
> ... For example, the clang build options contain "-mms-bitfields":
> 

Laszlo,

FYI -mms-bitfields was to force EFI ABI compatibility, not to enabled bit fields per say.  I can't remember why we used ms-bitfields vs. ms-struct?

Thanks,

Andrew Fish


> https://clang.llvm.org/docs/ClangCommandLineReference.html <https://clang.llvm.org/docs/ClangCommandLineReference.html>
> 
> --> "Set the default structure layout to be compatible with the
> Microsoft compiler standard".
> 
> The GCC docs are here:
> 
> https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html <https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html>
> 
> --> "Determined by ABI."
> 
> These structures make me shudder, but if they work, I just close my eyes
> and move on. :/
> 
> Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org>
> https://lists.01.org/mailman/listinfo/edk2-devel <https://lists.01.org/mailman/listinfo/edk2-devel>
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel