diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c index 886d236226..97f3fa5afc 100644 --- a/OvmfPkg/PlatformPei/MemDetect.c +++ b/OvmfPkg/PlatformPei/MemDetect.c @@ -19,16 +19,19 @@ Module Name: // // The package level header files this module uses // +#include #include // // The Library classes this module consumes // +#include #include #include #include #include #include +#include #include #include #include @@ -49,7 +52,54 @@ Q35TsegMbytesInitialization ( VOID ) { - mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes); + UINT16 ExtendedTsegMbytes; + RETURN_STATUS PcdStatus; + + if (mHostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) { + DEBUG (( + DEBUG_ERROR, + "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; " + "only DID=0x%04x (Q35) is supported\n", + __FUNCTION__, + mHostBridgeDevId, + INTEL_Q35_MCH_DEVICE_ID + )); + ASSERT (FALSE); + CpuDeadLoop (); + } + + // + // Check if QEMU offers an extended TSEG. + // + // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB + // register, and reading back the register. + // + // On a QEMU machine type that does not offer an extended TSEG, the initial + // write overwrites whatever value a malicious guest OS may have placed in + // the (unimplemented) register, before entering S3 or rebooting. + // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged. + // + // On a QEMU machine type that offers an extended TSEG, the initial write + // triggers an update to the register. Subsequently, the value read back + // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the + // number of megabytes. + // + PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY); + ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB)); + if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) { + mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes); + return; + } + + DEBUG (( + DEBUG_INFO, + "%a: QEMU offers an extended TSEG (%d MB)\n", + __FUNCTION__, + ExtendedTsegMbytes + )); + PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes); + ASSERT_RETURN_ERROR (PcdStatus); + mQ35TsegMbytes = ExtendedTsegMbytes; } diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c index b8a28450d6..98cfaaa28e 100644 --- a/OvmfPkg/PlatformPei/Platform.c +++ b/OvmfPkg/PlatformPei/Platform.c @@ -645,6 +645,11 @@ InitializePlatform ( AddressWidthInitialization (); MaxCpuCountInitialization (); + // + // Query Host Bridge DID + // + mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); + if (FeaturePcdGet (PcdSmmSmramRequire)) { Q35TsegMbytesInitialization (); } @@ -658,11 +663,6 @@ InitializePlatform ( InitializeXen (); } - // - // Query Host Bridge DID - // - mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); - if (mBootMode != BOOT_ON_S3_RESUME) { if (!FeaturePcdGet (PcdSmmSmramRequire)) { ReserveEmuVariableNvStore (); diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h index d2d627b221..ae855531c1 100644 --- a/OvmfPkg/PlatformPei/Platform.h +++ b/OvmfPkg/PlatformPei/Platform.h @@ -108,4 +108,6 @@ extern UINT8 mPhysMemAddressWidth; extern UINT32 mMaxCpuCount; +extern UINT16 mHostBridgeDevId; + #endif // _PLATFORM_PEI_H_INCLUDED_