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