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