]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / PciHotPlugInitDxe / PciHotPlugInit.c
index 5c98f806def6acb28e72347dd3ea8c7b456d8245..c122855b735d6f9bde730b2f252fed00328ed446 100644 (file)
@@ -4,33 +4,38 @@
 \r
   Copyright (C) 2016, Red Hat, Inc.\r
 \r
-  This program and the accompanying materials are licensed and made available\r
-  under the terms and conditions of the BSD License which accompanies this\r
-  distribution. The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
 #include <IndustryStandard/Acpi10.h>\r
+#include <IndustryStandard/Q35MchIch9.h>\r
+#include <IndustryStandard/QemuPciBridgeCapabilities.h>\r
 \r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/DevicePathLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/PciCapLib.h>\r
+#include <Library/PciCapPciSegmentLib.h>\r
+#include <Library/PciLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 \r
 #include <Protocol/PciHotPlugInit.h>\r
 #include <Protocol/PciRootBridgeIo.h>\r
 \r
+//\r
+// TRUE if the PCI platform supports extended config space, FALSE otherwise.\r
+//\r
+STATIC BOOLEAN  mPciExtConfSpaceSupported;\r
+\r
 //\r
 // The protocol interface this driver produces.\r
 //\r
 // Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform\r
 // Init 1.4a Spec, Volume 5.\r
 //\r
-STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;\r
-\r
+STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL  mPciHotPlugInit;\r
 \r
 //\r
 // Resource padding template for the GetResourcePadding() protocol member\r
@@ -42,82 +47,356 @@ STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;
 // This structure is interpreted by the ApplyResourcePadding() function in the\r
 // edk2 PCI Bus UEFI_DRIVER.\r
 //\r
+// We can request padding for at most four resource types, each of which is\r
+// optional, independently of the others:\r
+// (a) bus numbers,\r
+// (b) IO space,\r
+// (c) non-prefetchable MMIO space (32-bit only),\r
+// (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).\r
+//\r
 #pragma pack (1)\r
 typedef struct {\r
-  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR MmioPadding;\r
-  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR IoPadding;\r
-  EFI_ACPI_END_TAG_DESCRIPTOR       EndDesc;\r
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR    Padding[4];\r
+  EFI_ACPI_END_TAG_DESCRIPTOR          EndDesc;\r
 } RESOURCE_PADDING;\r
 #pragma pack ()\r
 \r
-STATIC CONST RESOURCE_PADDING mPadding = {\r
+/**\r
+  Initialize a RESOURCE_PADDING object.\r
+\r
+  @param[out] ResourcePadding  The caller-allocated RESOURCE_PADDING object to\r
+                               initialize.\r
+**/\r
+STATIC\r
+VOID\r
+InitializeResourcePadding (\r
+  OUT RESOURCE_PADDING  *ResourcePadding\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  ZeroMem (ResourcePadding, sizeof *ResourcePadding);\r
+\r
+  //\r
+  // Fill in the Padding fields that don't vary across resource types.\r
+  //\r
+  for (Index = 0; Index < ARRAY_SIZE (ResourcePadding->Padding); ++Index) {\r
+    EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptor;\r
+\r
+    Descriptor       = ResourcePadding->Padding + Index;\r
+    Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
+    Descriptor->Len  = (UINT16)(\r
+                                sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
+                                OFFSET_OF (\r
+                                  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
+                                  ResType\r
+                                  )\r
+                                );\r
+  }\r
+\r
+  //\r
+  // Fill in the End Tag.\r
+  //\r
+  ResourcePadding->EndDesc.Desc = ACPI_END_TAG_DESCRIPTOR;\r
+}\r
+\r
+/**\r
+  Set up a descriptor entry for reserving IO space.\r
+\r
+  @param[in,out] Descriptor  The descriptor to configure. The caller shall have\r
+                             initialized Descriptor earlier, with\r
+                             InitializeResourcePadding().\r
+\r
+  @param[in] SizeExponent    The size and natural alignment of the reservation\r
+                             are determined by raising two to this power.\r
+**/\r
+STATIC\r
+VOID\r
+SetIoPadding (\r
+  IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptor,\r
+  IN     UINTN                              SizeExponent\r
+  )\r
+{\r
+  Descriptor->ResType      = ACPI_ADDRESS_SPACE_TYPE_IO;\r
+  Descriptor->AddrLen      = LShiftU64 (1, SizeExponent);\r
+  Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;\r
+}\r
+\r
+/**\r
+  Set up a descriptor entry for reserving MMIO space.\r
+\r
+  @param[in,out] Descriptor    The descriptor to configure. The caller shall\r
+                               have initialized Descriptor earlier, with\r
+                               InitializeResourcePadding().\r
+\r
+  @param[in] Prefetchable      TRUE if the descriptor should reserve\r
+                               prefetchable MMIO space. Pass FALSE for\r
+                               reserving non-prefetchable MMIO space.\r
+\r
+  @param[in] ThirtyTwoBitOnly  TRUE if the reservation should be limited to\r
+                               32-bit address space. FALSE if the reservation\r
+                               can be satisfied from 64-bit address space.\r
+                               ThirtyTwoBitOnly is ignored if Prefetchable is\r
+                               FALSE; in that case ThirtyTwoBitOnly is always\r
+                               considered TRUE.\r
+\r
+  @param[in] SizeExponent      The size and natural alignment of the\r
+                               reservation are determined by raising two to\r
+                               this power.\r
+**/\r
+STATIC\r
+VOID\r
+SetMmioPadding (\r
+  IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptor,\r
+  IN     BOOLEAN                            Prefetchable,\r
+  IN     BOOLEAN                            ThirtyTwoBitOnly,\r
+  IN     UINTN                              SizeExponent\r
+  )\r
+{\r
+  Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
+  if (Prefetchable) {\r
+    Descriptor->SpecificFlag =\r
+      EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
+    Descriptor->AddrSpaceGranularity = ThirtyTwoBitOnly ? 32 : 64;\r
+  } else {\r
+    Descriptor->SpecificFlag =\r
+      EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE;\r
+    Descriptor->AddrSpaceGranularity = 32;\r
+  }\r
+\r
+  Descriptor->AddrLen      = LShiftU64 (1, SizeExponent);\r
+  Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;\r
+}\r
+\r
+/**\r
+  Round up a positive 32-bit value to the next whole power of two, and return\r
+  the bit position of the highest bit set in the result. Equivalent to\r
+  ceil(log2(x)).\r
+\r
+  @param[in] Operand  The 32-bit operand to evaluate.\r
+\r
+  @retval -1     Operand is zero.\r
+\r
+  @retval -1     Operand is positive, not a whole power of two, and rounding it\r
+                 up to the next power of two does not fit into 32 bits.\r
+\r
+  @retval 0..31  Otherwise, return ceil(log2(Value)).\r
+**/\r
+STATIC\r
+INTN\r
+HighBitSetRoundUp32 (\r
+  IN UINT32  Operand\r
+  )\r
+{\r
+  INTN  HighBit;\r
+\r
+  HighBit = HighBitSet32 (Operand);\r
+  if (HighBit == -1) {\r
+    //\r
+    // Operand is zero.\r
+    //\r
+    return HighBit;\r
+  }\r
+\r
+  if ((Operand & (Operand - 1)) != 0) {\r
+    //\r
+    // Operand is not a whole power of two.\r
+    //\r
+    ++HighBit;\r
+  }\r
+\r
+  return (HighBit < 32) ? HighBit : -1;\r
+}\r
+\r
+/**\r
+  Round up a positive 64-bit value to the next whole power of two, and return\r
+  the bit position of the highest bit set in the result. Equivalent to\r
+  ceil(log2(x)).\r
+\r
+  @param[in] Operand  The 64-bit operand to evaluate.\r
+\r
+  @retval -1     Operand is zero.\r
+\r
+  @retval -1     Operand is positive, not a whole power of two, and rounding it\r
+                 up to the next power of two does not fit into 64 bits.\r
+\r
+  @retval 0..63  Otherwise, return ceil(log2(Value)).\r
+**/\r
+STATIC\r
+INTN\r
+HighBitSetRoundUp64 (\r
+  IN UINT64  Operand\r
+  )\r
+{\r
+  INTN  HighBit;\r
+\r
+  HighBit = HighBitSet64 (Operand);\r
+  if (HighBit == -1) {\r
+    //\r
+    // Operand is zero.\r
+    //\r
+    return HighBit;\r
+  }\r
+\r
+  if ((Operand & (Operand - 1)) != 0) {\r
+    //\r
+    // Operand is not a whole power of two.\r
+    //\r
+    ++HighBit;\r
+  }\r
+\r
+  return (HighBit < 64) ? HighBit : -1;\r
+}\r
+\r
+/**\r
+  Look up the QEMU-specific Resource Reservation capability in the conventional\r
+  config space of a Hotplug Controller (that is, PCI Bridge).\r
+\r
+  On error, the contents of ReservationHint are indeterminate.\r
+\r
+  @param[in] HpcPciAddress     The address of the PCI Bridge -- Bus, Device,\r
+                               Function -- in UEFI (not PciLib) encoding.\r
+\r
+  @param[out] ReservationHint  The caller-allocated capability structure to\r
+                               populate from the PCI Bridge's config space.\r
+\r
+  @retval EFI_SUCCESS    The capability has been found, ReservationHint has\r
+                         been populated.\r
+\r
+  @retval EFI_NOT_FOUND  The capability is missing.\r
+\r
+  @return                Error codes from PciCapPciSegmentLib and PciCapLib.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+QueryReservationHint (\r
+  IN  CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS  *HpcPciAddress,\r
+  OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION    *ReservationHint\r
+  )\r
+{\r
+  UINT16        PciVendorId;\r
+  EFI_STATUS    Status;\r
+  PCI_CAP_DEV   *PciDevice;\r
+  PCI_CAP_LIST  *CapList;\r
+  UINT16        VendorInstance;\r
+  PCI_CAP       *VendorCap;\r
+\r
   //\r
-  // MmioPadding\r
+  // Check the vendor identifier.\r
   //\r
-  {\r
-    ACPI_ADDRESS_SPACE_DESCRIPTOR,                 // Desc\r
-    (UINT16)(                                      // Len\r
-      sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
-      OFFSET_OF (\r
-        EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
-        ResType\r
-        )\r
-      ),\r
-    ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType\r
-    0,                           // GenFlag:\r
-                                 //   ignored\r
-    0,                           // SpecificFlag:\r
-                                 //   non-prefetchable\r
-    32,                          // AddrSpaceGranularity:\r
-                                 //   reserve 32-bit aperture\r
-    0,                           // AddrRangeMin:\r
-                                 //   ignored\r
-    SIZE_2MB - 1,                // AddrRangeMax:\r
-                                 //   align at 2MB\r
-    0,                           // AddrTranslationOffset:\r
-                                 //   ignored\r
-    SIZE_2MB                     // AddrLen:\r
-                                 //   2MB padding\r
-  },\r
+  PciVendorId = PciRead16 (\r
+                  PCI_LIB_ADDRESS (\r
+                    HpcPciAddress->Bus,\r
+                    HpcPciAddress->Device,\r
+                    HpcPciAddress->Function,\r
+                    PCI_VENDOR_ID_OFFSET\r
+                    )\r
+                  );\r
+  if (PciVendorId != QEMU_PCI_BRIDGE_VENDOR_ID_REDHAT) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
 \r
   //\r
-  // IoPadding\r
+  // Parse the capabilities lists.\r
   //\r
-  {\r
-    ACPI_ADDRESS_SPACE_DESCRIPTOR,                 // Desc\r
-    (UINT16)(                                      // Len\r
-      sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
-      OFFSET_OF (\r
-        EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
-        ResType\r
-        )\r
-      ),\r
-    ACPI_ADDRESS_SPACE_TYPE_IO,// ResType\r
-    0,                          // GenFlag:\r
-                                //   ignored\r
-    0,                          // SpecificFlag:\r
-                                //   ignored\r
-    0,                          // AddrSpaceGranularity:\r
-                                //   ignored\r
-    0,                          // AddrRangeMin:\r
-                                //   ignored\r
-    512 - 1,                    // AddrRangeMax:\r
-                                //   align at 512 IO ports\r
-    0,                          // AddrTranslationOffset:\r
-                                //   ignored\r
-    512                         // AddrLen:\r
-                                //   512 IO ports\r
-  },\r
+  Status = PciCapPciSegmentDeviceInit (\r
+             mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,\r
+             0, // Segment\r
+             HpcPciAddress->Bus,\r
+             HpcPciAddress->Device,\r
+             HpcPciAddress->Function,\r
+             &PciDevice\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = PciCapListInit (PciDevice, &CapList);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitPciDevice;\r
+  }\r
 \r
   //\r
-  // EndDesc\r
+  // Scan the vendor capability instances for the Resource Reservation\r
+  // capability.\r
   //\r
-  {\r
-    ACPI_END_TAG_DESCRIPTOR, // Desc\r
-    0                        // Checksum: to be ignored\r
+  VendorInstance = 0;\r
+  for ( ; ;) {\r
+    UINT8  VendorLength;\r
+    UINT8  BridgeCapType;\r
+\r
+    Status = PciCapListFindCap (\r
+               CapList,\r
+               PciCapNormal,\r
+               EFI_PCI_CAPABILITY_ID_VENDOR,\r
+               VendorInstance++,\r
+               &VendorCap\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto UninitCapList;\r
+    }\r
+\r
+    //\r
+    // Check the vendor capability length.\r
+    //\r
+    Status = PciCapRead (\r
+               PciDevice,\r
+               VendorCap,\r
+               OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),\r
+               &VendorLength,\r
+               sizeof VendorLength\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto UninitCapList;\r
+    }\r
+\r
+    if (VendorLength != sizeof *ReservationHint) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check the vendor bridge capability type.\r
+    //\r
+    Status = PciCapRead (\r
+               PciDevice,\r
+               VendorCap,\r
+               OFFSET_OF (QEMU_PCI_BRIDGE_CAPABILITY_HDR, Type),\r
+               &BridgeCapType,\r
+               sizeof BridgeCapType\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto UninitCapList;\r
+    }\r
+\r
+    if (BridgeCapType ==\r
+        QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION)\r
+    {\r
+      //\r
+      // We have a match.\r
+      //\r
+      break;\r
+    }\r
   }\r
-};\r
 \r
+  //\r
+  // Populate ReservationHint.\r
+  //\r
+  Status = PciCapRead (\r
+             PciDevice,\r
+             VendorCap,\r
+             0, // SourceOffsetInCap\r
+             ReservationHint,\r
+             sizeof *ReservationHint\r
+             );\r
+\r
+UninitCapList:\r
+  PciCapListUninit (CapList);\r
+\r
+UninitPciDevice:\r
+  PciCapPciSegmentDeviceUninit (PciDevice);\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
   Returns a list of root Hot Plug Controllers (HPCs) that require\r
@@ -149,12 +428,12 @@ STATIC
 EFI_STATUS\r
 EFIAPI\r
 GetRootHpcList (\r
-  IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
-  OUT UINTN                          *HpcCount,\r
-  OUT EFI_HPC_LOCATION               **HpcList\r
+  IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL  *This,\r
+  OUT UINTN                           *HpcCount,\r
+  OUT EFI_HPC_LOCATION                **HpcList\r
   )\r
 {\r
-  if (HpcCount == NULL || HpcList == NULL) {\r
+  if ((HpcCount == NULL) || (HpcList == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -163,11 +442,10 @@ GetRootHpcList (
   // that would require special initialization.\r
   //\r
   *HpcCount = 0;\r
-  *HpcList = NULL;\r
+  *HpcList  = NULL;\r
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
   Initializes one root Hot Plug Controller (HPC). This process may causes\r
   initialization of its subordinate buses.\r
@@ -207,11 +485,11 @@ STATIC
 EFI_STATUS\r
 EFIAPI\r
 InitializeRootHpc (\r
-  IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL       *HpcDevicePath,\r
-  IN  UINT64                         HpcPciAddress,\r
-  IN  EFI_EVENT                      Event, OPTIONAL\r
-  OUT EFI_HPC_STATE                  *HpcState\r
+  IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL  *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *HpcDevicePath,\r
+  IN  UINT64                          HpcPciAddress,\r
+  IN  EFI_EVENT                       Event  OPTIONAL,\r
+  OUT EFI_HPC_STATE                   *HpcState\r
   )\r
 {\r
   //\r
@@ -223,10 +501,10 @@ InitializeRootHpc (
   if (HpcState == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+\r
   return EFI_UNSUPPORTED;\r
 }\r
 \r
-\r
 /**\r
   Returns the resource padding that is required by the PCI bus that is\r
   controlled by the specified Hot Plug Controller (HPC).\r
@@ -267,35 +545,223 @@ STATIC
 EFI_STATUS\r
 EFIAPI\r
 GetResourcePadding (\r
-  IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL       *HpcDevicePath,\r
-  IN  UINT64                         HpcPciAddress,\r
-  OUT EFI_HPC_STATE                  *HpcState,\r
-  OUT VOID                           **Padding,\r
-  OUT EFI_HPC_PADDING_ATTRIBUTES     *Attributes\r
+  IN  EFI_PCI_HOT_PLUG_INIT_PROTOCOL  *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *HpcDevicePath,\r
+  IN  UINT64                          HpcPciAddress,\r
+  OUT EFI_HPC_STATE                   *HpcState,\r
+  OUT VOID                            **Padding,\r
+  OUT EFI_HPC_PADDING_ATTRIBUTES      *Attributes\r
   )\r
 {\r
-  DEBUG_CODE (\r
-    EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;\r
-    CHAR16                                      *DevicePathString;\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS      *Address;\r
+  BOOLEAN                                          DefaultIo;\r
+  BOOLEAN                                          DefaultMmio;\r
+  RESOURCE_PADDING                                 ReservationRequest;\r
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR                *FirstResource;\r
+  EFI_STATUS                                       ReservationHintStatus;\r
+  QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION  ReservationHint;\r
+\r
+  Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+  CHAR16  *DevicePathString;\r
+\r
+  DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);\r
+\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a: Address=%02x:%02x.%x DevicePath=%s\n",\r
+    __FUNCTION__,\r
+    Address->Bus,\r
+    Address->Device,\r
+    Address->Function,\r
+    (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString\r
+    ));\r
+\r
+  if (DevicePathString != NULL) {\r
+    FreePool (DevicePathString);\r
+  }\r
+\r
+  DEBUG_CODE_END ();\r
+\r
+  if ((HpcState == NULL) || (Padding == NULL) || (Attributes == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DefaultIo   = TRUE;\r
+  DefaultMmio = TRUE;\r
 \r
-    Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;\r
-    DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);\r
+  //\r
+  // Init ReservationRequest, and point FirstResource one past the last\r
+  // descriptor entry. We're going to build the entries backwards from\r
+  // ReservationRequest.EndDesc.\r
+  //\r
+  InitializeResourcePadding (&ReservationRequest);\r
+  FirstResource = ReservationRequest.Padding +\r
+                  ARRAY_SIZE (ReservationRequest.Padding);\r
+\r
+  //\r
+  // Try to get the QEMU-specific Resource Reservation capability.\r
+  //\r
+  ReservationHintStatus = QueryReservationHint (Address, &ReservationHint);\r
+  if (!EFI_ERROR (ReservationHintStatus)) {\r
+    INTN  HighBit;\r
+\r
+    DEBUG ((\r
+      DEBUG_VERBOSE,\r
+      "%a: BusNumbers=0x%x Io=0x%Lx NonPrefetchable32BitMmio=0x%x\n"\r
+      "%a: Prefetchable32BitMmio=0x%x Prefetchable64BitMmio=0x%Lx\n",\r
+      __FUNCTION__,\r
+      ReservationHint.BusNumbers,\r
+      ReservationHint.Io,\r
+      ReservationHint.NonPrefetchable32BitMmio,\r
+      __FUNCTION__,\r
+      ReservationHint.Prefetchable32BitMmio,\r
+      ReservationHint.Prefetchable64BitMmio\r
+      ));\r
+\r
+    //\r
+    // (a) Reserve bus numbers.\r
+    //\r
+    switch (ReservationHint.BusNumbers) {\r
+      case 0:\r
+        //\r
+        // No reservation needed.\r
+        //\r
+        break;\r
+      case MAX_UINT32:\r
+        //\r
+        // Firmware default (unspecified). Treat it as "no reservation needed".\r
+        //\r
+        break;\r
+      default:\r
+        //\r
+        // Request the specified amount.\r
+        //\r
+        --FirstResource;\r
+        FirstResource->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
+        FirstResource->AddrLen = ReservationHint.BusNumbers;\r
+        break;\r
+    }\r
 \r
-    DEBUG ((EFI_D_VERBOSE, "%a: Address=%02x:%02x.%x DevicePath=%s\n",\r
-      __FUNCTION__, Address->Bus, Address->Device, Address->Function,\r
-      (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString));\r
+    //\r
+    // (b) Reserve IO space.\r
+    //\r
+    switch (ReservationHint.Io) {\r
+      case 0:\r
+        //\r
+        // No reservation needed, disable our built-in.\r
+        //\r
+        DefaultIo = FALSE;\r
+        break;\r
+      case MAX_UINT64:\r
+        //\r
+        // Firmware default (unspecified). Stick with our built-in.\r
+        //\r
+        break;\r
+      default:\r
+        //\r
+        // Round the specified amount up to the next power of two. If rounding is\r
+        // successful, reserve the rounded value. Fall back to the default\r
+        // otherwise.\r
+        //\r
+        HighBit = HighBitSetRoundUp64 (ReservationHint.Io);\r
+        if (HighBit != -1) {\r
+          SetIoPadding (--FirstResource, (UINTN)HighBit);\r
+          DefaultIo = FALSE;\r
+        }\r
+\r
+        break;\r
+    }\r
 \r
-    if (DevicePathString != NULL) {\r
-      FreePool (DevicePathString);\r
+    //\r
+    // (c) Reserve non-prefetchable MMIO space (32-bit only).\r
+    //\r
+    switch (ReservationHint.NonPrefetchable32BitMmio) {\r
+      case 0:\r
+        //\r
+        // No reservation needed, disable our built-in.\r
+        //\r
+        DefaultMmio = FALSE;\r
+        break;\r
+      case MAX_UINT32:\r
+        //\r
+        // Firmware default (unspecified). Stick with our built-in.\r
+        //\r
+        break;\r
+      default:\r
+        //\r
+        // Round the specified amount up to the next power of two. If rounding is\r
+        // successful, reserve the rounded value. Fall back to the default\r
+        // otherwise.\r
+        //\r
+        HighBit = HighBitSetRoundUp32 (ReservationHint.NonPrefetchable32BitMmio);\r
+        if (HighBit != -1) {\r
+          SetMmioPadding (--FirstResource, FALSE, TRUE, (UINTN)HighBit);\r
+          DefaultMmio = FALSE;\r
+        }\r
+\r
+        break;\r
     }\r
-    );\r
 \r
-  if (HpcState == NULL || Padding == NULL || Attributes == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+    //\r
+    // (d) Reserve prefetchable MMIO space (either 32-bit or 64-bit, never\r
+    // both).\r
+    //\r
+    // For either space, we treat 0 as "no reservation needed", and the maximum\r
+    // value as "firmware default". The latter is unspecified, and we interpret\r
+    // it as the former.\r
+    //\r
+    // Otherwise, round the specified amount up to the next power of two. If\r
+    // rounding is successful, reserve the rounded value. Do not reserve\r
+    // prefetchable MMIO space otherwise.\r
+    //\r
+    if ((ReservationHint.Prefetchable32BitMmio > 0) &&\r
+        (ReservationHint.Prefetchable32BitMmio < MAX_UINT32))\r
+    {\r
+      HighBit = HighBitSetRoundUp32 (ReservationHint.Prefetchable32BitMmio);\r
+      if (HighBit != -1) {\r
+        SetMmioPadding (--FirstResource, TRUE, TRUE, (UINTN)HighBit);\r
+      }\r
+    } else if ((ReservationHint.Prefetchable64BitMmio > 0) &&\r
+               (ReservationHint.Prefetchable64BitMmio < MAX_UINT64))\r
+    {\r
+      HighBit = HighBitSetRoundUp64 (ReservationHint.Prefetchable64BitMmio);\r
+      if (HighBit != -1) {\r
+        SetMmioPadding (--FirstResource, TRUE, FALSE, (UINTN)HighBit);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (DefaultIo) {\r
+    //\r
+    // Request defaults.\r
+    //\r
+    SetIoPadding (--FirstResource, (UINTN)HighBitSetRoundUp64 (512));\r
+  }\r
+\r
+  if (DefaultMmio) {\r
+    //\r
+    // Request defaults.\r
+    //\r
+    SetMmioPadding (\r
+      --FirstResource,\r
+      FALSE,\r
+      TRUE,\r
+      (UINTN)HighBitSetRoundUp32 (SIZE_2MB)\r
+      );\r
   }\r
 \r
-  *Padding = AllocateCopyPool (sizeof mPadding, &mPadding);\r
+  //\r
+  // Output a copy of ReservationRequest from the lowest-address populated\r
+  // entry until the end of the structure (including\r
+  // ReservationRequest.EndDesc). If no reservations are necessary, we'll only\r
+  // output the End Tag.\r
+  //\r
+  *Padding = AllocateCopyPool (\r
+               (UINT8 *)(&ReservationRequest + 1) - (UINT8 *)FirstResource,\r
+               FirstResource\r
+               );\r
   if (*Padding == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -313,7 +779,6 @@ GetResourcePadding (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
   Entry point for this driver.\r
 \r
@@ -327,16 +792,22 @@ GetResourcePadding (
 EFI_STATUS\r
 EFIAPI\r
 DriverInitialize (\r
-  IN EFI_HANDLE       ImageHandle,\r
-  IN EFI_SYSTEM_TABLE *SystemTable\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS  Status;\r
 \r
-  mPciHotPlugInit.GetRootHpcList = GetRootHpcList;\r
-  mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;\r
+  mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==\r
+                               INTEL_Q35_MCH_DEVICE_ID);\r
+  mPciHotPlugInit.GetRootHpcList     = GetRootHpcList;\r
+  mPciHotPlugInit.InitializeRootHpc  = InitializeRootHpc;\r
   mPciHotPlugInit.GetResourcePadding = GetResourcePadding;\r
-  Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,\r
-                  &gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);\r
+  Status                             = gBS->InstallMultipleProtocolInterfaces (\r
+                                              &ImageHandle,\r
+                                              &gEfiPciHotPlugInitProtocolGuid,\r
+                                              &mPciHotPlugInit,\r
+                                              NULL\r
+                                              );\r
   return Status;\r
 }\r