summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OvmfPkg/OvmfPkgIa32.dsc8
-rw-r--r--OvmfPkg/OvmfPkgIa32X64.dsc8
-rw-r--r--OvmfPkg/OvmfPkgX64.dsc8
-rw-r--r--OvmfPkg/PlatformPei/Platform.c81
-rw-r--r--OvmfPkg/PlatformPei/PlatformPei.inf3
5 files changed, 104 insertions, 4 deletions
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 9b603f001f..aae1972950 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -395,6 +395,14 @@
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
!endif
+ # This PCD is used to set the base address of the PCI express hierarchy. It
+ # is only consulted when OVMF runs on Q35. In that case it is programmed into
+ # the PCIEXBAR register.
+ #
+ # On Q35 machine types that QEMU intends to support in the long term, QEMU
+ # never lets the RAM below 4 GB exceed 2 GB.
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0x80000000
+
!ifdef $(SOURCE_DEBUG_ENABLE)
gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2
!endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 1d68eb95d6..0422dda09f 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -400,6 +400,14 @@
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
!endif
+ # This PCD is used to set the base address of the PCI express hierarchy. It
+ # is only consulted when OVMF runs on Q35. In that case it is programmed into
+ # the PCIEXBAR register.
+ #
+ # On Q35 machine types that QEMU intends to support in the long term, QEMU
+ # never lets the RAM below 4 GB exceed 2 GB.
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0x80000000
+
!ifdef $(SOURCE_DEBUG_ENABLE)
gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2
!endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index b971ee8bb5..18517e3376 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -400,6 +400,14 @@
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
!endif
+ # This PCD is used to set the base address of the PCI express hierarchy. It
+ # is only consulted when OVMF runs on Q35. In that case it is programmed into
+ # the PCIEXBAR register.
+ #
+ # On Q35 machine types that QEMU intends to support in the long term, QEMU
+ # never lets the RAM below 4 GB exceed 2 GB.
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0x80000000
+
!ifdef $(SOURCE_DEBUG_ENABLE)
gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2
!endif
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 8e4da41001..0fc227803a 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -212,17 +212,20 @@ MemMapInitialization (
if (!mXen) {
UINT32 TopOfLowRam;
+ UINT64 PciExBarBase;
UINT32 PciBase;
UINT32 PciSize;
TopOfLowRam = GetSystemMemorySizeBelow4gb ();
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
//
- // On Q35 machine types that QEMU intends to support in the long term,
- // QEMU never lets the RAM below 4 GB exceed 2 GB.
+ // The MMCONFIG area is expected to fall between the top of low RAM and
+ // the base of the 32-bit PCI host aperture.
//
- PciBase = BASE_2GB;
- ASSERT (TopOfLowRam <= PciBase);
+ PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT (TopOfLowRam <= PciExBarBase);
+ ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
+ PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
} else {
PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
}
@@ -248,6 +251,30 @@ MemMapInitialization (
AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+ //
+ // Note: there should be an
+ //
+ // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+ //
+ // call below, just like the one above for RCBA. However, Linux insists
+ // that the MMCONFIG area be marked in the E820 or UEFI memory map as
+ // "reserved memory" -- Linux does not content itself with a simple gap
+ // in the memory map wherever the MCFG ACPI table points to.
+ //
+ // This appears to be a safety measure. The PCI Firmware Specification
+ // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
+ // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
+ // [...]". (Emphasis added here.)
+ //
+ // Normally we add memory resource descriptor HOBs in
+ // QemuInitializeRam(), and pre-allocate from those with memory
+ // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
+ // is most definitely not RAM; so, as an exception, cover it with
+ // uncacheable reserved memory right here.
+ //
+ AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+ BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,
+ EfiReservedMemoryType);
}
AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);
}
@@ -317,6 +344,47 @@ NoexecDxeInitialization (
}
VOID
+PciExBarInitialization (
+ VOID
+ )
+{
+ union {
+ UINT64 Uint64;
+ UINT32 Uint32[2];
+ } PciExBarBase;
+
+ //
+ // We only support the 256MB size for the MMCONFIG area:
+ // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
+ //
+ // The masks used below enforce the Q35 requirements that the MMCONFIG area
+ // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
+ //
+ // Note that (b) also ensures that the minimum address width we have
+ // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
+ // for DXE's page tables to cover the MMCONFIG area.
+ //
+ PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
+ ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
+
+ //
+ // Clear the PCIEXBAREN bit first, before programming the high register.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
+
+ //
+ // Program the high register. Then program the low register, setting the
+ // MMCONFIG area size and enabling decoding at once.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
+ PciWrite32 (
+ DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
+ PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
+ );
+}
+
+VOID
MiscInitialization (
VOID
)
@@ -393,6 +461,11 @@ MiscInitialization (
POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
);
+
+ //
+ // Set PCI Express Register Range Base Address
+ //
+ PciExBarInitialization ();
}
}
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 8480839efc..6dc5ff079f 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -94,6 +94,9 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+
[FeaturePcd]
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire