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>
19 #include <IndustryStandard/CloudHv.h>
20 #include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>
22 #include <Register/Intel/SmramSaveStateMap.h>
25 // The Library classes this module consumes
27 #include <Library/BaseLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/HardwareInfoLib.h>
31 #include <Library/HobLib.h>
32 #include <Library/IoLib.h>
33 #include <Library/MemEncryptSevLib.h>
34 #include <Library/PcdLib.h>
35 #include <Library/PciLib.h>
36 #include <Library/PeimEntryPoint.h>
37 #include <Library/ResourcePublicationLib.h>
38 #include <Library/MtrrLib.h>
39 #include <Library/QemuFwCfgLib.h>
40 #include <Library/QemuFwCfgSimpleParserLib.h>
41 #include <Library/TdxLib.h>
43 #include <Library/PlatformInitLib.h>
47 PlatformQemuUc32BaseInitialization (
48 IN OUT EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
51 UINT32 LowerMemorySize
;
53 if (PlatformInfoHob
->HostBridgeDevId
== 0xffff /* microvm */) {
57 if (PlatformInfoHob
->HostBridgeDevId
== INTEL_Q35_MCH_DEVICE_ID
) {
59 // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
60 // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
61 // setting PcdPciExpressBaseAddress such that describing the
62 // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
63 // variable MTRRs (preferably 1 or 2).
65 ASSERT (PcdGet64 (PcdPciExpressBaseAddress
) <= MAX_UINT32
);
66 PlatformInfoHob
->Uc32Base
= (UINT32
)PcdGet64 (PcdPciExpressBaseAddress
);
70 if (PlatformInfoHob
->HostBridgeDevId
== CLOUDHV_DEVICE_ID
) {
71 PlatformInfoHob
->Uc32Size
= CLOUDHV_MMIO_HOLE_SIZE
;
72 PlatformInfoHob
->Uc32Base
= CLOUDHV_MMIO_HOLE_ADDRESS
;
76 ASSERT (PlatformInfoHob
->HostBridgeDevId
== INTEL_82441_DEVICE_ID
);
78 // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
79 // variable MTRR suffices by truncating the size to a whole power of two,
80 // while keeping the end affixed to 4GB. This will round the base up.
82 LowerMemorySize
= PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob
);
83 PlatformInfoHob
->Uc32Size
= GetPowerOfTwo32 ((UINT32
)(SIZE_4GB
- LowerMemorySize
));
84 PlatformInfoHob
->Uc32Base
= (UINT32
)(SIZE_4GB
- PlatformInfoHob
->Uc32Size
);
86 // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
87 // Therefore Uc32Base is at least 2GB.
89 ASSERT (PlatformInfoHob
->Uc32Base
>= BASE_2GB
);
91 if (PlatformInfoHob
->Uc32Base
!= LowerMemorySize
) {
94 "%a: rounded UC32 base from 0x%x up to 0x%x, for "
95 "an UC32 size of 0x%x\n",
98 PlatformInfoHob
->Uc32Base
,
99 PlatformInfoHob
->Uc32Size
105 Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
106 of the 32-bit address range.
108 Find the highest exclusive >=4GB RAM address, or produce memory resource
109 descriptor HOBs for RAM entries that start at or above 4GB.
111 @param[out] MaxAddress If MaxAddress is NULL, then PlatformScanOrAdd64BitE820Ram()
112 produces memory resource descriptor HOBs for RAM
113 entries that start at or above 4GB.
115 Otherwise, MaxAddress holds the highest exclusive
116 >=4GB RAM address on output. If QEMU's fw_cfg E820
117 RAM map contains no RAM entry that starts outside of
118 the 32-bit address range, then MaxAddress is exactly
121 @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
123 @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
124 whole multiple of sizeof(EFI_E820_ENTRY64). No
125 RAM entry was processed.
127 @return Error codes from QemuFwCfgFindFile(). No RAM
132 PlatformScanOrAdd64BitE820Ram (
133 IN BOOLEAN AddHighHob
,
134 OUT UINT64
*LowMemory OPTIONAL
,
135 OUT UINT64
*MaxAddress OPTIONAL
139 FIRMWARE_CONFIG_ITEM FwCfgItem
;
141 EFI_E820_ENTRY64 E820Entry
;
144 Status
= QemuFwCfgFindFile ("etc/e820", &FwCfgItem
, &FwCfgSize
);
145 if (EFI_ERROR (Status
)) {
149 if (FwCfgSize
% sizeof E820Entry
!= 0) {
150 return EFI_PROTOCOL_ERROR
;
153 if (LowMemory
!= NULL
) {
157 if (MaxAddress
!= NULL
) {
158 *MaxAddress
= BASE_4GB
;
161 QemuFwCfgSelectItem (FwCfgItem
);
162 for (Processed
= 0; Processed
< FwCfgSize
; Processed
+= sizeof E820Entry
) {
163 QemuFwCfgReadBytes (sizeof E820Entry
, &E820Entry
);
166 "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
172 if (E820Entry
.Type
== EfiAcpiAddressRangeMemory
) {
173 if (AddHighHob
&& (E820Entry
.BaseAddr
>= BASE_4GB
)) {
178 // Round up the start address, and round down the end address.
180 Base
= ALIGN_VALUE (E820Entry
.BaseAddr
, (UINT64
)EFI_PAGE_SIZE
);
181 End
= (E820Entry
.BaseAddr
+ E820Entry
.Length
) &
182 ~(UINT64
)EFI_PAGE_MASK
;
184 PlatformAddMemoryRangeHob (Base
, End
);
187 "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
195 if (MaxAddress
|| LowMemory
) {
198 Candidate
= E820Entry
.BaseAddr
+ E820Entry
.Length
;
199 if (MaxAddress
&& (Candidate
> *MaxAddress
)) {
200 *MaxAddress
= Candidate
;
203 "%a: MaxAddress=0x%Lx\n",
209 if (LowMemory
&& (Candidate
> *LowMemory
) && (Candidate
< BASE_4GB
)) {
210 *LowMemory
= Candidate
;
213 "%a: LowMemory=0x%Lx\n",
228 @param Entries Pointer to PVH memmap
229 @param Count Number of entries
234 GetPvhMemmapEntries (
235 struct hvm_memmap_table_entry
**Entries
,
239 UINT32
*PVHResetVectorData
;
240 struct hvm_start_info
*pvh_start_info
;
242 PVHResetVectorData
= (VOID
*)(UINTN
)PcdGet32 (PcdXenPvhStartOfDayStructPtr
);
243 if (PVHResetVectorData
== 0) {
244 return EFI_NOT_FOUND
;
247 pvh_start_info
= (struct hvm_start_info
*)(UINTN
)PVHResetVectorData
[0];
249 *Entries
= (struct hvm_memmap_table_entry
*)(UINTN
)pvh_start_info
->memmap_paddr
;
250 *Count
= pvh_start_info
->memmap_entries
;
257 GetHighestSystemMemoryAddressFromPvhMemmap (
261 struct hvm_memmap_table_entry
*Memmap
;
262 UINT32 MemmapEntriesCount
;
263 struct hvm_memmap_table_entry
*Entry
;
266 UINT64 HighestAddress
;
271 Status
= GetPvhMemmapEntries (&Memmap
, &MemmapEntriesCount
);
272 ASSERT_EFI_ERROR (Status
);
274 for (Loop
= 0; Loop
< MemmapEntriesCount
; Loop
++) {
275 Entry
= Memmap
+ Loop
;
276 EntryEnd
= Entry
->addr
+ Entry
->size
;
278 if ((Entry
->type
== XEN_HVM_MEMMAP_TYPE_RAM
) &&
279 (EntryEnd
> HighestAddress
))
281 if (Below4gb
&& (EntryEnd
<= BASE_4GB
)) {
282 HighestAddress
= EntryEnd
;
283 } else if (!Below4gb
&& (EntryEnd
>= BASE_4GB
)) {
284 HighestAddress
= EntryEnd
;
289 return HighestAddress
;
294 PlatformGetSystemMemorySizeBelow4gb (
295 IN EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
299 UINT64 LowerMemorySize
= 0;
303 if (PlatformInfoHob
->HostBridgeDevId
== CLOUDHV_DEVICE_ID
) {
304 // Get the information from PVH memmap
305 return (UINT32
)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE
);
308 Status
= PlatformScanOrAdd64BitE820Ram (FALSE
, &LowerMemorySize
, NULL
);
309 if ((Status
== EFI_SUCCESS
) && (LowerMemorySize
> 0)) {
310 return (UINT32
)LowerMemorySize
;
314 // CMOS 0x34/0x35 specifies the system memory above 16 MB.
315 // * CMOS(0x35) is the high byte
316 // * CMOS(0x34) is the low byte
317 // * The size is specified in 64kb chunks
318 // * Since this is memory above 16MB, the 16MB must be added
319 // into the calculation to get the total memory size.
322 Cmos0x34
= (UINT8
)PlatformCmosRead8 (0x34);
323 Cmos0x35
= (UINT8
)PlatformCmosRead8 (0x35);
325 return (UINT32
)(((UINTN
)((Cmos0x35
<< 8) + Cmos0x34
) << 16) + SIZE_16MB
);
330 PlatformGetSystemMemorySizeAbove4gb (
337 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
338 // * CMOS(0x5d) is the most significant size byte
339 // * CMOS(0x5c) is the middle size byte
340 // * CMOS(0x5b) is the least significant size byte
341 // * The size is specified in 64kb chunks
345 for (CmosIndex
= 0x5d; CmosIndex
>= 0x5b; CmosIndex
--) {
346 Size
= (UINT32
)(Size
<< 8) + (UINT32
)PlatformCmosRead8 (CmosIndex
);
349 return LShiftU64 (Size
, 16);
353 Return the highest address that DXE could possibly use, plus one.
357 PlatformGetFirstNonAddress (
358 IN OUT EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
361 UINT64 FirstNonAddress
;
362 UINT32 FwCfgPciMmio64Mb
;
364 FIRMWARE_CONFIG_ITEM FwCfgItem
;
366 UINT64 HotPlugMemoryEnd
;
369 // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
374 // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
375 // address from it. This can express an address >= 4GB+1TB.
377 // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
378 // can only express a size smaller than 1TB), and add it to 4GB.
380 Status
= PlatformScanOrAdd64BitE820Ram (FALSE
, NULL
, &FirstNonAddress
);
381 if (EFI_ERROR (Status
)) {
382 FirstNonAddress
= BASE_4GB
+ PlatformGetSystemMemorySizeAbove4gb ();
386 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
387 // resources to 32-bit anyway. See DegradeResource() in
388 // "PciResourceSupport.c".
391 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
392 return FirstNonAddress
;
398 // See if the user specified the number of megabytes for the 64-bit PCI host
399 // aperture. Accept an aperture size up to 16TB.
401 // As signaled by the "X-" prefix, this knob is experimental, and might go
404 Status
= QemuFwCfgParseUint32 (
405 "opt/ovmf/X-PciMmio64Mb",
410 case EFI_UNSUPPORTED
:
414 if (FwCfgPciMmio64Mb
<= 0x1000000) {
415 PlatformInfoHob
->PcdPciMmio64Size
= LShiftU64 (FwCfgPciMmio64Mb
, 20);
425 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
431 if (PlatformInfoHob
->PcdPciMmio64Size
== 0) {
432 if (PlatformInfoHob
->BootMode
!= BOOT_ON_S3_RESUME
) {
435 "%a: disabling 64-bit PCI host aperture\n",
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 PlatformInfoHob
->PcdPciMmio64Base
= ALIGN_VALUE (FirstNonAddress
, (UINT64
)SIZE_1GB
);
478 PlatformInfoHob
->PcdPciMmio64Size
= ALIGN_VALUE (PlatformInfoHob
->PcdPciMmio64Size
, (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 PlatformInfoHob
->PcdPciMmio64Base
= ALIGN_VALUE (PlatformInfoHob
->PcdPciMmio64Base
, GetPowerOfTwo64 (PlatformInfoHob
->PcdPciMmio64Size
));
489 // The useful address space ends with the 64-bit PCI host aperture.
491 FirstNonAddress
= PlatformInfoHob
->PcdPciMmio64Base
+ PlatformInfoHob
->PcdPciMmio64Size
;
492 return FirstNonAddress
;
496 * Use CPUID to figure physical address width. Does *not* work
497 * reliable on qemu. For historical reasons qemu returns phys-bits=40
498 * even in case the host machine supports less than that.
500 * qemu has a cpu property (host-phys-bits={on,off}) to change that
501 * and make sure guest phys-bits are not larger than host phys-bits.,
502 * but it is off by default. Exception: microvm machine type
503 * hard-wires that property to on.
507 PlatformAddressWidthFromCpuid (
508 IN OUT EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
513 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
514 if (RegEax
>= 0x80000008) {
515 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
516 PlatformInfoHob
->PhysMemAddressWidth
= (UINT8
)RegEax
;
518 PlatformInfoHob
->PhysMemAddressWidth
= 36;
521 PlatformInfoHob
->FirstNonAddress
= LShiftU64 (1, PlatformInfoHob
->PhysMemAddressWidth
);
525 "%a: cpuid: phys-bits is %d\n",
527 PlatformInfoHob
->PhysMemAddressWidth
532 Iterate over the PCI host bridges resources information optionally provided
533 in fw-cfg and find the highest address contained in the PCI MMIO windows. If
534 the information is found, return the exclusive end; one past the last usable
537 @param[out] PciMmioAddressEnd Pointer to one-after End Address updated with
538 information extracted from host-provided data
539 or zero if no information available or an
542 @retval EFI_SUCCESS PCI information was read and the output
543 parameter updated with the last valid
544 address in the 64-bit MMIO range.
545 @retval EFI_INVALID_PARAMETER Pointer parameter is invalid
546 @retval EFI_INCOMPATIBLE_VERSION Hardware information found in fw-cfg
547 has an incompatible format
548 @retval EFI_UNSUPPORTED Fw-cfg is not supported, thus host
549 provided information, if any, cannot be
551 @retval EFI_NOT_FOUND No PCI host bridge information provided
556 PlatformScanHostProvided64BitPciMmioEnd (
557 OUT UINT64
*PciMmioAddressEnd
561 HOST_BRIDGE_INFO HostBridge
;
562 FIRMWARE_CONFIG_ITEM FwCfgItem
;
564 UINTN FwCfgReadIndex
;
566 UINT64 Above4GMmioEnd
;
568 if (PciMmioAddressEnd
== NULL
) {
569 return EFI_INVALID_PARAMETER
;
572 *PciMmioAddressEnd
= 0;
575 Status
= QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem
, &FwCfgSize
);
576 if (EFI_ERROR (Status
)) {
580 QemuFwCfgSelectItem (FwCfgItem
);
583 while (FwCfgReadIndex
< FwCfgSize
) {
584 Status
= QemuFwCfgReadNextHardwareInfoByType (
585 HardwareInfoTypeHostBridge
,
593 if (Status
!= EFI_SUCCESS
) {
595 // No more data available to read in the file, break
596 // loop and finish process
601 Status
= HardwareInfoPciHostBridgeLastMmioAddress (
608 if (Status
!= EFI_SUCCESS
) {
610 // Error parsing MMIO apertures and extracting last MMIO
611 // address, reset PciMmioAddressEnd as if no information was
612 // found, to avoid moving forward with incomplete data, and
617 "%a: ignoring malformed hardware information from fw_cfg\n",
620 *PciMmioAddressEnd
= 0;
624 if (Above4GMmioEnd
> *PciMmioAddressEnd
) {
625 *PciMmioAddressEnd
= Above4GMmioEnd
;
629 if (*PciMmioAddressEnd
> 0) {
631 // Host-provided PCI information was found and a MMIO window end
633 // Increase the End address by one to have the output pointing to
634 // one after the address in use (exclusive end).
636 *PciMmioAddressEnd
+= 1;
640 "%a: Pci64End=0x%Lx\n",
648 return EFI_NOT_FOUND
;
652 Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
656 PlatformAddressWidthInitialization (
657 IN OUT EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
660 UINT64 FirstNonAddress
;
661 UINT8 PhysMemAddressWidth
;
664 if (PlatformInfoHob
->HostBridgeDevId
== 0xffff /* microvm */) {
665 PlatformAddressWidthFromCpuid (PlatformInfoHob
);
670 // First scan host-provided hardware information to assess if the address
671 // space is already known. If so, guest must use those values.
673 Status
= PlatformScanHostProvided64BitPciMmioEnd (&FirstNonAddress
);
675 if (EFI_ERROR (Status
)) {
677 // If the host did not provide valid hardware information leading to a
678 // hard-defined 64-bit MMIO end, fold back to calculating the minimum range
680 // As guest-physical memory size grows, the permanent PEI RAM requirements
681 // are dominated by the identity-mapping page tables built by the DXE IPL.
682 // The DXL IPL keys off of the physical address bits advertized in the CPU
683 // HOB. To conserve memory, we calculate the minimum address width here.
685 FirstNonAddress
= PlatformGetFirstNonAddress (PlatformInfoHob
);
688 PhysMemAddressWidth
= (UINT8
)HighBitSet64 (FirstNonAddress
);
691 // If FirstNonAddress is not an integral power of two, then we need an
694 if ((FirstNonAddress
& (FirstNonAddress
- 1)) != 0) {
695 ++PhysMemAddressWidth
;
699 // The minimum address width is 36 (covers up to and excluding 64 GB, which
700 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
701 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
702 // can simply assert that here, since 48 bits are good enough for 256 TB.
704 if (PhysMemAddressWidth
<= 36) {
705 PhysMemAddressWidth
= 36;
708 #if defined (MDE_CPU_X64)
709 if (TdIsEnabled ()) {
710 if (TdSharedPageMask () == (1ULL << 47)) {
711 PhysMemAddressWidth
= 48;
713 PhysMemAddressWidth
= 52;
717 ASSERT (PhysMemAddressWidth
<= 52);
719 ASSERT (PhysMemAddressWidth
<= 48);
722 PlatformInfoHob
->FirstNonAddress
= FirstNonAddress
;
723 PlatformInfoHob
->PhysMemAddressWidth
= PhysMemAddressWidth
;
728 QemuInitializeRamBelow1gb (
729 IN EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
732 if (PlatformInfoHob
->SmmSmramRequire
&& PlatformInfoHob
->Q35SmramAtDefaultSmbase
) {
733 PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE
);
734 PlatformAddReservedMemoryBaseSizeHob (
736 MCH_DEFAULT_SMBASE_SIZE
,
740 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
< BASE_512KB
+ BASE_128KB
,
741 "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
743 PlatformAddMemoryRangeHob (
744 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
,
745 BASE_512KB
+ BASE_128KB
748 PlatformAddMemoryRangeHob (0, BASE_512KB
+ BASE_128KB
);
753 Peform Memory Detection for QEMU / KVM
758 PlatformQemuInitializeRam (
759 IN EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
762 UINT64 LowerMemorySize
;
763 UINT64 UpperMemorySize
;
764 MTRR_SETTINGS MtrrSettings
;
767 DEBUG ((DEBUG_INFO
, "%a called\n", __FUNCTION__
));
770 // Determine total memory size available
772 LowerMemorySize
= PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob
);
774 if (PlatformInfoHob
->BootMode
== BOOT_ON_S3_RESUME
) {
776 // Create the following memory HOB as an exception on the S3 boot path.
778 // Normally we'd create memory HOBs only on the normal boot path. However,
779 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
780 // well, for "borrowing" a subset of it temporarily, for the AP startup
783 // CpuMpPei saves the original contents of the borrowed area in permanent
784 // PEI RAM, in a backup buffer allocated with the normal PEI services.
785 // CpuMpPei restores the original contents ("returns" the borrowed area) at
786 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
787 // transferring control to the OS's wakeup vector in the FACS.
789 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
790 // restore the original contents. Furthermore, we expect all such PEIMs
791 // (CpuMpPei included) to claim the borrowed areas by producing memory
792 // allocation HOBs, and to honor preexistent memory allocation HOBs when
793 // looking for an area to borrow.
795 QemuInitializeRamBelow1gb (PlatformInfoHob
);
798 // Create memory HOBs
800 QemuInitializeRamBelow1gb (PlatformInfoHob
);
802 if (PlatformInfoHob
->SmmSmramRequire
) {
805 TsegSize
= PlatformInfoHob
->Q35TsegMbytes
* SIZE_1MB
;
806 PlatformAddMemoryRangeHob (BASE_1MB
, LowerMemorySize
- TsegSize
);
807 PlatformAddReservedMemoryBaseSizeHob (
808 LowerMemorySize
- TsegSize
,
813 PlatformAddMemoryRangeHob (BASE_1MB
, LowerMemorySize
);
817 // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
818 // entries. Otherwise, create a single memory HOB with the flat >=4GB
819 // memory size read from the CMOS.
821 Status
= PlatformScanOrAdd64BitE820Ram (TRUE
, NULL
, NULL
);
822 if (EFI_ERROR (Status
)) {
823 UpperMemorySize
= PlatformGetSystemMemorySizeAbove4gb ();
824 if (UpperMemorySize
!= 0) {
825 PlatformAddMemoryBaseSizeHob (BASE_4GB
, UpperMemorySize
);
831 // We'd like to keep the following ranges uncached:
833 // - [LowerMemorySize, 4 GB)
835 // Everything else should be WB. Unfortunately, programming the inverse (ie.
836 // keeping the default UC, and configuring the complement set of the above as
837 // WB) is not reliable in general, because the end of the upper RAM can have
838 // practically any alignment, and we may not have enough variable MTRRs to
841 if (IsMtrrSupported () && (PlatformInfoHob
->HostBridgeDevId
!= CLOUDHV_DEVICE_ID
)) {
842 MtrrGetAllMtrrs (&MtrrSettings
);
845 // MTRRs disabled, fixed MTRRs disabled, default type is uncached
847 ASSERT ((MtrrSettings
.MtrrDefType
& BIT11
) == 0);
848 ASSERT ((MtrrSettings
.MtrrDefType
& BIT10
) == 0);
849 ASSERT ((MtrrSettings
.MtrrDefType
& 0xFF) == 0);
852 // flip default type to writeback
854 SetMem (&MtrrSettings
.Fixed
, sizeof MtrrSettings
.Fixed
, 0x06);
855 ZeroMem (&MtrrSettings
.Variables
, sizeof MtrrSettings
.Variables
);
856 MtrrSettings
.MtrrDefType
|= BIT11
| BIT10
| 6;
857 MtrrSetAllMtrrs (&MtrrSettings
);
860 // Set memory range from 640KB to 1MB to uncacheable
862 Status
= MtrrSetMemoryAttribute (
863 BASE_512KB
+ BASE_128KB
,
864 BASE_1MB
- (BASE_512KB
+ BASE_128KB
),
867 ASSERT_EFI_ERROR (Status
);
870 // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
871 // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
873 Status
= MtrrSetMemoryAttribute (
874 PlatformInfoHob
->Uc32Base
,
875 SIZE_4GB
- PlatformInfoHob
->Uc32Base
,
878 ASSERT_EFI_ERROR (Status
);
884 PlatformQemuInitializeRamForS3 (
885 IN EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
888 if (PlatformInfoHob
->S3Supported
&& (PlatformInfoHob
->BootMode
!= BOOT_ON_S3_RESUME
)) {
890 // This is the memory range that will be used for PEI on S3 resume
892 BuildMemoryAllocationHob (
893 PlatformInfoHob
->S3AcpiReservedMemoryBase
,
894 PlatformInfoHob
->S3AcpiReservedMemorySize
,
899 // Cover the initial RAM area used as stack and temporary PEI heap.
901 // This is reserved as ACPI NVS so it can be used on S3 resume.
903 BuildMemoryAllocationHob (
904 PcdGet32 (PcdOvmfSecPeiTempRamBase
),
905 PcdGet32 (PcdOvmfSecPeiTempRamSize
),
910 // SEC stores its table of GUIDed section handlers here.
912 BuildMemoryAllocationHob (
913 PcdGet64 (PcdGuidedExtractHandlerTableAddress
),
914 PcdGet32 (PcdGuidedExtractHandlerTableSize
),
920 // Reserve the initial page tables built by the reset vector code.
922 // Since this memory range will be used by the Reset Vector on S3
923 // resume, it must be reserved as ACPI NVS.
925 BuildMemoryAllocationHob (
926 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecPageTablesBase
),
927 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecPageTablesSize
),
931 if (PlatformInfoHob
->SevEsIsEnabled
) {
933 // If SEV-ES is enabled, reserve the GHCB-related memory area. This
934 // includes the extra page table used to break down the 2MB page
935 // mapping into 4KB page entries where the GHCB resides and the
938 // Since this memory range will be used by the Reset Vector on S3
939 // resume, it must be reserved as ACPI NVS.
941 BuildMemoryAllocationHob (
942 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbPageTableBase
),
943 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbPageTableSize
),
946 BuildMemoryAllocationHob (
947 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbBase
),
948 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbSize
),
951 BuildMemoryAllocationHob (
952 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbBackupBase
),
953 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfSecGhcbBackupSize
),
961 if (PlatformInfoHob
->BootMode
!= BOOT_ON_S3_RESUME
) {
962 if (!PlatformInfoHob
->SmmSmramRequire
) {
964 // Reserve the lock box storage area
966 // Since this memory range will be used on S3 resume, it must be
967 // reserved as ACPI NVS.
969 // If S3 is unsupported, then various drivers might still write to the
970 // LockBox area. We ought to prevent DXE from serving allocation requests
971 // such that they would overlap the LockBox storage.
974 (VOID
*)(UINTN
)PcdGet32 (PcdOvmfLockBoxStorageBase
),
975 (UINTN
)PcdGet32 (PcdOvmfLockBoxStorageSize
)
977 BuildMemoryAllocationHob (
978 (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfLockBoxStorageBase
),
979 (UINT64
)(UINTN
)PcdGet32 (PcdOvmfLockBoxStorageSize
),
980 PlatformInfoHob
->S3Supported
? EfiACPIMemoryNVS
: EfiBootServicesData
984 if (PlatformInfoHob
->SmmSmramRequire
) {
988 // Make sure the TSEG area that we reported as a reserved memory resource
989 // cannot be used for reserved memory allocations.
991 TsegSize
= PlatformInfoHob
->Q35TsegMbytes
* SIZE_1MB
;
992 BuildMemoryAllocationHob (
993 PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob
) - TsegSize
,
995 EfiReservedMemoryType
998 // Similarly, allocate away the (already reserved) SMRAM at the default
999 // SMBASE, if it exists.
1001 if (PlatformInfoHob
->Q35SmramAtDefaultSmbase
) {
1002 BuildMemoryAllocationHob (
1004 MCH_DEFAULT_SMBASE_SIZE
,
1005 EfiReservedMemoryType
1011 if (FixedPcdGet32 (PcdOvmfWorkAreaSize
) != 0) {
1013 // Reserve the work area.
1015 // Since this memory range will be used by the Reset Vector on S3
1016 // resume, it must be reserved as ACPI NVS.
1018 // If S3 is unsupported, then various drivers might still write to the
1019 // work area. We ought to prevent DXE from serving allocation requests
1020 // such that they would overlap the work area.
1022 BuildMemoryAllocationHob (
1023 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FixedPcdGet32 (PcdOvmfWorkAreaBase
),
1024 (UINT64
)(UINTN
)FixedPcdGet32 (PcdOvmfWorkAreaSize
),
1025 PlatformInfoHob
->S3Supported
? EfiACPIMemoryNVS
: EfiBootServicesData