]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PlatformPei/MemDetect.c
OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization
[mirror_edk2.git] / OvmfPkg / PlatformPei / MemDetect.c
CommitLineData
49ba9447 1/**@file\r
2 Memory Detection for Virtual Machines.\r
3\r
035ce3b3 4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
b26f0cf9 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
49ba9447 6\r
7Module Name:\r
8\r
9 MemDetect.c\r
10\r
11**/\r
12\r
13//\r
14// The package level header files this module uses\r
15//\r
1fceaddb 16#include <IndustryStandard/E820.h>\r
49edde15 17#include <IndustryStandard/I440FxPiix4.h>\r
d5e06444 18#include <IndustryStandard/Q35MchIch9.h>\r
9afcd48a 19#include <IndustryStandard/CloudHv.h>\r
82bfd2e8 20#include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>\r
49ba9447 21#include <PiPei.h>\r
adec2bd5 22#include <Register/Intel/SmramSaveStateMap.h>\r
49ba9447 23\r
24//\r
25// The Library classes this module consumes\r
26//\r
d5e06444 27#include <Library/BaseLib.h>\r
6a7cba79 28#include <Library/BaseMemoryLib.h>\r
49ba9447 29#include <Library/DebugLib.h>\r
30#include <Library/HobLib.h>\r
31#include <Library/IoLib.h>\r
0bbed066 32#include <Library/MemEncryptSevLib.h>\r
c1c2669c 33#include <Library/PcdLib.h>\r
d5e06444 34#include <Library/PciLib.h>\r
49ba9447 35#include <Library/PeimEntryPoint.h>\r
36#include <Library/ResourcePublicationLib.h>\r
e8e5cd4a 37#include <Library/MtrrLib.h>\r
7e5b1b67 38#include <Library/QemuFwCfgLib.h>\r
98800cce 39#include <Library/QemuFwCfgSimpleParserLib.h>\r
49ba9447 40\r
41#include "Platform.h"\r
49ba9447 42\r
23bfb5c0
LE
43VOID\r
44Q35TsegMbytesInitialization (\r
45 VOID\r
46 )\r
47{\r
ac0a286f
MK
48 UINT16 ExtendedTsegMbytes;\r
49 RETURN_STATUS PcdStatus;\r
d5e06444 50\r
9a9b33b3 51 ASSERT (mPlatformInfoHob.HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);\r
d5e06444
LE
52\r
53 //\r
54 // Check if QEMU offers an extended TSEG.\r
55 //\r
56 // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB\r
57 // register, and reading back the register.\r
58 //\r
59 // On a QEMU machine type that does not offer an extended TSEG, the initial\r
60 // write overwrites whatever value a malicious guest OS may have placed in\r
61 // the (unimplemented) register, before entering S3 or rebooting.\r
62 // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.\r
63 //\r
64 // On a QEMU machine type that offers an extended TSEG, the initial write\r
65 // triggers an update to the register. Subsequently, the value read back\r
66 // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the\r
67 // number of megabytes.\r
68 //\r
69 PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY);\r
70 ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));\r
71 if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) {\r
9a9b33b3 72 mPlatformInfoHob.Q35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);\r
d5e06444
LE
73 return;\r
74 }\r
75\r
76 DEBUG ((\r
77 DEBUG_INFO,\r
78 "%a: QEMU offers an extended TSEG (%d MB)\n",\r
79 __FUNCTION__,\r
80 ExtendedTsegMbytes\r
81 ));\r
82 PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);\r
83 ASSERT_RETURN_ERROR (PcdStatus);\r
9a9b33b3 84 mPlatformInfoHob.Q35TsegMbytes = ExtendedTsegMbytes;\r
23bfb5c0
LE
85}\r
86\r
73974f80
LE
87VOID\r
88Q35SmramAtDefaultSmbaseInitialization (\r
89 VOID\r
90 )\r
91{\r
ac0a286f 92 RETURN_STATUS PcdStatus;\r
73974f80 93\r
9a9b33b3 94 ASSERT (mPlatformInfoHob.HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);\r
73974f80 95\r
9a9b33b3 96 mPlatformInfoHob.Q35SmramAtDefaultSmbase = FALSE;\r
75839f97 97 if (FeaturePcdGet (PcdCsmEnable)) {\r
ac0a286f
MK
98 DEBUG ((\r
99 DEBUG_INFO,\r
100 "%a: SMRAM at default SMBASE not checked due to CSM\n",\r
101 __FUNCTION__\r
102 ));\r
75839f97 103 } else {\r
ac0a286f
MK
104 UINTN CtlReg;\r
105 UINT8 CtlRegVal;\r
75839f97
LE
106\r
107 CtlReg = DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL);\r
108 PciWrite8 (CtlReg, MCH_DEFAULT_SMBASE_QUERY);\r
9a9b33b3
MX
109 CtlRegVal = PciRead8 (CtlReg);\r
110 mPlatformInfoHob.Q35SmramAtDefaultSmbase = (BOOLEAN)(CtlRegVal ==\r
111 MCH_DEFAULT_SMBASE_IN_RAM);\r
ac0a286f
MK
112 DEBUG ((\r
113 DEBUG_INFO,\r
114 "%a: SMRAM at default SMBASE %a\n",\r
115 __FUNCTION__,\r
9a9b33b3 116 mPlatformInfoHob.Q35SmramAtDefaultSmbase ? "found" : "not found"\r
ac0a286f 117 ));\r
75839f97
LE
118 }\r
119\r
ac0a286f
MK
120 PcdStatus = PcdSetBoolS (\r
121 PcdQ35SmramAtDefaultSmbase,\r
9a9b33b3 122 mPlatformInfoHob.Q35SmramAtDefaultSmbase\r
ac0a286f 123 );\r
73974f80
LE
124 ASSERT_RETURN_ERROR (PcdStatus);\r
125}\r
126\r
49edde15 127VOID\r
f3801cf2
MX
128EFIAPI\r
129PlatformQemuUc32BaseInitialization (\r
9a9b33b3 130 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
49edde15
LE
131 )\r
132{\r
ac0a286f 133 UINT32 LowerMemorySize;\r
49edde15 134\r
9a9b33b3 135 if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {\r
6a8e9ad2
GH
136 return;\r
137 }\r
138\r
9a9b33b3 139 if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
49edde15
LE
140 //\r
141 // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,\r
142 // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for\r
143 // setting PcdPciExpressBaseAddress such that describing the\r
144 // [PcdPciExpressBaseAddress, 4GB) range require a very small number of\r
145 // variable MTRRs (preferably 1 or 2).\r
146 //\r
147 ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);\r
9a9b33b3 148 PlatformInfoHob->Uc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);\r
49edde15
LE
149 return;\r
150 }\r
151\r
9a9b33b3
MX
152 if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {\r
153 PlatformInfoHob->Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;\r
154 PlatformInfoHob->Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;\r
9afcd48a
SB
155 return;\r
156 }\r
157\r
9a9b33b3 158 ASSERT (PlatformInfoHob->HostBridgeDevId == INTEL_82441_DEVICE_ID);\r
49edde15
LE
159 //\r
160 // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one\r
161 // variable MTRR suffices by truncating the size to a whole power of two,\r
162 // while keeping the end affixed to 4GB. This will round the base up.\r
163 //\r
9a9b33b3
MX
164 LowerMemorySize = GetSystemMemorySizeBelow4gb (PlatformInfoHob);\r
165 PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));\r
166 PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size);\r
49edde15
LE
167 //\r
168 // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.\r
169 // Therefore mQemuUc32Base is at least 2GB.\r
170 //\r
9a9b33b3 171 ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB);\r
49edde15 172\r
9a9b33b3 173 if (PlatformInfoHob->Uc32Base != LowerMemorySize) {\r
ac0a286f
MK
174 DEBUG ((\r
175 DEBUG_VERBOSE,\r
176 "%a: rounded UC32 base from 0x%x up to 0x%x, for "\r
177 "an UC32 size of 0x%x\n",\r
178 __FUNCTION__,\r
179 LowerMemorySize,\r
9a9b33b3
MX
180 PlatformInfoHob->Uc32Base,\r
181 PlatformInfoHob->Uc32Size\r
ac0a286f 182 ));\r
49edde15
LE
183 }\r
184}\r
185\r
1fceaddb
LE
186/**\r
187 Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside\r
188 of the 32-bit address range.\r
189\r
190 Find the highest exclusive >=4GB RAM address, or produce memory resource\r
191 descriptor HOBs for RAM entries that start at or above 4GB.\r
192\r
3dd47f95 193 @param[out] MaxAddress If MaxAddress is NULL, then PlatformScanOrAdd64BitE820Ram()\r
1fceaddb
LE
194 produces memory resource descriptor HOBs for RAM\r
195 entries that start at or above 4GB.\r
196\r
197 Otherwise, MaxAddress holds the highest exclusive\r
198 >=4GB RAM address on output. If QEMU's fw_cfg E820\r
199 RAM map contains no RAM entry that starts outside of\r
200 the 32-bit address range, then MaxAddress is exactly\r
201 4GB on output.\r
202\r
203 @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.\r
204\r
205 @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a\r
206 whole multiple of sizeof(EFI_E820_ENTRY64). No\r
207 RAM entry was processed.\r
208\r
209 @return Error codes from QemuFwCfgFindFile(). No RAM\r
210 entry was processed.\r
211**/\r
212STATIC\r
213EFI_STATUS\r
3dd47f95 214PlatformScanOrAdd64BitE820Ram (\r
557dede8
GH
215 IN BOOLEAN AddHighHob,\r
216 OUT UINT64 *LowMemory OPTIONAL,\r
ac0a286f 217 OUT UINT64 *MaxAddress OPTIONAL\r
1fceaddb
LE
218 )\r
219{\r
ac0a286f
MK
220 EFI_STATUS Status;\r
221 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
222 UINTN FwCfgSize;\r
223 EFI_E820_ENTRY64 E820Entry;\r
224 UINTN Processed;\r
1fceaddb
LE
225\r
226 Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);\r
227 if (EFI_ERROR (Status)) {\r
228 return Status;\r
229 }\r
ac0a286f 230\r
1fceaddb
LE
231 if (FwCfgSize % sizeof E820Entry != 0) {\r
232 return EFI_PROTOCOL_ERROR;\r
233 }\r
234\r
557dede8
GH
235 if (LowMemory != NULL) {\r
236 *LowMemory = 0;\r
237 }\r
238\r
1fceaddb
LE
239 if (MaxAddress != NULL) {\r
240 *MaxAddress = BASE_4GB;\r
241 }\r
242\r
243 QemuFwCfgSelectItem (FwCfgItem);\r
244 for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {\r
245 QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);\r
246 DEBUG ((\r
247 DEBUG_VERBOSE,\r
248 "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",\r
249 __FUNCTION__,\r
250 E820Entry.BaseAddr,\r
251 E820Entry.Length,\r
252 E820Entry.Type\r
253 ));\r
557dede8
GH
254 if (E820Entry.Type == EfiAcpiAddressRangeMemory) {\r
255 if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) {\r
ac0a286f
MK
256 UINT64 Base;\r
257 UINT64 End;\r
1fceaddb
LE
258\r
259 //\r
260 // Round up the start address, and round down the end address.\r
261 //\r
262 Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE);\r
ac0a286f
MK
263 End = (E820Entry.BaseAddr + E820Entry.Length) &\r
264 ~(UINT64)EFI_PAGE_MASK;\r
1fceaddb 265 if (Base < End) {\r
102cafed 266 PlatformAddMemoryRangeHob (Base, End);\r
1fceaddb
LE
267 DEBUG ((\r
268 DEBUG_VERBOSE,\r
102cafed 269 "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",\r
1fceaddb
LE
270 __FUNCTION__,\r
271 Base,\r
272 End\r
273 ));\r
274 }\r
557dede8
GH
275 }\r
276\r
277 if (MaxAddress || LowMemory) {\r
ac0a286f 278 UINT64 Candidate;\r
1fceaddb
LE
279\r
280 Candidate = E820Entry.BaseAddr + E820Entry.Length;\r
557dede8 281 if (MaxAddress && (Candidate > *MaxAddress)) {\r
1fceaddb
LE
282 *MaxAddress = Candidate;\r
283 DEBUG ((\r
284 DEBUG_VERBOSE,\r
285 "%a: MaxAddress=0x%Lx\n",\r
286 __FUNCTION__,\r
287 *MaxAddress\r
288 ));\r
289 }\r
557dede8
GH
290\r
291 if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) {\r
292 *LowMemory = Candidate;\r
293 DEBUG ((\r
294 DEBUG_VERBOSE,\r
295 "%a: LowMemory=0x%Lx\n",\r
296 __FUNCTION__,\r
297 *LowMemory\r
298 ));\r
299 }\r
1fceaddb
LE
300 }\r
301 }\r
302 }\r
ac0a286f 303\r
1fceaddb
LE
304 return EFI_SUCCESS;\r
305}\r
306\r
82bfd2e8
SB
307/**\r
308 Returns PVH memmap\r
309\r
310 @param Entries Pointer to PVH memmap\r
311 @param Count Number of entries\r
312\r
313 @return EFI_STATUS\r
314**/\r
315EFI_STATUS\r
316GetPvhMemmapEntries (\r
317 struct hvm_memmap_table_entry **Entries,\r
318 UINT32 *Count\r
319 )\r
320{\r
321 UINT32 *PVHResetVectorData;\r
322 struct hvm_start_info *pvh_start_info;\r
323\r
324 PVHResetVectorData = (VOID *)(UINTN)PcdGet32 (PcdXenPvhStartOfDayStructPtr);\r
325 if (PVHResetVectorData == 0) {\r
326 return EFI_NOT_FOUND;\r
327 }\r
328\r
329 pvh_start_info = (struct hvm_start_info *)(UINTN)PVHResetVectorData[0];\r
330\r
331 *Entries = (struct hvm_memmap_table_entry *)(UINTN)pvh_start_info->memmap_paddr;\r
332 *Count = pvh_start_info->memmap_entries;\r
333\r
334 return EFI_SUCCESS;\r
335}\r
336\r
337STATIC\r
338UINT64\r
339GetHighestSystemMemoryAddressFromPvhMemmap (\r
340 BOOLEAN Below4gb\r
341 )\r
342{\r
343 struct hvm_memmap_table_entry *Memmap;\r
344 UINT32 MemmapEntriesCount;\r
345 struct hvm_memmap_table_entry *Entry;\r
346 EFI_STATUS Status;\r
347 UINT32 Loop;\r
348 UINT64 HighestAddress;\r
349 UINT64 EntryEnd;\r
350\r
351 HighestAddress = 0;\r
352\r
353 Status = GetPvhMemmapEntries (&Memmap, &MemmapEntriesCount);\r
354 ASSERT_EFI_ERROR (Status);\r
355\r
356 for (Loop = 0; Loop < MemmapEntriesCount; Loop++) {\r
357 Entry = Memmap + Loop;\r
358 EntryEnd = Entry->addr + Entry->size;\r
359\r
360 if ((Entry->type == XEN_HVM_MEMMAP_TYPE_RAM) &&\r
361 (EntryEnd > HighestAddress))\r
362 {\r
363 if (Below4gb && (EntryEnd <= BASE_4GB)) {\r
364 HighestAddress = EntryEnd;\r
365 } else if (!Below4gb && (EntryEnd >= BASE_4GB)) {\r
366 HighestAddress = EntryEnd;\r
367 }\r
368 }\r
369 }\r
370\r
371 return HighestAddress;\r
372}\r
373\r
4b455f7b 374UINT32\r
c0e10976 375GetSystemMemorySizeBelow4gb (\r
9a9b33b3 376 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
49ba9447 377 )\r
378{\r
759e3c6d
GH
379 EFI_STATUS Status;\r
380 UINT64 LowerMemorySize = 0;\r
e6ea1464
AB
381 UINT8 Cmos0x34;\r
382 UINT8 Cmos0x35;\r
759e3c6d 383\r
9a9b33b3 384 if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {\r
82bfd2e8
SB
385 // Get the information from PVH memmap\r
386 return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE);\r
387 }\r
388\r
3dd47f95 389 Status = PlatformScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);\r
e6ea1464
AB
390 if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) {\r
391 return (UINT32)LowerMemorySize;\r
392 }\r
393\r
394 //\r
395 // CMOS 0x34/0x35 specifies the system memory above 16 MB.\r
396 // * CMOS(0x35) is the high byte\r
397 // * CMOS(0x34) is the low byte\r
398 // * The size is specified in 64kb chunks\r
399 // * Since this is memory above 16MB, the 16MB must be added\r
400 // into the calculation to get the total memory size.\r
401 //\r
402\r
57bcfc3b
MX
403 Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);\r
404 Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);\r
e6ea1464
AB
405\r
406 return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);\r
407}\r
408\r
409STATIC\r
410UINT64\r
3dd47f95 411PlatformGetSystemMemorySizeAbove4gb (\r
e6ea1464
AB
412 )\r
413{\r
414 UINT32 Size;\r
415 UINTN CmosIndex;\r
416\r
417 //\r
418 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.\r
419 // * CMOS(0x5d) is the most significant size byte\r
420 // * CMOS(0x5c) is the middle size byte\r
421 // * CMOS(0x5b) is the least significant size byte\r
422 // * The size is specified in 64kb chunks\r
423 //\r
424\r
425 Size = 0;\r
426 for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {\r
57bcfc3b 427 Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);\r
e6ea1464
AB
428 }\r
429\r
430 return LShiftU64 (Size, 16);\r
c0e10976 431}\r
432\r
d5371680
LE
433/**\r
434 Return the highest address that DXE could possibly use, plus one.\r
435**/\r
436STATIC\r
437UINT64\r
3dd47f95 438PlatformGetFirstNonAddress (\r
9a9b33b3 439 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
d5371680
LE
440 )\r
441{\r
ac0a286f 442 UINT64 FirstNonAddress;\r
ac0a286f
MK
443 UINT32 FwCfgPciMmio64Mb;\r
444 EFI_STATUS Status;\r
445 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
446 UINTN FwCfgSize;\r
447 UINT64 HotPlugMemoryEnd;\r
d5371680 448\r
1fceaddb
LE
449 //\r
450 // set FirstNonAddress to suppress incorrect compiler/analyzer warnings\r
451 //\r
452 FirstNonAddress = 0;\r
453\r
454 //\r
455 // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM\r
456 // address from it. This can express an address >= 4GB+1TB.\r
457 //\r
e6ea1464
AB
458 // Otherwise, get the flat size of the memory above 4GB from the CMOS (which\r
459 // can only express a size smaller than 1TB), and add it to 4GB.\r
460 //\r
3dd47f95 461 Status = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);\r
1fceaddb 462 if (EFI_ERROR (Status)) {\r
3dd47f95 463 FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();\r
1fceaddb 464 }\r
7e5b1b67
LE
465\r
466 //\r
467 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO\r
468 // resources to 32-bit anyway. See DegradeResource() in\r
469 // "PciResourceSupport.c".\r
470 //\r
ac0a286f 471 #ifdef MDE_CPU_IA32\r
7e5b1b67
LE
472 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
473 return FirstNonAddress;\r
474 }\r
ac0a286f
MK
475\r
476 #endif\r
7e5b1b67 477\r
7e5b1b67
LE
478 //\r
479 // See if the user specified the number of megabytes for the 64-bit PCI host\r
98800cce 480 // aperture. Accept an aperture size up to 16TB.\r
7e5b1b67
LE
481 //\r
482 // As signaled by the "X-" prefix, this knob is experimental, and might go\r
483 // away at any time.\r
484 //\r
ac0a286f
MK
485 Status = QemuFwCfgParseUint32 (\r
486 "opt/ovmf/X-PciMmio64Mb",\r
487 FALSE,\r
488 &FwCfgPciMmio64Mb\r
489 );\r
98800cce 490 switch (Status) {\r
ac0a286f
MK
491 case EFI_UNSUPPORTED:\r
492 case EFI_NOT_FOUND:\r
98800cce 493 break;\r
ac0a286f
MK
494 case EFI_SUCCESS:\r
495 if (FwCfgPciMmio64Mb <= 0x1000000) {\r
9a9b33b3 496 PlatformInfoHob->PcdPciMmio64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);\r
ac0a286f
MK
497 break;\r
498 }\r
499\r
98800cce
LE
500 //\r
501 // fall through\r
502 //\r
ac0a286f
MK
503 default:\r
504 DEBUG ((\r
505 DEBUG_WARN,\r
506 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",\r
507 __FUNCTION__\r
508 ));\r
509 break;\r
7e5b1b67
LE
510 }\r
511\r
9a9b33b3
MX
512 if (PlatformInfoHob->PcdPciMmio64Size == 0) {\r
513 if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {\r
ac0a286f
MK
514 DEBUG ((\r
515 DEBUG_INFO,\r
516 "%a: disabling 64-bit PCI host aperture\n",\r
517 __FUNCTION__\r
518 ));\r
7e5b1b67
LE
519 }\r
520\r
521 //\r
522 // There's nothing more to do; the amount of memory above 4GB fully\r
523 // determines the highest address plus one. The memory hotplug area (see\r
524 // below) plays no role for the firmware in this case.\r
525 //\r
526 return FirstNonAddress;\r
527 }\r
528\r
529 //\r
530 // The "etc/reserved-memory-end" fw_cfg file, when present, contains an\r
531 // absolute, exclusive end address for the memory hotplug area. This area\r
532 // starts right at the end of the memory above 4GB. The 64-bit PCI host\r
533 // aperture must be placed above it.\r
534 //\r
ac0a286f
MK
535 Status = QemuFwCfgFindFile (\r
536 "etc/reserved-memory-end",\r
537 &FwCfgItem,\r
538 &FwCfgSize\r
539 );\r
540 if (!EFI_ERROR (Status) && (FwCfgSize == sizeof HotPlugMemoryEnd)) {\r
7e5b1b67
LE
541 QemuFwCfgSelectItem (FwCfgItem);\r
542 QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);\r
ac0a286f
MK
543 DEBUG ((\r
544 DEBUG_VERBOSE,\r
545 "%a: HotPlugMemoryEnd=0x%Lx\n",\r
546 __FUNCTION__,\r
547 HotPlugMemoryEnd\r
548 ));\r
7e5b1b67
LE
549\r
550 ASSERT (HotPlugMemoryEnd >= FirstNonAddress);\r
551 FirstNonAddress = HotPlugMemoryEnd;\r
552 }\r
553\r
554 //\r
555 // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so\r
556 // that the host can map it with 1GB hugepages. Follow suit.\r
557 //\r
9a9b33b3
MX
558 PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);\r
559 PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (UINT64)SIZE_1GB);\r
7e5b1b67
LE
560\r
561 //\r
562 // The 64-bit PCI host aperture should also be "naturally" aligned. The\r
563 // alignment is determined by rounding the size of the aperture down to the\r
564 // next smaller or equal power of two. That is, align the aperture by the\r
565 // largest BAR size that can fit into it.\r
566 //\r
9a9b33b3 567 PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Base, GetPowerOfTwo64 (PlatformInfoHob->PcdPciMmio64Size));\r
7e5b1b67 568\r
7e5b1b67
LE
569 //\r
570 // The useful address space ends with the 64-bit PCI host aperture.\r
571 //\r
9a9b33b3 572 FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;\r
d5371680
LE
573 return FirstNonAddress;\r
574}\r
575\r
bc89fe48 576/**\r
3dd47f95 577 Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.\r
bc89fe48
LE
578**/\r
579VOID\r
3dd47f95
MX
580EFIAPI\r
581PlatformAddressWidthInitialization (\r
9a9b33b3 582 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
bc89fe48
LE
583 )\r
584{\r
ac0a286f 585 UINT64 FirstNonAddress;\r
9a9b33b3 586 UINT8 PhysMemAddressWidth;\r
bc89fe48
LE
587\r
588 //\r
589 // As guest-physical memory size grows, the permanent PEI RAM requirements\r
590 // are dominated by the identity-mapping page tables built by the DXE IPL.\r
591 // The DXL IPL keys off of the physical address bits advertized in the CPU\r
592 // HOB. To conserve memory, we calculate the minimum address width here.\r
593 //\r
3dd47f95 594 FirstNonAddress = PlatformGetFirstNonAddress (PlatformInfoHob);\r
9a9b33b3 595 PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);\r
bc89fe48
LE
596\r
597 //\r
598 // If FirstNonAddress is not an integral power of two, then we need an\r
599 // additional bit.\r
600 //\r
601 if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {\r
9a9b33b3 602 ++PhysMemAddressWidth;\r
bc89fe48
LE
603 }\r
604\r
605 //\r
606 // The minimum address width is 36 (covers up to and excluding 64 GB, which\r
607 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for\r
608 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We\r
609 // can simply assert that here, since 48 bits are good enough for 256 TB.\r
610 //\r
9a9b33b3
MX
611 if (PhysMemAddressWidth <= 36) {\r
612 PhysMemAddressWidth = 36;\r
bc89fe48 613 }\r
ac0a286f 614\r
9a9b33b3
MX
615 ASSERT (PhysMemAddressWidth <= 48);\r
616\r
617 PlatformInfoHob->FirstNonAddress = FirstNonAddress;\r
618 PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;\r
bc89fe48
LE
619}\r
620\r
3dd47f95
MX
621/**\r
622 Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.\r
623**/\r
624VOID\r
625AddressWidthInitialization (\r
626 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
627 )\r
628{\r
629 RETURN_STATUS PcdStatus;\r
630\r
631 PlatformAddressWidthInitialization (PlatformInfoHob);\r
632\r
633 //\r
634 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO\r
635 // resources to 32-bit anyway. See DegradeResource() in\r
636 // "PciResourceSupport.c".\r
637 //\r
638 #ifdef MDE_CPU_IA32\r
639 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
640 return;\r
641 }\r
642\r
643 #endif\r
644\r
645 if (PlatformInfoHob->PcdPciMmio64Size == 0) {\r
646 if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {\r
647 DEBUG ((\r
648 DEBUG_INFO,\r
649 "%a: disabling 64-bit PCI host aperture\n",\r
650 __FUNCTION__\r
651 ));\r
652 PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);\r
653 ASSERT_RETURN_ERROR (PcdStatus);\r
654 }\r
655\r
656 return;\r
657 }\r
658\r
659 if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {\r
660 //\r
661 // The core PciHostBridgeDxe driver will automatically add this range to\r
662 // the GCD memory space map through our PciHostBridgeLib instance; here we\r
663 // only need to set the PCDs.\r
664 //\r
665 PcdStatus = PcdSet64S (PcdPciMmio64Base, PlatformInfoHob->PcdPciMmio64Base);\r
666 ASSERT_RETURN_ERROR (PcdStatus);\r
667 PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);\r
668 ASSERT_RETURN_ERROR (PcdStatus);\r
669\r
670 DEBUG ((\r
671 DEBUG_INFO,\r
672 "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",\r
673 __FUNCTION__,\r
674 PlatformInfoHob->PcdPciMmio64Base,\r
675 PlatformInfoHob->PcdPciMmio64Size\r
676 ));\r
677 }\r
678}\r
679\r
bc89fe48
LE
680/**\r
681 Calculate the cap for the permanent PEI memory.\r
682**/\r
683STATIC\r
684UINT32\r
685GetPeiMemoryCap (\r
686 VOID\r
687 )\r
688{\r
ac0a286f
MK
689 BOOLEAN Page1GSupport;\r
690 UINT32 RegEax;\r
691 UINT32 RegEdx;\r
692 UINT32 Pml4Entries;\r
693 UINT32 PdpEntries;\r
694 UINTN TotalPages;\r
bc89fe48
LE
695\r
696 //\r
697 // If DXE is 32-bit, then just return the traditional 64 MB cap.\r
698 //\r
ac0a286f 699 #ifdef MDE_CPU_IA32\r
bc89fe48
LE
700 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
701 return SIZE_64MB;\r
702 }\r
ac0a286f
MK
703\r
704 #endif\r
bc89fe48
LE
705\r
706 //\r
707 // Dependent on physical address width, PEI memory allocations can be\r
708 // dominated by the page tables built for 64-bit DXE. So we key the cap off\r
709 // of those. The code below is based on CreateIdentityMappingPageTables() in\r
710 // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".\r
711 //\r
712 Page1GSupport = FALSE;\r
713 if (PcdGetBool (PcdUse1GPageTable)) {\r
714 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
715 if (RegEax >= 0x80000001) {\r
716 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
717 if ((RegEdx & BIT26) != 0) {\r
718 Page1GSupport = TRUE;\r
719 }\r
720 }\r
721 }\r
722\r
9a9b33b3 723 if (mPlatformInfoHob.PhysMemAddressWidth <= 39) {\r
bc89fe48 724 Pml4Entries = 1;\r
9a9b33b3 725 PdpEntries = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 30);\r
bc89fe48
LE
726 ASSERT (PdpEntries <= 0x200);\r
727 } else {\r
9a9b33b3 728 Pml4Entries = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 39);\r
bc89fe48
LE
729 ASSERT (Pml4Entries <= 0x200);\r
730 PdpEntries = 512;\r
731 }\r
732\r
733 TotalPages = Page1GSupport ? Pml4Entries + 1 :\r
ac0a286f 734 (PdpEntries + 1) * Pml4Entries + 1;\r
bc89fe48
LE
735 ASSERT (TotalPages <= 0x40201);\r
736\r
737 //\r
738 // Add 64 MB for miscellaneous allocations. Note that for\r
3dd47f95 739 // PhysMemAddressWidth values close to 36, the cap will actually be\r
bc89fe48
LE
740 // dominated by this increment.\r
741 //\r
742 return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);\r
743}\r
744\r
36658fff
WL
745/**\r
746 Publish PEI core memory\r
747\r
748 @return EFI_SUCCESS The PEIM initialized successfully.\r
749\r
750**/\r
751EFI_STATUS\r
752PublishPeiMemory (\r
753 VOID\r
754 )\r
755{\r
ac0a286f
MK
756 EFI_STATUS Status;\r
757 EFI_PHYSICAL_ADDRESS MemoryBase;\r
758 UINT64 MemorySize;\r
759 UINT32 LowerMemorySize;\r
760 UINT32 PeiMemoryCap;\r
9a9b33b3
MX
761 UINT32 S3AcpiReservedMemoryBase;\r
762 UINT32 S3AcpiReservedMemorySize;\r
36658fff 763\r
9a9b33b3
MX
764 LowerMemorySize = GetSystemMemorySizeBelow4gb (&mPlatformInfoHob);\r
765 if (mPlatformInfoHob.SmmSmramRequire) {\r
45d87081
LE
766 //\r
767 // TSEG is chipped from the end of low RAM\r
768 //\r
9a9b33b3 769 LowerMemorySize -= mPlatformInfoHob.Q35TsegMbytes * SIZE_1MB;\r
45d87081
LE
770 }\r
771\r
9a9b33b3
MX
772 S3AcpiReservedMemoryBase = 0;\r
773 S3AcpiReservedMemorySize = 0;\r
774\r
45d87081
LE
775 //\r
776 // If S3 is supported, then the S3 permanent PEI memory is placed next,\r
777 // downwards. Its size is primarily dictated by CpuMpPei. The formula below\r
778 // is an approximation.\r
779 //\r
9a9b33b3
MX
780 if (mPlatformInfoHob.S3Supported) {\r
781 S3AcpiReservedMemorySize = SIZE_512KB +\r
782 mPlatformInfoHob.PcdCpuMaxLogicalProcessorNumber *\r
783 PcdGet32 (PcdCpuApStackSize);\r
784 S3AcpiReservedMemoryBase = LowerMemorySize - S3AcpiReservedMemorySize;\r
785 LowerMemorySize = S3AcpiReservedMemoryBase;\r
45d87081
LE
786 }\r
787\r
9a9b33b3
MX
788 mPlatformInfoHob.S3AcpiReservedMemoryBase = S3AcpiReservedMemoryBase;\r
789 mPlatformInfoHob.S3AcpiReservedMemorySize = S3AcpiReservedMemorySize;\r
790\r
791 if (mPlatformInfoHob.BootMode == BOOT_ON_S3_RESUME) {\r
792 MemoryBase = S3AcpiReservedMemoryBase;\r
793 MemorySize = S3AcpiReservedMemorySize;\r
8e54500f 794 } else {\r
bc89fe48 795 PeiMemoryCap = GetPeiMemoryCap ();\r
ac0a286f
MK
796 DEBUG ((\r
797 DEBUG_INFO,\r
3dd47f95 798 "%a: PhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",\r
ac0a286f 799 __FUNCTION__,\r
9a9b33b3 800 mPlatformInfoHob.PhysMemAddressWidth,\r
ac0a286f
MK
801 PeiMemoryCap >> 10\r
802 ));\r
bc89fe48 803\r
8e54500f
JJ
804 //\r
805 // Determine the range of memory to use during PEI\r
806 //\r
efb0f16e
LE
807 // Technically we could lay the permanent PEI RAM over SEC's temporary\r
808 // decompression and scratch buffer even if "secure S3" is needed, since\r
809 // their lifetimes don't overlap. However, PeiFvInitialization() will cover\r
810 // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory\r
811 // allocation HOB, and other allocations served from the permanent PEI RAM\r
812 // shouldn't overlap with that HOB.\r
813 //\r
9a9b33b3 814 MemoryBase = mPlatformInfoHob.S3Supported && mPlatformInfoHob.SmmSmramRequire ?\r
ac0a286f
MK
815 PcdGet32 (PcdOvmfDecompressionScratchEnd) :\r
816 PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);\r
8e54500f 817 MemorySize = LowerMemorySize - MemoryBase;\r
bc89fe48
LE
818 if (MemorySize > PeiMemoryCap) {\r
819 MemoryBase = LowerMemorySize - PeiMemoryCap;\r
820 MemorySize = PeiMemoryCap;\r
8e54500f 821 }\r
36658fff
WL
822 }\r
823\r
adec2bd5
LE
824 //\r
825 // MEMFD_BASE_ADDRESS separates the SMRAM at the default SMBASE from the\r
826 // normal boot permanent PEI RAM. Regarding the S3 boot path, the S3\r
827 // permanent PEI RAM is located even higher.\r
828 //\r
9a9b33b3 829 if (mPlatformInfoHob.SmmSmramRequire && mPlatformInfoHob.Q35SmramAtDefaultSmbase) {\r
adec2bd5
LE
830 ASSERT (SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE <= MemoryBase);\r
831 }\r
832\r
36658fff
WL
833 //\r
834 // Publish this memory to the PEI Core\r
835 //\r
ac0a286f 836 Status = PublishSystemMemory (MemoryBase, MemorySize);\r
36658fff
WL
837 ASSERT_EFI_ERROR (Status);\r
838\r
839 return Status;\r
840}\r
841\r
84b223c1
LE
842STATIC\r
843VOID\r
844QemuInitializeRamBelow1gb (\r
9a9b33b3 845 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
84b223c1
LE
846 )\r
847{\r
9a9b33b3 848 if (PlatformInfoHob->SmmSmramRequire && PlatformInfoHob->Q35SmramAtDefaultSmbase) {\r
102cafed
MX
849 PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);\r
850 PlatformAddReservedMemoryBaseSizeHob (\r
ac0a286f
MK
851 SMM_DEFAULT_SMBASE,\r
852 MCH_DEFAULT_SMBASE_SIZE,\r
853 TRUE /* Cacheable */\r
854 );\r
84b223c1
LE
855 STATIC_ASSERT (\r
856 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,\r
857 "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"\r
858 );\r
102cafed 859 PlatformAddMemoryRangeHob (\r
ac0a286f
MK
860 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,\r
861 BASE_512KB + BASE_128KB\r
862 );\r
84b223c1 863 } else {\r
102cafed 864 PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);\r
84b223c1
LE
865 }\r
866}\r
867\r
49ba9447 868/**\r
c034906e 869 Peform Memory Detection for QEMU / KVM\r
49ba9447 870\r
871**/\r
c034906e
JJ
872STATIC\r
873VOID\r
874QemuInitializeRam (\r
9a9b33b3 875 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
49ba9447 876 )\r
877{\r
ac0a286f 878 UINT64 LowerMemorySize;\r
e6ea1464 879 UINT64 UpperMemorySize;\r
ac0a286f
MK
880 MTRR_SETTINGS MtrrSettings;\r
881 EFI_STATUS Status;\r
49ba9447 882\r
70d5086c 883 DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));\r
49ba9447 884\r
885 //\r
886 // Determine total memory size available\r
887 //\r
9a9b33b3 888 LowerMemorySize = GetSystemMemorySizeBelow4gb (PlatformInfoHob);\r
49ba9447 889\r
9a9b33b3 890 if (PlatformInfoHob->BootMode == BOOT_ON_S3_RESUME) {\r
e3e3090a
LE
891 //\r
892 // Create the following memory HOB as an exception on the S3 boot path.\r
893 //\r
894 // Normally we'd create memory HOBs only on the normal boot path. However,\r
895 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as\r
896 // well, for "borrowing" a subset of it temporarily, for the AP startup\r
897 // vector.\r
898 //\r
899 // CpuMpPei saves the original contents of the borrowed area in permanent\r
900 // PEI RAM, in a backup buffer allocated with the normal PEI services.\r
901 // CpuMpPei restores the original contents ("returns" the borrowed area) at\r
902 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before\r
8c0b0b34 903 // transferring control to the OS's wakeup vector in the FACS.\r
e3e3090a
LE
904 //\r
905 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to\r
906 // restore the original contents. Furthermore, we expect all such PEIMs\r
907 // (CpuMpPei included) to claim the borrowed areas by producing memory\r
908 // allocation HOBs, and to honor preexistent memory allocation HOBs when\r
909 // looking for an area to borrow.\r
910 //\r
9a9b33b3 911 QemuInitializeRamBelow1gb (PlatformInfoHob);\r
e3e3090a 912 } else {\r
bd386eaf
JJ
913 //\r
914 // Create memory HOBs\r
915 //\r
9a9b33b3 916 QemuInitializeRamBelow1gb (PlatformInfoHob);\r
b09c1c6f 917\r
9a9b33b3 918 if (PlatformInfoHob->SmmSmramRequire) {\r
ac0a286f 919 UINT32 TsegSize;\r
b09c1c6f 920\r
9a9b33b3 921 TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;\r
102cafed
MX
922 PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);\r
923 PlatformAddReservedMemoryBaseSizeHob (\r
ac0a286f
MK
924 LowerMemorySize - TsegSize,\r
925 TsegSize,\r
926 TRUE\r
927 );\r
b09c1c6f 928 } else {\r
102cafed 929 PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);\r
b09c1c6f
LE
930 }\r
931\r
1fceaddb
LE
932 //\r
933 // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM\r
934 // entries. Otherwise, create a single memory HOB with the flat >=4GB\r
935 // memory size read from the CMOS.\r
936 //\r
3dd47f95 937 Status = PlatformScanOrAdd64BitE820Ram (TRUE, NULL, NULL);\r
e6ea1464 938 if (EFI_ERROR (Status)) {\r
3dd47f95 939 UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb ();\r
e6ea1464 940 if (UpperMemorySize != 0) {\r
102cafed 941 PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);\r
e6ea1464
AB
942 }\r
943 }\r
bd386eaf 944 }\r
49ba9447 945\r
79d274b8
LE
946 //\r
947 // We'd like to keep the following ranges uncached:\r
948 // - [640 KB, 1 MB)\r
949 // - [LowerMemorySize, 4 GB)\r
950 //\r
951 // Everything else should be WB. Unfortunately, programming the inverse (ie.\r
952 // keeping the default UC, and configuring the complement set of the above as\r
953 // WB) is not reliable in general, because the end of the upper RAM can have\r
954 // practically any alignment, and we may not have enough variable MTRRs to\r
955 // cover it exactly.\r
956 //\r
9a9b33b3 957 if (IsMtrrSupported () && (PlatformInfoHob->HostBridgeDevId != CLOUDHV_DEVICE_ID)) {\r
79d274b8
LE
958 MtrrGetAllMtrrs (&MtrrSettings);\r
959\r
960 //\r
961 // MTRRs disabled, fixed MTRRs disabled, default type is uncached\r
962 //\r
963 ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);\r
964 ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);\r
965 ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);\r
966\r
967 //\r
968 // flip default type to writeback\r
969 //\r
970 SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);\r
971 ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);\r
972 MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;\r
973 MtrrSetAllMtrrs (&MtrrSettings);\r
e8e5cd4a 974\r
79d274b8
LE
975 //\r
976 // Set memory range from 640KB to 1MB to uncacheable\r
977 //\r
ac0a286f
MK
978 Status = MtrrSetMemoryAttribute (\r
979 BASE_512KB + BASE_128KB,\r
980 BASE_1MB - (BASE_512KB + BASE_128KB),\r
981 CacheUncacheable\r
982 );\r
79d274b8 983 ASSERT_EFI_ERROR (Status);\r
e8e5cd4a 984\r
79d274b8 985 //\r
49edde15
LE
986 // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI\r
987 // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.\r
79d274b8 988 //\r
ac0a286f 989 Status = MtrrSetMemoryAttribute (\r
9a9b33b3
MX
990 PlatformInfoHob->Uc32Base,\r
991 SIZE_4GB - PlatformInfoHob->Uc32Base,\r
ac0a286f
MK
992 CacheUncacheable\r
993 );\r
79d274b8 994 ASSERT_EFI_ERROR (Status);\r
c0e10976 995 }\r
49ba9447 996}\r
997\r
c034906e
JJ
998/**\r
999 Publish system RAM and reserve memory regions\r
1000\r
1001**/\r
1002VOID\r
1003InitializeRamRegions (\r
9a9b33b3 1004 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
c034906e
JJ
1005 )\r
1006{\r
9a9b33b3 1007 QemuInitializeRam (PlatformInfoHob);\r
8e54500f 1008\r
ea3a12d9
BS
1009 SevInitializeRam ();\r
1010\r
9a9b33b3 1011 if (PlatformInfoHob->S3Supported && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {\r
8e54500f
JJ
1012 //\r
1013 // This is the memory range that will be used for PEI on S3 resume\r
1014 //\r
1015 BuildMemoryAllocationHob (\r
9a9b33b3
MX
1016 PlatformInfoHob->S3AcpiReservedMemoryBase,\r
1017 PlatformInfoHob->S3AcpiReservedMemorySize,\r
8e54500f
JJ
1018 EfiACPIMemoryNVS\r
1019 );\r
e249f906
LE
1020\r
1021 //\r
1022 // Cover the initial RAM area used as stack and temporary PEI heap.\r
1023 //\r
1024 // This is reserved as ACPI NVS so it can be used on S3 resume.\r
1025 //\r
1026 BuildMemoryAllocationHob (\r
1027 PcdGet32 (PcdOvmfSecPeiTempRamBase),\r
1028 PcdGet32 (PcdOvmfSecPeiTempRamSize),\r
1029 EfiACPIMemoryNVS\r
1030 );\r
78a38b73 1031\r
ad43bc6b
LE
1032 //\r
1033 // SEC stores its table of GUIDed section handlers here.\r
1034 //\r
1035 BuildMemoryAllocationHob (\r
1036 PcdGet64 (PcdGuidedExtractHandlerTableAddress),\r
1037 PcdGet32 (PcdGuidedExtractHandlerTableSize),\r
1038 EfiACPIMemoryNVS\r
1039 );\r
1040\r
ac0a286f 1041 #ifdef MDE_CPU_X64\r
78a38b73
LE
1042 //\r
1043 // Reserve the initial page tables built by the reset vector code.\r
1044 //\r
1045 // Since this memory range will be used by the Reset Vector on S3\r
1046 // resume, it must be reserved as ACPI NVS.\r
1047 //\r
1048 BuildMemoryAllocationHob (\r
ac0a286f
MK
1049 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase),\r
1050 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecPageTablesSize),\r
78a38b73
LE
1051 EfiACPIMemoryNVS\r
1052 );\r
0bbed066 1053\r
9a9b33b3 1054 if (PlatformInfoHob->SevEsIsEnabled) {\r
0bbed066
TL
1055 //\r
1056 // If SEV-ES is enabled, reserve the GHCB-related memory area. This\r
1057 // includes the extra page table used to break down the 2MB page\r
1058 // mapping into 4KB page entries where the GHCB resides and the\r
1059 // GHCB area itself.\r
1060 //\r
1061 // Since this memory range will be used by the Reset Vector on S3\r
1062 // resume, it must be reserved as ACPI NVS.\r
1063 //\r
1064 BuildMemoryAllocationHob (\r
ac0a286f
MK
1065 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableBase),\r
1066 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableSize),\r
0bbed066
TL
1067 EfiACPIMemoryNVS\r
1068 );\r
1069 BuildMemoryAllocationHob (\r
ac0a286f
MK
1070 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase),\r
1071 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbSize),\r
0bbed066
TL
1072 EfiACPIMemoryNVS\r
1073 );\r
36265424 1074 BuildMemoryAllocationHob (\r
ac0a286f
MK
1075 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase),\r
1076 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupSize),\r
36265424
TL
1077 EfiACPIMemoryNVS\r
1078 );\r
0bbed066 1079 }\r
ac0a286f
MK
1080\r
1081 #endif\r
0e8a31f5 1082 }\r
6a7cba79 1083\r
9a9b33b3
MX
1084 if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {\r
1085 if (!PlatformInfoHob->SmmSmramRequire) {\r
1a7edbbc
LE
1086 //\r
1087 // Reserve the lock box storage area\r
1088 //\r
1089 // Since this memory range will be used on S3 resume, it must be\r
1090 // reserved as ACPI NVS.\r
1091 //\r
1092 // If S3 is unsupported, then various drivers might still write to the\r
1093 // LockBox area. We ought to prevent DXE from serving allocation requests\r
1094 // such that they would overlap the LockBox storage.\r
1095 //\r
1096 ZeroMem (\r
ac0a286f
MK
1097 (VOID *)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),\r
1098 (UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize)\r
1a7edbbc
LE
1099 );\r
1100 BuildMemoryAllocationHob (\r
ac0a286f
MK
1101 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),\r
1102 (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),\r
9a9b33b3 1103 PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData\r
1a7edbbc
LE
1104 );\r
1105 }\r
b09c1c6f 1106\r
9a9b33b3 1107 if (PlatformInfoHob->SmmSmramRequire) {\r
ac0a286f 1108 UINT32 TsegSize;\r
b09c1c6f
LE
1109\r
1110 //\r
1111 // Make sure the TSEG area that we reported as a reserved memory resource\r
1112 // cannot be used for reserved memory allocations.\r
1113 //\r
9a9b33b3 1114 TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;\r
b09c1c6f 1115 BuildMemoryAllocationHob (\r
9a9b33b3 1116 GetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize,\r
b09c1c6f
LE
1117 TsegSize,\r
1118 EfiReservedMemoryType\r
1119 );\r
84b223c1
LE
1120 //\r
1121 // Similarly, allocate away the (already reserved) SMRAM at the default\r
1122 // SMBASE, if it exists.\r
1123 //\r
9a9b33b3 1124 if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {\r
84b223c1
LE
1125 BuildMemoryAllocationHob (\r
1126 SMM_DEFAULT_SMBASE,\r
1127 MCH_DEFAULT_SMBASE_SIZE,\r
1128 EfiReservedMemoryType\r
1129 );\r
1130 }\r
b09c1c6f 1131 }\r
0731236f 1132\r
ac0a286f 1133 #ifdef MDE_CPU_X64\r
80e67af9 1134 if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {\r
0731236f 1135 //\r
80e67af9 1136 // Reserve the work area.\r
0731236f
TL
1137 //\r
1138 // Since this memory range will be used by the Reset Vector on S3\r
1139 // resume, it must be reserved as ACPI NVS.\r
1140 //\r
1141 // If S3 is unsupported, then various drivers might still write to the\r
1142 // work area. We ought to prevent DXE from serving allocation requests\r
1143 // such that they would overlap the work area.\r
1144 //\r
1145 BuildMemoryAllocationHob (\r
ac0a286f
MK
1146 (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),\r
1147 (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),\r
9a9b33b3 1148 PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData\r
0731236f
TL
1149 );\r
1150 }\r
ac0a286f
MK
1151\r
1152 #endif\r
8e54500f 1153 }\r
c034906e 1154}\r