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