\r
if (!mXen) {\r
UINT32 TopOfLowRam;\r
+ UINT64 PciExBarBase;\r
UINT32 PciBase;\r
UINT32 PciSize;\r
\r
TopOfLowRam = GetSystemMemorySizeBelow4gb ();\r
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
//\r
- // On Q35 machine types that QEMU intends to support in the long term,\r
- // QEMU never lets the RAM below 4 GB exceed 2 GB.\r
+ // The MMCONFIG area is expected to fall between the top of low RAM and\r
+ // the base of the 32-bit PCI host aperture.\r
//\r
- PciBase = BASE_2GB;\r
- ASSERT (TopOfLowRam <= PciBase);\r
+ PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);\r
+ ASSERT (TopOfLowRam <= PciExBarBase);\r
+ ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);\r
+ PciBase = (UINT32)(PciExBarBase + SIZE_256MB);\r
} else {\r
PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;\r
}\r
AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);\r
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);\r
+ //\r
+ // Note: there should be an\r
+ //\r
+ // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);\r
+ //\r
+ // call below, just like the one above for RCBA. However, Linux insists\r
+ // that the MMCONFIG area be marked in the E820 or UEFI memory map as\r
+ // "reserved memory" -- Linux does not content itself with a simple gap\r
+ // in the memory map wherever the MCFG ACPI table points to.\r
+ //\r
+ // This appears to be a safety measure. The PCI Firmware Specification\r
+ // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can\r
+ // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory\r
+ // [...]". (Emphasis added here.)\r
+ //\r
+ // Normally we add memory resource descriptor HOBs in\r
+ // QemuInitializeRam(), and pre-allocate from those with memory\r
+ // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area\r
+ // is most definitely not RAM; so, as an exception, cover it with\r
+ // uncacheable reserved memory right here.\r
+ //\r
+ AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);\r
+ BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,\r
+ EfiReservedMemoryType);\r
}\r
AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);\r
}\r
UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);\r
}\r
\r
+VOID\r
+PciExBarInitialization (\r
+ VOID\r
+ )\r
+{\r
+ union {\r
+ UINT64 Uint64;\r
+ UINT32 Uint32[2];\r
+ } PciExBarBase;\r
+\r
+ //\r
+ // We only support the 256MB size for the MMCONFIG area:\r
+ // 256 buses * 32 devices * 8 functions * 4096 bytes config space.\r
+ //\r
+ // The masks used below enforce the Q35 requirements that the MMCONFIG area\r
+ // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.\r
+ //\r
+ // Note that (b) also ensures that the minimum address width we have\r
+ // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice\r
+ // for DXE's page tables to cover the MMCONFIG area.\r
+ //\r
+ PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);\r
+ ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);\r
+ ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);\r
+\r
+ //\r
+ // Clear the PCIEXBAREN bit first, before programming the high register.\r
+ //\r
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);\r
+\r
+ //\r
+ // Program the high register. Then program the low register, setting the\r
+ // MMCONFIG area size and enabling decoding at once.\r
+ //\r
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);\r
+ PciWrite32 (\r
+ DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),\r
+ PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN\r
+ );\r
+}\r
+\r
VOID\r
MiscInitialization (\r
VOID\r
POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),\r
ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN\r
);\r
+\r
+ //\r
+ // Set PCI Express Register Range Base Address\r
+ //\r
+ PciExBarInitialization ();\r
}\r
}\r
\r