X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FPlatformPei%2FPlatform.c;h=3e9fda7c7ab019c11fe4b32b5ca75d7a33a88196;hb=3e1d93c32efc7d716baeaa0d5d0ef96528141060;hp=7d0941209f252bb5db0c1e0341081f567f1cf9a5;hpb=03845e90cc432cc59da44aa9fc3bd7b18288c201;p=mirror_edk2.git
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 7d0941209f..3e9fda7c7a 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -1,7 +1,7 @@
/**@file
Platform PEI driver
- Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
Copyright (c) 2011, Andrei Warkentin
This program and the accompanying materials
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -68,6 +69,7 @@ EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
BOOLEAN mS3Supported = FALSE;
+UINT32 mMaxCpuCount;
VOID
AddIoMemoryBaseSizeHob (
@@ -151,40 +153,18 @@ AddMemoryRangeHob (
}
-VOID
-AddUntestedMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_SYSTEM_MEMORY,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,
- MemoryBase,
- MemorySize
- );
-}
-
-
-VOID
-AddUntestedMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- )
-{
- AddUntestedMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
-}
-
VOID
MemMapInitialization (
VOID
)
{
+ UINT64 PciIoBase;
+ UINT64 PciIoSize;
+ RETURN_STATUS PcdStatus;
+
+ PciIoBase = 0xC000;
+ PciIoSize = 0x4000;
+
//
// Create Memory Type Information HOB
//
@@ -194,17 +174,6 @@ MemMapInitialization (
sizeof(mDefaultMemoryTypeInformation)
);
- //
- // Add PCI IO Port space available for PCI resource allocations.
- //
- BuildResourceDescriptorHob (
- EFI_RESOURCE_IO,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
- PcdGet64 (PcdPciIoBase),
- PcdGet64 (PcdPciIoSize)
- );
-
//
// Video memory + Legacy BIOS region
//
@@ -212,18 +181,21 @@ MemMapInitialization (
if (!mXen) {
UINT32 TopOfLowRam;
+ UINT64 PciExBarBase;
UINT32 PciBase;
UINT32 PciSize;
TopOfLowRam = GetSystemMemorySizeBelow4gb ();
+ PciExBarBase = 0;
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
//
- // A 3GB base will always fall into Q35's 32-bit PCI host aperture,
- // regardless of the Q35 MMCONFIG BAR. Correspondingly, QEMU never lets
- // the RAM below 4 GB exceed it.
+ // 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 + BASE_1GB;
- 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;
}
@@ -243,15 +215,67 @@ MemMapInitialization (
//
PciSize = 0xFC000000 - PciBase;
AddIoMemoryBaseSizeHob (PciBase, PciSize);
- PcdSet64 (PcdPciMmio32Base, PciBase);
- PcdSet64 (PcdPciMmio32Size, PciSize);
+ PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
+ ASSERT_RETURN_ERROR (PcdStatus);
+
AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
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);
+
+ //
+ // On Q35, the IO Port space is available for PCI resource allocations from
+ // 0x6000 up.
+ //
+ if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ PciIoBase = 0x6000;
+ PciIoSize = 0xA000;
+ ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
+ }
}
+
+ //
+ // Add PCI IO Port space available for PCI resource allocations.
+ //
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+ PciIoBase,
+ PciIoSize
+ );
+ PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
+ ASSERT_RETURN_ERROR (PcdStatus);
}
EFI_STATUS
@@ -300,11 +324,13 @@ GetNamedFwCfgBoolean (
#define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName) \
do { \
- BOOLEAN Setting; \
+ BOOLEAN Setting; \
+ RETURN_STATUS PcdStatus; \
\
if (!EFI_ERROR (GetNamedFwCfgBoolean ( \
"opt/ovmf/" #TokenName, &Setting))) { \
- PcdSetBool (TokenName, Setting); \
+ PcdStatus = PcdSetBoolS (TokenName, Setting); \
+ ASSERT_RETURN_ERROR (PcdStatus); \
} \
} while (0)
@@ -317,15 +343,59 @@ NoexecDxeInitialization (
UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);
}
+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
)
{
- UINTN PmCmd;
- UINTN Pmba;
- UINTN AcpiCtlReg;
- UINT8 AcpiEnBit;
+ UINTN PmCmd;
+ UINTN Pmba;
+ UINT32 PmbaAndVal;
+ UINT32 PmbaOrVal;
+ UINTN AcpiCtlReg;
+ UINT8 AcpiEnBit;
+ RETURN_STATUS PcdStatus;
//
// Disable A20 Mask
@@ -346,12 +416,16 @@ MiscInitialization (
case INTEL_82441_DEVICE_ID:
PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+ PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
+ PmbaOrVal = PIIX4_PMBA_VALUE;
AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
break;
case INTEL_Q35_MCH_DEVICE_ID:
PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
+ PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
+ PmbaOrVal = ICH9_PMBASE_VALUE;
AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
break;
@@ -361,7 +435,8 @@ MiscInitialization (
ASSERT (FALSE);
return;
}
- PcdSet16 (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
+ PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
+ ASSERT_RETURN_ERROR (PcdStatus);
//
// If the appropriate IOspace enable bit is set, assume the ACPI PMBA
@@ -373,7 +448,7 @@ MiscInitialization (
// The PEI phase should be exited with fully accessibe ACPI PM IO space:
// 1. set PMBA
//
- PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress));
+ PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
//
// 2. set PCICMD/IOSE
@@ -394,6 +469,11 @@ MiscInitialization (
POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
);
+
+ //
+ // Set PCI Express Register Range Base Address
+ //
+ PciExBarInitialization ();
}
}
@@ -423,6 +503,7 @@ ReserveEmuVariableNvStore (
)
{
EFI_PHYSICAL_ADDRESS VariableStore;
+ RETURN_STATUS PcdStatus;
//
// Allocate storage for NV variables early on so it will be
@@ -432,16 +513,16 @@ ReserveEmuVariableNvStore (
//
VariableStore =
(EFI_PHYSICAL_ADDRESS)(UINTN)
- AllocateAlignedRuntimePages (
- EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)),
- PcdGet32 (PcdFlashNvStorageFtwSpareSize)
+ AllocateRuntimePages (
+ EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
);
DEBUG ((EFI_D_INFO,
"Reserved variable store memory: 0x%lX; size: %dkb\n",
VariableStore,
(2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
));
- PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore);
+ PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
+ ASSERT_RETURN_ERROR (PcdStatus);
}
@@ -487,6 +568,47 @@ S3Verification (
}
+/**
+ Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.
+ Set the mMaxCpuCount variable.
+**/
+VOID
+MaxCpuCountInitialization (
+ VOID
+ )
+{
+ UINT16 ProcessorCount;
+ RETURN_STATUS PcdStatus;
+
+ QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
+ ProcessorCount = QemuFwCfgRead16 ();
+ //
+ // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount
+ // from the PCD default. No change to PCDs.
+ //
+ if (ProcessorCount == 0) {
+ mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+ return;
+ }
+ //
+ // Otherwise, set mMaxCpuCount to the value reported by QEMU.
+ //
+ mMaxCpuCount = ProcessorCount;
+ //
+ // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b)
+ // to wait, in the initial AP bringup, exactly as long as it takes for all of
+ // the APs to report in. For this, we set the longest representable timeout
+ // (approx. 71 minutes).
+ //
+ PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__,
+ ProcessorCount));
+}
+
+
/**
Perform Platform PEI initialization.
@@ -503,6 +625,8 @@ InitializePlatform (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
+ EFI_STATUS Status;
+
DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));
DebugDumpCmos ();
@@ -512,11 +636,14 @@ InitializePlatform (
if (QemuFwCfgS3Enabled ()) {
DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n"));
mS3Supported = TRUE;
+ Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
+ ASSERT_EFI_ERROR (Status);
}
S3Verification ();
BootModeInitialization ();
AddressWidthInitialization ();
+ MaxCpuCountInitialization ();
PublishPeiMemory ();
@@ -533,13 +660,16 @@ InitializePlatform (
mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
if (mBootMode != BOOT_ON_S3_RESUME) {
- ReserveEmuVariableNvStore ();
+ if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+ ReserveEmuVariableNvStore ();
+ }
PeiFvInitialization ();
MemMapInitialization ();
NoexecDxeInitialization ();
}
MiscInitialization ();
+ InstallFeatureControlCallback ();
return EFI_SUCCESS;
}