]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformPei/MemDetect.c
OvmfPkg/PlatformPei: honor extended TSEG in PcdQ35TsegMbytes if available
[mirror_edk2.git] / OvmfPkg / PlatformPei / MemDetect.c
1 /**@file
2 Memory Detection for Virtual Machines.
3
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name:
14
15 MemDetect.c
16
17 **/
18
19 //
20 // The package level header files this module uses
21 //
22 #include <IndustryStandard/Q35MchIch9.h>
23 #include <PiPei.h>
24
25 //
26 // The Library classes this module consumes
27 //
28 #include <Library/BaseLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/DebugLib.h>
31 #include <Library/HobLib.h>
32 #include <Library/IoLib.h>
33 #include <Library/PcdLib.h>
34 #include <Library/PciLib.h>
35 #include <Library/PeimEntryPoint.h>
36 #include <Library/ResourcePublicationLib.h>
37 #include <Library/MtrrLib.h>
38 #include <Library/QemuFwCfgLib.h>
39
40 #include "Platform.h"
41 #include "Cmos.h"
42
43 UINT8 mPhysMemAddressWidth;
44
45 STATIC UINT32 mS3AcpiReservedMemoryBase;
46 STATIC UINT32 mS3AcpiReservedMemorySize;
47
48 STATIC UINT16 mQ35TsegMbytes;
49
50 VOID
51 Q35TsegMbytesInitialization (
52 VOID
53 )
54 {
55 UINT16 ExtendedTsegMbytes;
56 RETURN_STATUS PcdStatus;
57
58 if (mHostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) {
59 DEBUG ((
60 DEBUG_ERROR,
61 "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
62 "only DID=0x%04x (Q35) is supported\n",
63 __FUNCTION__,
64 mHostBridgeDevId,
65 INTEL_Q35_MCH_DEVICE_ID
66 ));
67 ASSERT (FALSE);
68 CpuDeadLoop ();
69 }
70
71 //
72 // Check if QEMU offers an extended TSEG.
73 //
74 // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB
75 // register, and reading back the register.
76 //
77 // On a QEMU machine type that does not offer an extended TSEG, the initial
78 // write overwrites whatever value a malicious guest OS may have placed in
79 // the (unimplemented) register, before entering S3 or rebooting.
80 // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.
81 //
82 // On a QEMU machine type that offers an extended TSEG, the initial write
83 // triggers an update to the register. Subsequently, the value read back
84 // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the
85 // number of megabytes.
86 //
87 PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY);
88 ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));
89 if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) {
90 mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);
91 return;
92 }
93
94 DEBUG ((
95 DEBUG_INFO,
96 "%a: QEMU offers an extended TSEG (%d MB)\n",
97 __FUNCTION__,
98 ExtendedTsegMbytes
99 ));
100 PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);
101 ASSERT_RETURN_ERROR (PcdStatus);
102 mQ35TsegMbytes = ExtendedTsegMbytes;
103 }
104
105
106 UINT32
107 GetSystemMemorySizeBelow4gb (
108 VOID
109 )
110 {
111 UINT8 Cmos0x34;
112 UINT8 Cmos0x35;
113
114 //
115 // CMOS 0x34/0x35 specifies the system memory above 16 MB.
116 // * CMOS(0x35) is the high byte
117 // * CMOS(0x34) is the low byte
118 // * The size is specified in 64kb chunks
119 // * Since this is memory above 16MB, the 16MB must be added
120 // into the calculation to get the total memory size.
121 //
122
123 Cmos0x34 = (UINT8) CmosRead8 (0x34);
124 Cmos0x35 = (UINT8) CmosRead8 (0x35);
125
126 return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
127 }
128
129
130 STATIC
131 UINT64
132 GetSystemMemorySizeAbove4gb (
133 )
134 {
135 UINT32 Size;
136 UINTN CmosIndex;
137
138 //
139 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
140 // * CMOS(0x5d) is the most significant size byte
141 // * CMOS(0x5c) is the middle size byte
142 // * CMOS(0x5b) is the least significant size byte
143 // * The size is specified in 64kb chunks
144 //
145
146 Size = 0;
147 for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
148 Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);
149 }
150
151 return LShiftU64 (Size, 16);
152 }
153
154
155 /**
156 Return the highest address that DXE could possibly use, plus one.
157 **/
158 STATIC
159 UINT64
160 GetFirstNonAddress (
161 VOID
162 )
163 {
164 UINT64 FirstNonAddress;
165 UINT64 Pci64Base, Pci64Size;
166 CHAR8 MbString[7 + 1];
167 EFI_STATUS Status;
168 FIRMWARE_CONFIG_ITEM FwCfgItem;
169 UINTN FwCfgSize;
170 UINT64 HotPlugMemoryEnd;
171 RETURN_STATUS PcdStatus;
172
173 FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
174
175 //
176 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
177 // resources to 32-bit anyway. See DegradeResource() in
178 // "PciResourceSupport.c".
179 //
180 #ifdef MDE_CPU_IA32
181 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
182 return FirstNonAddress;
183 }
184 #endif
185
186 //
187 // Otherwise, in order to calculate the highest address plus one, we must
188 // consider the 64-bit PCI host aperture too. Fetch the default size.
189 //
190 Pci64Size = PcdGet64 (PcdPciMmio64Size);
191
192 //
193 // See if the user specified the number of megabytes for the 64-bit PCI host
194 // aperture. The number of non-NUL characters in MbString allows for
195 // 9,999,999 MB, which is approximately 10 TB.
196 //
197 // As signaled by the "X-" prefix, this knob is experimental, and might go
198 // away at any time.
199 //
200 Status = QemuFwCfgFindFile ("opt/ovmf/X-PciMmio64Mb", &FwCfgItem,
201 &FwCfgSize);
202 if (!EFI_ERROR (Status)) {
203 if (FwCfgSize >= sizeof MbString) {
204 DEBUG ((EFI_D_WARN,
205 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
206 __FUNCTION__));
207 } else {
208 QemuFwCfgSelectItem (FwCfgItem);
209 QemuFwCfgReadBytes (FwCfgSize, MbString);
210 MbString[FwCfgSize] = '\0';
211 Pci64Size = LShiftU64 (AsciiStrDecimalToUint64 (MbString), 20);
212 }
213 }
214
215 if (Pci64Size == 0) {
216 if (mBootMode != BOOT_ON_S3_RESUME) {
217 DEBUG ((EFI_D_INFO, "%a: disabling 64-bit PCI host aperture\n",
218 __FUNCTION__));
219 PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
220 ASSERT_RETURN_ERROR (PcdStatus);
221 }
222
223 //
224 // There's nothing more to do; the amount of memory above 4GB fully
225 // determines the highest address plus one. The memory hotplug area (see
226 // below) plays no role for the firmware in this case.
227 //
228 return FirstNonAddress;
229 }
230
231 //
232 // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
233 // absolute, exclusive end address for the memory hotplug area. This area
234 // starts right at the end of the memory above 4GB. The 64-bit PCI host
235 // aperture must be placed above it.
236 //
237 Status = QemuFwCfgFindFile ("etc/reserved-memory-end", &FwCfgItem,
238 &FwCfgSize);
239 if (!EFI_ERROR (Status) && FwCfgSize == sizeof HotPlugMemoryEnd) {
240 QemuFwCfgSelectItem (FwCfgItem);
241 QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);
242
243 ASSERT (HotPlugMemoryEnd >= FirstNonAddress);
244 FirstNonAddress = HotPlugMemoryEnd;
245 }
246
247 //
248 // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
249 // that the host can map it with 1GB hugepages. Follow suit.
250 //
251 Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
252 Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
253
254 //
255 // The 64-bit PCI host aperture should also be "naturally" aligned. The
256 // alignment is determined by rounding the size of the aperture down to the
257 // next smaller or equal power of two. That is, align the aperture by the
258 // largest BAR size that can fit into it.
259 //
260 Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
261
262 if (mBootMode != BOOT_ON_S3_RESUME) {
263 //
264 // The core PciHostBridgeDxe driver will automatically add this range to
265 // the GCD memory space map through our PciHostBridgeLib instance; here we
266 // only need to set the PCDs.
267 //
268 PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
269 ASSERT_RETURN_ERROR (PcdStatus);
270 PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
271 ASSERT_RETURN_ERROR (PcdStatus);
272
273 DEBUG ((EFI_D_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
274 __FUNCTION__, Pci64Base, Pci64Size));
275 }
276
277 //
278 // The useful address space ends with the 64-bit PCI host aperture.
279 //
280 FirstNonAddress = Pci64Base + Pci64Size;
281 return FirstNonAddress;
282 }
283
284
285 /**
286 Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
287 **/
288 VOID
289 AddressWidthInitialization (
290 VOID
291 )
292 {
293 UINT64 FirstNonAddress;
294
295 //
296 // As guest-physical memory size grows, the permanent PEI RAM requirements
297 // are dominated by the identity-mapping page tables built by the DXE IPL.
298 // The DXL IPL keys off of the physical address bits advertized in the CPU
299 // HOB. To conserve memory, we calculate the minimum address width here.
300 //
301 FirstNonAddress = GetFirstNonAddress ();
302 mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
303
304 //
305 // If FirstNonAddress is not an integral power of two, then we need an
306 // additional bit.
307 //
308 if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
309 ++mPhysMemAddressWidth;
310 }
311
312 //
313 // The minimum address width is 36 (covers up to and excluding 64 GB, which
314 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
315 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
316 // can simply assert that here, since 48 bits are good enough for 256 TB.
317 //
318 if (mPhysMemAddressWidth <= 36) {
319 mPhysMemAddressWidth = 36;
320 }
321 ASSERT (mPhysMemAddressWidth <= 48);
322 }
323
324
325 /**
326 Calculate the cap for the permanent PEI memory.
327 **/
328 STATIC
329 UINT32
330 GetPeiMemoryCap (
331 VOID
332 )
333 {
334 BOOLEAN Page1GSupport;
335 UINT32 RegEax;
336 UINT32 RegEdx;
337 UINT32 Pml4Entries;
338 UINT32 PdpEntries;
339 UINTN TotalPages;
340
341 //
342 // If DXE is 32-bit, then just return the traditional 64 MB cap.
343 //
344 #ifdef MDE_CPU_IA32
345 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
346 return SIZE_64MB;
347 }
348 #endif
349
350 //
351 // Dependent on physical address width, PEI memory allocations can be
352 // dominated by the page tables built for 64-bit DXE. So we key the cap off
353 // of those. The code below is based on CreateIdentityMappingPageTables() in
354 // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
355 //
356 Page1GSupport = FALSE;
357 if (PcdGetBool (PcdUse1GPageTable)) {
358 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
359 if (RegEax >= 0x80000001) {
360 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
361 if ((RegEdx & BIT26) != 0) {
362 Page1GSupport = TRUE;
363 }
364 }
365 }
366
367 if (mPhysMemAddressWidth <= 39) {
368 Pml4Entries = 1;
369 PdpEntries = 1 << (mPhysMemAddressWidth - 30);
370 ASSERT (PdpEntries <= 0x200);
371 } else {
372 Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
373 ASSERT (Pml4Entries <= 0x200);
374 PdpEntries = 512;
375 }
376
377 TotalPages = Page1GSupport ? Pml4Entries + 1 :
378 (PdpEntries + 1) * Pml4Entries + 1;
379 ASSERT (TotalPages <= 0x40201);
380
381 //
382 // Add 64 MB for miscellaneous allocations. Note that for
383 // mPhysMemAddressWidth values close to 36, the cap will actually be
384 // dominated by this increment.
385 //
386 return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
387 }
388
389
390 /**
391 Publish PEI core memory
392
393 @return EFI_SUCCESS The PEIM initialized successfully.
394
395 **/
396 EFI_STATUS
397 PublishPeiMemory (
398 VOID
399 )
400 {
401 EFI_STATUS Status;
402 EFI_PHYSICAL_ADDRESS MemoryBase;
403 UINT64 MemorySize;
404 UINT32 LowerMemorySize;
405 UINT32 PeiMemoryCap;
406
407 LowerMemorySize = GetSystemMemorySizeBelow4gb ();
408 if (FeaturePcdGet (PcdSmmSmramRequire)) {
409 //
410 // TSEG is chipped from the end of low RAM
411 //
412 LowerMemorySize -= mQ35TsegMbytes * SIZE_1MB;
413 }
414
415 //
416 // If S3 is supported, then the S3 permanent PEI memory is placed next,
417 // downwards. Its size is primarily dictated by CpuMpPei. The formula below
418 // is an approximation.
419 //
420 if (mS3Supported) {
421 mS3AcpiReservedMemorySize = SIZE_512KB +
422 mMaxCpuCount *
423 PcdGet32 (PcdCpuApStackSize);
424 mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;
425 LowerMemorySize = mS3AcpiReservedMemoryBase;
426 }
427
428 if (mBootMode == BOOT_ON_S3_RESUME) {
429 MemoryBase = mS3AcpiReservedMemoryBase;
430 MemorySize = mS3AcpiReservedMemorySize;
431 } else {
432 PeiMemoryCap = GetPeiMemoryCap ();
433 DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
434 __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));
435
436 //
437 // Determine the range of memory to use during PEI
438 //
439 // Technically we could lay the permanent PEI RAM over SEC's temporary
440 // decompression and scratch buffer even if "secure S3" is needed, since
441 // their lifetimes don't overlap. However, PeiFvInitialization() will cover
442 // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
443 // allocation HOB, and other allocations served from the permanent PEI RAM
444 // shouldn't overlap with that HOB.
445 //
446 MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?
447 PcdGet32 (PcdOvmfDecompressionScratchEnd) :
448 PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);
449 MemorySize = LowerMemorySize - MemoryBase;
450 if (MemorySize > PeiMemoryCap) {
451 MemoryBase = LowerMemorySize - PeiMemoryCap;
452 MemorySize = PeiMemoryCap;
453 }
454 }
455
456 //
457 // Publish this memory to the PEI Core
458 //
459 Status = PublishSystemMemory(MemoryBase, MemorySize);
460 ASSERT_EFI_ERROR (Status);
461
462 return Status;
463 }
464
465
466 /**
467 Peform Memory Detection for QEMU / KVM
468
469 **/
470 STATIC
471 VOID
472 QemuInitializeRam (
473 VOID
474 )
475 {
476 UINT64 LowerMemorySize;
477 UINT64 UpperMemorySize;
478 MTRR_SETTINGS MtrrSettings;
479 EFI_STATUS Status;
480
481 DEBUG ((EFI_D_INFO, "%a called\n", __FUNCTION__));
482
483 //
484 // Determine total memory size available
485 //
486 LowerMemorySize = GetSystemMemorySizeBelow4gb ();
487 UpperMemorySize = GetSystemMemorySizeAbove4gb ();
488
489 if (mBootMode == BOOT_ON_S3_RESUME) {
490 //
491 // Create the following memory HOB as an exception on the S3 boot path.
492 //
493 // Normally we'd create memory HOBs only on the normal boot path. However,
494 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
495 // well, for "borrowing" a subset of it temporarily, for the AP startup
496 // vector.
497 //
498 // CpuMpPei saves the original contents of the borrowed area in permanent
499 // PEI RAM, in a backup buffer allocated with the normal PEI services.
500 // CpuMpPei restores the original contents ("returns" the borrowed area) at
501 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
502 // transferring control to the OS's wakeup vector in the FACS.
503 //
504 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
505 // restore the original contents. Furthermore, we expect all such PEIMs
506 // (CpuMpPei included) to claim the borrowed areas by producing memory
507 // allocation HOBs, and to honor preexistent memory allocation HOBs when
508 // looking for an area to borrow.
509 //
510 AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
511 } else {
512 //
513 // Create memory HOBs
514 //
515 AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
516
517 if (FeaturePcdGet (PcdSmmSmramRequire)) {
518 UINT32 TsegSize;
519
520 TsegSize = mQ35TsegMbytes * SIZE_1MB;
521 AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
522 AddReservedMemoryBaseSizeHob (LowerMemorySize - TsegSize, TsegSize,
523 TRUE);
524 } else {
525 AddMemoryRangeHob (BASE_1MB, LowerMemorySize);
526 }
527
528 if (UpperMemorySize != 0) {
529 AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
530 }
531 }
532
533 //
534 // We'd like to keep the following ranges uncached:
535 // - [640 KB, 1 MB)
536 // - [LowerMemorySize, 4 GB)
537 //
538 // Everything else should be WB. Unfortunately, programming the inverse (ie.
539 // keeping the default UC, and configuring the complement set of the above as
540 // WB) is not reliable in general, because the end of the upper RAM can have
541 // practically any alignment, and we may not have enough variable MTRRs to
542 // cover it exactly.
543 //
544 if (IsMtrrSupported ()) {
545 MtrrGetAllMtrrs (&MtrrSettings);
546
547 //
548 // MTRRs disabled, fixed MTRRs disabled, default type is uncached
549 //
550 ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
551 ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
552 ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
553
554 //
555 // flip default type to writeback
556 //
557 SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
558 ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
559 MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
560 MtrrSetAllMtrrs (&MtrrSettings);
561
562 //
563 // Set memory range from 640KB to 1MB to uncacheable
564 //
565 Status = MtrrSetMemoryAttribute (BASE_512KB + BASE_128KB,
566 BASE_1MB - (BASE_512KB + BASE_128KB), CacheUncacheable);
567 ASSERT_EFI_ERROR (Status);
568
569 //
570 // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as
571 // uncacheable
572 //
573 Status = MtrrSetMemoryAttribute (LowerMemorySize,
574 SIZE_4GB - LowerMemorySize, CacheUncacheable);
575 ASSERT_EFI_ERROR (Status);
576 }
577 }
578
579 /**
580 Publish system RAM and reserve memory regions
581
582 **/
583 VOID
584 InitializeRamRegions (
585 VOID
586 )
587 {
588 if (!mXen) {
589 QemuInitializeRam ();
590 } else {
591 XenPublishRamRegions ();
592 }
593
594 if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
595 //
596 // This is the memory range that will be used for PEI on S3 resume
597 //
598 BuildMemoryAllocationHob (
599 mS3AcpiReservedMemoryBase,
600 mS3AcpiReservedMemorySize,
601 EfiACPIMemoryNVS
602 );
603
604 //
605 // Cover the initial RAM area used as stack and temporary PEI heap.
606 //
607 // This is reserved as ACPI NVS so it can be used on S3 resume.
608 //
609 BuildMemoryAllocationHob (
610 PcdGet32 (PcdOvmfSecPeiTempRamBase),
611 PcdGet32 (PcdOvmfSecPeiTempRamSize),
612 EfiACPIMemoryNVS
613 );
614
615 //
616 // SEC stores its table of GUIDed section handlers here.
617 //
618 BuildMemoryAllocationHob (
619 PcdGet64 (PcdGuidedExtractHandlerTableAddress),
620 PcdGet32 (PcdGuidedExtractHandlerTableSize),
621 EfiACPIMemoryNVS
622 );
623
624 #ifdef MDE_CPU_X64
625 //
626 // Reserve the initial page tables built by the reset vector code.
627 //
628 // Since this memory range will be used by the Reset Vector on S3
629 // resume, it must be reserved as ACPI NVS.
630 //
631 BuildMemoryAllocationHob (
632 (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecPageTablesBase),
633 (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
634 EfiACPIMemoryNVS
635 );
636 #endif
637 }
638
639 if (mBootMode != BOOT_ON_S3_RESUME) {
640 if (!FeaturePcdGet (PcdSmmSmramRequire)) {
641 //
642 // Reserve the lock box storage area
643 //
644 // Since this memory range will be used on S3 resume, it must be
645 // reserved as ACPI NVS.
646 //
647 // If S3 is unsupported, then various drivers might still write to the
648 // LockBox area. We ought to prevent DXE from serving allocation requests
649 // such that they would overlap the LockBox storage.
650 //
651 ZeroMem (
652 (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
653 (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)
654 );
655 BuildMemoryAllocationHob (
656 (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
657 (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),
658 mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
659 );
660 }
661
662 if (FeaturePcdGet (PcdSmmSmramRequire)) {
663 UINT32 TsegSize;
664
665 //
666 // Make sure the TSEG area that we reported as a reserved memory resource
667 // cannot be used for reserved memory allocations.
668 //
669 TsegSize = mQ35TsegMbytes * SIZE_1MB;
670 BuildMemoryAllocationHob (
671 GetSystemMemorySizeBelow4gb() - TsegSize,
672 TsegSize,
673 EfiReservedMemoryType
674 );
675 }
676 }
677 }