\r
**/\r
#include <PiDxe.h>\r
-#include <Library/PciHostBridgeLib.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <IndustryStandard/Q35MchIch9.h>\r
+\r
+#include <Protocol/PciHostBridgeResourceAllocation.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PciHostBridgeLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/QemuFwCfgLib.h>\r
+#include "PciHostBridge.h"\r
+\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
+} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH;\r
+#pragma pack ()\r
+\r
\r
GLOBAL_REMOVE_IF_UNREFERENCED\r
CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {\r
L"Mem", L"I/O", L"Bus"\r
};\r
\r
+\r
+STATIC\r
+CONST\r
+OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {\r
+ {\r
+ {\r
+ ACPI_DEVICE_PATH,\r
+ ACPI_DP,\r
+ {\r
+ (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)),\r
+ (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ EISA_PNP_ID(0x0A03), // HID\r
+ 0 // UID\r
+ },\r
+\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ {\r
+ END_DEVICE_PATH_LENGTH,\r
+ 0\r
+ }\r
+ }\r
+};\r
+\r
+STATIC PCI_ROOT_BRIDGE_APERTURE mNonExistAperture = { MAX_UINT64, 0 };\r
+\r
+/**\r
+ Initialize a PCI_ROOT_BRIDGE structure.\r
+\r
+ @param[in] Supports Supported attributes.\r
+\r
+ @param[in] Attributes Initial attributes.\r
+\r
+ @param[in] AllocAttributes Allocation attributes.\r
+\r
+ @param[in] RootBusNumber The bus number to store in RootBus.\r
+\r
+ @param[in] MaxSubBusNumber The inclusive maximum bus number that can be\r
+ assigned to any subordinate bus found behind any\r
+ PCI bridge hanging off this root bus.\r
+\r
+ The caller is repsonsible for ensuring that\r
+ RootBusNumber <= MaxSubBusNumber. If\r
+ RootBusNumber equals MaxSubBusNumber, then the\r
+ root bus has no room for subordinate buses.\r
+\r
+ @param[in] Io IO aperture.\r
+\r
+ @param[in] Mem MMIO aperture.\r
+\r
+ @param[in] MemAbove4G MMIO aperture above 4G.\r
+\r
+ @param[in] PMem Prefetchable MMIO aperture.\r
+\r
+ @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
+\r
+ @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the\r
+ caller) that should be filled in by this\r
+ function.\r
+\r
+ @retval EFI_SUCCESS Initialization successful. A device path\r
+ consisting of an ACPI device path node, with\r
+ UID = RootBusNumber, has been allocated and\r
+ linked into RootBus.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+InitRootBridge (\r
+ IN UINT64 Supports,\r
+ IN UINT64 Attributes,\r
+ IN UINT64 AllocAttributes,\r
+ IN UINT8 RootBusNumber,\r
+ IN UINT8 MaxSubBusNumber,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,\r
+ OUT PCI_ROOT_BRIDGE *RootBus\r
+ )\r
+{\r
+ OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;\r
+\r
+ //\r
+ // Be safe if other fields are added to PCI_ROOT_BRIDGE later.\r
+ //\r
+ ZeroMem (RootBus, sizeof *RootBus);\r
+\r
+ RootBus->Segment = 0;\r
+\r
+ RootBus->Supports = Supports;\r
+ RootBus->Attributes = Attributes;\r
+\r
+ RootBus->DmaAbove4G = FALSE;\r
+\r
+ RootBus->AllocationAttributes = AllocAttributes;\r
+ RootBus->Bus.Base = RootBusNumber;\r
+ RootBus->Bus.Limit = MaxSubBusNumber;\r
+ CopyMem (&RootBus->Io, Io, sizeof (*Io));\r
+ CopyMem (&RootBus->Mem, Mem, sizeof (*Mem));\r
+ CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G));\r
+ CopyMem (&RootBus->PMem, PMem, sizeof (*PMem));\r
+ CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G));\r
+\r
+ RootBus->NoExtendedConfigSpace = (PcdGet16 (PcdOvmfHostBridgePciDevId) !=\r
+ INTEL_Q35_MCH_DEVICE_ID);\r
+\r
+ DevicePath = AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate,\r
+ &mRootBridgeDevicePathTemplate);\r
+ if (DevicePath == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ DevicePath->AcpiDevicePath.UID = RootBusNumber;\r
+ RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
+\r
+ DEBUG ((EFI_D_INFO,\r
+ "%a: populated root bus %d, with room for %d subordinate bus(es)\n",\r
+ __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge().\r
+\r
+ param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and\r
+ initialized with InitRootBridge(), that should be\r
+ uninitialized. This function doesn't free RootBus.\r
+**/\r
+STATIC\r
+VOID\r
+UninitRootBridge (\r
+ IN PCI_ROOT_BRIDGE *RootBus\r
+ )\r
+{\r
+ FreePool (RootBus->DevicePath);\r
+}\r
+\r
+\r
/**\r
Return all the root bridge instances in an array.\r
\r
UINTN *Count\r
)\r
{\r
+ EFI_STATUS Status;\r
+ FIRMWARE_CONFIG_ITEM FwCfgItem;\r
+ UINTN FwCfgSize;\r
+ UINT64 ExtraRootBridges;\r
+ PCI_ROOT_BRIDGE *Bridges;\r
+ UINTN Initialized;\r
+ UINTN LastRootBridgeNumber;\r
+ UINTN RootBridgeNumber;\r
+ UINT64 Attributes;\r
+ UINT64 AllocationAttributes;\r
+ PCI_ROOT_BRIDGE_APERTURE Io;\r
+ PCI_ROOT_BRIDGE_APERTURE Mem;\r
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G;\r
+\r
+ if (PcdGetBool (PcdPciDisableBusEnumeration)) {\r
+ return ScanForRootBridges (Count);\r
+ }\r
+\r
+ ZeroMem (&Io, sizeof (Io));\r
+ ZeroMem (&Mem, sizeof (Mem));\r
+ ZeroMem (&MemAbove4G, sizeof (MemAbove4G));\r
+\r
+ Attributes = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO |\r
+ EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |\r
+ EFI_PCI_ATTRIBUTE_ISA_IO_16 |\r
+ EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |\r
+ EFI_PCI_ATTRIBUTE_VGA_MEMORY |\r
+ EFI_PCI_ATTRIBUTE_VGA_IO_16 |\r
+ EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;\r
+\r
+ AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;\r
+ if (PcdGet64 (PcdPciMmio64Size) > 0) {\r
+ AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;\r
+ MemAbove4G.Base = PcdGet64 (PcdPciMmio64Base);\r
+ MemAbove4G.Limit = PcdGet64 (PcdPciMmio64Base) +\r
+ PcdGet64 (PcdPciMmio64Size) - 1;\r
+ } else {\r
+ CopyMem (&MemAbove4G, &mNonExistAperture, sizeof (mNonExistAperture));\r
+ }\r
+\r
+ Io.Base = PcdGet64 (PcdPciIoBase);\r
+ Io.Limit = PcdGet64 (PcdPciIoBase) + (PcdGet64 (PcdPciIoSize) - 1);\r
+ Mem.Base = PcdGet64 (PcdPciMmio32Base);\r
+ Mem.Limit = PcdGet64 (PcdPciMmio32Base) + (PcdGet64 (PcdPciMmio32Size) - 1);\r
+\r
*Count = 0;\r
+\r
+ //\r
+ // QEMU provides the number of extra root buses, shortening the exhaustive\r
+ // search below. If there is no hint, the feature is missing.\r
+ //\r
+ Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
+ if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) {\r
+ ExtraRootBridges = 0;\r
+ } else {\r
+ QemuFwCfgSelectItem (FwCfgItem);\r
+ QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges);\r
+\r
+ if (ExtraRootBridges > PCI_MAX_BUS) {\r
+ DEBUG ((EFI_D_ERROR, "%a: invalid count of extra root buses (%Lu) "\r
+ "reported by QEMU\n", __FUNCTION__, ExtraRootBridges));\r
+ return NULL;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n",\r
+ __FUNCTION__, ExtraRootBridges));\r
+ }\r
+\r
+ //\r
+ // Allocate the "main" root bridge, and any extra root bridges.\r
+ //\r
+ Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);\r
+ if (Bridges == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
+ return NULL;\r
+ }\r
+ Initialized = 0;\r
+\r
+ //\r
+ // The "main" root bus is always there.\r
+ //\r
+ LastRootBridgeNumber = 0;\r
+\r
+ //\r
+ // Scan all other root buses. If function 0 of any device on a bus returns a\r
+ // VendorId register value different from all-bits-one, then that bus is\r
+ // alive.\r
+ //\r
+ for (RootBridgeNumber = 1;\r
+ RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges;\r
+ ++RootBridgeNumber) {\r
+ UINTN Device;\r
+\r
+ for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {\r
+ if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,\r
+ PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {\r
+ break;\r
+ }\r
+ }\r
+ if (Device <= PCI_MAX_DEVICE) {\r
+ //\r
+ // Found the next root bus. We can now install the *previous* one,\r
+ // because now we know how big a bus number range *that* one has, for any\r
+ // subordinate buses that might exist behind PCI bridges hanging off it.\r
+ //\r
+ Status = InitRootBridge (\r
+ Attributes,\r
+ Attributes,\r
+ AllocationAttributes,\r
+ (UINT8) LastRootBridgeNumber,\r
+ (UINT8) (RootBridgeNumber - 1),\r
+ &Io,\r
+ &Mem,\r
+ &MemAbove4G,\r
+ &mNonExistAperture,\r
+ &mNonExistAperture,\r
+ &Bridges[Initialized]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeBridges;\r
+ }\r
+ ++Initialized;\r
+ LastRootBridgeNumber = RootBridgeNumber;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Install the last root bus (which might be the only, ie. main, root bus, if\r
+ // we've found no extra root buses).\r
+ //\r
+ Status = InitRootBridge (\r
+ Attributes,\r
+ Attributes,\r
+ AllocationAttributes,\r
+ (UINT8) LastRootBridgeNumber,\r
+ PCI_MAX_BUS,\r
+ &Io,\r
+ &Mem,\r
+ &MemAbove4G,\r
+ &mNonExistAperture,\r
+ &mNonExistAperture,\r
+ &Bridges[Initialized]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeBridges;\r
+ }\r
+ ++Initialized;\r
+\r
+ *Count = Initialized;\r
+ return Bridges;\r
+\r
+FreeBridges:\r
+ while (Initialized > 0) {\r
+ --Initialized;\r
+ UninitRootBridge (&Bridges[Initialized]);\r
+ }\r
+\r
+ FreePool (Bridges);\r
return NULL;\r
}\r
\r
+\r
/**\r
Free the root bridge instances array returned from\r
PciHostBridgeGetRootBridges().\r
UINTN Count\r
)\r
{\r
- return;\r
+ if (Bridges == NULL && Count == 0) {\r
+ return;\r
+ }\r
+ ASSERT (Bridges != NULL && Count > 0);\r
+\r
+ do {\r
+ --Count;\r
+ UninitRootBridge (&Bridges[Count]);\r
+ } while (Count > 0);\r
+\r
+ FreePool (Bridges);\r
}\r
\r
+\r
/**\r
Inform the platform that the resource conflict happens.\r
\r
DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));\r
for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
ASSERT (Descriptor->ResType <\r
- (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /\r
- sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])\r
- )\r
+ ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr)\r
);\r
DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",\r
mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],\r