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>
20 #include <Register/Intel/SmramSaveStateMap.h>
23 // The Library classes this module consumes
25 #include <Library/BaseLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DebugLib.h>
28 #include <Library/HobLib.h>
29 #include <Library/IoLib.h>
30 #include <Library/MemEncryptSevLib.h>
31 #include <Library/PcdLib.h>
32 #include <Library/PciLib.h>
33 #include <Library/PeimEntryPoint.h>
34 #include <Library/ResourcePublicationLib.h>
35 #include <Library/MtrrLib.h>
36 #include <Library/QemuFwCfgLib.h>
37 #include <Library/QemuFwCfgSimpleParserLib.h>
42 UINT8 mPhysMemAddressWidth
;
44 STATIC UINT32 mS3AcpiReservedMemoryBase
;
45 STATIC UINT32 mS3AcpiReservedMemorySize
;
47 STATIC UINT16 mQ35TsegMbytes
;
49 BOOLEAN mQ35SmramAtDefaultSmbase
;
54 Q35TsegMbytesInitialization (
58 UINT16 ExtendedTsegMbytes
;
59 RETURN_STATUS PcdStatus
;
61 ASSERT (mHostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
);
64 // Check if QEMU offers an extended TSEG.
66 // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB
67 // register, and reading back the register.
69 // On a QEMU machine type that does not offer an extended TSEG, the initial
70 // write overwrites whatever value a malicious guest OS may have placed in
71 // the (unimplemented) register, before entering S3 or rebooting.
72 // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.
74 // On a QEMU machine type that offers an extended TSEG, the initial write
75 // triggers an update to the register. Subsequently, the value read back
76 // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the
77 // number of megabytes.
79 PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB
), MCH_EXT_TSEG_MB_QUERY
);
80 ExtendedTsegMbytes
= PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB
));
81 if (ExtendedTsegMbytes
== MCH_EXT_TSEG_MB_QUERY
) {
82 mQ35TsegMbytes
= PcdGet16 (PcdQ35TsegMbytes
);
88 "%a: QEMU offers an extended TSEG (%d MB)\n",
92 PcdStatus
= PcdSet16S (PcdQ35TsegMbytes
, ExtendedTsegMbytes
);
93 ASSERT_RETURN_ERROR (PcdStatus
);
94 mQ35TsegMbytes
= ExtendedTsegMbytes
;
98 Q35SmramAtDefaultSmbaseInitialization (
102 RETURN_STATUS PcdStatus
;
104 ASSERT (mHostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
);
106 mQ35SmramAtDefaultSmbase
= FALSE
;
107 if (FeaturePcdGet (PcdCsmEnable
)) {
110 "%a: SMRAM at default SMBASE not checked due to CSM\n",
117 CtlReg
= DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL
);
118 PciWrite8 (CtlReg
, MCH_DEFAULT_SMBASE_QUERY
);
119 CtlRegVal
= PciRead8 (CtlReg
);
120 mQ35SmramAtDefaultSmbase
= (BOOLEAN
)(CtlRegVal
==
121 MCH_DEFAULT_SMBASE_IN_RAM
);
124 "%a: SMRAM at default SMBASE %a\n",
126 mQ35SmramAtDefaultSmbase
? "found" : "not found"
130 PcdStatus
= PcdSetBoolS (
131 PcdQ35SmramAtDefaultSmbase
,
132 mQ35SmramAtDefaultSmbase
134 ASSERT_RETURN_ERROR (PcdStatus
);
138 QemuUc32BaseInitialization (
142 UINT32 LowerMemorySize
;
145 if (mHostBridgeDevId
== 0xffff /* microvm */) {
149 if (mHostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
) {
151 // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
152 // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
153 // setting PcdPciExpressBaseAddress such that describing the
154 // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
155 // variable MTRRs (preferably 1 or 2).
157 ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress
) <= MAX_UINT32
);
158 mQemuUc32Base
= (UINT32
)FixedPcdGet64 (PcdPciExpressBaseAddress
);
162 ASSERT (mHostBridgeDevId
== INTEL_82441_DEVICE_ID
);
164 // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
165 // variable MTRR suffices by truncating the size to a whole power of two,
166 // while keeping the end affixed to 4GB. This will round the base up.
168 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
169 Uc32Size
= GetPowerOfTwo32 ((UINT32
)(SIZE_4GB
- LowerMemorySize
));
170 mQemuUc32Base
= (UINT32
)(SIZE_4GB
- Uc32Size
);
172 // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
173 // Therefore mQemuUc32Base is at least 2GB.
175 ASSERT (mQemuUc32Base
>= BASE_2GB
);
177 if (mQemuUc32Base
!= LowerMemorySize
) {
180 "%a: rounded UC32 base from 0x%x up to 0x%x, for "
181 "an UC32 size of 0x%x\n",
191 Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
192 of the 32-bit address range.
194 Find the highest exclusive >=4GB RAM address, or produce memory resource
195 descriptor HOBs for RAM entries that start at or above 4GB.
197 @param[out] MaxAddress If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
198 produces memory resource descriptor HOBs for RAM
199 entries that start at or above 4GB.
201 Otherwise, MaxAddress holds the highest exclusive
202 >=4GB RAM address on output. If QEMU's fw_cfg E820
203 RAM map contains no RAM entry that starts outside of
204 the 32-bit address range, then MaxAddress is exactly
207 @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
209 @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
210 whole multiple of sizeof(EFI_E820_ENTRY64). No
211 RAM entry was processed.
213 @return Error codes from QemuFwCfgFindFile(). No RAM
218 ScanOrAdd64BitE820Ram (
219 OUT UINT64
*MaxAddress OPTIONAL
223 FIRMWARE_CONFIG_ITEM FwCfgItem
;
225 EFI_E820_ENTRY64 E820Entry
;
228 Status
= QemuFwCfgFindFile ("etc/e820", &FwCfgItem
, &FwCfgSize
);
229 if (EFI_ERROR (Status
)) {
233 if (FwCfgSize
% sizeof E820Entry
!= 0) {
234 return EFI_PROTOCOL_ERROR
;
237 if (MaxAddress
!= NULL
) {
238 *MaxAddress
= BASE_4GB
;
241 QemuFwCfgSelectItem (FwCfgItem
);
242 for (Processed
= 0; Processed
< FwCfgSize
; Processed
+= sizeof E820Entry
) {
243 QemuFwCfgReadBytes (sizeof E820Entry
, &E820Entry
);
246 "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
252 if ((E820Entry
.Type
== EfiAcpiAddressRangeMemory
) &&
253 (E820Entry
.BaseAddr
>= BASE_4GB
))
255 if (MaxAddress
== NULL
) {
260 // Round up the start address, and round down the end address.
262 Base
= ALIGN_VALUE (E820Entry
.BaseAddr
, (UINT64
)EFI_PAGE_SIZE
);
263 End
= (E820Entry
.BaseAddr
+ E820Entry
.Length
) &
264 ~(UINT64
)EFI_PAGE_MASK
;
266 AddMemoryRangeHob (Base
, End
);
269 "%a: AddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
278 Candidate
= E820Entry
.BaseAddr
+ E820Entry
.Length
;
279 if (Candidate
> *MaxAddress
) {
280 *MaxAddress
= Candidate
;
283 "%a: MaxAddress=0x%Lx\n",
296 GetSystemMemorySizeBelow4gb (
304 // CMOS 0x34/0x35 specifies the system memory above 16 MB.
305 // * CMOS(0x35) is the high byte
306 // * CMOS(0x34) is the low byte
307 // * The size is specified in 64kb chunks
308 // * Since this is memory above 16MB, the 16MB must be added
309 // into the calculation to get the total memory size.
312 Cmos0x34
= (UINT8
)CmosRead8 (0x34);
313 Cmos0x35
= (UINT8
)CmosRead8 (0x35);
315 return (UINT32
)(((UINTN
)((Cmos0x35
<< 8) + Cmos0x34
) << 16) + SIZE_16MB
);
320 GetSystemMemorySizeAbove4gb (
327 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
328 // * CMOS(0x5d) is the most significant size byte
329 // * CMOS(0x5c) is the middle size byte
330 // * CMOS(0x5b) is the least significant size byte
331 // * The size is specified in 64kb chunks
335 for (CmosIndex
= 0x5d; CmosIndex
>= 0x5b; CmosIndex
--) {
336 Size
= (UINT32
)(Size
<< 8) + (UINT32
)CmosRead8 (CmosIndex
);
339 return LShiftU64 (Size
, 16);
343 Return the highest address that DXE could possibly use, plus one.
351 UINT64 FirstNonAddress
;
352 UINT64 Pci64Base
, Pci64Size
;
353 UINT32 FwCfgPciMmio64Mb
;
355 FIRMWARE_CONFIG_ITEM FwCfgItem
;
357 UINT64 HotPlugMemoryEnd
;
358 RETURN_STATUS PcdStatus
;
361 // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
366 // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
367 // address from it. This can express an address >= 4GB+1TB.
369 // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
370 // can only express a size smaller than 1TB), and add it to 4GB.
372 Status
= ScanOrAdd64BitE820Ram (&FirstNonAddress
);
373 if (EFI_ERROR (Status
)) {
374 FirstNonAddress
= BASE_4GB
+ GetSystemMemorySizeAbove4gb ();
378 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
379 // resources to 32-bit anyway. See DegradeResource() in
380 // "PciResourceSupport.c".
383 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
384 return FirstNonAddress
;
390 // Otherwise, in order to calculate the highest address plus one, we must
391 // consider the 64-bit PCI host aperture too. Fetch the default size.
393 Pci64Size
= PcdGet64 (PcdPciMmio64Size
);
396 // See if the user specified the number of megabytes for the 64-bit PCI host
397 // aperture. Accept an aperture size up to 16TB.
399 // As signaled by the "X-" prefix, this knob is experimental, and might go
402 Status
= QemuFwCfgParseUint32 (
403 "opt/ovmf/X-PciMmio64Mb",
408 case EFI_UNSUPPORTED
:
412 if (FwCfgPciMmio64Mb
<= 0x1000000) {
413 Pci64Size
= LShiftU64 (FwCfgPciMmio64Mb
, 20);
423 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
429 if (Pci64Size
== 0) {
430 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
433 "%a: disabling 64-bit PCI host aperture\n",
436 PcdStatus
= PcdSet64S (PcdPciMmio64Size
, 0);
437 ASSERT_RETURN_ERROR (PcdStatus
);
441 // There's nothing more to do; the amount of memory above 4GB fully
442 // determines the highest address plus one. The memory hotplug area (see
443 // below) plays no role for the firmware in this case.
445 return FirstNonAddress
;
449 // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
450 // absolute, exclusive end address for the memory hotplug area. This area
451 // starts right at the end of the memory above 4GB. The 64-bit PCI host
452 // aperture must be placed above it.
454 Status
= QemuFwCfgFindFile (
455 "etc/reserved-memory-end",
459 if (!EFI_ERROR (Status
) && (FwCfgSize
== sizeof HotPlugMemoryEnd
)) {
460 QemuFwCfgSelectItem (FwCfgItem
);
461 QemuFwCfgReadBytes (FwCfgSize
, &HotPlugMemoryEnd
);
464 "%a: HotPlugMemoryEnd=0x%Lx\n",
469 ASSERT (HotPlugMemoryEnd
>= FirstNonAddress
);
470 FirstNonAddress
= HotPlugMemoryEnd
;
474 // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
475 // that the host can map it with 1GB hugepages. Follow suit.
477 Pci64Base
= ALIGN_VALUE (FirstNonAddress
, (UINT64
)SIZE_1GB
);
478 Pci64Size
= ALIGN_VALUE (Pci64Size
, (UINT64
)SIZE_1GB
);
481 // The 64-bit PCI host aperture should also be "naturally" aligned. The
482 // alignment is determined by rounding the size of the aperture down to the
483 // next smaller or equal power of two. That is, align the aperture by the
484 // largest BAR size that can fit into it.
486 Pci64Base
= ALIGN_VALUE (Pci64Base
, GetPowerOfTwo64 (Pci64Size
));
488 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
490 // The core PciHostBridgeDxe driver will automatically add this range to
491 // the GCD memory space map through our PciHostBridgeLib instance; here we
492 // only need to set the PCDs.
494 PcdStatus
= PcdSet64S (PcdPciMmio64Base
, Pci64Base
);
495 ASSERT_RETURN_ERROR (PcdStatus
);
496 PcdStatus
= PcdSet64S (PcdPciMmio64Size
, Pci64Size
);
497 ASSERT_RETURN_ERROR (PcdStatus
);
501 "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
509 // The useful address space ends with the 64-bit PCI host aperture.
511 FirstNonAddress
= Pci64Base
+ Pci64Size
;
512 return FirstNonAddress
;
516 Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
519 AddressWidthInitialization (
523 UINT64 FirstNonAddress
;
526 // As guest-physical memory size grows, the permanent PEI RAM requirements
527 // are dominated by the identity-mapping page tables built by the DXE IPL.
528 // The DXL IPL keys off of the physical address bits advertized in the CPU
529 // HOB. To conserve memory, we calculate the minimum address width here.
531 FirstNonAddress
= GetFirstNonAddress ();
532 mPhysMemAddressWidth
= (UINT8
)HighBitSet64 (FirstNonAddress
);
535 // If FirstNonAddress is not an integral power of two, then we need an
538 if ((FirstNonAddress
& (FirstNonAddress
- 1)) != 0) {
539 ++mPhysMemAddressWidth
;
543 // The minimum address width is 36 (covers up to and excluding 64 GB, which
544 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
545 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
546 // can simply assert that here, since 48 bits are good enough for 256 TB.
548 if (mPhysMemAddressWidth
<= 36) {
549 mPhysMemAddressWidth
= 36;
552 ASSERT (mPhysMemAddressWidth
<= 48);
556 Calculate the cap for the permanent PEI memory.
564 BOOLEAN Page1GSupport
;
572 // If DXE is 32-bit, then just return the traditional 64 MB cap.
575 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
582 // Dependent on physical address width, PEI memory allocations can be
583 // dominated by the page tables built for 64-bit DXE. So we key the cap off
584 // of those. The code below is based on CreateIdentityMappingPageTables() in
585 // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
587 Page1GSupport
= FALSE
;
588 if (PcdGetBool (PcdUse1GPageTable
)) {
589 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
590 if (RegEax
>= 0x80000001) {
591 AsmCpuid (0x80000001, NULL
, NULL
, NULL
, &RegEdx
);
592 if ((RegEdx
& BIT26
) != 0) {
593 Page1GSupport
= TRUE
;
598 if (mPhysMemAddressWidth
<= 39) {
600 PdpEntries
= 1 << (mPhysMemAddressWidth
- 30);
601 ASSERT (PdpEntries
<= 0x200);
603 Pml4Entries
= 1 << (mPhysMemAddressWidth
- 39);
604 ASSERT (Pml4Entries
<= 0x200);
608 TotalPages
= Page1GSupport
? Pml4Entries
+ 1 :
609 (PdpEntries
+ 1) * Pml4Entries
+ 1;
610 ASSERT (TotalPages
<= 0x40201);
613 // Add 64 MB for miscellaneous allocations. Note that for
614 // mPhysMemAddressWidth values close to 36, the cap will actually be
615 // dominated by this increment.
617 return (UINT32
)(EFI_PAGES_TO_SIZE (TotalPages
) + SIZE_64MB
);
621 Publish PEI core memory
623 @return EFI_SUCCESS The PEIM initialized successfully.
632 EFI_PHYSICAL_ADDRESS MemoryBase
;
634 UINT32 LowerMemorySize
;
637 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
638 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
640 // TSEG is chipped from the end of low RAM
642 LowerMemorySize
-= mQ35TsegMbytes
* SIZE_1MB
;
646 // If S3 is supported, then the S3 permanent PEI memory is placed next,
647 // downwards. Its size is primarily dictated by CpuMpPei. The formula below
648 // is an approximation.
651 mS3AcpiReservedMemorySize
= SIZE_512KB
+
653 PcdGet32 (PcdCpuApStackSize
);
654 mS3AcpiReservedMemoryBase
= LowerMemorySize
- mS3AcpiReservedMemorySize
;
655 LowerMemorySize
= mS3AcpiReservedMemoryBase
;
658 if (mBootMode
== BOOT_ON_S3_RESUME
) {
659 MemoryBase
= mS3AcpiReservedMemoryBase
;
660 MemorySize
= mS3AcpiReservedMemorySize
;
662 PeiMemoryCap
= GetPeiMemoryCap ();
665 "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
667 mPhysMemAddressWidth
,
672 // Determine the range of memory to use during PEI
674 // Technically we could lay the permanent PEI RAM over SEC's temporary
675 // decompression and scratch buffer even if "secure S3" is needed, since
676 // their lifetimes don't overlap. However, PeiFvInitialization() will cover
677 // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
678 // allocation HOB, and other allocations served from the permanent PEI RAM
679 // shouldn't overlap with that HOB.
681 MemoryBase
= mS3Supported
&& FeaturePcdGet (PcdSmmSmramRequire
) ?
682 PcdGet32 (PcdOvmfDecompressionScratchEnd
) :
683 PcdGet32 (PcdOvmfDxeMemFvBase
) + PcdGet32 (PcdOvmfDxeMemFvSize
);
684 MemorySize
= LowerMemorySize
- MemoryBase
;
685 if (MemorySize
> PeiMemoryCap
) {
686 MemoryBase
= LowerMemorySize
- PeiMemoryCap
;
687 MemorySize
= PeiMemoryCap
;
692 // MEMFD_BASE_ADDRESS separates the SMRAM at the default SMBASE from the
693 // normal boot permanent PEI RAM. Regarding the S3 boot path, the S3
694 // permanent PEI RAM is located even higher.
696 if (FeaturePcdGet (PcdSmmSmramRequire
) && mQ35SmramAtDefaultSmbase
) {
697 ASSERT (SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
<= MemoryBase
);
701 // Publish this memory to the PEI Core
703 Status
= PublishSystemMemory (MemoryBase
, MemorySize
);
704 ASSERT_EFI_ERROR (Status
);
711 QemuInitializeRamBelow1gb (
715 if (FeaturePcdGet (PcdSmmSmramRequire
) && mQ35SmramAtDefaultSmbase
) {
716 AddMemoryRangeHob (0, SMM_DEFAULT_SMBASE
);
717 AddReservedMemoryBaseSizeHob (
719 MCH_DEFAULT_SMBASE_SIZE
,
723 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
< BASE_512KB
+ BASE_128KB
,
724 "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
727 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
,
728 BASE_512KB
+ BASE_128KB
731 AddMemoryRangeHob (0, BASE_512KB
+ BASE_128KB
);
736 Peform Memory Detection for QEMU / KVM
745 UINT64 LowerMemorySize
;
746 UINT64 UpperMemorySize
;
747 MTRR_SETTINGS MtrrSettings
;
750 DEBUG ((DEBUG_INFO
, "%a called\n", __FUNCTION__
));
753 // Determine total memory size available
755 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
756 UpperMemorySize
= GetSystemMemorySizeAbove4gb ();
758 if (mBootMode
== BOOT_ON_S3_RESUME
) {
760 // Create the following memory HOB as an exception on the S3 boot path.
762 // Normally we'd create memory HOBs only on the normal boot path. However,
763 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
764 // well, for "borrowing" a subset of it temporarily, for the AP startup
767 // CpuMpPei saves the original contents of the borrowed area in permanent
768 // PEI RAM, in a backup buffer allocated with the normal PEI services.
769 // CpuMpPei restores the original contents ("returns" the borrowed area) at
770 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
771 // transferring control to the OS's wakeup vector in the FACS.
773 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
774 // restore the original contents. Furthermore, we expect all such PEIMs
775 // (CpuMpPei included) to claim the borrowed areas by producing memory
776 // allocation HOBs, and to honor preexistent memory allocation HOBs when
777 // looking for an area to borrow.
779 QemuInitializeRamBelow1gb ();
782 // Create memory HOBs
784 QemuInitializeRamBelow1gb ();
786 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
789 TsegSize
= mQ35TsegMbytes
* SIZE_1MB
;
790 AddMemoryRangeHob (BASE_1MB
, LowerMemorySize
- TsegSize
);
791 AddReservedMemoryBaseSizeHob (
792 LowerMemorySize
- TsegSize
,
797 AddMemoryRangeHob (BASE_1MB
, LowerMemorySize
);
801 // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
802 // entries. Otherwise, create a single memory HOB with the flat >=4GB
803 // memory size read from the CMOS.
805 Status
= ScanOrAdd64BitE820Ram (NULL
);
806 if (EFI_ERROR (Status
) && (UpperMemorySize
!= 0)) {
807 AddMemoryBaseSizeHob (BASE_4GB
, UpperMemorySize
);
812 // We'd like to keep the following ranges uncached:
814 // - [LowerMemorySize, 4 GB)
816 // Everything else should be WB. Unfortunately, programming the inverse (ie.
817 // keeping the default UC, and configuring the complement set of the above as
818 // WB) is not reliable in general, because the end of the upper RAM can have
819 // practically any alignment, and we may not have enough variable MTRRs to
822 if (IsMtrrSupported ()) {
823 MtrrGetAllMtrrs (&MtrrSettings
);
826 // MTRRs disabled, fixed MTRRs disabled, default type is uncached
828 ASSERT ((MtrrSettings
.MtrrDefType
& BIT11
) == 0);
829 ASSERT ((MtrrSettings
.MtrrDefType
& BIT10
) == 0);
830 ASSERT ((MtrrSettings
.MtrrDefType
& 0xFF) == 0);
833 // flip default type to writeback
835 SetMem (&MtrrSettings
.Fixed
, sizeof MtrrSettings
.Fixed
, 0x06);
836 ZeroMem (&MtrrSettings
.Variables
, sizeof MtrrSettings
.Variables
);
837 MtrrSettings
.MtrrDefType
|= BIT11
| BIT10
| 6;
838 MtrrSetAllMtrrs (&MtrrSettings
);
841 // Set memory range from 640KB to 1MB to uncacheable
843 Status
= MtrrSetMemoryAttribute (
844 BASE_512KB
+ BASE_128KB
,
845 BASE_1MB
- (BASE_512KB
+ BASE_128KB
),
848 ASSERT_EFI_ERROR (Status
);
851 // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
852 // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
854 Status
= MtrrSetMemoryAttribute (
856 SIZE_4GB
- mQemuUc32Base
,
859 ASSERT_EFI_ERROR (Status
);
864 Publish system RAM and reserve memory regions
868 InitializeRamRegions (
872 QemuInitializeRam ();
874 if (mS3Supported
&& (mBootMode
!= BOOT_ON_S3_RESUME
)) {
876 // This is the memory range that will be used for PEI on S3 resume
878 BuildMemoryAllocationHob (
879 mS3AcpiReservedMemoryBase
,
880 mS3AcpiReservedMemorySize
,
885 // Cover the initial RAM area used as stack and temporary PEI heap.
887 // This is reserved as ACPI NVS so it can be used on S3 resume.
889 BuildMemoryAllocationHob (
890 PcdGet32 (PcdOvmfSecPeiTempRamBase
),
891 PcdGet32 (PcdOvmfSecPeiTempRamSize
),
896 // SEC stores its table of GUIDed section handlers here.
898 BuildMemoryAllocationHob (
899 PcdGet64 (PcdGuidedExtractHandlerTableAddress
),
900 PcdGet32 (PcdGuidedExtractHandlerTableSize
),
906 // Reserve the initial page tables built by the reset vector code.
908 // Since this memory range will be used by the Reset Vector on S3
909 // resume, it must be reserved as ACPI NVS.
911 BuildMemoryAllocationHob (
912 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecPageTablesBase
),
913 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecPageTablesSize
),
917 if (MemEncryptSevEsIsEnabled ()) {
919 // If SEV-ES is enabled, reserve the GHCB-related memory area. This
920 // includes the extra page table used to break down the 2MB page
921 // mapping into 4KB page entries where the GHCB resides and the
924 // Since this memory range will be used by the Reset Vector on S3
925 // resume, it must be reserved as ACPI NVS.
927 BuildMemoryAllocationHob (
928 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbPageTableBase
),
929 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbPageTableSize
),
932 BuildMemoryAllocationHob (
933 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbBase
),
934 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbSize
),
937 BuildMemoryAllocationHob (
938 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbBackupBase
),
939 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbBackupSize
),
947 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
948 if (!FeaturePcdGet (PcdSmmSmramRequire
)) {
950 // Reserve the lock box storage area
952 // Since this memory range will be used on S3 resume, it must be
953 // reserved as ACPI NVS.
955 // If S3 is unsupported, then various drivers might still write to the
956 // LockBox area. We ought to prevent DXE from serving allocation requests
957 // such that they would overlap the LockBox storage.
960 (VOID
*)(UINTN
)PcdGet32 (PcdOvmfLockBoxStorageBase
),
961 (UINTN
)PcdGet32 (PcdOvmfLockBoxStorageSize
)
963 BuildMemoryAllocationHob (
964 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfLockBoxStorageBase
),
965 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfLockBoxStorageSize
),
966 mS3Supported
? EfiACPIMemoryNVS
: EfiBootServicesData
970 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
974 // Make sure the TSEG area that we reported as a reserved memory resource
975 // cannot be used for reserved memory allocations.
977 TsegSize
= mQ35TsegMbytes
* SIZE_1MB
;
978 BuildMemoryAllocationHob (
979 GetSystemMemorySizeBelow4gb () - TsegSize
,
981 EfiReservedMemoryType
984 // Similarly, allocate away the (already reserved) SMRAM at the default
985 // SMBASE, if it exists.
987 if (mQ35SmramAtDefaultSmbase
) {
988 BuildMemoryAllocationHob (
990 MCH_DEFAULT_SMBASE_SIZE
,
991 EfiReservedMemoryType
997 if (FixedPcdGet32 (PcdOvmfWorkAreaSize
) != 0) {
999 // Reserve the work area.
1001 // Since this memory range will be used by the Reset Vector on S3
1002 // resume, it must be reserved as ACPI NVS.
1004 // If S3 is unsupported, then various drivers might still write to the
1005 // work area. We ought to prevent DXE from serving allocation requests
1006 // such that they would overlap the work area.
1008 BuildMemoryAllocationHob (
1009 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FixedPcdGet32 (PcdOvmfWorkAreaBase
),
1010 (UINT64
)(UINTN
)FixedPcdGet32 (PcdOvmfWorkAreaSize
),
1011 mS3Supported
? EfiACPIMemoryNVS
: EfiBootServicesData