\r
STATIC UINT16 mQ35TsegMbytes;\r
\r
+UINT32 mQemuUc32Base;\r
+\r
VOID\r
Q35TsegMbytesInitialization (\r
VOID\r
// cover it exactly.\r
//\r
if (IsMtrrSupported ()) {\r
+ UINT32 Uc32Size;\r
+\r
MtrrGetAllMtrrs (&MtrrSettings);\r
\r
//\r
\r
//\r
// Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as\r
- // uncacheable\r
- //\r
- Status = MtrrSetMemoryAttribute (LowerMemorySize,\r
- SIZE_4GB - LowerMemorySize, CacheUncacheable);\r
+ // uncacheable. Make sure one variable MTRR suffices by truncating the size\r
+ // to a whole power of two. This will round the base *up*, and a gap (not\r
+ // used for either RAM or MMIO) may stay in the middle, marked as\r
+ // cacheable-by-default.\r
+ //\r
+ Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));\r
+ mQemuUc32Base = (UINT32)(SIZE_4GB - Uc32Size);\r
+ if (mQemuUc32Base != LowerMemorySize) {\r
+ DEBUG ((DEBUG_VERBOSE, "%a: rounded UC32 base from 0x%x up to 0x%x, for "\r
+ "an UC32 size of 0x%x\n", __FUNCTION__, (UINT32)LowerMemorySize,\r
+ mQemuUc32Base, Uc32Size));\r
+ }\r
+\r
+ Status = MtrrSetMemoryAttribute (mQemuUc32Base, Uc32Size,\r
+ CacheUncacheable);\r
ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ mQemuUc32Base = (UINT32)LowerMemorySize;\r
}\r
}\r
\r