Message ID | 20161208153340.2285-6-anthony.perard@citrix.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 12/08/16 16:33, Anthony PERARD wrote: > A copy of OvmfPkg/Library/PciHostBridgeLib > > Removing support for pci bus enumeration, I think, and only use scan of > already enumerated pci bus. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > --- > .../Library/XenPciHostBridgeLib/XenPciHostBridge.h | 75 ++++ > .../XenPciHostBridgeLib/XenPciHostBridgeLib.c | 291 +++++++++++++ > .../XenPciHostBridgeLib/XenPciHostBridgeLib.inf | 58 +++ > OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c | 456 +++++++++++++++++++++ > 4 files changed, 880 insertions(+) > create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h > create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c > create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf > create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c (1) I think the following subject line is more idiomatic: OvmfPkg: add XenPciHostBridgeLib Then, I'll practically repeat my comments for the previous patch: (2) You might want to add Citrix copyright notices to new files. (3) The Xen-related code that remains in the original PciHostBridgeLib instance should be possible to remove later; if that's the case, can you please write a subsequent patch for that too? (4) The removed functionality should be named more precisely in the commit message: - PciHostBridgeGetRootBridges(): the search for extra PCI root buses (which come from QEMU's pxb and pxb-pcie devices) is removed (hence the "etc/extra-pci-roots" fw_cfg file is no longer consulted either, which is otherwise used to speed up the search). The Xen-specific ScanForRootBridges() function call is hardwired. (5) It would be nice to hint at the reason (which is implemented in a later patch) why a separate module is a good idea here. That is, why the expected PVH2 functionality is best not added to the current PciHostBridgeLib instance. More below: > diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h > new file mode 100644 > index 0000000..c23d40c > --- /dev/null > +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h > @@ -0,0 +1,75 @@ > +/** @file > + Header file of OVMF instance of PciHostBridgeLib. > + > + Copyright (c) 2016, 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. > + > +**/ > + > +PCI_ROOT_BRIDGE * > +ScanForRootBridges ( > + UINTN *NumberOfRootBridges > +); > + > +/** > + Initialize a PCI_ROOT_BRIDGE structure. > + > + @param[in] Supports Supported attributes. > + > + @param[in] Attributes Initial attributes. > + > + @param[in] AllocAttributes Allocation attributes. > + > + @param[in] RootBusNumber The bus number to store in RootBus. > + > + @param[in] MaxSubBusNumber The inclusive maximum bus number that can be > + assigned to any subordinate bus found behind any > + PCI bridge hanging off this root bus. > + > + The caller is repsonsible for ensuring that > + RootBusNumber <= MaxSubBusNumber. If > + RootBusNumber equals MaxSubBusNumber, then the > + root bus has no room for subordinate buses. > + > + @param[in] Io IO aperture. > + > + @param[in] Mem MMIO aperture. > + > + @param[in] MemAbove4G MMIO aperture above 4G. > + > + @param[in] PMem Prefetchable MMIO aperture. > + > + @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. > + > + @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the > + caller) that should be filled in by this > + function. > + > + @retval EFI_SUCCESS Initialization successful. A device path > + consisting of an ACPI device path node, with > + UID = RootBusNumber, has been allocated and > + linked into RootBus. > + > + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. > +**/ > +EFI_STATUS > +InitRootBridge ( > + IN UINT64 Supports, > + IN UINT64 Attributes, > + IN UINT64 AllocAttributes, > + IN UINT8 RootBusNumber, > + IN UINT8 MaxSubBusNumber, > + IN PCI_ROOT_BRIDGE_APERTURE *Io, > + IN PCI_ROOT_BRIDGE_APERTURE *Mem, > + IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, > + IN PCI_ROOT_BRIDGE_APERTURE *PMem, > + IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G, > + OUT PCI_ROOT_BRIDGE *RootBus > + ); > diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c > new file mode 100644 > index 0000000..efcd830 > --- /dev/null > +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c > @@ -0,0 +1,291 @@ > +/** @file > + OVMF's instance of the PCI Host Bridge Library. > + > + Copyright (C) 2016, Red Hat, Inc. > + Copyright (c) 2016, 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 <PiDxe.h> > + > +#include <IndustryStandard/Pci.h> > +#include <IndustryStandard/Q35MchIch9.h> > + > +#include <Protocol/PciHostBridgeResourceAllocation.h> > +#include <Protocol/PciRootBridgeIo.h> > + > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > +#include <Library/DevicePathLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/PciHostBridgeLib.h> > +#include <Library/PciLib.h> > +#include <Library/QemuFwCfgLib.h> > +#include "XenPciHostBridge.h" > + > + > +#pragma pack(1) > +typedef struct { > + ACPI_HID_DEVICE_PATH AcpiDevicePath; > + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; > +} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH; > +#pragma pack () > + > + > +GLOBAL_REMOVE_IF_UNREFERENCED > +CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = { > + L"Mem", L"I/O", L"Bus" > +}; > + > + > +STATIC > +CONST > +OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = { > + { > + { > + ACPI_DEVICE_PATH, > + ACPI_DP, > + { > + (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)), > + (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8) > + } > + }, > + EISA_PNP_ID(0x0A03), // HID > + 0 // UID > + }, > + > + { > + END_DEVICE_PATH_TYPE, > + END_ENTIRE_DEVICE_PATH_SUBTYPE, > + { > + END_DEVICE_PATH_LENGTH, > + 0 > + } > + } > +}; > + > +/** > + Initialize a PCI_ROOT_BRIDGE structure. > + > + @param[in] Supports Supported attributes. > + > + @param[in] Attributes Initial attributes. > + > + @param[in] AllocAttributes Allocation attributes. > + > + @param[in] RootBusNumber The bus number to store in RootBus. > + > + @param[in] MaxSubBusNumber The inclusive maximum bus number that can be > + assigned to any subordinate bus found behind any > + PCI bridge hanging off this root bus. > + > + The caller is repsonsible for ensuring that > + RootBusNumber <= MaxSubBusNumber. If > + RootBusNumber equals MaxSubBusNumber, then the > + root bus has no room for subordinate buses. > + > + @param[in] Io IO aperture. > + > + @param[in] Mem MMIO aperture. > + > + @param[in] MemAbove4G MMIO aperture above 4G. > + > + @param[in] PMem Prefetchable MMIO aperture. > + > + @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. > + > + @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the > + caller) that should be filled in by this > + function. > + > + @retval EFI_SUCCESS Initialization successful. A device path > + consisting of an ACPI device path node, with > + UID = RootBusNumber, has been allocated and > + linked into RootBus. > + > + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. > +**/ > +EFI_STATUS > +InitRootBridge ( > + IN UINT64 Supports, > + IN UINT64 Attributes, > + IN UINT64 AllocAttributes, > + IN UINT8 RootBusNumber, > + IN UINT8 MaxSubBusNumber, > + IN PCI_ROOT_BRIDGE_APERTURE *Io, > + IN PCI_ROOT_BRIDGE_APERTURE *Mem, > + IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, > + IN PCI_ROOT_BRIDGE_APERTURE *PMem, > + IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G, > + OUT PCI_ROOT_BRIDGE *RootBus > + ) > +{ > + OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath; > + > + // > + // Be safe if other fields are added to PCI_ROOT_BRIDGE later. > + // > + ZeroMem (RootBus, sizeof *RootBus); > + > + RootBus->Segment = 0; > + > + RootBus->Supports = Supports; > + RootBus->Attributes = Attributes; > + > + RootBus->DmaAbove4G = FALSE; > + > + RootBus->AllocationAttributes = AllocAttributes; > + RootBus->Bus.Base = RootBusNumber; > + RootBus->Bus.Limit = MaxSubBusNumber; > + CopyMem (&RootBus->Io, Io, sizeof (*Io)); > + CopyMem (&RootBus->Mem, Mem, sizeof (*Mem)); > + CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G)); > + CopyMem (&RootBus->PMem, PMem, sizeof (*PMem)); > + CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G)); > + > + RootBus->NoExtendedConfigSpace = (PcdGet16 (PcdOvmfHostBridgePciDevId) != > + INTEL_Q35_MCH_DEVICE_ID); > + > + DevicePath = AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate, > + &mRootBridgeDevicePathTemplate); > + if (DevicePath == NULL) { > + DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES)); > + return EFI_OUT_OF_RESOURCES; > + } > + DevicePath->AcpiDevicePath.UID = RootBusNumber; > + RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; > + > + DEBUG ((EFI_D_INFO, > + "%a: populated root bus %d, with room for %d subordinate bus(es)\n", > + __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber)); > + return EFI_SUCCESS; > +} > + > + > +/** > + Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge(). > + > + param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and > + initialized with InitRootBridge(), that should be > + uninitialized. This function doesn't free RootBus. > +**/ > +STATIC > +VOID > +UninitRootBridge ( > + IN PCI_ROOT_BRIDGE *RootBus > + ) > +{ > + FreePool (RootBus->DevicePath); > +} > + > + > +/** > + Return all the root bridge instances in an array. > + > + @param Count Return the count of root bridge instances. > + > + @return All the root bridge instances in an array. > + The array should be passed into PciHostBridgeFreeRootBridges() > + when it's not used. > +**/ > +PCI_ROOT_BRIDGE * > +EFIAPI > +PciHostBridgeGetRootBridges ( > + UINTN *Count > + ) > +{ > + ASSERT (PcdGetBool (PcdPciDisableBusEnumeration)); > + return ScanForRootBridges (Count); > +} > + > + > +/** > + Free the root bridge instances array returned from > + PciHostBridgeGetRootBridges(). > + > + @param The root bridge instances array. > + @param The count of the array. > +**/ > +VOID > +EFIAPI > +PciHostBridgeFreeRootBridges ( > + PCI_ROOT_BRIDGE *Bridges, > + UINTN Count > + ) > +{ > + if (Bridges == NULL && Count == 0) { > + return; > + } > + ASSERT (Bridges != NULL && Count > 0); > + > + do { > + --Count; > + UninitRootBridge (&Bridges[Count]); > + } while (Count > 0); > + > + FreePool (Bridges); > +} > + > + > +/** > + Inform the platform that the resource conflict happens. > + > + @param HostBridgeHandle Handle of the Host Bridge. > + @param Configuration Pointer to PCI I/O and PCI memory resource > + descriptors. The Configuration contains the resources > + for all the root bridges. The resource for each root > + bridge is terminated with END descriptor and an > + additional END is appended indicating the end of the > + entire resources. The resource descriptor field > + values follow the description in > + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL > + .SubmitResources(). > +**/ > +VOID > +EFIAPI > +PciHostBridgeResourceConflict ( > + EFI_HANDLE HostBridgeHandle, > + VOID *Configuration > + ) > +{ > + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; > + UINTN RootBridgeIndex; > + DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n")); > + > + RootBridgeIndex = 0; > + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; > + while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { > + DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); > + for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) { > + ASSERT (Descriptor->ResType < > + ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr) > + ); > + DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n", > + mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType], > + Descriptor->AddrLen, Descriptor->AddrRangeMax > + )); > + if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { > + DEBUG ((EFI_D_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n", > + Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag, > + ((Descriptor->SpecificFlag & > + EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE > + ) != 0) ? L" (Prefetchable)" : L"" > + )); > + } > + } > + // > + // Skip the END descriptor for root bridge > + // > + ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR); > + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( > + (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1 > + ); > + } > +} > diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf > new file mode 100644 > index 0000000..3b8f003 > --- /dev/null > +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf > @@ -0,0 +1,58 @@ > +## @file > +# OVMF's instance of the PCI Host Bridge Library. > +# > +# Copyright (C) 2016, Red Hat, Inc. > +# Copyright (c) 2016, 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 = XenPciHostBridgeLib > + FILE_GUID = 9F2BC05E-51EA-4AED-9A3E-7699641734E8 (6) You forgot to generate a new FILE_GUID with uuidgen. Thanks Laszlo > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = PciHostBridgeLib > + > +# > +# The following information is for reference only and not required by the build > +# tools. > +# > +# VALID_ARCHITECTURES = IA32 X64 IPF EBC > +# > + > +[Sources] > + XenPciHostBridgeLib.c > + XenSupport.c > + XenPciHostBridge.h > + > +[Packages] > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + OvmfPkg/OvmfPkg.dec > + > +[LibraryClasses] > + BaseMemoryLib > + DebugLib > + DevicePathLib > + MemoryAllocationLib > + PciLib > + > +[Pcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase > + gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize > + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base > + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size > + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base > + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size > + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId > + gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration > diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c b/OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c > new file mode 100644 > index 0000000..a45945f > --- /dev/null > +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c > @@ -0,0 +1,456 @@ > +/** @file > + Scan the entire PCI bus for root bridges to support OVMF above Xen. > + > + Copyright (c) 2016, 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 <PiDxe.h> > + > +#include <IndustryStandard/Pci.h> > +#include <IndustryStandard/Q35MchIch9.h> > + > +#include <Protocol/PciHostBridgeResourceAllocation.h> > +#include <Protocol/PciRootBridgeIo.h> > + > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/PciHostBridgeLib.h> > +#include <Library/PciLib.h> > +#include "XenPciHostBridge.h" > + > +STATIC > +VOID > +PcatPciRootBridgeBarExisted ( > + IN UINTN Address, > + OUT UINT32 *OriginalValue, > + OUT UINT32 *Value > + ) > +{ > + // > + // Preserve the original value > + // > + *OriginalValue = PciRead32 (Address); > + > + // > + // Disable timer interrupt while the BAR is probed > + // > + DisableInterrupts (); > + > + PciWrite32 (Address, 0xFFFFFFFF); > + *Value = PciRead32 (Address); > + PciWrite32 (Address, *OriginalValue); > + > + // > + // Enable interrupt > + // > + EnableInterrupts (); > +} > + > +STATIC > +VOID > +PcatPciRootBridgeParseBars ( > + IN UINT16 Command, > + IN UINTN Bus, > + IN UINTN Device, > + IN UINTN Function, > + IN UINTN BarOffsetBase, > + IN UINTN BarOffsetEnd, > + IN PCI_ROOT_BRIDGE_APERTURE *Io, > + IN PCI_ROOT_BRIDGE_APERTURE *Mem, > + IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, > + IN PCI_ROOT_BRIDGE_APERTURE *PMem, > + IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G > + > +) > +{ > + UINT32 OriginalValue; > + UINT32 Value; > + UINT32 OriginalUpperValue; > + UINT32 UpperValue; > + UINT64 Mask; > + UINTN Offset; > + UINT64 Base; > + UINT64 Length; > + UINT64 Limit; > + PCI_ROOT_BRIDGE_APERTURE *MemAperture; > + > + for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) { > + PcatPciRootBridgeBarExisted ( > + PCI_LIB_ADDRESS (Bus, Device, Function, Offset), > + &OriginalValue, &Value > + ); > + if (Value == 0) { > + continue; > + } > + if ((Value & BIT0) == BIT0) { > + // > + // IO Bar > + // > + if (Command & EFI_PCI_COMMAND_IO_SPACE) { > + Mask = 0xfffffffc; > + Base = OriginalValue & Mask; > + Length = ((~(Value & Mask)) & Mask) + 0x04; > + if (!(Value & 0xFFFF0000)) { > + Length &= 0x0000FFFF; > + } > + Limit = Base + Length - 1; > + > + if (Base < Limit) { > + if (Io->Base > Base) { > + Io->Base = Base; > + } > + if (Io->Limit < Limit) { > + Io->Limit = Limit; > + } > + } > + } > + } else { > + // > + // Mem Bar > + // > + if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) { > + > + Mask = 0xfffffff0; > + Base = OriginalValue & Mask; > + Length = Value & Mask; > + > + if ((Value & (BIT1 | BIT2)) == 0) { > + // > + // 32bit > + // > + Length = ((~Length) + 1) & 0xffffffff; > + > + if ((Value & BIT3) == BIT3) { > + MemAperture = PMem; > + } else { > + MemAperture = Mem; > + } > + } else { > + // > + // 64bit > + // > + Offset += 4; > + PcatPciRootBridgeBarExisted ( > + PCI_LIB_ADDRESS (Bus, Device, Function, Offset), > + &OriginalUpperValue, > + &UpperValue > + ); > + > + Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32); > + Length = Length | LShiftU64 ((UINT64) UpperValue, 32); > + Length = (~Length) + 1; > + > + if ((Value & BIT3) == BIT3) { > + MemAperture = PMemAbove4G; > + } else { > + MemAperture = MemAbove4G; > + } > + } > + > + Limit = Base + Length - 1; > + if (Base < Limit) { > + if (MemAperture->Base > Base) { > + MemAperture->Base = Base; > + } > + if (MemAperture->Limit < Limit) { > + MemAperture->Limit = Limit; > + } > + } > + } > + } > + } > +} > + > +PCI_ROOT_BRIDGE * > +ScanForRootBridges ( > + UINTN *NumberOfRootBridges > + ) > +{ > + UINTN PrimaryBus; > + UINTN SubBus; > + UINT8 Device; > + UINT8 Function; > + UINTN NumberOfDevices; > + UINTN Address; > + PCI_TYPE01 Pci; > + UINT64 Attributes; > + UINT64 Base; > + UINT64 Limit; > + UINT64 Value; > + PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture; > + PCI_ROOT_BRIDGE *RootBridges; > + UINTN BarOffsetEnd; > + > + > + *NumberOfRootBridges = 0; > + RootBridges = NULL; > + > + // > + // After scanning all the PCI devices on the PCI root bridge's primary bus, > + // update the Primary Bus Number for the next PCI root bridge to be this PCI > + // root bridge's subordinate bus number + 1. > + // > + for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) { > + SubBus = PrimaryBus; > + Attributes = 0; > + Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64; > + Io.Limit = Mem.Limit = MemAbove4G.Limit = PMem.Limit = PMemAbove4G.Limit = 0; > + // > + // Scan all the PCI devices on the primary bus of the PCI root bridge > + // > + for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) { > + > + for (Function = 0; Function <= PCI_MAX_FUNC; Function++) { > + > + // > + // Compute the PCI configuration address of the PCI device to probe > + // > + Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0); > + > + // > + // Read the Vendor ID from the PCI Configuration Header > + // > + if (PciRead16 (Address) == MAX_UINT16) { > + if (Function == 0) { > + // > + // If the PCI Configuration Read fails, or a PCI device does not > + // exist, then skip this entire PCI device > + // > + break; > + } else { > + // > + // If PCI function != 0, VendorId == 0xFFFF, we continue to search > + // PCI function. > + // > + continue; > + } > + } > + > + // > + // Read the entire PCI Configuration Header > + // > + PciReadBuffer (Address, sizeof (Pci), &Pci); > + > + // > + // Increment the number of PCI device found on the primary bus of the > + // PCI root bridge > + // > + NumberOfDevices++; > + > + // > + // Look for devices with the VGA Palette Snoop enabled in the COMMAND > + // register of the PCI Config Header > + // > + if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) { > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; > + } > + > + BarOffsetEnd = 0; > + > + // > + // PCI-PCI Bridge > + // > + if (IS_PCI_BRIDGE (&Pci)) { > + // > + // Get the Bus range that the PPB is decoding > + // > + if (Pci.Bridge.SubordinateBus > SubBus) { > + // > + // If the suborinate bus number of the PCI-PCI bridge is greater > + // than the PCI root bridge's current subordinate bus number, > + // then update the PCI root bridge's subordinate bus number > + // > + SubBus = Pci.Bridge.SubordinateBus; > + } > + > + // > + // Get the I/O range that the PPB is decoding > + // > + Value = Pci.Bridge.IoBase & 0x0f; > + Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8; > + Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff; > + if (Value == BIT0) { > + Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16); > + Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16); > + } > + if (Base < Limit) { > + if (Io.Base > Base) { > + Io.Base = Base; > + } > + if (Io.Limit < Limit) { > + Io.Limit = Limit; > + } > + } > + > + // > + // Get the Memory range that the PPB is decoding > + // > + Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16; > + Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff; > + if (Base < Limit) { > + if (Mem.Base > Base) { > + Mem.Base = Base; > + } > + if (Mem.Limit < Limit) { > + Mem.Limit = Limit; > + } > + } > + > + // > + // Get the Prefetchable Memory range that the PPB is decoding > + // > + Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f; > + Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16; > + Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0) > + << 16) | 0xfffff; > + MemAperture = &PMem; > + if (Value == BIT0) { > + Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32); > + Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32); > + MemAperture = &PMemAbove4G; > + } > + if (Base < Limit) { > + if (MemAperture->Base > Base) { > + MemAperture->Base = Base; > + } > + if (MemAperture->Limit < Limit) { > + MemAperture->Limit = Limit; > + } > + } > + > + // > + // Look at the PPB Configuration for legacy decoding attributes > + // > + if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) > + == EFI_PCI_BRIDGE_CONTROL_ISA) { > + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; > + Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; > + } > + if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) > + == EFI_PCI_BRIDGE_CONTROL_VGA) { > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; > + if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) > + != 0) { > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; > + } > + } > + > + BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]); > + } else { > + // > + // Parse the BARs of the PCI device to get what I/O Ranges, Memory > + // Ranges, and Prefetchable Memory Ranges the device is decoding > + // > + if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) { > + BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]); > + } > + } > + > + PcatPciRootBridgeParseBars ( > + Pci.Hdr.Command, > + PrimaryBus, > + Device, > + Function, > + OFFSET_OF (PCI_TYPE00, Device.Bar), > + BarOffsetEnd, > + &Io, > + &Mem, &MemAbove4G, > + &PMem, &PMemAbove4G > + ); > + > + // > + // See if the PCI device is an IDE controller > + // > + if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE, > + PCI_CLASS_MASS_STORAGE_IDE)) { > + if (Pci.Hdr.ClassCode[0] & 0x80) { > + Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; > + } > + if (Pci.Hdr.ClassCode[0] & 0x01) { > + Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; > + } > + if (Pci.Hdr.ClassCode[0] & 0x04) { > + Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; > + } > + } > + > + // > + // See if the PCI device is a legacy VGA controller or > + // a standard VGA controller > + // > + if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) || > + IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA) > + ) { > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; > + } > + > + // > + // See if the PCI Device is a PCI - ISA or PCI - EISA > + // or ISA_POSITIVIE_DECODE Bridge device > + // > + if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) { > + if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA || > + Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA || > + Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) { > + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; > + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; > + Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; > + } > + } > + > + // > + // If this device is not a multi function device, then skip the rest > + // of this PCI device > + // > + if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { > + break; > + } > + } > + } > + > + // > + // If at least one PCI device was found on the primary bus of this PCI > + // root bridge, then the PCI root bridge exists. > + // > + if (NumberOfDevices > 0) { > + RootBridges = ReallocatePool ( > + (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE), > + (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE), > + RootBridges > + ); > + ASSERT (RootBridges != NULL); > + InitRootBridge ( > + Attributes, Attributes, 0, > + (UINT8) PrimaryBus, (UINT8) SubBus, > + &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G, > + &RootBridges[*NumberOfRootBridges] > + ); > + RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE; > + // > + // Increment the index for the next PCI Root Bridge > + // > + (*NumberOfRootBridges)++; > + } > + } > + > + return RootBridges; > +} >
diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h new file mode 100644 index 0000000..c23d40c --- /dev/null +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h @@ -0,0 +1,75 @@ +/** @file + Header file of OVMF instance of PciHostBridgeLib. + + Copyright (c) 2016, 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. + +**/ + +PCI_ROOT_BRIDGE * +ScanForRootBridges ( + UINTN *NumberOfRootBridges +); + +/** + Initialize a PCI_ROOT_BRIDGE structure. + + @param[in] Supports Supported attributes. + + @param[in] Attributes Initial attributes. + + @param[in] AllocAttributes Allocation attributes. + + @param[in] RootBusNumber The bus number to store in RootBus. + + @param[in] MaxSubBusNumber The inclusive maximum bus number that can be + assigned to any subordinate bus found behind any + PCI bridge hanging off this root bus. + + The caller is repsonsible for ensuring that + RootBusNumber <= MaxSubBusNumber. If + RootBusNumber equals MaxSubBusNumber, then the + root bus has no room for subordinate buses. + + @param[in] Io IO aperture. + + @param[in] Mem MMIO aperture. + + @param[in] MemAbove4G MMIO aperture above 4G. + + @param[in] PMem Prefetchable MMIO aperture. + + @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. + + @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the + caller) that should be filled in by this + function. + + @retval EFI_SUCCESS Initialization successful. A device path + consisting of an ACPI device path node, with + UID = RootBusNumber, has been allocated and + linked into RootBus. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. +**/ +EFI_STATUS +InitRootBridge ( + IN UINT64 Supports, + IN UINT64 Attributes, + IN UINT64 AllocAttributes, + IN UINT8 RootBusNumber, + IN UINT8 MaxSubBusNumber, + IN PCI_ROOT_BRIDGE_APERTURE *Io, + IN PCI_ROOT_BRIDGE_APERTURE *Mem, + IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, + IN PCI_ROOT_BRIDGE_APERTURE *PMem, + IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G, + OUT PCI_ROOT_BRIDGE *RootBus + ); diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c new file mode 100644 index 0000000..efcd830 --- /dev/null +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c @@ -0,0 +1,291 @@ +/** @file + OVMF's instance of the PCI Host Bridge Library. + + Copyright (C) 2016, Red Hat, Inc. + Copyright (c) 2016, 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 <PiDxe.h> + +#include <IndustryStandard/Pci.h> +#include <IndustryStandard/Q35MchIch9.h> + +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciRootBridgeIo.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PciHostBridgeLib.h> +#include <Library/PciLib.h> +#include <Library/QemuFwCfgLib.h> +#include "XenPciHostBridge.h" + + +#pragma pack(1) +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH; +#pragma pack () + + +GLOBAL_REMOVE_IF_UNREFERENCED +CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = { + L"Mem", L"I/O", L"Bus" +}; + + +STATIC +CONST +OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)), + (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8) + } + }, + EISA_PNP_ID(0x0A03), // HID + 0 // UID + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +/** + Initialize a PCI_ROOT_BRIDGE structure. + + @param[in] Supports Supported attributes. + + @param[in] Attributes Initial attributes. + + @param[in] AllocAttributes Allocation attributes. + + @param[in] RootBusNumber The bus number to store in RootBus. + + @param[in] MaxSubBusNumber The inclusive maximum bus number that can be + assigned to any subordinate bus found behind any + PCI bridge hanging off this root bus. + + The caller is repsonsible for ensuring that + RootBusNumber <= MaxSubBusNumber. If + RootBusNumber equals MaxSubBusNumber, then the + root bus has no room for subordinate buses. + + @param[in] Io IO aperture. + + @param[in] Mem MMIO aperture. + + @param[in] MemAbove4G MMIO aperture above 4G. + + @param[in] PMem Prefetchable MMIO aperture. + + @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. + + @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the + caller) that should be filled in by this + function. + + @retval EFI_SUCCESS Initialization successful. A device path + consisting of an ACPI device path node, with + UID = RootBusNumber, has been allocated and + linked into RootBus. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. +**/ +EFI_STATUS +InitRootBridge ( + IN UINT64 Supports, + IN UINT64 Attributes, + IN UINT64 AllocAttributes, + IN UINT8 RootBusNumber, + IN UINT8 MaxSubBusNumber, + IN PCI_ROOT_BRIDGE_APERTURE *Io, + IN PCI_ROOT_BRIDGE_APERTURE *Mem, + IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, + IN PCI_ROOT_BRIDGE_APERTURE *PMem, + IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G, + OUT PCI_ROOT_BRIDGE *RootBus + ) +{ + OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath; + + // + // Be safe if other fields are added to PCI_ROOT_BRIDGE later. + // + ZeroMem (RootBus, sizeof *RootBus); + + RootBus->Segment = 0; + + RootBus->Supports = Supports; + RootBus->Attributes = Attributes; + + RootBus->DmaAbove4G = FALSE; + + RootBus->AllocationAttributes = AllocAttributes; + RootBus->Bus.Base = RootBusNumber; + RootBus->Bus.Limit = MaxSubBusNumber; + CopyMem (&RootBus->Io, Io, sizeof (*Io)); + CopyMem (&RootBus->Mem, Mem, sizeof (*Mem)); + CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G)); + CopyMem (&RootBus->PMem, PMem, sizeof (*PMem)); + CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G)); + + RootBus->NoExtendedConfigSpace = (PcdGet16 (PcdOvmfHostBridgePciDevId) != + INTEL_Q35_MCH_DEVICE_ID); + + DevicePath = AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate, + &mRootBridgeDevicePathTemplate); + if (DevicePath == NULL) { + DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES)); + return EFI_OUT_OF_RESOURCES; + } + DevicePath->AcpiDevicePath.UID = RootBusNumber; + RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; + + DEBUG ((EFI_D_INFO, + "%a: populated root bus %d, with room for %d subordinate bus(es)\n", + __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber)); + return EFI_SUCCESS; +} + + +/** + Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge(). + + param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and + initialized with InitRootBridge(), that should be + uninitialized. This function doesn't free RootBus. +**/ +STATIC +VOID +UninitRootBridge ( + IN PCI_ROOT_BRIDGE *RootBus + ) +{ + FreePool (RootBus->DevicePath); +} + + +/** + Return all the root bridge instances in an array. + + @param Count Return the count of root bridge instances. + + @return All the root bridge instances in an array. + The array should be passed into PciHostBridgeFreeRootBridges() + when it's not used. +**/ +PCI_ROOT_BRIDGE * +EFIAPI +PciHostBridgeGetRootBridges ( + UINTN *Count + ) +{ + ASSERT (PcdGetBool (PcdPciDisableBusEnumeration)); + return ScanForRootBridges (Count); +} + + +/** + Free the root bridge instances array returned from + PciHostBridgeGetRootBridges(). + + @param The root bridge instances array. + @param The count of the array. +**/ +VOID +EFIAPI +PciHostBridgeFreeRootBridges ( + PCI_ROOT_BRIDGE *Bridges, + UINTN Count + ) +{ + if (Bridges == NULL && Count == 0) { + return; + } + ASSERT (Bridges != NULL && Count > 0); + + do { + --Count; + UninitRootBridge (&Bridges[Count]); + } while (Count > 0); + + FreePool (Bridges); +} + + +/** + Inform the platform that the resource conflict happens. + + @param HostBridgeHandle Handle of the Host Bridge. + @param Configuration Pointer to PCI I/O and PCI memory resource + descriptors. The Configuration contains the resources + for all the root bridges. The resource for each root + bridge is terminated with END descriptor and an + additional END is appended indicating the end of the + entire resources. The resource descriptor field + values follow the description in + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + .SubmitResources(). +**/ +VOID +EFIAPI +PciHostBridgeResourceConflict ( + EFI_HANDLE HostBridgeHandle, + VOID *Configuration + ) +{ + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + UINTN RootBridgeIndex; + DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n")); + + RootBridgeIndex = 0; + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); + for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) { + ASSERT (Descriptor->ResType < + ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr) + ); + DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n", + mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType], + Descriptor->AddrLen, Descriptor->AddrRangeMax + )); + if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + DEBUG ((EFI_D_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n", + Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag, + ((Descriptor->SpecificFlag & + EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE + ) != 0) ? L" (Prefetchable)" : L"" + )); + } + } + // + // Skip the END descriptor for root bridge + // + ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR); + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( + (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1 + ); + } +} diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf new file mode 100644 index 0000000..3b8f003 --- /dev/null +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf @@ -0,0 +1,58 @@ +## @file +# OVMF's instance of the PCI Host Bridge Library. +# +# Copyright (C) 2016, Red Hat, Inc. +# Copyright (c) 2016, 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 = XenPciHostBridgeLib + FILE_GUID = 9F2BC05E-51EA-4AED-9A3E-7699641734E8 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PciHostBridgeLib + +# +# The following information is for reference only and not required by the build +# tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + XenPciHostBridgeLib.c + XenSupport.c + XenPciHostBridge.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + PciLib + +[Pcd] + gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase + gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId + gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration diff --git a/OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c b/OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c new file mode 100644 index 0000000..a45945f --- /dev/null +++ b/OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c @@ -0,0 +1,456 @@ +/** @file + Scan the entire PCI bus for root bridges to support OVMF above Xen. + + Copyright (c) 2016, 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 <PiDxe.h> + +#include <IndustryStandard/Pci.h> +#include <IndustryStandard/Q35MchIch9.h> + +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciRootBridgeIo.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PciHostBridgeLib.h> +#include <Library/PciLib.h> +#include "XenPciHostBridge.h" + +STATIC +VOID +PcatPciRootBridgeBarExisted ( + IN UINTN Address, + OUT UINT32 *OriginalValue, + OUT UINT32 *Value + ) +{ + // + // Preserve the original value + // + *OriginalValue = PciRead32 (Address); + + // + // Disable timer interrupt while the BAR is probed + // + DisableInterrupts (); + + PciWrite32 (Address, 0xFFFFFFFF); + *Value = PciRead32 (Address); + PciWrite32 (Address, *OriginalValue); + + // + // Enable interrupt + // + EnableInterrupts (); +} + +STATIC +VOID +PcatPciRootBridgeParseBars ( + IN UINT16 Command, + IN UINTN Bus, + IN UINTN Device, + IN UINTN Function, + IN UINTN BarOffsetBase, + IN UINTN BarOffsetEnd, + IN PCI_ROOT_BRIDGE_APERTURE *Io, + IN PCI_ROOT_BRIDGE_APERTURE *Mem, + IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, + IN PCI_ROOT_BRIDGE_APERTURE *PMem, + IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G + +) +{ + UINT32 OriginalValue; + UINT32 Value; + UINT32 OriginalUpperValue; + UINT32 UpperValue; + UINT64 Mask; + UINTN Offset; + UINT64 Base; + UINT64 Length; + UINT64 Limit; + PCI_ROOT_BRIDGE_APERTURE *MemAperture; + + for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) { + PcatPciRootBridgeBarExisted ( + PCI_LIB_ADDRESS (Bus, Device, Function, Offset), + &OriginalValue, &Value + ); + if (Value == 0) { + continue; + } + if ((Value & BIT0) == BIT0) { + // + // IO Bar + // + if (Command & EFI_PCI_COMMAND_IO_SPACE) { + Mask = 0xfffffffc; + Base = OriginalValue & Mask; + Length = ((~(Value & Mask)) & Mask) + 0x04; + if (!(Value & 0xFFFF0000)) { + Length &= 0x0000FFFF; + } + Limit = Base + Length - 1; + + if (Base < Limit) { + if (Io->Base > Base) { + Io->Base = Base; + } + if (Io->Limit < Limit) { + Io->Limit = Limit; + } + } + } + } else { + // + // Mem Bar + // + if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) { + + Mask = 0xfffffff0; + Base = OriginalValue & Mask; + Length = Value & Mask; + + if ((Value & (BIT1 | BIT2)) == 0) { + // + // 32bit + // + Length = ((~Length) + 1) & 0xffffffff; + + if ((Value & BIT3) == BIT3) { + MemAperture = PMem; + } else { + MemAperture = Mem; + } + } else { + // + // 64bit + // + Offset += 4; + PcatPciRootBridgeBarExisted ( + PCI_LIB_ADDRESS (Bus, Device, Function, Offset), + &OriginalUpperValue, + &UpperValue + ); + + Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32); + Length = Length | LShiftU64 ((UINT64) UpperValue, 32); + Length = (~Length) + 1; + + if ((Value & BIT3) == BIT3) { + MemAperture = PMemAbove4G; + } else { + MemAperture = MemAbove4G; + } + } + + Limit = Base + Length - 1; + if (Base < Limit) { + if (MemAperture->Base > Base) { + MemAperture->Base = Base; + } + if (MemAperture->Limit < Limit) { + MemAperture->Limit = Limit; + } + } + } + } + } +} + +PCI_ROOT_BRIDGE * +ScanForRootBridges ( + UINTN *NumberOfRootBridges + ) +{ + UINTN PrimaryBus; + UINTN SubBus; + UINT8 Device; + UINT8 Function; + UINTN NumberOfDevices; + UINTN Address; + PCI_TYPE01 Pci; + UINT64 Attributes; + UINT64 Base; + UINT64 Limit; + UINT64 Value; + PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture; + PCI_ROOT_BRIDGE *RootBridges; + UINTN BarOffsetEnd; + + + *NumberOfRootBridges = 0; + RootBridges = NULL; + + // + // After scanning all the PCI devices on the PCI root bridge's primary bus, + // update the Primary Bus Number for the next PCI root bridge to be this PCI + // root bridge's subordinate bus number + 1. + // + for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) { + SubBus = PrimaryBus; + Attributes = 0; + Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64; + Io.Limit = Mem.Limit = MemAbove4G.Limit = PMem.Limit = PMemAbove4G.Limit = 0; + // + // Scan all the PCI devices on the primary bus of the PCI root bridge + // + for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) { + + for (Function = 0; Function <= PCI_MAX_FUNC; Function++) { + + // + // Compute the PCI configuration address of the PCI device to probe + // + Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0); + + // + // Read the Vendor ID from the PCI Configuration Header + // + if (PciRead16 (Address) == MAX_UINT16) { + if (Function == 0) { + // + // If the PCI Configuration Read fails, or a PCI device does not + // exist, then skip this entire PCI device + // + break; + } else { + // + // If PCI function != 0, VendorId == 0xFFFF, we continue to search + // PCI function. + // + continue; + } + } + + // + // Read the entire PCI Configuration Header + // + PciReadBuffer (Address, sizeof (Pci), &Pci); + + // + // Increment the number of PCI device found on the primary bus of the + // PCI root bridge + // + NumberOfDevices++; + + // + // Look for devices with the VGA Palette Snoop enabled in the COMMAND + // register of the PCI Config Header + // + if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; + } + + BarOffsetEnd = 0; + + // + // PCI-PCI Bridge + // + if (IS_PCI_BRIDGE (&Pci)) { + // + // Get the Bus range that the PPB is decoding + // + if (Pci.Bridge.SubordinateBus > SubBus) { + // + // If the suborinate bus number of the PCI-PCI bridge is greater + // than the PCI root bridge's current subordinate bus number, + // then update the PCI root bridge's subordinate bus number + // + SubBus = Pci.Bridge.SubordinateBus; + } + + // + // Get the I/O range that the PPB is decoding + // + Value = Pci.Bridge.IoBase & 0x0f; + Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8; + Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff; + if (Value == BIT0) { + Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16); + Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16); + } + if (Base < Limit) { + if (Io.Base > Base) { + Io.Base = Base; + } + if (Io.Limit < Limit) { + Io.Limit = Limit; + } + } + + // + // Get the Memory range that the PPB is decoding + // + Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16; + Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff; + if (Base < Limit) { + if (Mem.Base > Base) { + Mem.Base = Base; + } + if (Mem.Limit < Limit) { + Mem.Limit = Limit; + } + } + + // + // Get the Prefetchable Memory range that the PPB is decoding + // + Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f; + Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16; + Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0) + << 16) | 0xfffff; + MemAperture = &PMem; + if (Value == BIT0) { + Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32); + Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32); + MemAperture = &PMemAbove4G; + } + if (Base < Limit) { + if (MemAperture->Base > Base) { + MemAperture->Base = Base; + } + if (MemAperture->Limit < Limit) { + MemAperture->Limit = Limit; + } + } + + // + // Look at the PPB Configuration for legacy decoding attributes + // + if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) + == EFI_PCI_BRIDGE_CONTROL_ISA) { + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; + Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; + } + if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) + == EFI_PCI_BRIDGE_CONTROL_VGA) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) + != 0) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; + } + } + + BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]); + } else { + // + // Parse the BARs of the PCI device to get what I/O Ranges, Memory + // Ranges, and Prefetchable Memory Ranges the device is decoding + // + if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) { + BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]); + } + } + + PcatPciRootBridgeParseBars ( + Pci.Hdr.Command, + PrimaryBus, + Device, + Function, + OFFSET_OF (PCI_TYPE00, Device.Bar), + BarOffsetEnd, + &Io, + &Mem, &MemAbove4G, + &PMem, &PMemAbove4G + ); + + // + // See if the PCI device is an IDE controller + // + if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE, + PCI_CLASS_MASS_STORAGE_IDE)) { + if (Pci.Hdr.ClassCode[0] & 0x80) { + Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; + Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; + } + if (Pci.Hdr.ClassCode[0] & 0x01) { + Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; + } + if (Pci.Hdr.ClassCode[0] & 0x04) { + Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; + } + } + + // + // See if the PCI device is a legacy VGA controller or + // a standard VGA controller + // + if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) || + IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA) + ) { + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; + Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; + } + + // + // See if the PCI Device is a PCI - ISA or PCI - EISA + // or ISA_POSITIVIE_DECODE Bridge device + // + if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) { + if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA || + Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA || + Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) { + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; + Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; + Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; + } + } + + // + // If this device is not a multi function device, then skip the rest + // of this PCI device + // + if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { + break; + } + } + } + + // + // If at least one PCI device was found on the primary bus of this PCI + // root bridge, then the PCI root bridge exists. + // + if (NumberOfDevices > 0) { + RootBridges = ReallocatePool ( + (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE), + (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE), + RootBridges + ); + ASSERT (RootBridges != NULL); + InitRootBridge ( + Attributes, Attributes, 0, + (UINT8) PrimaryBus, (UINT8) SubBus, + &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G, + &RootBridges[*NumberOfRootBridges] + ); + RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE; + // + // Increment the index for the next PCI Root Bridge + // + (*NumberOfRootBridges)++; + } + } + + return RootBridges; +}
A copy of OvmfPkg/Library/PciHostBridgeLib Removing support for pci bus enumeration, I think, and only use scan of already enumerated pci bus. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> --- .../Library/XenPciHostBridgeLib/XenPciHostBridge.h | 75 ++++ .../XenPciHostBridgeLib/XenPciHostBridgeLib.c | 291 +++++++++++++ .../XenPciHostBridgeLib/XenPciHostBridgeLib.inf | 58 +++ OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c | 456 +++++++++++++++++++++ 4 files changed, 880 insertions(+) create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridge.h create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.c create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenPciHostBridgeLib.inf create mode 100644 OvmfPkg/Library/XenPciHostBridgeLib/XenSupport.c