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