]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PlatformPei/MemDetect.c
OvmfPkg/QemuFwCfgLib: Use BusMasterCommonBuffer to map FW_CFG_DMA_ACCESS
[mirror_edk2.git] / OvmfPkg / PlatformPei / MemDetect.c
CommitLineData
49ba9447 1/**@file\r
2 Memory Detection for Virtual Machines.\r
3\r
035ce3b3 4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
56d7640a 5 This program and the accompanying materials\r
49ba9447 6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13Module Name:\r
14\r
15 MemDetect.c\r
16\r
17**/\r
18\r
19//\r
20// The package level header files this module uses\r
21//\r
d5e06444 22#include <IndustryStandard/Q35MchIch9.h>\r
49ba9447 23#include <PiPei.h>\r
24\r
25//\r
26// The Library classes this module consumes\r
27//\r
d5e06444 28#include <Library/BaseLib.h>\r
6a7cba79 29#include <Library/BaseMemoryLib.h>\r
49ba9447 30#include <Library/DebugLib.h>\r
31#include <Library/HobLib.h>\r
32#include <Library/IoLib.h>\r
c1c2669c 33#include <Library/PcdLib.h>\r
d5e06444 34#include <Library/PciLib.h>\r
49ba9447 35#include <Library/PeimEntryPoint.h>\r
36#include <Library/ResourcePublicationLib.h>\r
e8e5cd4a 37#include <Library/MtrrLib.h>\r
7e5b1b67 38#include <Library/QemuFwCfgLib.h>\r
49ba9447 39\r
40#include "Platform.h"\r
41#include "Cmos.h"\r
42\r
bc89fe48
LE
43UINT8 mPhysMemAddressWidth;\r
44\r
45d87081
LE
45STATIC UINT32 mS3AcpiReservedMemoryBase;\r
46STATIC UINT32 mS3AcpiReservedMemorySize;\r
47\r
23bfb5c0
LE
48STATIC UINT16 mQ35TsegMbytes;\r
49\r
50VOID\r
51Q35TsegMbytesInitialization (\r
52 VOID\r
53 )\r
54{\r
d5e06444
LE
55 UINT16 ExtendedTsegMbytes;\r
56 RETURN_STATUS PcdStatus;\r
57\r
58 if (mHostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) {\r
59 DEBUG ((\r
60 DEBUG_ERROR,\r
61 "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "\r
62 "only DID=0x%04x (Q35) is supported\n",\r
63 __FUNCTION__,\r
64 mHostBridgeDevId,\r
65 INTEL_Q35_MCH_DEVICE_ID\r
66 ));\r
67 ASSERT (FALSE);\r
68 CpuDeadLoop ();\r
69 }\r
70\r
71 //\r
72 // Check if QEMU offers an extended TSEG.\r
73 //\r
74 // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB\r
75 // register, and reading back the register.\r
76 //\r
77 // On a QEMU machine type that does not offer an extended TSEG, the initial\r
78 // write overwrites whatever value a malicious guest OS may have placed in\r
79 // the (unimplemented) register, before entering S3 or rebooting.\r
80 // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.\r
81 //\r
82 // On a QEMU machine type that offers an extended TSEG, the initial write\r
83 // triggers an update to the register. Subsequently, the value read back\r
84 // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the\r
85 // number of megabytes.\r
86 //\r
87 PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY);\r
88 ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));\r
89 if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) {\r
90 mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);\r
91 return;\r
92 }\r
93\r
94 DEBUG ((\r
95 DEBUG_INFO,\r
96 "%a: QEMU offers an extended TSEG (%d MB)\n",\r
97 __FUNCTION__,\r
98 ExtendedTsegMbytes\r
99 ));\r
100 PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);\r
101 ASSERT_RETURN_ERROR (PcdStatus);\r
102 mQ35TsegMbytes = ExtendedTsegMbytes;\r
23bfb5c0
LE
103}\r
104\r
105\r
4b455f7b 106UINT32\r
c0e10976 107GetSystemMemorySizeBelow4gb (\r
4b455f7b 108 VOID\r
49ba9447 109 )\r
110{\r
111 UINT8 Cmos0x34;\r
112 UINT8 Cmos0x35;\r
113\r
114 //\r
115 // CMOS 0x34/0x35 specifies the system memory above 16 MB.\r
116 // * CMOS(0x35) is the high byte\r
117 // * CMOS(0x34) is the low byte\r
118 // * The size is specified in 64kb chunks\r
119 // * Since this is memory above 16MB, the 16MB must be added\r
120 // into the calculation to get the total memory size.\r
121 //\r
122\r
123 Cmos0x34 = (UINT8) CmosRead8 (0x34);\r
124 Cmos0x35 = (UINT8) CmosRead8 (0x35);\r
125\r
c4046161 126 return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);\r
49ba9447 127}\r
128\r
129\r
c0e10976 130STATIC\r
131UINT64\r
132GetSystemMemorySizeAbove4gb (\r
133 )\r
134{\r
135 UINT32 Size;\r
136 UINTN CmosIndex;\r
137\r
138 //\r
139 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.\r
140 // * CMOS(0x5d) is the most significant size byte\r
141 // * CMOS(0x5c) is the middle size byte\r
142 // * CMOS(0x5b) is the least significant size byte\r
143 // * The size is specified in 64kb chunks\r
144 //\r
145\r
146 Size = 0;\r
147 for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {\r
148 Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);\r
149 }\r
150\r
151 return LShiftU64 (Size, 16);\r
152}\r
153\r
bc89fe48 154\r
d5371680
LE
155/**\r
156 Return the highest address that DXE could possibly use, plus one.\r
157**/\r
158STATIC\r
159UINT64\r
160GetFirstNonAddress (\r
161 VOID\r
162 )\r
163{\r
164 UINT64 FirstNonAddress;\r
7e5b1b67
LE
165 UINT64 Pci64Base, Pci64Size;\r
166 CHAR8 MbString[7 + 1];\r
167 EFI_STATUS Status;\r
168 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
169 UINTN FwCfgSize;\r
170 UINT64 HotPlugMemoryEnd;\r
32e083c7 171 RETURN_STATUS PcdStatus;\r
d5371680
LE
172\r
173 FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();\r
7e5b1b67
LE
174\r
175 //\r
176 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO\r
177 // resources to 32-bit anyway. See DegradeResource() in\r
178 // "PciResourceSupport.c".\r
179 //\r
180#ifdef MDE_CPU_IA32\r
181 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
182 return FirstNonAddress;\r
183 }\r
184#endif\r
185\r
186 //\r
187 // Otherwise, in order to calculate the highest address plus one, we must\r
188 // consider the 64-bit PCI host aperture too. Fetch the default size.\r
189 //\r
190 Pci64Size = PcdGet64 (PcdPciMmio64Size);\r
191\r
192 //\r
193 // See if the user specified the number of megabytes for the 64-bit PCI host\r
194 // aperture. The number of non-NUL characters in MbString allows for\r
195 // 9,999,999 MB, which is approximately 10 TB.\r
196 //\r
197 // As signaled by the "X-" prefix, this knob is experimental, and might go\r
198 // away at any time.\r
199 //\r
200 Status = QemuFwCfgFindFile ("opt/ovmf/X-PciMmio64Mb", &FwCfgItem,\r
201 &FwCfgSize);\r
202 if (!EFI_ERROR (Status)) {\r
203 if (FwCfgSize >= sizeof MbString) {\r
204 DEBUG ((EFI_D_WARN,\r
205 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",\r
206 __FUNCTION__));\r
207 } else {\r
208 QemuFwCfgSelectItem (FwCfgItem);\r
209 QemuFwCfgReadBytes (FwCfgSize, MbString);\r
210 MbString[FwCfgSize] = '\0';\r
211 Pci64Size = LShiftU64 (AsciiStrDecimalToUint64 (MbString), 20);\r
212 }\r
213 }\r
214\r
215 if (Pci64Size == 0) {\r
216 if (mBootMode != BOOT_ON_S3_RESUME) {\r
217 DEBUG ((EFI_D_INFO, "%a: disabling 64-bit PCI host aperture\n",\r
218 __FUNCTION__));\r
32e083c7
LE
219 PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);\r
220 ASSERT_RETURN_ERROR (PcdStatus);\r
7e5b1b67
LE
221 }\r
222\r
223 //\r
224 // There's nothing more to do; the amount of memory above 4GB fully\r
225 // determines the highest address plus one. The memory hotplug area (see\r
226 // below) plays no role for the firmware in this case.\r
227 //\r
228 return FirstNonAddress;\r
229 }\r
230\r
231 //\r
232 // The "etc/reserved-memory-end" fw_cfg file, when present, contains an\r
233 // absolute, exclusive end address for the memory hotplug area. This area\r
234 // starts right at the end of the memory above 4GB. The 64-bit PCI host\r
235 // aperture must be placed above it.\r
236 //\r
237 Status = QemuFwCfgFindFile ("etc/reserved-memory-end", &FwCfgItem,\r
238 &FwCfgSize);\r
239 if (!EFI_ERROR (Status) && FwCfgSize == sizeof HotPlugMemoryEnd) {\r
240 QemuFwCfgSelectItem (FwCfgItem);\r
241 QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);\r
242\r
243 ASSERT (HotPlugMemoryEnd >= FirstNonAddress);\r
244 FirstNonAddress = HotPlugMemoryEnd;\r
245 }\r
246\r
247 //\r
248 // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so\r
249 // that the host can map it with 1GB hugepages. Follow suit.\r
250 //\r
251 Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);\r
252 Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);\r
253\r
254 //\r
255 // The 64-bit PCI host aperture should also be "naturally" aligned. The\r
256 // alignment is determined by rounding the size of the aperture down to the\r
257 // next smaller or equal power of two. That is, align the aperture by the\r
258 // largest BAR size that can fit into it.\r
259 //\r
260 Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));\r
261\r
262 if (mBootMode != BOOT_ON_S3_RESUME) {\r
263 //\r
264 // The core PciHostBridgeDxe driver will automatically add this range to\r
265 // the GCD memory space map through our PciHostBridgeLib instance; here we\r
266 // only need to set the PCDs.\r
267 //\r
32e083c7
LE
268 PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);\r
269 ASSERT_RETURN_ERROR (PcdStatus);\r
270 PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);\r
271 ASSERT_RETURN_ERROR (PcdStatus);\r
272\r
7e5b1b67
LE
273 DEBUG ((EFI_D_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",\r
274 __FUNCTION__, Pci64Base, Pci64Size));\r
275 }\r
276\r
277 //\r
278 // The useful address space ends with the 64-bit PCI host aperture.\r
279 //\r
280 FirstNonAddress = Pci64Base + Pci64Size;\r
d5371680
LE
281 return FirstNonAddress;\r
282}\r
283\r
284\r
bc89fe48
LE
285/**\r
286 Initialize the mPhysMemAddressWidth variable, based on guest RAM size.\r
287**/\r
288VOID\r
289AddressWidthInitialization (\r
290 VOID\r
291 )\r
292{\r
293 UINT64 FirstNonAddress;\r
294\r
295 //\r
296 // As guest-physical memory size grows, the permanent PEI RAM requirements\r
297 // are dominated by the identity-mapping page tables built by the DXE IPL.\r
298 // The DXL IPL keys off of the physical address bits advertized in the CPU\r
299 // HOB. To conserve memory, we calculate the minimum address width here.\r
300 //\r
d5371680 301 FirstNonAddress = GetFirstNonAddress ();\r
bc89fe48
LE
302 mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);\r
303\r
304 //\r
305 // If FirstNonAddress is not an integral power of two, then we need an\r
306 // additional bit.\r
307 //\r
308 if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {\r
309 ++mPhysMemAddressWidth;\r
310 }\r
311\r
312 //\r
313 // The minimum address width is 36 (covers up to and excluding 64 GB, which\r
314 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for\r
315 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We\r
316 // can simply assert that here, since 48 bits are good enough for 256 TB.\r
317 //\r
318 if (mPhysMemAddressWidth <= 36) {\r
319 mPhysMemAddressWidth = 36;\r
320 }\r
321 ASSERT (mPhysMemAddressWidth <= 48);\r
322}\r
323\r
324\r
325/**\r
326 Calculate the cap for the permanent PEI memory.\r
327**/\r
328STATIC\r
329UINT32\r
330GetPeiMemoryCap (\r
331 VOID\r
332 )\r
333{\r
334 BOOLEAN Page1GSupport;\r
335 UINT32 RegEax;\r
336 UINT32 RegEdx;\r
337 UINT32 Pml4Entries;\r
338 UINT32 PdpEntries;\r
339 UINTN TotalPages;\r
340\r
341 //\r
342 // If DXE is 32-bit, then just return the traditional 64 MB cap.\r
343 //\r
344#ifdef MDE_CPU_IA32\r
345 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
346 return SIZE_64MB;\r
347 }\r
348#endif\r
349\r
350 //\r
351 // Dependent on physical address width, PEI memory allocations can be\r
352 // dominated by the page tables built for 64-bit DXE. So we key the cap off\r
353 // of those. The code below is based on CreateIdentityMappingPageTables() in\r
354 // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".\r
355 //\r
356 Page1GSupport = FALSE;\r
357 if (PcdGetBool (PcdUse1GPageTable)) {\r
358 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
359 if (RegEax >= 0x80000001) {\r
360 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
361 if ((RegEdx & BIT26) != 0) {\r
362 Page1GSupport = TRUE;\r
363 }\r
364 }\r
365 }\r
366\r
367 if (mPhysMemAddressWidth <= 39) {\r
368 Pml4Entries = 1;\r
369 PdpEntries = 1 << (mPhysMemAddressWidth - 30);\r
370 ASSERT (PdpEntries <= 0x200);\r
371 } else {\r
372 Pml4Entries = 1 << (mPhysMemAddressWidth - 39);\r
373 ASSERT (Pml4Entries <= 0x200);\r
374 PdpEntries = 512;\r
375 }\r
376\r
377 TotalPages = Page1GSupport ? Pml4Entries + 1 :\r
378 (PdpEntries + 1) * Pml4Entries + 1;\r
379 ASSERT (TotalPages <= 0x40201);\r
380\r
381 //\r
382 // Add 64 MB for miscellaneous allocations. Note that for\r
383 // mPhysMemAddressWidth values close to 36, the cap will actually be\r
384 // dominated by this increment.\r
385 //\r
386 return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);\r
387}\r
388\r
389\r
36658fff
WL
390/**\r
391 Publish PEI core memory\r
392\r
393 @return EFI_SUCCESS The PEIM initialized successfully.\r
394\r
395**/\r
396EFI_STATUS\r
397PublishPeiMemory (\r
398 VOID\r
399 )\r
400{\r
401 EFI_STATUS Status;\r
402 EFI_PHYSICAL_ADDRESS MemoryBase;\r
403 UINT64 MemorySize;\r
fc3f005a 404 UINT32 LowerMemorySize;\r
bc89fe48 405 UINT32 PeiMemoryCap;\r
36658fff 406\r
45d87081
LE
407 LowerMemorySize = GetSystemMemorySizeBelow4gb ();\r
408 if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
409 //\r
410 // TSEG is chipped from the end of low RAM\r
411 //\r
23bfb5c0 412 LowerMemorySize -= mQ35TsegMbytes * SIZE_1MB;\r
45d87081
LE
413 }\r
414\r
415 //\r
416 // If S3 is supported, then the S3 permanent PEI memory is placed next,\r
417 // downwards. Its size is primarily dictated by CpuMpPei. The formula below\r
418 // is an approximation.\r
419 //\r
420 if (mS3Supported) {\r
421 mS3AcpiReservedMemorySize = SIZE_512KB +\r
45a70db3 422 mMaxCpuCount *\r
45d87081
LE
423 PcdGet32 (PcdCpuApStackSize);\r
424 mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;\r
425 LowerMemorySize = mS3AcpiReservedMemoryBase;\r
426 }\r
427\r
8e54500f 428 if (mBootMode == BOOT_ON_S3_RESUME) {\r
45d87081
LE
429 MemoryBase = mS3AcpiReservedMemoryBase;\r
430 MemorySize = mS3AcpiReservedMemorySize;\r
8e54500f 431 } else {\r
bc89fe48
LE
432 PeiMemoryCap = GetPeiMemoryCap ();\r
433 DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",\r
434 __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));\r
435\r
8e54500f
JJ
436 //\r
437 // Determine the range of memory to use during PEI\r
438 //\r
efb0f16e
LE
439 // Technically we could lay the permanent PEI RAM over SEC's temporary\r
440 // decompression and scratch buffer even if "secure S3" is needed, since\r
441 // their lifetimes don't overlap. However, PeiFvInitialization() will cover\r
442 // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory\r
443 // allocation HOB, and other allocations served from the permanent PEI RAM\r
444 // shouldn't overlap with that HOB.\r
445 //\r
446 MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?\r
447 PcdGet32 (PcdOvmfDecompressionScratchEnd) :\r
448 PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);\r
8e54500f 449 MemorySize = LowerMemorySize - MemoryBase;\r
bc89fe48
LE
450 if (MemorySize > PeiMemoryCap) {\r
451 MemoryBase = LowerMemorySize - PeiMemoryCap;\r
452 MemorySize = PeiMemoryCap;\r
8e54500f 453 }\r
36658fff
WL
454 }\r
455\r
456 //\r
457 // Publish this memory to the PEI Core\r
458 //\r
459 Status = PublishSystemMemory(MemoryBase, MemorySize);\r
460 ASSERT_EFI_ERROR (Status);\r
461\r
462 return Status;\r
463}\r
464\r
c0e10976 465\r
49ba9447 466/**\r
c034906e 467 Peform Memory Detection for QEMU / KVM\r
49ba9447 468\r
469**/\r
c034906e
JJ
470STATIC\r
471VOID\r
472QemuInitializeRam (\r
473 VOID\r
49ba9447 474 )\r
475{\r
c0e10976 476 UINT64 LowerMemorySize;\r
477 UINT64 UpperMemorySize;\r
79d274b8
LE
478 MTRR_SETTINGS MtrrSettings;\r
479 EFI_STATUS Status;\r
49ba9447 480\r
c034906e 481 DEBUG ((EFI_D_INFO, "%a called\n", __FUNCTION__));\r
49ba9447 482\r
483 //\r
484 // Determine total memory size available\r
485 //\r
c0e10976 486 LowerMemorySize = GetSystemMemorySizeBelow4gb ();\r
487 UpperMemorySize = GetSystemMemorySizeAbove4gb ();\r
49ba9447 488\r
e3e3090a
LE
489 if (mBootMode == BOOT_ON_S3_RESUME) {\r
490 //\r
491 // Create the following memory HOB as an exception on the S3 boot path.\r
492 //\r
493 // Normally we'd create memory HOBs only on the normal boot path. However,\r
494 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as\r
495 // well, for "borrowing" a subset of it temporarily, for the AP startup\r
496 // vector.\r
497 //\r
498 // CpuMpPei saves the original contents of the borrowed area in permanent\r
499 // PEI RAM, in a backup buffer allocated with the normal PEI services.\r
500 // CpuMpPei restores the original contents ("returns" the borrowed area) at\r
501 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before\r
8c0b0b34 502 // transferring control to the OS's wakeup vector in the FACS.\r
e3e3090a
LE
503 //\r
504 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to\r
505 // restore the original contents. Furthermore, we expect all such PEIMs\r
506 // (CpuMpPei included) to claim the borrowed areas by producing memory\r
507 // allocation HOBs, and to honor preexistent memory allocation HOBs when\r
508 // looking for an area to borrow.\r
509 //\r
510 AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);\r
511 } else {\r
bd386eaf
JJ
512 //\r
513 // Create memory HOBs\r
514 //\r
bd386eaf 515 AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);\r
b09c1c6f
LE
516\r
517 if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
518 UINT32 TsegSize;\r
519\r
23bfb5c0 520 TsegSize = mQ35TsegMbytes * SIZE_1MB;\r
b09c1c6f
LE
521 AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);\r
522 AddReservedMemoryBaseSizeHob (LowerMemorySize - TsegSize, TsegSize,\r
523 TRUE);\r
524 } else {\r
525 AddMemoryRangeHob (BASE_1MB, LowerMemorySize);\r
526 }\r
527\r
cfc80e2e 528 if (UpperMemorySize != 0) {\r
035ce3b3 529 AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);\r
cfc80e2e 530 }\r
bd386eaf 531 }\r
49ba9447 532\r
79d274b8
LE
533 //\r
534 // We'd like to keep the following ranges uncached:\r
535 // - [640 KB, 1 MB)\r
536 // - [LowerMemorySize, 4 GB)\r
537 //\r
538 // Everything else should be WB. Unfortunately, programming the inverse (ie.\r
539 // keeping the default UC, and configuring the complement set of the above as\r
540 // WB) is not reliable in general, because the end of the upper RAM can have\r
541 // practically any alignment, and we may not have enough variable MTRRs to\r
542 // cover it exactly.\r
543 //\r
544 if (IsMtrrSupported ()) {\r
545 MtrrGetAllMtrrs (&MtrrSettings);\r
546\r
547 //\r
548 // MTRRs disabled, fixed MTRRs disabled, default type is uncached\r
549 //\r
550 ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);\r
551 ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);\r
552 ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);\r
553\r
554 //\r
555 // flip default type to writeback\r
556 //\r
557 SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);\r
558 ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);\r
559 MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;\r
560 MtrrSetAllMtrrs (&MtrrSettings);\r
e8e5cd4a 561\r
79d274b8
LE
562 //\r
563 // Set memory range from 640KB to 1MB to uncacheable\r
564 //\r
565 Status = MtrrSetMemoryAttribute (BASE_512KB + BASE_128KB,\r
566 BASE_1MB - (BASE_512KB + BASE_128KB), CacheUncacheable);\r
567 ASSERT_EFI_ERROR (Status);\r
e8e5cd4a 568\r
79d274b8
LE
569 //\r
570 // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as\r
571 // uncacheable\r
572 //\r
573 Status = MtrrSetMemoryAttribute (LowerMemorySize,\r
574 SIZE_4GB - LowerMemorySize, CacheUncacheable);\r
575 ASSERT_EFI_ERROR (Status);\r
c0e10976 576 }\r
49ba9447 577}\r
578\r
c034906e
JJ
579/**\r
580 Publish system RAM and reserve memory regions\r
581\r
582**/\r
583VOID\r
584InitializeRamRegions (\r
585 VOID\r
586 )\r
587{\r
2818c158
JJ
588 if (!mXen) {\r
589 QemuInitializeRam ();\r
590 } else {\r
2818c158
JJ
591 XenPublishRamRegions ();\r
592 }\r
8e54500f
JJ
593\r
594 if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {\r
595 //\r
596 // This is the memory range that will be used for PEI on S3 resume\r
597 //\r
598 BuildMemoryAllocationHob (\r
45d87081
LE
599 mS3AcpiReservedMemoryBase,\r
600 mS3AcpiReservedMemorySize,\r
8e54500f
JJ
601 EfiACPIMemoryNVS\r
602 );\r
e249f906
LE
603\r
604 //\r
605 // Cover the initial RAM area used as stack and temporary PEI heap.\r
606 //\r
607 // This is reserved as ACPI NVS so it can be used on S3 resume.\r
608 //\r
609 BuildMemoryAllocationHob (\r
610 PcdGet32 (PcdOvmfSecPeiTempRamBase),\r
611 PcdGet32 (PcdOvmfSecPeiTempRamSize),\r
612 EfiACPIMemoryNVS\r
613 );\r
78a38b73 614\r
ad43bc6b
LE
615 //\r
616 // SEC stores its table of GUIDed section handlers here.\r
617 //\r
618 BuildMemoryAllocationHob (\r
619 PcdGet64 (PcdGuidedExtractHandlerTableAddress),\r
620 PcdGet32 (PcdGuidedExtractHandlerTableSize),\r
621 EfiACPIMemoryNVS\r
622 );\r
623\r
78a38b73
LE
624#ifdef MDE_CPU_X64\r
625 //\r
626 // Reserve the initial page tables built by the reset vector code.\r
627 //\r
628 // Since this memory range will be used by the Reset Vector on S3\r
629 // resume, it must be reserved as ACPI NVS.\r
630 //\r
631 BuildMemoryAllocationHob (\r
632 (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecPageTablesBase),\r
633 (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),\r
634 EfiACPIMemoryNVS\r
635 );\r
636#endif\r
0e8a31f5 637 }\r
6a7cba79 638\r
0e8a31f5 639 if (mBootMode != BOOT_ON_S3_RESUME) {\r
1a7edbbc
LE
640 if (!FeaturePcdGet (PcdSmmSmramRequire)) {\r
641 //\r
642 // Reserve the lock box storage area\r
643 //\r
644 // Since this memory range will be used on S3 resume, it must be\r
645 // reserved as ACPI NVS.\r
646 //\r
647 // If S3 is unsupported, then various drivers might still write to the\r
648 // LockBox area. We ought to prevent DXE from serving allocation requests\r
649 // such that they would overlap the LockBox storage.\r
650 //\r
651 ZeroMem (\r
652 (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),\r
653 (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)\r
654 );\r
655 BuildMemoryAllocationHob (\r
656 (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),\r
657 (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),\r
658 mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData\r
659 );\r
660 }\r
b09c1c6f
LE
661\r
662 if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
663 UINT32 TsegSize;\r
664\r
665 //\r
666 // Make sure the TSEG area that we reported as a reserved memory resource\r
667 // cannot be used for reserved memory allocations.\r
668 //\r
23bfb5c0 669 TsegSize = mQ35TsegMbytes * SIZE_1MB;\r
b09c1c6f
LE
670 BuildMemoryAllocationHob (\r
671 GetSystemMemorySizeBelow4gb() - TsegSize,\r
672 TsegSize,\r
673 EfiReservedMemoryType\r
674 );\r
675 }\r
8e54500f 676 }\r
c034906e 677}\r