2 Memory Detection for Virtual Machines.
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
14 // The package level header files this module uses
16 #include <IndustryStandard/E820.h>
17 #include <IndustryStandard/I440FxPiix4.h>
18 #include <IndustryStandard/Q35MchIch9.h>
22 // The Library classes this module consumes
24 #include <Library/BaseLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/HobLib.h>
28 #include <Library/IoLib.h>
29 #include <Library/PcdLib.h>
30 #include <Library/PciLib.h>
31 #include <Library/PeimEntryPoint.h>
32 #include <Library/ResourcePublicationLib.h>
33 #include <Library/MtrrLib.h>
34 #include <Library/QemuFwCfgLib.h>
39 UINT8 mPhysMemAddressWidth
;
41 STATIC UINT32 mS3AcpiReservedMemoryBase
;
42 STATIC UINT32 mS3AcpiReservedMemorySize
;
44 STATIC UINT16 mQ35TsegMbytes
;
46 BOOLEAN mQ35SmramAtDefaultSmbase
;
51 Q35TsegMbytesInitialization (
55 UINT16 ExtendedTsegMbytes
;
56 RETURN_STATUS PcdStatus
;
58 ASSERT (mHostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
);
61 // Check if QEMU offers an extended TSEG.
63 // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB
64 // register, and reading back the register.
66 // On a QEMU machine type that does not offer an extended TSEG, the initial
67 // write overwrites whatever value a malicious guest OS may have placed in
68 // the (unimplemented) register, before entering S3 or rebooting.
69 // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.
71 // On a QEMU machine type that offers an extended TSEG, the initial write
72 // triggers an update to the register. Subsequently, the value read back
73 // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the
74 // number of megabytes.
76 PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB
), MCH_EXT_TSEG_MB_QUERY
);
77 ExtendedTsegMbytes
= PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB
));
78 if (ExtendedTsegMbytes
== MCH_EXT_TSEG_MB_QUERY
) {
79 mQ35TsegMbytes
= PcdGet16 (PcdQ35TsegMbytes
);
85 "%a: QEMU offers an extended TSEG (%d MB)\n",
89 PcdStatus
= PcdSet16S (PcdQ35TsegMbytes
, ExtendedTsegMbytes
);
90 ASSERT_RETURN_ERROR (PcdStatus
);
91 mQ35TsegMbytes
= ExtendedTsegMbytes
;
96 Q35SmramAtDefaultSmbaseInitialization (
100 RETURN_STATUS PcdStatus
;
102 ASSERT (mHostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
);
104 mQ35SmramAtDefaultSmbase
= FALSE
;
105 PcdStatus
= PcdSetBoolS (PcdQ35SmramAtDefaultSmbase
,
106 mQ35SmramAtDefaultSmbase
);
107 ASSERT_RETURN_ERROR (PcdStatus
);
112 QemuUc32BaseInitialization (
116 UINT32 LowerMemorySize
;
123 if (mHostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
) {
125 // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
126 // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
127 // setting PcdPciExpressBaseAddress such that describing the
128 // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
129 // variable MTRRs (preferably 1 or 2).
131 ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress
) <= MAX_UINT32
);
132 mQemuUc32Base
= (UINT32
)FixedPcdGet64 (PcdPciExpressBaseAddress
);
136 ASSERT (mHostBridgeDevId
== INTEL_82441_DEVICE_ID
);
138 // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
139 // variable MTRR suffices by truncating the size to a whole power of two,
140 // while keeping the end affixed to 4GB. This will round the base up.
142 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
143 Uc32Size
= GetPowerOfTwo32 ((UINT32
)(SIZE_4GB
- LowerMemorySize
));
144 mQemuUc32Base
= (UINT32
)(SIZE_4GB
- Uc32Size
);
146 // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
147 // Therefore mQemuUc32Base is at least 2GB.
149 ASSERT (mQemuUc32Base
>= BASE_2GB
);
151 if (mQemuUc32Base
!= LowerMemorySize
) {
152 DEBUG ((DEBUG_VERBOSE
, "%a: rounded UC32 base from 0x%x up to 0x%x, for "
153 "an UC32 size of 0x%x\n", __FUNCTION__
, LowerMemorySize
, mQemuUc32Base
,
160 Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
161 of the 32-bit address range.
163 Find the highest exclusive >=4GB RAM address, or produce memory resource
164 descriptor HOBs for RAM entries that start at or above 4GB.
166 @param[out] MaxAddress If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
167 produces memory resource descriptor HOBs for RAM
168 entries that start at or above 4GB.
170 Otherwise, MaxAddress holds the highest exclusive
171 >=4GB RAM address on output. If QEMU's fw_cfg E820
172 RAM map contains no RAM entry that starts outside of
173 the 32-bit address range, then MaxAddress is exactly
176 @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
178 @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
179 whole multiple of sizeof(EFI_E820_ENTRY64). No
180 RAM entry was processed.
182 @return Error codes from QemuFwCfgFindFile(). No RAM
187 ScanOrAdd64BitE820Ram (
188 OUT UINT64
*MaxAddress OPTIONAL
192 FIRMWARE_CONFIG_ITEM FwCfgItem
;
194 EFI_E820_ENTRY64 E820Entry
;
197 Status
= QemuFwCfgFindFile ("etc/e820", &FwCfgItem
, &FwCfgSize
);
198 if (EFI_ERROR (Status
)) {
201 if (FwCfgSize
% sizeof E820Entry
!= 0) {
202 return EFI_PROTOCOL_ERROR
;
205 if (MaxAddress
!= NULL
) {
206 *MaxAddress
= BASE_4GB
;
209 QemuFwCfgSelectItem (FwCfgItem
);
210 for (Processed
= 0; Processed
< FwCfgSize
; Processed
+= sizeof E820Entry
) {
211 QemuFwCfgReadBytes (sizeof E820Entry
, &E820Entry
);
214 "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
220 if (E820Entry
.Type
== EfiAcpiAddressRangeMemory
&&
221 E820Entry
.BaseAddr
>= BASE_4GB
) {
222 if (MaxAddress
== NULL
) {
227 // Round up the start address, and round down the end address.
229 Base
= ALIGN_VALUE (E820Entry
.BaseAddr
, (UINT64
)EFI_PAGE_SIZE
);
230 End
= (E820Entry
.BaseAddr
+ E820Entry
.Length
) &
231 ~(UINT64
)EFI_PAGE_MASK
;
233 AddMemoryRangeHob (Base
, End
);
236 "%a: AddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
245 Candidate
= E820Entry
.BaseAddr
+ E820Entry
.Length
;
246 if (Candidate
> *MaxAddress
) {
247 *MaxAddress
= Candidate
;
250 "%a: MaxAddress=0x%Lx\n",
263 GetSystemMemorySizeBelow4gb (
271 // CMOS 0x34/0x35 specifies the system memory above 16 MB.
272 // * CMOS(0x35) is the high byte
273 // * CMOS(0x34) is the low byte
274 // * The size is specified in 64kb chunks
275 // * Since this is memory above 16MB, the 16MB must be added
276 // into the calculation to get the total memory size.
279 Cmos0x34
= (UINT8
) CmosRead8 (0x34);
280 Cmos0x35
= (UINT8
) CmosRead8 (0x35);
282 return (UINT32
) (((UINTN
)((Cmos0x35
<< 8) + Cmos0x34
) << 16) + SIZE_16MB
);
288 GetSystemMemorySizeAbove4gb (
295 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
296 // * CMOS(0x5d) is the most significant size byte
297 // * CMOS(0x5c) is the middle size byte
298 // * CMOS(0x5b) is the least significant size byte
299 // * The size is specified in 64kb chunks
303 for (CmosIndex
= 0x5d; CmosIndex
>= 0x5b; CmosIndex
--) {
304 Size
= (UINT32
) (Size
<< 8) + (UINT32
) CmosRead8 (CmosIndex
);
307 return LShiftU64 (Size
, 16);
312 Return the highest address that DXE could possibly use, plus one.
320 UINT64 FirstNonAddress
;
321 UINT64 Pci64Base
, Pci64Size
;
322 CHAR8 MbString
[7 + 1];
324 FIRMWARE_CONFIG_ITEM FwCfgItem
;
326 UINT64 HotPlugMemoryEnd
;
327 RETURN_STATUS PcdStatus
;
330 // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
335 // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
336 // address from it. This can express an address >= 4GB+1TB.
338 // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
339 // can only express a size smaller than 1TB), and add it to 4GB.
341 Status
= ScanOrAdd64BitE820Ram (&FirstNonAddress
);
342 if (EFI_ERROR (Status
)) {
343 FirstNonAddress
= BASE_4GB
+ GetSystemMemorySizeAbove4gb ();
347 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
348 // resources to 32-bit anyway. See DegradeResource() in
349 // "PciResourceSupport.c".
352 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
353 return FirstNonAddress
;
358 // Otherwise, in order to calculate the highest address plus one, we must
359 // consider the 64-bit PCI host aperture too. Fetch the default size.
361 Pci64Size
= PcdGet64 (PcdPciMmio64Size
);
364 // See if the user specified the number of megabytes for the 64-bit PCI host
365 // aperture. The number of non-NUL characters in MbString allows for
366 // 9,999,999 MB, which is approximately 10 TB.
368 // As signaled by the "X-" prefix, this knob is experimental, and might go
371 Status
= QemuFwCfgFindFile ("opt/ovmf/X-PciMmio64Mb", &FwCfgItem
,
373 if (!EFI_ERROR (Status
)) {
374 if (FwCfgSize
>= sizeof MbString
) {
376 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
379 QemuFwCfgSelectItem (FwCfgItem
);
380 QemuFwCfgReadBytes (FwCfgSize
, MbString
);
381 MbString
[FwCfgSize
] = '\0';
382 Pci64Size
= LShiftU64 (AsciiStrDecimalToUint64 (MbString
), 20);
386 if (Pci64Size
== 0) {
387 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
388 DEBUG ((EFI_D_INFO
, "%a: disabling 64-bit PCI host aperture\n",
390 PcdStatus
= PcdSet64S (PcdPciMmio64Size
, 0);
391 ASSERT_RETURN_ERROR (PcdStatus
);
395 // There's nothing more to do; the amount of memory above 4GB fully
396 // determines the highest address plus one. The memory hotplug area (see
397 // below) plays no role for the firmware in this case.
399 return FirstNonAddress
;
403 // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
404 // absolute, exclusive end address for the memory hotplug area. This area
405 // starts right at the end of the memory above 4GB. The 64-bit PCI host
406 // aperture must be placed above it.
408 Status
= QemuFwCfgFindFile ("etc/reserved-memory-end", &FwCfgItem
,
410 if (!EFI_ERROR (Status
) && FwCfgSize
== sizeof HotPlugMemoryEnd
) {
411 QemuFwCfgSelectItem (FwCfgItem
);
412 QemuFwCfgReadBytes (FwCfgSize
, &HotPlugMemoryEnd
);
413 DEBUG ((DEBUG_VERBOSE
, "%a: HotPlugMemoryEnd=0x%Lx\n", __FUNCTION__
,
416 ASSERT (HotPlugMemoryEnd
>= FirstNonAddress
);
417 FirstNonAddress
= HotPlugMemoryEnd
;
421 // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
422 // that the host can map it with 1GB hugepages. Follow suit.
424 Pci64Base
= ALIGN_VALUE (FirstNonAddress
, (UINT64
)SIZE_1GB
);
425 Pci64Size
= ALIGN_VALUE (Pci64Size
, (UINT64
)SIZE_1GB
);
428 // The 64-bit PCI host aperture should also be "naturally" aligned. The
429 // alignment is determined by rounding the size of the aperture down to the
430 // next smaller or equal power of two. That is, align the aperture by the
431 // largest BAR size that can fit into it.
433 Pci64Base
= ALIGN_VALUE (Pci64Base
, GetPowerOfTwo64 (Pci64Size
));
435 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
437 // The core PciHostBridgeDxe driver will automatically add this range to
438 // the GCD memory space map through our PciHostBridgeLib instance; here we
439 // only need to set the PCDs.
441 PcdStatus
= PcdSet64S (PcdPciMmio64Base
, Pci64Base
);
442 ASSERT_RETURN_ERROR (PcdStatus
);
443 PcdStatus
= PcdSet64S (PcdPciMmio64Size
, Pci64Size
);
444 ASSERT_RETURN_ERROR (PcdStatus
);
446 DEBUG ((EFI_D_INFO
, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
447 __FUNCTION__
, Pci64Base
, Pci64Size
));
451 // The useful address space ends with the 64-bit PCI host aperture.
453 FirstNonAddress
= Pci64Base
+ Pci64Size
;
454 return FirstNonAddress
;
459 Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
462 AddressWidthInitialization (
466 UINT64 FirstNonAddress
;
469 // As guest-physical memory size grows, the permanent PEI RAM requirements
470 // are dominated by the identity-mapping page tables built by the DXE IPL.
471 // The DXL IPL keys off of the physical address bits advertized in the CPU
472 // HOB. To conserve memory, we calculate the minimum address width here.
474 FirstNonAddress
= GetFirstNonAddress ();
475 mPhysMemAddressWidth
= (UINT8
)HighBitSet64 (FirstNonAddress
);
478 // If FirstNonAddress is not an integral power of two, then we need an
481 if ((FirstNonAddress
& (FirstNonAddress
- 1)) != 0) {
482 ++mPhysMemAddressWidth
;
486 // The minimum address width is 36 (covers up to and excluding 64 GB, which
487 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
488 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
489 // can simply assert that here, since 48 bits are good enough for 256 TB.
491 if (mPhysMemAddressWidth
<= 36) {
492 mPhysMemAddressWidth
= 36;
494 ASSERT (mPhysMemAddressWidth
<= 48);
499 Calculate the cap for the permanent PEI memory.
507 BOOLEAN Page1GSupport
;
515 // If DXE is 32-bit, then just return the traditional 64 MB cap.
518 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
524 // Dependent on physical address width, PEI memory allocations can be
525 // dominated by the page tables built for 64-bit DXE. So we key the cap off
526 // of those. The code below is based on CreateIdentityMappingPageTables() in
527 // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
529 Page1GSupport
= FALSE
;
530 if (PcdGetBool (PcdUse1GPageTable
)) {
531 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
532 if (RegEax
>= 0x80000001) {
533 AsmCpuid (0x80000001, NULL
, NULL
, NULL
, &RegEdx
);
534 if ((RegEdx
& BIT26
) != 0) {
535 Page1GSupport
= TRUE
;
540 if (mPhysMemAddressWidth
<= 39) {
542 PdpEntries
= 1 << (mPhysMemAddressWidth
- 30);
543 ASSERT (PdpEntries
<= 0x200);
545 Pml4Entries
= 1 << (mPhysMemAddressWidth
- 39);
546 ASSERT (Pml4Entries
<= 0x200);
550 TotalPages
= Page1GSupport
? Pml4Entries
+ 1 :
551 (PdpEntries
+ 1) * Pml4Entries
+ 1;
552 ASSERT (TotalPages
<= 0x40201);
555 // Add 64 MB for miscellaneous allocations. Note that for
556 // mPhysMemAddressWidth values close to 36, the cap will actually be
557 // dominated by this increment.
559 return (UINT32
)(EFI_PAGES_TO_SIZE (TotalPages
) + SIZE_64MB
);
564 Publish PEI core memory
566 @return EFI_SUCCESS The PEIM initialized successfully.
575 EFI_PHYSICAL_ADDRESS MemoryBase
;
577 UINT32 LowerMemorySize
;
580 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
581 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
583 // TSEG is chipped from the end of low RAM
585 LowerMemorySize
-= mQ35TsegMbytes
* SIZE_1MB
;
589 // If S3 is supported, then the S3 permanent PEI memory is placed next,
590 // downwards. Its size is primarily dictated by CpuMpPei. The formula below
591 // is an approximation.
594 mS3AcpiReservedMemorySize
= SIZE_512KB
+
596 PcdGet32 (PcdCpuApStackSize
);
597 mS3AcpiReservedMemoryBase
= LowerMemorySize
- mS3AcpiReservedMemorySize
;
598 LowerMemorySize
= mS3AcpiReservedMemoryBase
;
601 if (mBootMode
== BOOT_ON_S3_RESUME
) {
602 MemoryBase
= mS3AcpiReservedMemoryBase
;
603 MemorySize
= mS3AcpiReservedMemorySize
;
605 PeiMemoryCap
= GetPeiMemoryCap ();
606 DEBUG ((EFI_D_INFO
, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
607 __FUNCTION__
, mPhysMemAddressWidth
, PeiMemoryCap
>> 10));
610 // Determine the range of memory to use during PEI
612 // Technically we could lay the permanent PEI RAM over SEC's temporary
613 // decompression and scratch buffer even if "secure S3" is needed, since
614 // their lifetimes don't overlap. However, PeiFvInitialization() will cover
615 // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
616 // allocation HOB, and other allocations served from the permanent PEI RAM
617 // shouldn't overlap with that HOB.
619 MemoryBase
= mS3Supported
&& FeaturePcdGet (PcdSmmSmramRequire
) ?
620 PcdGet32 (PcdOvmfDecompressionScratchEnd
) :
621 PcdGet32 (PcdOvmfDxeMemFvBase
) + PcdGet32 (PcdOvmfDxeMemFvSize
);
622 MemorySize
= LowerMemorySize
- MemoryBase
;
623 if (MemorySize
> PeiMemoryCap
) {
624 MemoryBase
= LowerMemorySize
- PeiMemoryCap
;
625 MemorySize
= PeiMemoryCap
;
630 // Publish this memory to the PEI Core
632 Status
= PublishSystemMemory(MemoryBase
, MemorySize
);
633 ASSERT_EFI_ERROR (Status
);
640 Peform Memory Detection for QEMU / KVM
649 UINT64 LowerMemorySize
;
650 UINT64 UpperMemorySize
;
651 MTRR_SETTINGS MtrrSettings
;
654 DEBUG ((EFI_D_INFO
, "%a called\n", __FUNCTION__
));
657 // Determine total memory size available
659 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
660 UpperMemorySize
= GetSystemMemorySizeAbove4gb ();
662 if (mBootMode
== BOOT_ON_S3_RESUME
) {
664 // Create the following memory HOB as an exception on the S3 boot path.
666 // Normally we'd create memory HOBs only on the normal boot path. However,
667 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
668 // well, for "borrowing" a subset of it temporarily, for the AP startup
671 // CpuMpPei saves the original contents of the borrowed area in permanent
672 // PEI RAM, in a backup buffer allocated with the normal PEI services.
673 // CpuMpPei restores the original contents ("returns" the borrowed area) at
674 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
675 // transferring control to the OS's wakeup vector in the FACS.
677 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
678 // restore the original contents. Furthermore, we expect all such PEIMs
679 // (CpuMpPei included) to claim the borrowed areas by producing memory
680 // allocation HOBs, and to honor preexistent memory allocation HOBs when
681 // looking for an area to borrow.
683 AddMemoryRangeHob (0, BASE_512KB
+ BASE_128KB
);
686 // Create memory HOBs
688 AddMemoryRangeHob (0, BASE_512KB
+ BASE_128KB
);
690 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
693 TsegSize
= mQ35TsegMbytes
* SIZE_1MB
;
694 AddMemoryRangeHob (BASE_1MB
, LowerMemorySize
- TsegSize
);
695 AddReservedMemoryBaseSizeHob (LowerMemorySize
- TsegSize
, TsegSize
,
698 AddMemoryRangeHob (BASE_1MB
, LowerMemorySize
);
702 // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
703 // entries. Otherwise, create a single memory HOB with the flat >=4GB
704 // memory size read from the CMOS.
706 Status
= ScanOrAdd64BitE820Ram (NULL
);
707 if (EFI_ERROR (Status
) && UpperMemorySize
!= 0) {
708 AddMemoryBaseSizeHob (BASE_4GB
, UpperMemorySize
);
713 // We'd like to keep the following ranges uncached:
715 // - [LowerMemorySize, 4 GB)
717 // Everything else should be WB. Unfortunately, programming the inverse (ie.
718 // keeping the default UC, and configuring the complement set of the above as
719 // WB) is not reliable in general, because the end of the upper RAM can have
720 // practically any alignment, and we may not have enough variable MTRRs to
723 if (IsMtrrSupported ()) {
724 MtrrGetAllMtrrs (&MtrrSettings
);
727 // MTRRs disabled, fixed MTRRs disabled, default type is uncached
729 ASSERT ((MtrrSettings
.MtrrDefType
& BIT11
) == 0);
730 ASSERT ((MtrrSettings
.MtrrDefType
& BIT10
) == 0);
731 ASSERT ((MtrrSettings
.MtrrDefType
& 0xFF) == 0);
734 // flip default type to writeback
736 SetMem (&MtrrSettings
.Fixed
, sizeof MtrrSettings
.Fixed
, 0x06);
737 ZeroMem (&MtrrSettings
.Variables
, sizeof MtrrSettings
.Variables
);
738 MtrrSettings
.MtrrDefType
|= BIT11
| BIT10
| 6;
739 MtrrSetAllMtrrs (&MtrrSettings
);
742 // Set memory range from 640KB to 1MB to uncacheable
744 Status
= MtrrSetMemoryAttribute (BASE_512KB
+ BASE_128KB
,
745 BASE_1MB
- (BASE_512KB
+ BASE_128KB
), CacheUncacheable
);
746 ASSERT_EFI_ERROR (Status
);
749 // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
750 // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
752 Status
= MtrrSetMemoryAttribute (mQemuUc32Base
, SIZE_4GB
- mQemuUc32Base
,
754 ASSERT_EFI_ERROR (Status
);
759 Publish system RAM and reserve memory regions
763 InitializeRamRegions (
768 QemuInitializeRam ();
770 XenPublishRamRegions ();
773 if (mS3Supported
&& mBootMode
!= BOOT_ON_S3_RESUME
) {
775 // This is the memory range that will be used for PEI on S3 resume
777 BuildMemoryAllocationHob (
778 mS3AcpiReservedMemoryBase
,
779 mS3AcpiReservedMemorySize
,
784 // Cover the initial RAM area used as stack and temporary PEI heap.
786 // This is reserved as ACPI NVS so it can be used on S3 resume.
788 BuildMemoryAllocationHob (
789 PcdGet32 (PcdOvmfSecPeiTempRamBase
),
790 PcdGet32 (PcdOvmfSecPeiTempRamSize
),
795 // SEC stores its table of GUIDed section handlers here.
797 BuildMemoryAllocationHob (
798 PcdGet64 (PcdGuidedExtractHandlerTableAddress
),
799 PcdGet32 (PcdGuidedExtractHandlerTableSize
),
805 // Reserve the initial page tables built by the reset vector code.
807 // Since this memory range will be used by the Reset Vector on S3
808 // resume, it must be reserved as ACPI NVS.
810 BuildMemoryAllocationHob (
811 (EFI_PHYSICAL_ADDRESS
)(UINTN
) PcdGet32 (PcdOvmfSecPageTablesBase
),
812 (UINT64
)(UINTN
) PcdGet32 (PcdOvmfSecPageTablesSize
),
818 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
819 if (!FeaturePcdGet (PcdSmmSmramRequire
)) {
821 // Reserve the lock box storage area
823 // Since this memory range will be used on S3 resume, it must be
824 // reserved as ACPI NVS.
826 // If S3 is unsupported, then various drivers might still write to the
827 // LockBox area. We ought to prevent DXE from serving allocation requests
828 // such that they would overlap the LockBox storage.
831 (VOID
*)(UINTN
) PcdGet32 (PcdOvmfLockBoxStorageBase
),
832 (UINTN
) PcdGet32 (PcdOvmfLockBoxStorageSize
)
834 BuildMemoryAllocationHob (
835 (EFI_PHYSICAL_ADDRESS
)(UINTN
) PcdGet32 (PcdOvmfLockBoxStorageBase
),
836 (UINT64
)(UINTN
) PcdGet32 (PcdOvmfLockBoxStorageSize
),
837 mS3Supported
? EfiACPIMemoryNVS
: EfiBootServicesData
841 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
845 // Make sure the TSEG area that we reported as a reserved memory resource
846 // cannot be used for reserved memory allocations.
848 TsegSize
= mQ35TsegMbytes
* SIZE_1MB
;
849 BuildMemoryAllocationHob (
850 GetSystemMemorySizeBelow4gb() - TsegSize
,
852 EfiReservedMemoryType