Extend the existing IncompatiblePciDeviceSupportDxe driver to support
explicit PCI BAR placement. CheckDevice() checks for a fixed-bars entry
first, then falls back to the existing 64-bit-MMIO-preference descriptor.

Add FixedBars.c/.h to encapsulate fixed-BAR handling. Parse QEMU's
etc/fixed-bars fw_cfg blob, reserve the specified PCI BAR address
ranges in the GCD memory space map before PCI enumeration, provide fixed
BAR descriptors to PciBusDxe during device discovery.

Also, IncompatiblePciDeviceSupportDxe's CcProbe() call has no CcProbeLib
resolution on ArmVirtQemu, which causes the build to fail. This patch
adds a CcProbeLib resolution for ArmVirtQemu.

Signed-off-by: Tushar Dave <[email protected]>
---
 ArmVirtPkg/ArmVirtQemu.dsc                    |   2 +
 ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc          |   1 +
 .../FixedBars.c                               | 413 ++++++++++++++++++
 .../FixedBars.h                               |  63 +++
 .../IncompatiblePciDeviceSupport.c            | 114 +++--
 .../IncompatiblePciDeviceSupport.inf          |   8 +-
 6 files changed, 570 insertions(+), 31 deletions(-)
 create mode 100644 OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.c
 create mode 100644 OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.h

diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index a3f8a2d0ac..d331a3a9bd 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -67,6 +67,7 @@
 !include ArmVirtPkg/ArmVirt.dsc.inc
 
 [LibraryClasses.common]
+  CcProbeLib|MdePkg/Library/CcProbeLibNull/CcProbeLibNull.inf
   ArmTransferListLib|ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf
 
   QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioDxeLib.inf
@@ -392,6 +393,7 @@
   #
   # PCI support
   #
+  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
 
   #
diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc 
b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
index 3fb6a1da9d..3f0b00b2e7 100644
--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
+++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
@@ -159,6 +159,7 @@ READ_LOCK_STATUS   = TRUE
   # PCI support
   #
   INF UefiCpuPkg/CpuMmio2Dxe/CpuMmio2Dxe.inf
+  INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
   INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
   INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.c 
b/OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.c
new file mode 100644
index 0000000000..f307fb285c
--- /dev/null
+++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.c
@@ -0,0 +1,413 @@
+/** @file
+  Fixed PCI BAR placement using metadata provided by QEMU through the
+  "etc/fixed-bars" fw_cfg blob.
+
+  Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "FixedBars.h"
+
+/* byte-for-byte identical to QEMU's structs in hw/pci/pci-fixed-bar.h */
+#pragma pack (1)
+
+typedef struct {
+  UINT32    Version;
+  UINT32    NumDevices;
+} QEMU_FIXED_BARS_HDR;                       /* 8 bytes */
+
+typedef struct {
+  UINT16    VendorId;
+  UINT16    DeviceId;
+  UINT8     DevFlags;
+  UINT8     RpBus;
+  UINT8     NumBars;
+  UINT8     Reserved;
+  CHAR8     FwPath[128];                     /* qdev_get_fw_dev_path(), unused 
here */
+} QEMU_FIXED_BARS_DEVICE;                    /* 136 bytes */
+
+typedef struct {
+  UINT8     Bar;
+  UINT8     Reserved[3];
+  UINT32    Flags;
+  UINT64    Address;
+  UINT64    Size;
+} QEMU_FIXED_BARS_BAR;                       /* 24 bytes */
+
+#pragma pack ()
+
+#define QEMU_FIXED_BARS_VERSION      1
+#define QEMU_FIXED_BAR_F_MEM64       BIT0
+#define QEMU_FIXED_BAR_F_PREF        BIT1
+#define QEMU_FIXED_BARS_DEV_F_FIXED  BIT0
+
+/*
+ * ACPI general-flag bits (ACPI 6.x 6.4.3.5.1):
+ *   BIT2 = _MIF (minimum address fixed)
+ *   BIT3 = _MAF (maximum address fixed)
+ * Both set means AddrRangeMin carries the exact required base address.
+ */
+#define ACPI_ADDR_FLAG_FIXED  (BIT2 | BIT3)
+
+/* Raw blob kept in memory; device entries point into it. */
+STATIC UINT8              *mBlobData;
+STATIC QEMU_FIXED_BARS_HDR mHdr;
+
+/* Pre-parsed per-device index built from the blob at startup. */
+typedef struct {
+  UINT16                VendorId;
+  UINT16                DeviceId;
+  UINT8                 DevFlags;
+  UINT8                 RpBus;    /* primary bus of the root port */
+  UINT8                 NumBars;
+  QEMU_FIXED_BARS_BAR  *Bars;    /* pointer into mBlobData */
+} QFBD_DEVICE;
+
+/*
+ * Per-(VendorId, DeviceId) class. FixedBarsCheckDevice() is called once per
+ * PCI function and once per scan pass. Different VID:DID classes must
+ * advance their counters independently so that one class cannot disturb
+ * the position of another across scan passes.
+ *
+ * Assumptions:
+ *   - QEMU emits blob entries in the same order PciBusDxe discovers devices.
+ *   - For identical VID:DID devices, discovery order is stable across passes.
+ *   - The counter is maintained per VID:DID class, not globally.
+ */
+typedef struct {
+  UINT16    VendorId;
+  UINT16    DeviceId;
+  UINTN     Count;       /* number of devices with this VID:DID in the blob */
+  UINTN     CurrentIdx;  /* next entry to serve; wraps at Count */
+} QFBD_DEVICE_CLASS;
+
+STATIC QFBD_DEVICE        *mDevices;
+STATIC UINTN               mNumDevices;
+STATIC QFBD_DEVICE_CLASS  *mClasses;   /* heap-allocated; mNumDevices entries 
max */
+STATIC UINTN               mNumClasses;
+
+STATIC VOID
+ReserveFixedBarRanges (
+  VOID
+  )
+{
+  UINTN       DevIdx;
+  UINTN       BarIdx;
+  UINT64      Min64;
+  UINT64      Max64;
+  UINT64      Min32;
+  UINT64      Max32;
+  UINT64      Gran;
+  UINT64      Base;
+  UINT64      Size;
+  EFI_STATUS  Status;
+
+  Min64 = MAX_UINT64;
+  Max64 = 0;
+  Min32 = MAX_UINT64;
+  Max32 = 0;
+  Gran  = SIZE_1MB;
+
+  for (DevIdx = 0; DevIdx < mNumDevices; DevIdx++) {
+    QFBD_DEVICE  *Dev = &mDevices[DevIdx];
+
+    if (!(Dev->DevFlags & QEMU_FIXED_BARS_DEV_F_FIXED)) {
+      continue;
+    }
+    for (BarIdx = 0; BarIdx < Dev->NumBars; BarIdx++) {
+      QEMU_FIXED_BARS_BAR  *Bar = &Dev->Bars[BarIdx];
+
+      if (Bar->Flags & QEMU_FIXED_BAR_F_MEM64) {
+        if (Bar->Address < Min64) {
+          Min64 = Bar->Address;
+        }
+        if (Bar->Address + Bar->Size > Max64) {
+          Max64 = Bar->Address + Bar->Size;
+        }
+      } else {
+        if (Bar->Address < Min32) {
+          Min32 = Bar->Address;
+        }
+        if (Bar->Address + Bar->Size > Max32) {
+          Max32 = Bar->Address + Bar->Size;
+        }
+      }
+    }
+  }
+
+  if (Min64 < Max64) {
+    Base   = Min64 & ~(Gran - 1);
+    Size   = ALIGN_VALUE (Max64 - Base, Gran);
+    Status = gDS->AllocateMemorySpace (
+                    EfiGcdAllocateAddress,
+                    EfiGcdMemoryTypeMemoryMappedIo,
+                    0, Size, &Base, gImageHandle, NULL
+                    );
+    DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_INFO,
+            "QFBD: reserve 64-bit 0x%016Lx+0x%016Lx: %r\n",
+            Base, Size, Status));
+  }
+
+  if (Min32 < Max32) {
+    Base   = Min32 & ~(Gran - 1);
+    Size   = ALIGN_VALUE (Max32 - Base, Gran);
+    Status = gDS->AllocateMemorySpace (
+                    EfiGcdAllocateAddress,
+                    EfiGcdMemoryTypeMemoryMappedIo,
+                    0, Size, &Base, gImageHandle, NULL
+                    );
+    DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_INFO,
+            "QFBD: reserve 32-bit 0x%016Lx+0x%016Lx: %r\n",
+            Base, Size, Status));
+  }
+}
+
+/* Walk the blob once, build the mDevices[] index and the mClasses[] table. */
+STATIC VOID
+InitDevices (
+  IN UINTN  BlobSize
+  )
+{
+  UINT8  *Ptr = mBlobData + sizeof (QEMU_FIXED_BARS_HDR);
+  UINT8  *End = mBlobData + BlobSize;
+  UINTN   DevIdx, ClassIdx;
+
+  for (DevIdx = 0; DevIdx < mHdr.NumDevices; DevIdx++) {
+    QEMU_FIXED_BARS_DEVICE  *Dev;
+    UINT8                   *Next;
+
+    if (Ptr + sizeof (QEMU_FIXED_BARS_DEVICE) > End) {
+      DEBUG ((DEBUG_ERROR, "QFBD: blob truncated at device %u\n", 
(UINT32)DevIdx));
+      break;
+    }
+
+    Dev  = (QEMU_FIXED_BARS_DEVICE *)Ptr;
+    Next = Ptr
+         + sizeof (QEMU_FIXED_BARS_DEVICE)
+         + Dev->NumBars * sizeof (QEMU_FIXED_BARS_BAR);
+
+    if (Next > End) {
+      DEBUG ((DEBUG_ERROR, "QFBD: blob truncated at device %u\n", 
(UINT32)DevIdx));
+      break;
+    }
+
+    mDevices[mNumDevices].VendorId  = Dev->VendorId;
+    mDevices[mNumDevices].DeviceId  = Dev->DeviceId;
+    mDevices[mNumDevices].DevFlags  = Dev->DevFlags;
+    mDevices[mNumDevices].RpBus     = Dev->RpBus;
+    mDevices[mNumDevices].NumBars   = Dev->NumBars;
+    mDevices[mNumDevices].Bars      = (QEMU_FIXED_BARS_BAR *)(
+      Ptr + sizeof (QEMU_FIXED_BARS_DEVICE)
+      );
+    mNumDevices++;
+
+    /* Find or create the class entry for this VID:DID. */
+    for (ClassIdx = 0; ClassIdx < mNumClasses; ClassIdx++) {
+      if (mClasses[ClassIdx].VendorId == Dev->VendorId &&
+          mClasses[ClassIdx].DeviceId == Dev->DeviceId)
+      {
+        mClasses[ClassIdx].Count++;
+        break;
+      }
+    }
+    if (ClassIdx == mNumClasses) {
+      mClasses[mNumClasses].VendorId   = Dev->VendorId;
+      mClasses[mNumClasses].DeviceId   = Dev->DeviceId;
+      mClasses[mNumClasses].Count      = 1;
+      mClasses[mNumClasses].CurrentIdx = 0;
+      mNumClasses++;
+    }
+
+    DEBUG ((DEBUG_INFO,
+            "QFBD: device %04x:%04x num_bars=%u\n",
+            Dev->VendorId, Dev->DeviceId, Dev->NumBars));
+
+    Ptr = Next;
+  }
+
+  for (ClassIdx = 0; ClassIdx < mNumClasses; ClassIdx++) {
+    DEBUG ((DEBUG_INFO,
+            "QFBD: class %04x:%04x count=%u\n",
+            mClasses[ClassIdx].VendorId, mClasses[ClassIdx].DeviceId,
+            (UINT32)mClasses[ClassIdx].Count));
+  }
+}
+
+EFI_STATUS
+FixedBarsCheckDevice (
+  IN  UINTN  VendorId,
+  IN  UINTN  DeviceId,
+  OUT VOID   **Descriptors,
+  OUT UINTN  *DescriptorsSize
+  )
+{
+  QFBD_DEVICE_CLASS                  *Class;
+  QFBD_DEVICE                        *Dev;
+  UINTN                               BarIdx, DevIdx, MatchCount, ClassIdx;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Desc;
+
+  *Descriptors     = NULL;
+  *DescriptorsSize = 0;
+
+  if (mNumClasses == 0) {
+    return EFI_SUCCESS;
+  }
+
+  /* Look up the per-VID:DID class. */
+  Class = NULL;
+  for (ClassIdx = 0; ClassIdx < mNumClasses; ClassIdx++) {
+    if (mClasses[ClassIdx].VendorId == (UINT16)VendorId &&
+        mClasses[ClassIdx].DeviceId == (UINT16)DeviceId)
+    {
+      Class = &mClasses[ClassIdx];
+      break;
+    }
+  }
+  if (Class == NULL) {
+    return EFI_SUCCESS;  /* not a fixed-bar device */
+  }
+
+  /* Find the CurrentIdx-th device in mDevices[] matching this VID:DID. */
+  Dev        = NULL;
+  MatchCount = 0;
+  for (DevIdx = 0; DevIdx < mNumDevices; DevIdx++) {
+    if (mDevices[DevIdx].VendorId == (UINT16)VendorId &&
+        mDevices[DevIdx].DeviceId == (UINT16)DeviceId)
+    {
+      if (MatchCount == Class->CurrentIdx) {
+        Dev = &mDevices[DevIdx];
+        break;
+      }
+      MatchCount++;
+    }
+  }
+  if (Dev == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  /* Always advance the counter so ordering stays in sync with the blob. */
+  Class->CurrentIdx++;
+  if (Class->CurrentIdx >= Class->Count) {
+    Class->CurrentIdx = 0;
+  }
+
+  if (!(Dev->DevFlags & QEMU_FIXED_BARS_DEV_F_FIXED)) {
+    return EFI_SUCCESS;
+  }
+
+  Desc = AllocateZeroPool (Dev->NumBars * sizeof (*Desc));
+  if (Desc == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  *Descriptors     = Desc;
+  *DescriptorsSize = Dev->NumBars * sizeof (*Desc);
+
+  for (BarIdx = 0; BarIdx < Dev->NumBars; BarIdx++) {
+    QEMU_FIXED_BARS_BAR  *Bar = &Dev->Bars[BarIdx];
+
+    Desc->Desc                   = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+    Desc->Len                    = (UINT16)(sizeof (*Desc) - 3);
+    Desc->ResType                = ACPI_ADDRESS_SPACE_TYPE_MEM;
+    Desc->GenFlag                = ACPI_ADDR_FLAG_FIXED;
+    Desc->SpecificFlag           = 0;
+    Desc->AddrSpaceGranularity   = (Bar->Flags & QEMU_FIXED_BAR_F_MEM64) ? 64 
: 32;
+    Desc->AddrRangeMin           = Bar->Address;
+    Desc->AddrRangeMax           = Bar->Size - 1;
+    Desc->AddrTranslationOffset  = BarIdx;
+    Desc->AddrLen                = Bar->Size;
+
+    DEBUG ((DEBUG_INFO,
+            "QFBD: %04x:%04x BAR%u -> 0x%016Lx size 0x%016Lx\n",
+            Dev->VendorId, Dev->DeviceId,
+            (UINT32)Bar->Bar, Bar->Address, Bar->Size));
+
+    Desc++;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FixedBarsInit (
+  OUT BOOLEAN  *HasFixedBarsDevices
+  )
+{
+  FIRMWARE_CONFIG_ITEM  FwCfgItem;
+  UINTN                 FwCfgSize;
+  EFI_STATUS            Status;
+
+  *HasFixedBarsDevices = FALSE;
+
+  Status = QemuFwCfgFindFile ("etc/fixed-bars", &FwCfgItem, &FwCfgSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "QFBD: etc/fixed-bars absent, nothing to do\n"));
+    return EFI_SUCCESS;
+  }
+
+  if (FwCfgSize < sizeof (mHdr)) {
+    DEBUG ((DEBUG_ERROR, "QFBD: blob too small (%Lu bytes)\n",
+            (UINT64)FwCfgSize));
+    return EFI_UNSUPPORTED;
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  QemuFwCfgReadBytes (sizeof (mHdr), &mHdr);
+
+  if (mHdr.Version != QEMU_FIXED_BARS_VERSION) {
+    DEBUG ((DEBUG_ERROR,
+            "QFBD: unsupported blob version %u (expected %u)\n",
+            mHdr.Version, QEMU_FIXED_BARS_VERSION));
+    return EFI_UNSUPPORTED;
+  }
+
+  if (mHdr.NumDevices == 0) {
+    DEBUG ((DEBUG_INFO, "QFBD: zero devices, nothing to do\n"));
+    return EFI_SUCCESS;
+  }
+
+  /* Read the full blob into a persistent buffer; device entries point into 
it. */
+  mBlobData = AllocatePool (FwCfgSize);
+  if (mBlobData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  QemuFwCfgReadBytes (FwCfgSize, mBlobData);
+  CopyMem (&mHdr, mBlobData, sizeof (mHdr));
+
+  mDevices = AllocateZeroPool (mHdr.NumDevices * sizeof (QFBD_DEVICE));
+  if (mDevices == NULL) {
+    FreePool (mBlobData);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  /* Worst case: every device has a unique VID:DID — allocate mNumDevices 
slots. */
+  mClasses = AllocateZeroPool (mHdr.NumDevices * sizeof (QFBD_DEVICE_CLASS));
+  if (mClasses == NULL) {
+    FreePool (mDevices);
+    FreePool (mBlobData);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DEBUG ((DEBUG_INFO, "QFBD: %u device(s)\n", mHdr.NumDevices));
+
+  mNumDevices = 0;
+  mNumClasses = 0;
+  InitDevices (FwCfgSize);
+  ReserveFixedBarRanges ();
+
+  *HasFixedBarsDevices = TRUE;
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.h 
b/OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.h
new file mode 100644
index 0000000000..837399986e
--- /dev/null
+++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/FixedBars.h
@@ -0,0 +1,63 @@
+/** @file
+  Public interface for FixedBars.c -- fixed PCI BAR placement using
+  metadata provided by QEMU through the "etc/fixed-bars" fw_cfg blob.
+
+  Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef FIXED_BARS_H_
+#define FIXED_BARS_H_
+
+#include <Uefi.h>
+
+/**
+  Read and parse the "etc/fixed-bars" fw_cfg blob (if present), and reserve
+  the fixed BAR address ranges it describes in the GCD memory space map.
+
+  Must be called once, from the owning driver's entry point, before that
+  driver installs EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL.
+
+  @param[out] HasFixedBarsDevices  TRUE if the blob was present and
+                                    described at least one fixed-BAR device;
+                                    FALSE otherwise (nothing else in this
+                                    file has any effect in that case).
+
+  @retval EFI_SUCCESS           Blob absent, empty, or successfully parsed.
+  @retval EFI_UNSUPPORTED       Blob present but malformed/wrong version.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failure.
+**/
+EFI_STATUS
+FixedBarsInit (
+  OUT BOOLEAN  *HasFixedBarsDevices
+  );
+
+/**
+  Return the fixed-BAR ACPI address-space descriptors for one PCI function,
+  if it has a matching entry in the "etc/fixed-bars" blob. Returns
+  *Descriptors == NULL, with *DescriptorsSize == 0, when the device is not
+  a fixed-BAR device.
+
+  @param[in]  VendorId        Device's PCI Vendor ID.
+  @param[in]  DeviceId        Device's PCI Device ID.
+  @param[out] Descriptors     Heap-allocated array of
+                              EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR, one per
+                              fixed BAR; caller takes ownership. NULL if no
+                              match.
+  @param[out] DescriptorsSize Size in bytes of *Descriptors.
+
+  @retval EFI_SUCCESS           Always, on non-allocation-failure paths
+                                (matches EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_
+                                PROTOCOL.CheckDevice()'s own contract).
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failure.
+**/
+EFI_STATUS
+FixedBarsCheckDevice (
+  IN  UINTN  VendorId,
+  IN  UINTN  DeviceId,
+  OUT VOID   **Descriptors,
+  OUT UINTN  *DescriptorsSize
+  );
+
+#endif
diff --git 
a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c 
b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
index ebf73d97db..5e40936f81 100644
--- a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
+++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
@@ -22,6 +22,8 @@
 
 #include <Protocol/IncompatiblePciDeviceSupport.h>
 
+#include "FixedBars.h"
+
 //
 // The protocol interface this driver produces.
 //
@@ -165,6 +167,57 @@ STATIC CONST EFI_ACPI_END_TAG_DESCRIPTOR  mEndDesc = {
 
   @retval EFI_SUCCESS   The function always returns EFI_SUCCESS.
 **/
+/**
+  This function copies Buffer into Configuration, then appends the
+  confidential-VM option ROM descriptor if applicable, and finally
+  appends the terminating End Tag.
+
+  @param[in]  Buffer        Descriptor bytes.
+  @param[in]  BufferSize    Size in bytes of Buffer.
+  @param[out] Configuration As in CheckDevice().
+
+  @retval EFI_SUCCESS           Configuration built and returned.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failure.
+**/
+STATIC
+EFI_STATUS
+BuildConfiguration (
+  IN  CONST VOID  *Buffer,
+  IN  UINTN       BufferSize,
+  OUT VOID        **Configuration
+  )
+{
+  UINTN  Length;
+  UINT8  *Ptr;
+
+  Length = BufferSize + sizeof mEndDesc;
+
+  //
+  // In Td guest OptionRom is not allowed.
+  //
+  if (CcProbe ()) {
+    Length += sizeof mOptionRomConfiguration;
+  }
+
+  *Configuration = AllocateZeroPool (Length);
+  if (*Configuration == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Ptr = (UINT8 *)(UINTN)*Configuration;
+  CopyMem (Ptr, Buffer, BufferSize);
+  Length = BufferSize;
+
+  if (CcProbe ()) {
+    CopyMem (Ptr + Length, &mOptionRomConfiguration, sizeof 
mOptionRomConfiguration);
+    Length += sizeof mOptionRomConfiguration;
+  }
+
+  CopyMem (Ptr + Length, &mEndDesc, sizeof mEndDesc);
+
+  return EFI_SUCCESS;
+}
+
 STATIC
 EFI_STATUS
 EFIAPI
@@ -178,8 +231,25 @@ CheckDevice (
   OUT VOID                                          **Configuration
   )
 {
-  UINTN  Length;
-  UINT8  *Ptr;
+  EFI_STATUS  Status;
+  VOID        *FixedBarsDescs;
+  UINTN       FixedBarsDescsSize;
+
+  //
+  // Dispatch hook: if this device has an entry in the "etc/fixed-bars"
+  // fw_cfg blob, use that instead of the hardcoded 64-bit-MMIO-preference
+  // descriptor below.
+  //
+  Status = FixedBarsCheckDevice (VendorId, DeviceId, &FixedBarsDescs, 
&FixedBarsDescsSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (FixedBarsDescs != NULL) {
+    Status = BuildConfiguration (FixedBarsDescs, FixedBarsDescsSize, 
Configuration);
+    FreePool (FixedBarsDescs);
+    return Status;
+  }
 
   //
   // Unlike the general description of this protocol member suggests, there is
@@ -200,18 +270,8 @@ CheckDevice (
   // the edk2 PCI Bus UEFI_DRIVER actually handles error codes; see the
   // UpdatePciInfo() function.
   //
-  Length = sizeof mMmio64Configuration + sizeof mEndDesc;
-
-  //
-  // In Td guest OptionRom is not allowed.
-  //
-  if (CcProbe ()) {
-    Length += sizeof mOptionRomConfiguration;
-  }
-
-  *Configuration = AllocateZeroPool (Length);
-
-  if (*Configuration == NULL) {
+  Status = BuildConfiguration (&mMmio64Configuration, sizeof 
mMmio64Configuration, Configuration);
+  if (EFI_ERROR (Status)) {
     DEBUG ((
       DEBUG_WARN,
       "%a: 64-bit MMIO BARs may be degraded for PCI 0x%04x:0x%04x (rev %d)\n",
@@ -220,21 +280,9 @@ CheckDevice (
       (UINT32)DeviceId,
       (UINT8)RevisionId
       ));
-    return EFI_OUT_OF_RESOURCES;
   }
 
-  Ptr = (UINT8 *)(UINTN)*Configuration;
-  CopyMem (Ptr, &mMmio64Configuration, sizeof mMmio64Configuration);
-  Length = sizeof mMmio64Configuration;
-
-  if (CcProbe ()) {
-    CopyMem (Ptr + Length, &mOptionRomConfiguration, sizeof 
mOptionRomConfiguration);
-    Length += sizeof mOptionRomConfiguration;
-  }
-
-  CopyMem (Ptr + Length, &mEndDesc, sizeof mEndDesc);
-
-  return EFI_SUCCESS;
+  return Status;
 }
 
 /**
@@ -257,12 +305,18 @@ DriverInitialize (
   )
 {
   EFI_STATUS  Status;
+  BOOLEAN     HasFixedBarsDevices;
+
+  Status = FixedBarsInit (&HasFixedBarsDevices);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
 
   //
-  // If there is no 64-bit PCI MMIO aperture, then 64-bit MMIO BARs have to be
-  // allocated under 4 GB unconditionally.
+  // If there is no 64-bit PCI MMIO aperture and no fixed-bars devices to
+  // place, do not install the protocol.
   //
-  if (PcdGet64 (PcdPciMmio64Size) == 0) {
+  if ((PcdGet64 (PcdPciMmio64Size) == 0) && !HasFixedBarsDevices) {
     return EFI_UNSUPPORTED;
   }
 
diff --git 
a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf 
b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
index b92662d0bb..b51f51c25e 100644
--- a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
+++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
@@ -18,21 +18,27 @@
 
 [Sources]
   IncompatiblePciDeviceSupport.c
+  FixedBars.c
+  FixedBars.h
 
 [Packages]
   MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
   OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
+  BaseMemoryLib
   CcProbeLib
   DebugLib
+  DxeServicesTableLib
   MemoryAllocationLib
   PcdLib
+  QemuFwCfgLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
 
 [Protocols]
-  gEfiIncompatiblePciDeviceSupportProtocolGuid ## SOMETIMES_PRODUCES
+  gEfiIncompatiblePciDeviceSupportProtocolGuid       ## SOMETIMES_PRODUCES
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size                ## CONSUMES
-- 
2.34.1


Reply via email to