1 /**@file
2   Memory Detection for Virtual Machines.
3 
4   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 Module Name:
8 
9   MemDetect.c
10 
11 **/
12 
13 //
14 // The package level header files this module uses
15 //
16 #include <IndustryStandard/E820.h>
17 #include <IndustryStandard/I440FxPiix4.h>
18 #include <IndustryStandard/Q35MchIch9.h>
19 #include <PiPei.h>
20 #include <Register/Intel/SmramSaveStateMap.h>
21 
22 //
23 // The Library classes this module consumes
24 //
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>
38 
39 #include "Platform.h"
40 #include "Cmos.h"
41 
42 UINT8 mPhysMemAddressWidth;
43 
44 STATIC UINT32 mS3AcpiReservedMemoryBase;
45 STATIC UINT32 mS3AcpiReservedMemorySize;
46 
47 STATIC UINT16 mQ35TsegMbytes;
48 
49 BOOLEAN mQ35SmramAtDefaultSmbase;
50 
51 UINT32 mQemuUc32Base;
52 
53 VOID
Q35TsegMbytesInitialization(VOID)54 Q35TsegMbytesInitialization (
55   VOID
56   )
57 {
58   UINT16        ExtendedTsegMbytes;
59   RETURN_STATUS PcdStatus;
60 
61   ASSERT (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);
62 
63   //
64   // Check if QEMU offers an extended TSEG.
65   //
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.
68   //
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.
73   //
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.
78   //
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);
83     return;
84   }
85 
86   DEBUG ((
87     DEBUG_INFO,
88     "%a: QEMU offers an extended TSEG (%d MB)\n",
89     __FUNCTION__,
90     ExtendedTsegMbytes
91     ));
92   PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);
93   ASSERT_RETURN_ERROR (PcdStatus);
94   mQ35TsegMbytes = ExtendedTsegMbytes;
95 }
96 
97 
98 VOID
Q35SmramAtDefaultSmbaseInitialization(VOID)99 Q35SmramAtDefaultSmbaseInitialization (
100   VOID
101   )
102 {
103   RETURN_STATUS PcdStatus;
104 
105   ASSERT (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);
106 
107   mQ35SmramAtDefaultSmbase = FALSE;
108   if (FeaturePcdGet (PcdCsmEnable)) {
109     DEBUG ((DEBUG_INFO, "%a: SMRAM at default SMBASE not checked due to CSM\n",
110       __FUNCTION__));
111   } else {
112     UINTN CtlReg;
113     UINT8 CtlRegVal;
114 
115     CtlReg = DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL);
116     PciWrite8 (CtlReg, MCH_DEFAULT_SMBASE_QUERY);
117     CtlRegVal = PciRead8 (CtlReg);
118     mQ35SmramAtDefaultSmbase = (BOOLEAN)(CtlRegVal ==
119                                          MCH_DEFAULT_SMBASE_IN_RAM);
120     DEBUG ((DEBUG_INFO, "%a: SMRAM at default SMBASE %a\n", __FUNCTION__,
121       mQ35SmramAtDefaultSmbase ? "found" : "not found"));
122   }
123 
124   PcdStatus = PcdSetBoolS (PcdQ35SmramAtDefaultSmbase,
125                 mQ35SmramAtDefaultSmbase);
126   ASSERT_RETURN_ERROR (PcdStatus);
127 }
128 
129 
130 VOID
QemuUc32BaseInitialization(VOID)131 QemuUc32BaseInitialization (
132   VOID
133   )
134 {
135   UINT32 LowerMemorySize;
136   UINT32 Uc32Size;
137 
138   if (mXen) {
139     return;
140   }
141 
142   if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
143     //
144     // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
145     // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
146     // setting PcdPciExpressBaseAddress such that describing the
147     // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
148     // variable MTRRs (preferably 1 or 2).
149     //
150     ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
151     mQemuUc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
152     return;
153   }
154 
155   ASSERT (mHostBridgeDevId == INTEL_82441_DEVICE_ID);
156   //
157   // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
158   // variable MTRR suffices by truncating the size to a whole power of two,
159   // while keeping the end affixed to 4GB. This will round the base up.
160   //
161   LowerMemorySize = GetSystemMemorySizeBelow4gb ();
162   Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
163   mQemuUc32Base = (UINT32)(SIZE_4GB - Uc32Size);
164   //
165   // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
166   // Therefore mQemuUc32Base is at least 2GB.
167   //
168   ASSERT (mQemuUc32Base >= BASE_2GB);
169 
170   if (mQemuUc32Base != LowerMemorySize) {
171     DEBUG ((DEBUG_VERBOSE, "%a: rounded UC32 base from 0x%x up to 0x%x, for "
172       "an UC32 size of 0x%x\n", __FUNCTION__, LowerMemorySize, mQemuUc32Base,
173       Uc32Size));
174   }
175 }
176 
177 
178 /**
179   Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
180   of the 32-bit address range.
181 
182   Find the highest exclusive >=4GB RAM address, or produce memory resource
183   descriptor HOBs for RAM entries that start at or above 4GB.
184 
185   @param[out] MaxAddress  If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
186                           produces memory resource descriptor HOBs for RAM
187                           entries that start at or above 4GB.
188 
189                           Otherwise, MaxAddress holds the highest exclusive
190                           >=4GB RAM address on output. If QEMU's fw_cfg E820
191                           RAM map contains no RAM entry that starts outside of
192                           the 32-bit address range, then MaxAddress is exactly
193                           4GB on output.
194 
195   @retval EFI_SUCCESS         The fw_cfg E820 RAM map was found and processed.
196 
197   @retval EFI_PROTOCOL_ERROR  The RAM map was found, but its size wasn't a
198                               whole multiple of sizeof(EFI_E820_ENTRY64). No
199                               RAM entry was processed.
200 
201   @return                     Error codes from QemuFwCfgFindFile(). No RAM
202                               entry was processed.
203 **/
204 STATIC
205 EFI_STATUS
ScanOrAdd64BitE820Ram(OUT UINT64 * MaxAddress OPTIONAL)206 ScanOrAdd64BitE820Ram (
207   OUT UINT64 *MaxAddress OPTIONAL
208   )
209 {
210   EFI_STATUS           Status;
211   FIRMWARE_CONFIG_ITEM FwCfgItem;
212   UINTN                FwCfgSize;
213   EFI_E820_ENTRY64     E820Entry;
214   UINTN                Processed;
215 
216   Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);
217   if (EFI_ERROR (Status)) {
218     return Status;
219   }
220   if (FwCfgSize % sizeof E820Entry != 0) {
221     return EFI_PROTOCOL_ERROR;
222   }
223 
224   if (MaxAddress != NULL) {
225     *MaxAddress = BASE_4GB;
226   }
227 
228   QemuFwCfgSelectItem (FwCfgItem);
229   for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {
230     QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);
231     DEBUG ((
232       DEBUG_VERBOSE,
233       "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
234       __FUNCTION__,
235       E820Entry.BaseAddr,
236       E820Entry.Length,
237       E820Entry.Type
238       ));
239     if (E820Entry.Type == EfiAcpiAddressRangeMemory &&
240         E820Entry.BaseAddr >= BASE_4GB) {
241       if (MaxAddress == NULL) {
242         UINT64 Base;
243         UINT64 End;
244 
245         //
246         // Round up the start address, and round down the end address.
247         //
248         Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE);
249         End = (E820Entry.BaseAddr + E820Entry.Length) &
250               ~(UINT64)EFI_PAGE_MASK;
251         if (Base < End) {
252           AddMemoryRangeHob (Base, End);
253           DEBUG ((
254             DEBUG_VERBOSE,
255             "%a: AddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
256             __FUNCTION__,
257             Base,
258             End
259             ));
260         }
261       } else {
262         UINT64 Candidate;
263 
264         Candidate = E820Entry.BaseAddr + E820Entry.Length;
265         if (Candidate > *MaxAddress) {
266           *MaxAddress = Candidate;
267           DEBUG ((
268             DEBUG_VERBOSE,
269             "%a: MaxAddress=0x%Lx\n",
270             __FUNCTION__,
271             *MaxAddress
272             ));
273         }
274       }
275     }
276   }
277   return EFI_SUCCESS;
278 }
279 
280 
281 UINT32
GetSystemMemorySizeBelow4gb(VOID)282 GetSystemMemorySizeBelow4gb (
283   VOID
284   )
285 {
286   UINT8 Cmos0x34;
287   UINT8 Cmos0x35;
288 
289   //
290   // CMOS 0x34/0x35 specifies the system memory above 16 MB.
291   // * CMOS(0x35) is the high byte
292   // * CMOS(0x34) is the low byte
293   // * The size is specified in 64kb chunks
294   // * Since this is memory above 16MB, the 16MB must be added
295   //   into the calculation to get the total memory size.
296   //
297 
298   Cmos0x34 = (UINT8) CmosRead8 (0x34);
299   Cmos0x35 = (UINT8) CmosRead8 (0x35);
300 
301   return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
302 }
303 
304 
305 STATIC
306 UINT64
GetSystemMemorySizeAbove4gb()307 GetSystemMemorySizeAbove4gb (
308   )
309 {
310   UINT32 Size;
311   UINTN  CmosIndex;
312 
313   //
314   // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
315   // * CMOS(0x5d) is the most significant size byte
316   // * CMOS(0x5c) is the middle size byte
317   // * CMOS(0x5b) is the least significant size byte
318   // * The size is specified in 64kb chunks
319   //
320 
321   Size = 0;
322   for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
323     Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);
324   }
325 
326   return LShiftU64 (Size, 16);
327 }
328 
329 
330 /**
331   Return the highest address that DXE could possibly use, plus one.
332 **/
333 STATIC
334 UINT64
GetFirstNonAddress(VOID)335 GetFirstNonAddress (
336   VOID
337   )
338 {
339   UINT64               FirstNonAddress;
340   UINT64               Pci64Base, Pci64Size;
341   UINT32               FwCfgPciMmio64Mb;
342   EFI_STATUS           Status;
343   FIRMWARE_CONFIG_ITEM FwCfgItem;
344   UINTN                FwCfgSize;
345   UINT64               HotPlugMemoryEnd;
346   RETURN_STATUS        PcdStatus;
347 
348   //
349   // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
350   //
351   FirstNonAddress = 0;
352 
353   //
354   // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
355   // address from it. This can express an address >= 4GB+1TB.
356   //
357   // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
358   // can only express a size smaller than 1TB), and add it to 4GB.
359   //
360   Status = ScanOrAdd64BitE820Ram (&FirstNonAddress);
361   if (EFI_ERROR (Status)) {
362     FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
363   }
364 
365   //
366   // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
367   // resources to 32-bit anyway. See DegradeResource() in
368   // "PciResourceSupport.c".
369   //
370 #ifdef MDE_CPU_IA32
371   if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
372     return FirstNonAddress;
373   }
374 #endif
375 
376   //
377   // Otherwise, in order to calculate the highest address plus one, we must
378   // consider the 64-bit PCI host aperture too. Fetch the default size.
379   //
380   Pci64Size = PcdGet64 (PcdPciMmio64Size);
381 
382   //
383   // See if the user specified the number of megabytes for the 64-bit PCI host
384   // aperture. Accept an aperture size up to 16TB.
385   //
386   // As signaled by the "X-" prefix, this knob is experimental, and might go
387   // away at any time.
388   //
389   Status = QemuFwCfgParseUint32 ("opt/ovmf/X-PciMmio64Mb", FALSE,
390              &FwCfgPciMmio64Mb);
391   switch (Status) {
392   case EFI_UNSUPPORTED:
393   case EFI_NOT_FOUND:
394     break;
395   case EFI_SUCCESS:
396     if (FwCfgPciMmio64Mb <= 0x1000000) {
397       Pci64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
398       break;
399     }
400     //
401     // fall through
402     //
403   default:
404     DEBUG ((DEBUG_WARN,
405       "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
406       __FUNCTION__));
407     break;
408   }
409 
410   if (Pci64Size == 0) {
411     if (mBootMode != BOOT_ON_S3_RESUME) {
412       DEBUG ((DEBUG_INFO, "%a: disabling 64-bit PCI host aperture\n",
413         __FUNCTION__));
414       PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
415       ASSERT_RETURN_ERROR (PcdStatus);
416     }
417 
418     //
419     // There's nothing more to do; the amount of memory above 4GB fully
420     // determines the highest address plus one. The memory hotplug area (see
421     // below) plays no role for the firmware in this case.
422     //
423     return FirstNonAddress;
424   }
425 
426   //
427   // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
428   // absolute, exclusive end address for the memory hotplug area. This area
429   // starts right at the end of the memory above 4GB. The 64-bit PCI host
430   // aperture must be placed above it.
431   //
432   Status = QemuFwCfgFindFile ("etc/reserved-memory-end", &FwCfgItem,
433              &FwCfgSize);
434   if (!EFI_ERROR (Status) && FwCfgSize == sizeof HotPlugMemoryEnd) {
435     QemuFwCfgSelectItem (FwCfgItem);
436     QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);
437     DEBUG ((DEBUG_VERBOSE, "%a: HotPlugMemoryEnd=0x%Lx\n", __FUNCTION__,
438       HotPlugMemoryEnd));
439 
440     ASSERT (HotPlugMemoryEnd >= FirstNonAddress);
441     FirstNonAddress = HotPlugMemoryEnd;
442   }
443 
444   //
445   // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
446   // that the host can map it with 1GB hugepages. Follow suit.
447   //
448   Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
449   Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
450 
451   //
452   // The 64-bit PCI host aperture should also be "naturally" aligned. The
453   // alignment is determined by rounding the size of the aperture down to the
454   // next smaller or equal power of two. That is, align the aperture by the
455   // largest BAR size that can fit into it.
456   //
457   Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
458 
459   if (mBootMode != BOOT_ON_S3_RESUME) {
460     //
461     // The core PciHostBridgeDxe driver will automatically add this range to
462     // the GCD memory space map through our PciHostBridgeLib instance; here we
463     // only need to set the PCDs.
464     //
465     PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
466     ASSERT_RETURN_ERROR (PcdStatus);
467     PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
468     ASSERT_RETURN_ERROR (PcdStatus);
469 
470     DEBUG ((DEBUG_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
471       __FUNCTION__, Pci64Base, Pci64Size));
472   }
473 
474   //
475   // The useful address space ends with the 64-bit PCI host aperture.
476   //
477   FirstNonAddress = Pci64Base + Pci64Size;
478   return FirstNonAddress;
479 }
480 
481 
482 /**
483   Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
484 **/
485 VOID
AddressWidthInitialization(VOID)486 AddressWidthInitialization (
487   VOID
488   )
489 {
490   UINT64 FirstNonAddress;
491 
492   //
493   // As guest-physical memory size grows, the permanent PEI RAM requirements
494   // are dominated by the identity-mapping page tables built by the DXE IPL.
495   // The DXL IPL keys off of the physical address bits advertized in the CPU
496   // HOB. To conserve memory, we calculate the minimum address width here.
497   //
498   FirstNonAddress      = GetFirstNonAddress ();
499   mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
500 
501   //
502   // If FirstNonAddress is not an integral power of two, then we need an
503   // additional bit.
504   //
505   if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
506     ++mPhysMemAddressWidth;
507   }
508 
509   //
510   // The minimum address width is 36 (covers up to and excluding 64 GB, which
511   // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
512   // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
513   // can simply assert that here, since 48 bits are good enough for 256 TB.
514   //
515   if (mPhysMemAddressWidth <= 36) {
516     mPhysMemAddressWidth = 36;
517   }
518   ASSERT (mPhysMemAddressWidth <= 48);
519 }
520 
521 
522 /**
523   Calculate the cap for the permanent PEI memory.
524 **/
525 STATIC
526 UINT32
GetPeiMemoryCap(VOID)527 GetPeiMemoryCap (
528   VOID
529   )
530 {
531   BOOLEAN Page1GSupport;
532   UINT32  RegEax;
533   UINT32  RegEdx;
534   UINT32  Pml4Entries;
535   UINT32  PdpEntries;
536   UINTN   TotalPages;
537 
538   //
539   // If DXE is 32-bit, then just return the traditional 64 MB cap.
540   //
541 #ifdef MDE_CPU_IA32
542   if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
543     return SIZE_64MB;
544   }
545 #endif
546 
547   //
548   // Dependent on physical address width, PEI memory allocations can be
549   // dominated by the page tables built for 64-bit DXE. So we key the cap off
550   // of those. The code below is based on CreateIdentityMappingPageTables() in
551   // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
552   //
553   Page1GSupport = FALSE;
554   if (PcdGetBool (PcdUse1GPageTable)) {
555     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
556     if (RegEax >= 0x80000001) {
557       AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
558       if ((RegEdx & BIT26) != 0) {
559         Page1GSupport = TRUE;
560       }
561     }
562   }
563 
564   if (mPhysMemAddressWidth <= 39) {
565     Pml4Entries = 1;
566     PdpEntries = 1 << (mPhysMemAddressWidth - 30);
567     ASSERT (PdpEntries <= 0x200);
568   } else {
569     Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
570     ASSERT (Pml4Entries <= 0x200);
571     PdpEntries = 512;
572   }
573 
574   TotalPages = Page1GSupport ? Pml4Entries + 1 :
575                                (PdpEntries + 1) * Pml4Entries + 1;
576   ASSERT (TotalPages <= 0x40201);
577 
578   //
579   // Add 64 MB for miscellaneous allocations. Note that for
580   // mPhysMemAddressWidth values close to 36, the cap will actually be
581   // dominated by this increment.
582   //
583   return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
584 }
585 
586 
587 /**
588   Publish PEI core memory
589 
590   @return EFI_SUCCESS     The PEIM initialized successfully.
591 
592 **/
593 EFI_STATUS
PublishPeiMemory(VOID)594 PublishPeiMemory (
595   VOID
596   )
597 {
598   EFI_STATUS                  Status;
599   EFI_PHYSICAL_ADDRESS        MemoryBase;
600   UINT64                      MemorySize;
601   UINT32                      LowerMemorySize;
602   UINT32                      PeiMemoryCap;
603 
604   LowerMemorySize = GetSystemMemorySizeBelow4gb ();
605   if (FeaturePcdGet (PcdSmmSmramRequire)) {
606     //
607     // TSEG is chipped from the end of low RAM
608     //
609     LowerMemorySize -= mQ35TsegMbytes * SIZE_1MB;
610   }
611 
612   //
613   // If S3 is supported, then the S3 permanent PEI memory is placed next,
614   // downwards. Its size is primarily dictated by CpuMpPei. The formula below
615   // is an approximation.
616   //
617   if (mS3Supported) {
618     mS3AcpiReservedMemorySize = SIZE_512KB +
619       mMaxCpuCount *
620       PcdGet32 (PcdCpuApStackSize);
621     mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;
622     LowerMemorySize = mS3AcpiReservedMemoryBase;
623   }
624 
625   if (mBootMode == BOOT_ON_S3_RESUME) {
626     MemoryBase = mS3AcpiReservedMemoryBase;
627     MemorySize = mS3AcpiReservedMemorySize;
628   } else {
629     PeiMemoryCap = GetPeiMemoryCap ();
630     DEBUG ((DEBUG_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
631       __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));
632 
633     //
634     // Determine the range of memory to use during PEI
635     //
636     // Technically we could lay the permanent PEI RAM over SEC's temporary
637     // decompression and scratch buffer even if "secure S3" is needed, since
638     // their lifetimes don't overlap. However, PeiFvInitialization() will cover
639     // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
640     // allocation HOB, and other allocations served from the permanent PEI RAM
641     // shouldn't overlap with that HOB.
642     //
643     MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?
644       PcdGet32 (PcdOvmfDecompressionScratchEnd) :
645       PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);
646     MemorySize = LowerMemorySize - MemoryBase;
647     if (MemorySize > PeiMemoryCap) {
648       MemoryBase = LowerMemorySize - PeiMemoryCap;
649       MemorySize = PeiMemoryCap;
650     }
651   }
652 
653   //
654   // MEMFD_BASE_ADDRESS separates the SMRAM at the default SMBASE from the
655   // normal boot permanent PEI RAM. Regarding the S3 boot path, the S3
656   // permanent PEI RAM is located even higher.
657   //
658   if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
659     ASSERT (SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE <= MemoryBase);
660   }
661 
662   //
663   // Publish this memory to the PEI Core
664   //
665   Status = PublishSystemMemory(MemoryBase, MemorySize);
666   ASSERT_EFI_ERROR (Status);
667 
668   return Status;
669 }
670 
671 
672 STATIC
673 VOID
QemuInitializeRamBelow1gb(VOID)674 QemuInitializeRamBelow1gb (
675   VOID
676   )
677 {
678   if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
679     AddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
680     AddReservedMemoryBaseSizeHob (SMM_DEFAULT_SMBASE, MCH_DEFAULT_SMBASE_SIZE,
681       TRUE /* Cacheable */);
682     STATIC_ASSERT (
683       SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,
684       "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
685       );
686     AddMemoryRangeHob (SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,
687       BASE_512KB + BASE_128KB);
688   } else {
689     AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
690   }
691 }
692 
693 
694 /**
695   Peform Memory Detection for QEMU / KVM
696 
697 **/
698 STATIC
699 VOID
QemuInitializeRam(VOID)700 QemuInitializeRam (
701   VOID
702   )
703 {
704   UINT64                      LowerMemorySize;
705   UINT64                      UpperMemorySize;
706   MTRR_SETTINGS               MtrrSettings;
707   EFI_STATUS                  Status;
708 
709   DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
710 
711   //
712   // Determine total memory size available
713   //
714   LowerMemorySize = GetSystemMemorySizeBelow4gb ();
715   UpperMemorySize = GetSystemMemorySizeAbove4gb ();
716 
717   if (mBootMode == BOOT_ON_S3_RESUME) {
718     //
719     // Create the following memory HOB as an exception on the S3 boot path.
720     //
721     // Normally we'd create memory HOBs only on the normal boot path. However,
722     // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
723     // well, for "borrowing" a subset of it temporarily, for the AP startup
724     // vector.
725     //
726     // CpuMpPei saves the original contents of the borrowed area in permanent
727     // PEI RAM, in a backup buffer allocated with the normal PEI services.
728     // CpuMpPei restores the original contents ("returns" the borrowed area) at
729     // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
730     // transferring control to the OS's wakeup vector in the FACS.
731     //
732     // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
733     // restore the original contents. Furthermore, we expect all such PEIMs
734     // (CpuMpPei included) to claim the borrowed areas by producing memory
735     // allocation HOBs, and to honor preexistent memory allocation HOBs when
736     // looking for an area to borrow.
737     //
738     QemuInitializeRamBelow1gb ();
739   } else {
740     //
741     // Create memory HOBs
742     //
743     QemuInitializeRamBelow1gb ();
744 
745     if (FeaturePcdGet (PcdSmmSmramRequire)) {
746       UINT32 TsegSize;
747 
748       TsegSize = mQ35TsegMbytes * SIZE_1MB;
749       AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
750       AddReservedMemoryBaseSizeHob (LowerMemorySize - TsegSize, TsegSize,
751         TRUE);
752     } else {
753       AddMemoryRangeHob (BASE_1MB, LowerMemorySize);
754     }
755 
756     //
757     // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
758     // entries. Otherwise, create a single memory HOB with the flat >=4GB
759     // memory size read from the CMOS.
760     //
761     Status = ScanOrAdd64BitE820Ram (NULL);
762     if (EFI_ERROR (Status) && UpperMemorySize != 0) {
763       AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
764     }
765   }
766 
767   //
768   // We'd like to keep the following ranges uncached:
769   // - [640 KB, 1 MB)
770   // - [LowerMemorySize, 4 GB)
771   //
772   // Everything else should be WB. Unfortunately, programming the inverse (ie.
773   // keeping the default UC, and configuring the complement set of the above as
774   // WB) is not reliable in general, because the end of the upper RAM can have
775   // practically any alignment, and we may not have enough variable MTRRs to
776   // cover it exactly.
777   //
778   if (IsMtrrSupported ()) {
779     MtrrGetAllMtrrs (&MtrrSettings);
780 
781     //
782     // MTRRs disabled, fixed MTRRs disabled, default type is uncached
783     //
784     ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
785     ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
786     ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
787 
788     //
789     // flip default type to writeback
790     //
791     SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
792     ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
793     MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
794     MtrrSetAllMtrrs (&MtrrSettings);
795 
796     //
797     // Set memory range from 640KB to 1MB to uncacheable
798     //
799     Status = MtrrSetMemoryAttribute (BASE_512KB + BASE_128KB,
800                BASE_1MB - (BASE_512KB + BASE_128KB), CacheUncacheable);
801     ASSERT_EFI_ERROR (Status);
802 
803     //
804     // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
805     // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
806     //
807     Status = MtrrSetMemoryAttribute (mQemuUc32Base, SIZE_4GB - mQemuUc32Base,
808                CacheUncacheable);
809     ASSERT_EFI_ERROR (Status);
810   }
811 }
812 
813 /**
814   Publish system RAM and reserve memory regions
815 
816 **/
817 VOID
InitializeRamRegions(VOID)818 InitializeRamRegions (
819   VOID
820   )
821 {
822   if (!mXen) {
823     QemuInitializeRam ();
824   } else {
825     XenPublishRamRegions ();
826   }
827 
828   if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
829     //
830     // This is the memory range that will be used for PEI on S3 resume
831     //
832     BuildMemoryAllocationHob (
833       mS3AcpiReservedMemoryBase,
834       mS3AcpiReservedMemorySize,
835       EfiACPIMemoryNVS
836       );
837 
838     //
839     // Cover the initial RAM area used as stack and temporary PEI heap.
840     //
841     // This is reserved as ACPI NVS so it can be used on S3 resume.
842     //
843     BuildMemoryAllocationHob (
844       PcdGet32 (PcdOvmfSecPeiTempRamBase),
845       PcdGet32 (PcdOvmfSecPeiTempRamSize),
846       EfiACPIMemoryNVS
847       );
848 
849     //
850     // SEC stores its table of GUIDed section handlers here.
851     //
852     BuildMemoryAllocationHob (
853       PcdGet64 (PcdGuidedExtractHandlerTableAddress),
854       PcdGet32 (PcdGuidedExtractHandlerTableSize),
855       EfiACPIMemoryNVS
856       );
857 
858 #ifdef MDE_CPU_X64
859     //
860     // Reserve the initial page tables built by the reset vector code.
861     //
862     // Since this memory range will be used by the Reset Vector on S3
863     // resume, it must be reserved as ACPI NVS.
864     //
865     BuildMemoryAllocationHob (
866       (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecPageTablesBase),
867       (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
868       EfiACPIMemoryNVS
869       );
870 
871     if (MemEncryptSevEsIsEnabled ()) {
872       //
873       // If SEV-ES is enabled, reserve the GHCB-related memory area. This
874       // includes the extra page table used to break down the 2MB page
875       // mapping into 4KB page entries where the GHCB resides and the
876       // GHCB area itself.
877       //
878       // Since this memory range will be used by the Reset Vector on S3
879       // resume, it must be reserved as ACPI NVS.
880       //
881       BuildMemoryAllocationHob (
882         (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableBase),
883         (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableSize),
884         EfiACPIMemoryNVS
885         );
886       BuildMemoryAllocationHob (
887         (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbBase),
888         (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbSize),
889         EfiACPIMemoryNVS
890         );
891     }
892 #endif
893   }
894 
895   if (mBootMode != BOOT_ON_S3_RESUME) {
896     if (!FeaturePcdGet (PcdSmmSmramRequire)) {
897       //
898       // Reserve the lock box storage area
899       //
900       // Since this memory range will be used on S3 resume, it must be
901       // reserved as ACPI NVS.
902       //
903       // If S3 is unsupported, then various drivers might still write to the
904       // LockBox area. We ought to prevent DXE from serving allocation requests
905       // such that they would overlap the LockBox storage.
906       //
907       ZeroMem (
908         (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
909         (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)
910         );
911       BuildMemoryAllocationHob (
912         (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
913         (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),
914         mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
915         );
916     }
917 
918     if (FeaturePcdGet (PcdSmmSmramRequire)) {
919       UINT32 TsegSize;
920 
921       //
922       // Make sure the TSEG area that we reported as a reserved memory resource
923       // cannot be used for reserved memory allocations.
924       //
925       TsegSize = mQ35TsegMbytes * SIZE_1MB;
926       BuildMemoryAllocationHob (
927         GetSystemMemorySizeBelow4gb() - TsegSize,
928         TsegSize,
929         EfiReservedMemoryType
930         );
931       //
932       // Similarly, allocate away the (already reserved) SMRAM at the default
933       // SMBASE, if it exists.
934       //
935       if (mQ35SmramAtDefaultSmbase) {
936         BuildMemoryAllocationHob (
937           SMM_DEFAULT_SMBASE,
938           MCH_DEFAULT_SMBASE_SIZE,
939           EfiReservedMemoryType
940           );
941       }
942     }
943 
944 #ifdef MDE_CPU_X64
945     if (MemEncryptSevEsIsEnabled ()) {
946       //
947       // If SEV-ES is enabled, reserve the SEV-ES work area.
948       //
949       // Since this memory range will be used by the Reset Vector on S3
950       // resume, it must be reserved as ACPI NVS.
951       //
952       // If S3 is unsupported, then various drivers might still write to the
953       // work area. We ought to prevent DXE from serving allocation requests
954       // such that they would overlap the work area.
955       //
956       BuildMemoryAllocationHob (
957         (EFI_PHYSICAL_ADDRESS)(UINTN) FixedPcdGet32 (PcdSevEsWorkAreaBase),
958         (UINT64)(UINTN) FixedPcdGet32 (PcdSevEsWorkAreaSize),
959         mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
960         );
961     }
962 #endif
963   }
964 }
965