Linux's is_mmconf_reserved() rejects an MMCONFIG range that no
Reserved entry in the UEFI memory map covers, so on some platforms the
OS never gets extended PCIe config space. A plain
EFI_RESOURCE_MEMORY_MAPPED_IO resource only reaches CoreGetMemoryMap()
when it also carries EFI_MEMORY_RUNTIME, which MCFG does not.

Add PcdPublishMcfgAsReservedMemory, a new PCD that publishes the range
as EFI_RESOURCE_MEMORY_RESERVED instead of MEMORY_MAPPED_IO. It
defaults to FALSE, so coreboot and Slim Bootloader platforms keep
today's behaviour. A following commit sets it TRUE under
CHAINLOAD_DEFAULTS and maps MEMORY_RESERVED in the AArch64 entry.

The MCFG-as-Reserved descriptor advertises UNCACHEABLE only, not the
full UC|WC|WT|WB mask MemInfoCallbackMmio() otherwise emits, so a HOB
consumer building page tables does not map config space write-back.

Two more fixes ride along, neither of them behind the new PCD:

  1) Publish the ECAM resource HOB directly from ACPI MCFG when the
     bootloader's memory map does not cover the range. On such
     platforms MemInfoCallbackMmio() never fires for the ECAM base and
     PciHostBridgeDxe faults on its first config-space access because
     the range is absent from the payload page tables.

  2) Walk all MCFG allocation entries when computing PcieBaseSize. A
     platform with multiple root bridges on segment 0 may split the
     bus range across entries with a shared BaseAddress; reading only
     entry [0] undersizes PcdPciExpressBaseSize and BasePciExpressLib
     short-circuits every config read on a higher bus to 0xFFFF.

Cc: Benjamin Doron <[email protected]>
Cc: Gua Guo <[email protected]>
Cc: Guo Dong <[email protected]>
Cc: James Lu <[email protected]>
Cc: Sean Rhodes <[email protected]>
Cc: Shuo Liu <[email protected]>
Assisted-by: claude-opus-5
Signed-off-by: Alexander Graf <[email protected]>
---
 UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c   | 51 ++++++++++-
 .../UefiPayloadEntry/UefiPayloadEntry.c       | 85 ++++++++++++++++++-
 .../UefiPayloadEntry/UefiPayloadEntry.inf     |  4 +-
 UefiPayloadPkg/UefiPayloadPkg.dec             | 20 +++++
 4 files changed, 154 insertions(+), 6 deletions(-)

diff --git a/UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c 
b/UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c
index 47ec8c773b..74436b4cc5 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c
+++ b/UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c
@@ -26,6 +26,10 @@ ParseAcpiInfo (
   )

 {

   EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE                                    
          *Fadt;

+  UINTN                                                                        
          Index;

+  UINTN                                                                        
          MmCfgCount;

+  UINT8                                                                        
          MinStart;

+  UINT8                                                                        
          MaxEnd;

   EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER               
          *MmCfgHdr;

   
EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE
  *MmCfgBase;

 

@@ -61,10 +65,53 @@ ParseAcpiInfo (
     AcpiBoardInfo->PmGpeEnBase = 0;

   }

 

-  if (MmCfgHdr != NULL) {

+  //

+  // A table shorter than one allocation structure carries no usable

+  // allocation: report no MCFG rather than computing a count from an

+  // underflowing length subtraction and walking off the end of it.

+  //

+  if ((MmCfgHdr != NULL) &&

+      (MmCfgHdr->Header.Length >= sizeof (*MmCfgHdr) + sizeof (*MmCfgBase)))

+  {

     MmCfgBase                      = 
(EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE
 *)((UINT8 *)MmCfgHdr + sizeof (*MmCfgHdr));

     AcpiBoardInfo->PcieBaseAddress = MmCfgBase->BaseAddress;

-    AcpiBoardInfo->PcieBaseSize    = (MmCfgBase->EndBusNumber + 1 - 
MmCfgBase->StartBusNumber) * 4096 * 32 * 8;

+

+    //

+    // Some platforms describe multiple root bridges on segment 0 with

+    // separate MCFG allocation entries that share the same BaseAddress

+    // but split the bus range.  PcieBaseSize gates every ECAM read via

+    // PcdPciExpressBaseSize, so span the lowest StartBusNumber to the

+    // highest EndBusNumber across all entries with the same base rather

+    // than only the first entry.  The window starts at StartBusNumber,

+    // so that term has to stay in the size or config accesses past the

+    // end of the window are permitted on any platform whose allocation

+    // does not begin at bus 0.

+    //

+    MmCfgCount = (MmCfgHdr->Header.Length - sizeof (*MmCfgHdr)) / sizeof 
(*MmCfgBase);

+    MinStart   = MmCfgBase->StartBusNumber;

+    MaxEnd     = MmCfgBase->EndBusNumber;

+    for (Index = 1; Index < MmCfgCount; Index++) {

+      if (MmCfgBase[Index].BaseAddress != MmCfgBase->BaseAddress) {

+        continue;

+      }

+

+      if (MmCfgBase[Index].StartBusNumber < MinStart) {

+        MinStart = MmCfgBase[Index].StartBusNumber;

+      }

+

+      if (MmCfgBase[Index].EndBusNumber > MaxEnd) {

+        MaxEnd = MmCfgBase[Index].EndBusNumber;

+      }

+    }

+

+    if (MaxEnd >= MinStart) {

+      AcpiBoardInfo->PcieBaseSize = ((UINT64)MaxEnd + 1 - MinStart) * 4096 * 
32 * 8;

+    } else {

+      //

+      // Reversed bus range: no usable window.

+      //

+      AcpiBoardInfo->PcieBaseSize = 0;

+    }

   } else {

     AcpiBoardInfo->PcieBaseAddress = 0;

     AcpiBoardInfo->PcieBaseSize    = 0;

diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c 
b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
index 55e692554c..be0af7be17 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
@@ -11,7 +11,8 @@
 #include <Library/BaseArchLibSupport.h>

 #include "UefiPayloadEntry.h"

 

-STATIC UINT32  mTopOfLowerUsableDram = 0;

+STATIC UINT32   mTopOfLowerUsableDram = 0;

+STATIC BOOLEAN  mMcfgResourceHobBuilt = FALSE;

 

 EFI_MEMORY_TYPE_INFORMATION  mDefaultMemoryTypeInformation[] = {

   { EfiACPIReclaimMemory,   FixedPcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory)  
 },

@@ -52,6 +53,20 @@ MemInfoCallbackMmio (
     return EFI_INVALID_PARAMETER;

   }

 

+  //

+  // Note any entry that overlaps the ECAM window, whether or not it

+  // starts at exactly its base.  BuildHobFromBl() publishes the window

+  // from ACPI MCFG only when nothing in the bootloader's map covered it,

+  // because CoreInitializeGcdServices() does not tolerate overlapping

+  // resource descriptor HOBs.

+  //

+  if ((AcpiBoardInfo->PcieBaseSize != 0) &&

+      (MemoryMapEntry->Base < (AcpiBoardInfo->PcieBaseAddress + 
AcpiBoardInfo->PcieBaseSize)) &&

+      ((MemoryMapEntry->Base + MemoryMapEntry->Size) > 
AcpiBoardInfo->PcieBaseAddress))

+  {

+    mMcfgResourceHobBuilt = TRUE;

+  }

+

   //

   // Skip types already handled in MemInfoCallback

   //

@@ -61,9 +76,39 @@ MemInfoCallbackMmio (
 

   if (MemoryMapEntry->Base == AcpiBoardInfo->PcieBaseAddress) {

     //

-    // MMCONF is always MMIO

+    // MMCONF is always MMIO. Optionally surface it as Reserved instead

+    // so that Linux's is_mmconf_reserved() check accepts it and

+    // MMCONFIG can be used for extended PCIe config space. A plain

+    // MMIO resource is only surfaced by CoreGetMemoryMap() when it

+    // also carries EFI_MEMORY_RUNTIME, which this range does not.

     //

-    Type = EFI_RESOURCE_MEMORY_MAPPED_IO;

+    if (FeaturePcdGet (PcdPublishMcfgAsReservedMemory)) {

+      //

+      // Reserved so Linux accepts it, but it is still device memory:

+      // advertise UNCACHEABLE only so that a consumer building page

+      // tables from these HOBs does not map config space write-back.

+      //

+      Type = EFI_RESOURCE_MEMORY_RESERVED;

+      BuildResourceDescriptorHob (

+        Type,

+        EFI_RESOURCE_ATTRIBUTE_PRESENT |

+        EFI_RESOURCE_ATTRIBUTE_INITIALIZED |

+        EFI_RESOURCE_ATTRIBUTE_TESTED |

+        EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE,

+        (EFI_PHYSICAL_ADDRESS)MemoryMapEntry->Base,

+        MemoryMapEntry->Size

+        );

+      DEBUG ((

+        DEBUG_INFO,

+        "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x (MMCONF, 
UC-only)\n",

+        MemoryMapEntry->Base,

+        MemoryMapEntry->Size,

+        Type

+        ));

+      return EFI_SUCCESS;

+    } else {

+      Type = EFI_RESOURCE_MEMORY_MAPPED_IO;

+    }

   } else if (MemoryMapEntry->Base < mTopOfLowerUsableDram) {

     //

     // It's in DRAM and thus must be reserved

@@ -463,6 +508,40 @@ BuildHobFromBl (
     return Status;

   }

 

+  //

+  // The bootloader's memory map may not cover the ECAM range at all,

+  // in which case MemInfoCallbackMmio() never fires for it.  Publish

+  // the range parsed from ACPI MCFG so that it is present in the GCD

+  // memory map (and, on AArch64, in the payload page tables) before

+  // PciHostBridgeDxe touches config space.

+  //

+  // Gated on the same PCD as the Reserved publication above: a platform

+  // that leaves the PCD at its default keeps the memory map it always

+  // had, and one that describes the window inside a larger range does

+  // not get a second, overlapping descriptor for it.

+  //

+  if (FeaturePcdGet (PcdPublishMcfgAsReservedMemory) &&

+      (AcpiBoardInfo->PcieBaseAddress != 0) &&

+      (AcpiBoardInfo->PcieBaseSize != 0) &&

+      !mMcfgResourceHobBuilt)

+  {

+    BuildResourceDescriptorHob (

+      EFI_RESOURCE_MEMORY_RESERVED,

+      EFI_RESOURCE_ATTRIBUTE_PRESENT |

+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |

+      EFI_RESOURCE_ATTRIBUTE_TESTED |

+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE,

+      (EFI_PHYSICAL_ADDRESS)AcpiBoardInfo->PcieBaseAddress,

+      AcpiBoardInfo->PcieBaseSize

+      );

+    DEBUG ((

+      DEBUG_INFO,

+      "buildhob: base = 0x%lx, size = 0x%lx (MMCONF from ACPI MCFG)\n",

+      AcpiBoardInfo->PcieBaseAddress,

+      AcpiBoardInfo->PcieBaseSize

+      ));

+  }

+

   //

   // Parse the misc info provided by bootloader

   //

diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf 
b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
index 656cef2218..91aa8e3f5d 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
@@ -75,13 +75,15 @@
   gEfiFirmwareInfoHobGuid

   gEfiSmmStoreInfoHobGuid

 

+[FeaturePcd]

+  gUefiPayloadPkgTokenSpaceGuid.PcdPublishMcfgAsReservedMemory  ## CONSUMES

+

 [FeaturePcd.IA32]

   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ## CONSUMES

 

 [FeaturePcd.X64]

   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables       ## CONSUMES

 

-

 [Pcd.IA32,Pcd.X64,Pcd.AARCH64]

   gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable                      ## 
SOMETIMES_CONSUMES

   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask    ## 
CONSUMES

diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec 
b/UefiPayloadPkg/UefiPayloadPkg.dec
index 63ccdb06ea..3c6352e0c6 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -118,3 +118,23 @@ 
gUefiPayloadPkgTokenSpaceGuid.PcdUseUniversalPayloadSerialPort|TRUE|BOOLEAN|0x00
 

 ## Indicates whether allows PCI Root Bridge to allocate DMA memory resource 
above 4G

 
gUefiPayloadPkgTokenSpaceGuid.PcdPciAllocateMemoryAbove4GB|FALSE|BOOLEAN|0x0000002E

+

+[PcdsFeatureFlag]

+## Publish the MCFG ECAM window as EFI_RESOURCE_MEMORY_RESERVED rather

+#  than EFI_RESOURCE_MEMORY_MAPPED_IO, so that it appears in the UEFI

+#  memory map as a Reserved entry.

+#

+#  Linux only uses MMCONFIG for extended PCIe configuration space if the

+#  window passes its is_mmconf_reserved() check, which requires the range

+#  to be covered by a Reserved entry in the firmware-provided memory map.

+#  A plain MMIO resource does not qualify: CoreGetMemoryMap() reports an

+#  MMIO range only when it also carries EFI_MEMORY_RUNTIME, which the ECAM

+#  window does not. The window is still device memory, so it is published

+#  advertising UNCACHEABLE only, and a consumer that builds page tables

+#  from these HOBs must not map configuration space write-back.

+#

+#  Declared as a feature flag rather than alongside the package's other

+#  boolean knobs in [PcdsFixedAtBuild, PcdsPatchableInModule] so that the

+#  publication code is eliminated outright on platforms that leave it off.

+# @Prompt Publish the MCFG ECAM window as Reserved memory.

+gUefiPayloadPkgTokenSpaceGuid.PcdPublishMcfgAsReservedMemory|FALSE|BOOLEAN|0x0000002F

-- 
2.47.3



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#122091): https://edk2.groups.io/g/devel/message/122091
Mute This Topic: https://groups.io/mt/120797244/21656
Group Owner: [email protected]
Unsubscribe: https://edk2.groups.io/g/devel/unsub [[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to