From 5c9bb86f171c9a3a89ac4b5b00518cb00bf32132 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Fri, 4 Aug 2017 13:18:37 +0800 Subject: [PATCH] MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib 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 Reviewed-by: Liming Gao --- .../BasePciSegmentLib.c | 71 + .../BasePciSegmentLibSegmentInfo.inf | 46 + .../BasePciSegmentLibSegmentInfo.uni | 21 + .../DxeRuntimePciSegmentLib.c | 321 ++++ .../DxeRuntimePciSegmentLibSegmentInfo.inf | 55 + .../DxeRuntimePciSegmentLibSegmentInfo.uni | 21 + .../PciSegmentLibCommon.c | 1375 +++++++++++++++++ .../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.
+ 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.
+# +# 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.
+// +// 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.
+ 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 +#include +#include +#include +#include +#include +#include + +/// +/// 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.
+# +# 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.
+// +// 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.
+ 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.
+ 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 +#include +#include +#include +#include +#include +#include + +/** + 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 @@ 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.39.2