]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PlatformInitLib/MemDetect.c
OvmfPkg/PlatformInitLib: Add PlatformAddHobCB
[mirror_edk2.git] / OvmfPkg / Library / PlatformInitLib / MemDetect.c
CommitLineData
10460942
MX
1/**@file\r
2 Memory Detection for Virtual Machines.\r
3\r
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7Module Name:\r
8\r
9 MemDetect.c\r
10\r
11**/\r
12\r
13//\r
14// The package level header files this module uses\r
15//\r
16#include <IndustryStandard/E820.h>\r
17#include <IndustryStandard/I440FxPiix4.h>\r
18#include <IndustryStandard/Q35MchIch9.h>\r
19#include <IndustryStandard/CloudHv.h>\r
20#include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>\r
21#include <PiPei.h>\r
22#include <Register/Intel/SmramSaveStateMap.h>\r
23\r
24//\r
25// The Library classes this module consumes\r
26//\r
27#include <Library/BaseLib.h>\r
28#include <Library/BaseMemoryLib.h>\r
e03b0d06 29#include <Library/CcProbeLib.h>\r
10460942 30#include <Library/DebugLib.h>\r
3497fd5c 31#include <Library/HardwareInfoLib.h>\r
10460942
MX
32#include <Library/HobLib.h>\r
33#include <Library/IoLib.h>\r
34#include <Library/MemEncryptSevLib.h>\r
35#include <Library/PcdLib.h>\r
36#include <Library/PciLib.h>\r
37#include <Library/PeimEntryPoint.h>\r
38#include <Library/ResourcePublicationLib.h>\r
39#include <Library/MtrrLib.h>\r
40#include <Library/QemuFwCfgLib.h>\r
41#include <Library/QemuFwCfgSimpleParserLib.h>\r
e23f8f52
MX
42#include <Library/TdxLib.h>\r
43\r
10460942
MX
44#include <Library/PlatformInitLib.h>\r
45\r
d1e41c62
MX
46#define MEGABYTE_SHIFT 20\r
47\r
10460942
MX
48VOID\r
49EFIAPI\r
50PlatformQemuUc32BaseInitialization (\r
51 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
52 )\r
53{\r
10460942
MX
54 if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {\r
55 return;\r
56 }\r
57\r
58 if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
124b7650 59 PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);\r
47f44097 60 ASSERT (PcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);\r
124b7650 61 ASSERT (PcdGet64 (PcdPciExpressBaseAddress) >= PlatformInfoHob->LowMemory);\r
2a0bd3bf 62\r
124b7650 63 if (PlatformInfoHob->LowMemory <= BASE_2GB) {\r
2a0bd3bf
GH
64 // Newer qemu with gigabyte aligned memory,\r
65 // 32-bit pci mmio window is 2G -> 4G then.\r
66 PlatformInfoHob->Uc32Base = BASE_2GB;\r
67 } else {\r
68 //\r
69 // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,\r
70 // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for\r
71 // setting PcdPciExpressBaseAddress such that describing the\r
72 // [PcdPciExpressBaseAddress, 4GB) range require a very small number of\r
73 // variable MTRRs (preferably 1 or 2).\r
74 //\r
75 PlatformInfoHob->Uc32Base = (UINT32)PcdGet64 (PcdPciExpressBaseAddress);\r
76 }\r
77\r
10460942
MX
78 return;\r
79 }\r
80\r
81 if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {\r
82 PlatformInfoHob->Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;\r
83 PlatformInfoHob->Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;\r
84 return;\r
85 }\r
86\r
87 ASSERT (PlatformInfoHob->HostBridgeDevId == INTEL_82441_DEVICE_ID);\r
88 //\r
89 // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one\r
90 // variable MTRR suffices by truncating the size to a whole power of two,\r
91 // while keeping the end affixed to 4GB. This will round the base up.\r
92 //\r
124b7650
GH
93 PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);\r
94 PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - PlatformInfoHob->LowMemory));\r
10460942
MX
95 PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size);\r
96 //\r
97 // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.\r
98 // Therefore Uc32Base is at least 2GB.\r
99 //\r
100 ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB);\r
101\r
124b7650 102 if (PlatformInfoHob->Uc32Base != PlatformInfoHob->LowMemory) {\r
10460942
MX
103 DEBUG ((\r
104 DEBUG_VERBOSE,\r
105 "%a: rounded UC32 base from 0x%x up to 0x%x, for "\r
106 "an UC32 size of 0x%x\n",\r
107 __FUNCTION__,\r
124b7650 108 PlatformInfoHob->LowMemory,\r
10460942
MX
109 PlatformInfoHob->Uc32Base,\r
110 PlatformInfoHob->Uc32Size\r
111 ));\r
112 }\r
113}\r
114\r
e0375304
GH
115typedef VOID (*E820_SCAN_CALLBACK) (\r
116 EFI_E820_ENTRY64 *E820Entry,\r
117 EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
118 );\r
119\r
120/**\r
121 Store first address not used by e820 RAM entries in\r
122 PlatformInfoHob->FirstNonAddress\r
123**/\r
124STATIC\r
125VOID\r
126PlatformGetFirstNonAddressCB (\r
127 IN EFI_E820_ENTRY64 *E820Entry,\r
128 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
129 )\r
130{\r
131 UINT64 Candidate;\r
132\r
133 if (E820Entry->Type != EfiAcpiAddressRangeMemory) {\r
134 return;\r
135 }\r
136\r
137 Candidate = E820Entry->BaseAddr + E820Entry->Length;\r
138 if (PlatformInfoHob->FirstNonAddress < Candidate) {\r
139 DEBUG ((DEBUG_INFO, "%a: FirstNonAddress=0x%Lx\n", __FUNCTION__, Candidate));\r
140 PlatformInfoHob->FirstNonAddress = Candidate;\r
141 }\r
142}\r
143\r
124b7650
GH
144/**\r
145 Store the low (below 4G) memory size in\r
146 PlatformInfoHob->LowMemory\r
147**/\r
148STATIC\r
149VOID\r
150PlatformGetLowMemoryCB (\r
151 IN EFI_E820_ENTRY64 *E820Entry,\r
152 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
153 )\r
154{\r
155 UINT64 Candidate;\r
156\r
157 if (E820Entry->Type != EfiAcpiAddressRangeMemory) {\r
158 return;\r
159 }\r
160\r
161 Candidate = E820Entry->BaseAddr + E820Entry->Length;\r
162 if (Candidate >= BASE_4GB) {\r
163 return;\r
164 }\r
165\r
166 if (PlatformInfoHob->LowMemory < Candidate) {\r
167 DEBUG ((DEBUG_INFO, "%a: LowMemory=0x%Lx\n", __FUNCTION__, Candidate));\r
168 PlatformInfoHob->LowMemory = (UINT32)Candidate;\r
169 }\r
170}\r
171\r
328076cf
GH
172/**\r
173 Create HOBs for reservations and RAM (except low memory).\r
174**/\r
175STATIC\r
176VOID\r
177PlatformAddHobCB (\r
178 IN EFI_E820_ENTRY64 *E820Entry,\r
179 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
180 )\r
181{\r
182 UINT64 Base, End;\r
183\r
184 Base = E820Entry->BaseAddr;\r
185 End = E820Entry->BaseAddr + E820Entry->Length;\r
186\r
187 switch (E820Entry->Type) {\r
188 case EfiAcpiAddressRangeMemory:\r
189 if (Base >= BASE_4GB) {\r
190 //\r
191 // Round up the start address, and round down the end address.\r
192 //\r
193 Base = ALIGN_VALUE (Base, (UINT64)EFI_PAGE_SIZE);\r
194 End = End & ~(UINT64)EFI_PAGE_MASK;\r
195 if (Base < End) {\r
196 DEBUG ((DEBUG_INFO, "%a: HighMemory [0x%Lx, 0x%Lx)\n", __FUNCTION__, Base, End));\r
197 PlatformAddMemoryRangeHob (Base, End);\r
198 }\r
199 }\r
200\r
201 break;\r
202 case EfiAcpiAddressRangeReserved:\r
203 BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_RESERVED, 0, Base, End);\r
204 DEBUG ((DEBUG_INFO, "%a: Reserved [0x%Lx, 0x%Lx)\n", __FUNCTION__, Base, End));\r
205 break;\r
206 default:\r
207 DEBUG ((\r
208 DEBUG_WARN,\r
209 "%a: Type %u [0x%Lx, 0x%Lx) (NOT HANDLED)\n",\r
210 __FUNCTION__,\r
211 E820Entry->Type,\r
212 Base,\r
213 End\r
214 ));\r
215 break;\r
216 }\r
217}\r
218\r
e0375304
GH
219/**\r
220 Iterate over the entries in QEMU's fw_cfg E820 RAM map, call the\r
221 passed callback for each entry.\r
222\r
223 @param[in] Callback The callback function to be called.\r
224\r
225 @param[in out] PlatformInfoHob PlatformInfo struct which is passed\r
226 through to the callback.\r
227\r
228 @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.\r
229\r
230 @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a\r
231 whole multiple of sizeof(EFI_E820_ENTRY64). No\r
232 RAM entry was processed.\r
233\r
234 @return Error codes from QemuFwCfgFindFile(). No RAM\r
235 entry was processed.\r
236**/\r
237STATIC\r
238EFI_STATUS\r
239PlatformScanE820 (\r
240 IN E820_SCAN_CALLBACK Callback,\r
241 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
242 )\r
243{\r
244 EFI_STATUS Status;\r
245 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
246 UINTN FwCfgSize;\r
247 EFI_E820_ENTRY64 E820Entry;\r
248 UINTN Processed;\r
249\r
250 Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);\r
251 if (EFI_ERROR (Status)) {\r
252 return Status;\r
253 }\r
254\r
255 if (FwCfgSize % sizeof E820Entry != 0) {\r
256 return EFI_PROTOCOL_ERROR;\r
257 }\r
258\r
259 QemuFwCfgSelectItem (FwCfgItem);\r
260 for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {\r
261 QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);\r
262 Callback (&E820Entry, PlatformInfoHob);\r
263 }\r
264\r
265 return EFI_SUCCESS;\r
266}\r
267\r
10460942
MX
268/**\r
269 Returns PVH memmap\r
270\r
271 @param Entries Pointer to PVH memmap\r
272 @param Count Number of entries\r
273\r
274 @return EFI_STATUS\r
275**/\r
276EFI_STATUS\r
277GetPvhMemmapEntries (\r
278 struct hvm_memmap_table_entry **Entries,\r
279 UINT32 *Count\r
280 )\r
281{\r
282 UINT32 *PVHResetVectorData;\r
283 struct hvm_start_info *pvh_start_info;\r
284\r
285 PVHResetVectorData = (VOID *)(UINTN)PcdGet32 (PcdXenPvhStartOfDayStructPtr);\r
286 if (PVHResetVectorData == 0) {\r
287 return EFI_NOT_FOUND;\r
288 }\r
289\r
290 pvh_start_info = (struct hvm_start_info *)(UINTN)PVHResetVectorData[0];\r
291\r
292 *Entries = (struct hvm_memmap_table_entry *)(UINTN)pvh_start_info->memmap_paddr;\r
293 *Count = pvh_start_info->memmap_entries;\r
294\r
295 return EFI_SUCCESS;\r
296}\r
297\r
298STATIC\r
299UINT64\r
300GetHighestSystemMemoryAddressFromPvhMemmap (\r
301 BOOLEAN Below4gb\r
302 )\r
303{\r
304 struct hvm_memmap_table_entry *Memmap;\r
305 UINT32 MemmapEntriesCount;\r
306 struct hvm_memmap_table_entry *Entry;\r
307 EFI_STATUS Status;\r
308 UINT32 Loop;\r
309 UINT64 HighestAddress;\r
310 UINT64 EntryEnd;\r
311\r
312 HighestAddress = 0;\r
313\r
314 Status = GetPvhMemmapEntries (&Memmap, &MemmapEntriesCount);\r
315 ASSERT_EFI_ERROR (Status);\r
316\r
317 for (Loop = 0; Loop < MemmapEntriesCount; Loop++) {\r
318 Entry = Memmap + Loop;\r
319 EntryEnd = Entry->addr + Entry->size;\r
320\r
321 if ((Entry->type == XEN_HVM_MEMMAP_TYPE_RAM) &&\r
322 (EntryEnd > HighestAddress))\r
323 {\r
324 if (Below4gb && (EntryEnd <= BASE_4GB)) {\r
325 HighestAddress = EntryEnd;\r
326 } else if (!Below4gb && (EntryEnd >= BASE_4GB)) {\r
327 HighestAddress = EntryEnd;\r
328 }\r
329 }\r
330 }\r
331\r
332 return HighestAddress;\r
333}\r
334\r
124b7650 335VOID\r
10460942
MX
336EFIAPI\r
337PlatformGetSystemMemorySizeBelow4gb (\r
338 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
339 )\r
340{\r
341 EFI_STATUS Status;\r
10460942
MX
342 UINT8 Cmos0x34;\r
343 UINT8 Cmos0x35;\r
344\r
e03b0d06
SB
345 if ((PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) &&\r
346 (CcProbe () != CcGuestTypeIntelTdx))\r
347 {\r
10460942 348 // Get the information from PVH memmap\r
124b7650
GH
349 PlatformInfoHob->LowMemory = (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE);\r
350 return;\r
10460942
MX
351 }\r
352\r
124b7650
GH
353 Status = PlatformScanE820 (PlatformGetLowMemoryCB, PlatformInfoHob);\r
354 if (!EFI_ERROR (Status) && (PlatformInfoHob->LowMemory > 0)) {\r
355 return;\r
10460942
MX
356 }\r
357\r
358 //\r
359 // CMOS 0x34/0x35 specifies the system memory above 16 MB.\r
360 // * CMOS(0x35) is the high byte\r
361 // * CMOS(0x34) is the low byte\r
362 // * The size is specified in 64kb chunks\r
363 // * Since this is memory above 16MB, the 16MB must be added\r
364 // into the calculation to get the total memory size.\r
365 //\r
366\r
367 Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);\r
368 Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);\r
369\r
124b7650 370 PlatformInfoHob->LowMemory = (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);\r
10460942
MX
371}\r
372\r
373STATIC\r
374UINT64\r
375PlatformGetSystemMemorySizeAbove4gb (\r
376 )\r
377{\r
378 UINT32 Size;\r
379 UINTN CmosIndex;\r
380\r
381 //\r
382 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.\r
383 // * CMOS(0x5d) is the most significant size byte\r
384 // * CMOS(0x5c) is the middle size byte\r
385 // * CMOS(0x5b) is the least significant size byte\r
386 // * The size is specified in 64kb chunks\r
387 //\r
388\r
389 Size = 0;\r
390 for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {\r
391 Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);\r
392 }\r
393\r
394 return LShiftU64 (Size, 16);\r
395}\r
396\r
397/**\r
398 Return the highest address that DXE could possibly use, plus one.\r
399**/\r
400STATIC\r
e0375304 401VOID\r
10460942
MX
402PlatformGetFirstNonAddress (\r
403 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
404 )\r
405{\r
10460942
MX
406 UINT32 FwCfgPciMmio64Mb;\r
407 EFI_STATUS Status;\r
408 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
409 UINTN FwCfgSize;\r
410 UINT64 HotPlugMemoryEnd;\r
411\r
10460942
MX
412 //\r
413 // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM\r
414 // address from it. This can express an address >= 4GB+1TB.\r
415 //\r
416 // Otherwise, get the flat size of the memory above 4GB from the CMOS (which\r
417 // can only express a size smaller than 1TB), and add it to 4GB.\r
418 //\r
e0375304
GH
419 PlatformInfoHob->FirstNonAddress = BASE_4GB;\r
420 Status = PlatformScanE820 (PlatformGetFirstNonAddressCB, PlatformInfoHob);\r
10460942 421 if (EFI_ERROR (Status)) {\r
e0375304 422 PlatformInfoHob->FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();\r
10460942
MX
423 }\r
424\r
425 //\r
426 // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO\r
427 // resources to 32-bit anyway. See DegradeResource() in\r
428 // "PciResourceSupport.c".\r
429 //\r
430 #ifdef MDE_CPU_IA32\r
431 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
e0375304 432 return;\r
10460942
MX
433 }\r
434\r
435 #endif\r
436\r
437 //\r
438 // See if the user specified the number of megabytes for the 64-bit PCI host\r
439 // aperture. Accept an aperture size up to 16TB.\r
440 //\r
441 // As signaled by the "X-" prefix, this knob is experimental, and might go\r
442 // away at any time.\r
443 //\r
444 Status = QemuFwCfgParseUint32 (\r
445 "opt/ovmf/X-PciMmio64Mb",\r
446 FALSE,\r
447 &FwCfgPciMmio64Mb\r
448 );\r
449 switch (Status) {\r
450 case EFI_UNSUPPORTED:\r
451 case EFI_NOT_FOUND:\r
452 break;\r
453 case EFI_SUCCESS:\r
454 if (FwCfgPciMmio64Mb <= 0x1000000) {\r
455 PlatformInfoHob->PcdPciMmio64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);\r
456 break;\r
457 }\r
458\r
459 //\r
460 // fall through\r
461 //\r
462 default:\r
463 DEBUG ((\r
464 DEBUG_WARN,\r
465 "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",\r
466 __FUNCTION__\r
467 ));\r
468 break;\r
469 }\r
470\r
471 if (PlatformInfoHob->PcdPciMmio64Size == 0) {\r
472 if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {\r
473 DEBUG ((\r
474 DEBUG_INFO,\r
475 "%a: disabling 64-bit PCI host aperture\n",\r
476 __FUNCTION__\r
477 ));\r
478 }\r
479\r
480 //\r
481 // There's nothing more to do; the amount of memory above 4GB fully\r
482 // determines the highest address plus one. The memory hotplug area (see\r
483 // below) plays no role for the firmware in this case.\r
484 //\r
e0375304 485 return;\r
10460942
MX
486 }\r
487\r
488 //\r
489 // The "etc/reserved-memory-end" fw_cfg file, when present, contains an\r
490 // absolute, exclusive end address for the memory hotplug area. This area\r
491 // starts right at the end of the memory above 4GB. The 64-bit PCI host\r
492 // aperture must be placed above it.\r
493 //\r
494 Status = QemuFwCfgFindFile (\r
495 "etc/reserved-memory-end",\r
496 &FwCfgItem,\r
497 &FwCfgSize\r
498 );\r
499 if (!EFI_ERROR (Status) && (FwCfgSize == sizeof HotPlugMemoryEnd)) {\r
500 QemuFwCfgSelectItem (FwCfgItem);\r
501 QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);\r
502 DEBUG ((\r
503 DEBUG_VERBOSE,\r
504 "%a: HotPlugMemoryEnd=0x%Lx\n",\r
505 __FUNCTION__,\r
506 HotPlugMemoryEnd\r
507 ));\r
508\r
e0375304
GH
509 ASSERT (HotPlugMemoryEnd >= PlatformInfoHob->FirstNonAddress);\r
510 PlatformInfoHob->FirstNonAddress = HotPlugMemoryEnd;\r
10460942
MX
511 }\r
512\r
513 //\r
514 // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so\r
515 // that the host can map it with 1GB hugepages. Follow suit.\r
516 //\r
e0375304 517 PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->FirstNonAddress, (UINT64)SIZE_1GB);\r
10460942
MX
518 PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (UINT64)SIZE_1GB);\r
519\r
520 //\r
521 // The 64-bit PCI host aperture should also be "naturally" aligned. The\r
522 // alignment is determined by rounding the size of the aperture down to the\r
523 // next smaller or equal power of two. That is, align the aperture by the\r
524 // largest BAR size that can fit into it.\r
525 //\r
526 PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Base, GetPowerOfTwo64 (PlatformInfoHob->PcdPciMmio64Size));\r
527\r
528 //\r
529 // The useful address space ends with the 64-bit PCI host aperture.\r
530 //\r
e0375304
GH
531 PlatformInfoHob->FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;\r
532 return;\r
10460942
MX
533}\r
534\r
bd10d4e2 535/*\r
8f9ef9c9 536 * Use CPUID to figure physical address width.\r
bd10d4e2 537 *\r
8f9ef9c9
GH
538 * Does *not* work reliable on qemu. For historical reasons qemu\r
539 * returns phys-bits=40 by default even in case the host machine\r
540 * supports less than that.\r
541 *\r
542 * So we apply the following rules (which can be enabled/disabled\r
543 * using the QemuQuirk parameter) to figure whenever we can work with\r
544 * the returned physical address width or not:\r
545 *\r
546 * (1) If it is 41 or higher consider it valid.\r
547 * (2) If it is 40 or lower consider it valid in case it matches a\r
548 * known-good value for the CPU vendor, which is:\r
549 * -> 36 or 39 for Intel\r
550 * -> 40 for AMD\r
551 * (3) Otherwise consider it invalid.\r
552 *\r
553 * Recommendation: Run qemu with host-phys-bits=on. That will make\r
554 * sure guest phys-bits is not larger than host phys-bits. Some\r
555 * distro builds do that by default.\r
bd10d4e2
GH
556 */\r
557VOID\r
558EFIAPI\r
559PlatformAddressWidthFromCpuid (\r
8f9ef9c9
GH
560 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob,\r
561 IN BOOLEAN QemuQuirk\r
bd10d4e2
GH
562 )\r
563{\r
8f9ef9c9
GH
564 UINT32 RegEax, RegEbx, RegEcx, RegEdx, Max;\r
565 UINT8 PhysBits;\r
566 CHAR8 Signature[13] = { 0 };\r
567 BOOLEAN Valid = FALSE;\r
568 BOOLEAN Page1GSupport = FALSE;\r
569\r
570 AsmCpuid (0x80000000, &RegEax, &RegEbx, &RegEcx, &RegEdx);\r
571 *(UINT32 *)(Signature + 0) = RegEbx;\r
572 *(UINT32 *)(Signature + 4) = RegEdx;\r
573 *(UINT32 *)(Signature + 8) = RegEcx;\r
574 Max = RegEax;\r
575\r
576 if (Max >= 0x80000001) {\r
577 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
578 if ((RegEdx & BIT26) != 0) {\r
579 Page1GSupport = TRUE;\r
580 }\r
581 }\r
bd10d4e2 582\r
8f9ef9c9 583 if (Max >= 0x80000008) {\r
bd10d4e2 584 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
8f9ef9c9 585 PhysBits = (UINT8)RegEax;\r
bd10d4e2 586 } else {\r
8f9ef9c9 587 PhysBits = 36;\r
bd10d4e2
GH
588 }\r
589\r
8f9ef9c9
GH
590 if (!QemuQuirk) {\r
591 Valid = TRUE;\r
592 } else if (PhysBits >= 41) {\r
593 Valid = TRUE;\r
594 } else if (AsciiStrCmp (Signature, "GenuineIntel") == 0) {\r
595 if ((PhysBits == 36) || (PhysBits == 39)) {\r
596 Valid = TRUE;\r
597 }\r
598 } else if (AsciiStrCmp (Signature, "AuthenticAMD") == 0) {\r
599 if (PhysBits == 40) {\r
600 Valid = TRUE;\r
601 }\r
602 }\r
bd10d4e2
GH
603\r
604 DEBUG ((\r
605 DEBUG_INFO,\r
8f9ef9c9 606 "%a: Signature: '%a', PhysBits: %d, QemuQuirk: %a, Valid: %a\n",\r
bd10d4e2 607 __FUNCTION__,\r
8f9ef9c9
GH
608 Signature,\r
609 PhysBits,\r
610 QemuQuirk ? "On" : "Off",\r
611 Valid ? "Yes" : "No"\r
bd10d4e2 612 ));\r
8f9ef9c9
GH
613\r
614 if (Valid) {\r
615 if (PhysBits > 47) {\r
616 /*\r
617 * Avoid 5-level paging altogether for now, which limits\r
618 * PhysBits to 48. Also avoid using address bit 48, due to sign\r
619 * extension we can't identity-map these addresses (and lots of\r
620 * places in edk2 assume we have everything identity-mapped).\r
621 * So the actual limit is 47.\r
622 */\r
623 DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 47 (avoid 5-level paging)\n", __func__));\r
624 PhysBits = 47;\r
625 }\r
626\r
627 if (!Page1GSupport && (PhysBits > 40)) {\r
628 DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 40 (no 1G pages available)\n", __func__));\r
629 PhysBits = 40;\r
630 }\r
631\r
632 PlatformInfoHob->PhysMemAddressWidth = PhysBits;\r
633 PlatformInfoHob->FirstNonAddress = LShiftU64 (1, PlatformInfoHob->PhysMemAddressWidth);\r
634 }\r
bd10d4e2
GH
635}\r
636\r
ecb778d0
GH
637VOID\r
638EFIAPI\r
639PlatformDynamicMmioWindow (\r
640 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
641 )\r
642{\r
643 UINT64 AddrSpace, MmioSpace;\r
644\r
645 AddrSpace = LShiftU64 (1, PlatformInfoHob->PhysMemAddressWidth);\r
646 MmioSpace = LShiftU64 (1, PlatformInfoHob->PhysMemAddressWidth - 3);\r
647\r
648 if ((PlatformInfoHob->PcdPciMmio64Size < MmioSpace) &&\r
649 (PlatformInfoHob->PcdPciMmio64Base + MmioSpace < AddrSpace))\r
650 {\r
651 DEBUG ((DEBUG_INFO, "%a: using dynamic mmio window\n", __func__));\r
652 DEBUG ((DEBUG_INFO, "%a: Addr Space 0x%Lx (%Ld GB)\n", __func__, AddrSpace, RShiftU64 (AddrSpace, 30)));\r
653 DEBUG ((DEBUG_INFO, "%a: MMIO Space 0x%Lx (%Ld GB)\n", __func__, MmioSpace, RShiftU64 (MmioSpace, 30)));\r
654 PlatformInfoHob->PcdPciMmio64Size = MmioSpace;\r
655 PlatformInfoHob->PcdPciMmio64Base = AddrSpace - MmioSpace;\r
656 } else {\r
657 DEBUG ((DEBUG_INFO, "%a: using classic mmio window\n", __func__));\r
658 }\r
659\r
660 DEBUG ((DEBUG_INFO, "%a: Pci64 Base 0x%Lx\n", __func__, PlatformInfoHob->PcdPciMmio64Base));\r
661 DEBUG ((DEBUG_INFO, "%a: Pci64 Size 0x%Lx\n", __func__, PlatformInfoHob->PcdPciMmio64Size));\r
662}\r
663\r
3497fd5c
NOL
664/**\r
665 Iterate over the PCI host bridges resources information optionally provided\r
666 in fw-cfg and find the highest address contained in the PCI MMIO windows. If\r
667 the information is found, return the exclusive end; one past the last usable\r
668 address.\r
669\r
670 @param[out] PciMmioAddressEnd Pointer to one-after End Address updated with\r
671 information extracted from host-provided data\r
672 or zero if no information available or an\r
673 error happened\r
674\r
675 @retval EFI_SUCCESS PCI information was read and the output\r
676 parameter updated with the last valid\r
677 address in the 64-bit MMIO range.\r
678 @retval EFI_INVALID_PARAMETER Pointer parameter is invalid\r
679 @retval EFI_INCOMPATIBLE_VERSION Hardware information found in fw-cfg\r
680 has an incompatible format\r
681 @retval EFI_UNSUPPORTED Fw-cfg is not supported, thus host\r
682 provided information, if any, cannot be\r
683 read\r
684 @retval EFI_NOT_FOUND No PCI host bridge information provided\r
685 by the host.\r
686**/\r
687STATIC\r
688EFI_STATUS\r
689PlatformScanHostProvided64BitPciMmioEnd (\r
690 OUT UINT64 *PciMmioAddressEnd\r
691 )\r
692{\r
693 EFI_STATUS Status;\r
694 HOST_BRIDGE_INFO HostBridge;\r
695 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
696 UINTN FwCfgSize;\r
697 UINTN FwCfgReadIndex;\r
698 UINTN ReadDataSize;\r
699 UINT64 Above4GMmioEnd;\r
700\r
701 if (PciMmioAddressEnd == NULL) {\r
702 return EFI_INVALID_PARAMETER;\r
703 }\r
704\r
705 *PciMmioAddressEnd = 0;\r
706 Above4GMmioEnd = 0;\r
707\r
708 Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);\r
709 if (EFI_ERROR (Status)) {\r
710 return Status;\r
711 }\r
712\r
713 QemuFwCfgSelectItem (FwCfgItem);\r
714\r
715 FwCfgReadIndex = 0;\r
716 while (FwCfgReadIndex < FwCfgSize) {\r
717 Status = QemuFwCfgReadNextHardwareInfoByType (\r
718 HardwareInfoTypeHostBridge,\r
719 sizeof (HostBridge),\r
720 FwCfgSize,\r
721 &HostBridge,\r
722 &ReadDataSize,\r
723 &FwCfgReadIndex\r
724 );\r
725\r
726 if (Status != EFI_SUCCESS) {\r
727 //\r
728 // No more data available to read in the file, break\r
729 // loop and finish process\r
730 //\r
731 break;\r
732 }\r
733\r
734 Status = HardwareInfoPciHostBridgeLastMmioAddress (\r
735 &HostBridge,\r
736 ReadDataSize,\r
737 TRUE,\r
738 &Above4GMmioEnd\r
739 );\r
740\r
741 if (Status != EFI_SUCCESS) {\r
742 //\r
743 // Error parsing MMIO apertures and extracting last MMIO\r
744 // address, reset PciMmioAddressEnd as if no information was\r
745 // found, to avoid moving forward with incomplete data, and\r
746 // bail out\r
747 //\r
748 DEBUG ((\r
749 DEBUG_ERROR,\r
750 "%a: ignoring malformed hardware information from fw_cfg\n",\r
751 __FUNCTION__\r
752 ));\r
753 *PciMmioAddressEnd = 0;\r
754 return Status;\r
755 }\r
756\r
757 if (Above4GMmioEnd > *PciMmioAddressEnd) {\r
758 *PciMmioAddressEnd = Above4GMmioEnd;\r
759 }\r
760 }\r
761\r
762 if (*PciMmioAddressEnd > 0) {\r
763 //\r
764 // Host-provided PCI information was found and a MMIO window end\r
765 // derived from it.\r
766 // Increase the End address by one to have the output pointing to\r
767 // one after the address in use (exclusive end).\r
768 //\r
769 *PciMmioAddressEnd += 1;\r
770\r
771 DEBUG ((\r
772 DEBUG_INFO,\r
773 "%a: Pci64End=0x%Lx\n",\r
774 __FUNCTION__,\r
775 *PciMmioAddressEnd\r
776 ));\r
777\r
778 return EFI_SUCCESS;\r
779 }\r
780\r
781 return EFI_NOT_FOUND;\r
782}\r
783\r
10460942
MX
784/**\r
785 Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.\r
786**/\r
787VOID\r
788EFIAPI\r
789PlatformAddressWidthInitialization (\r
790 IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
791 )\r
792{\r
3497fd5c
NOL
793 UINT8 PhysMemAddressWidth;\r
794 EFI_STATUS Status;\r
10460942 795\r
bd10d4e2 796 if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {\r
8f9ef9c9 797 PlatformAddressWidthFromCpuid (PlatformInfoHob, FALSE);\r
bd10d4e2
GH
798 return;\r
799 }\r
800\r
10460942 801 //\r
3497fd5c
NOL
802 // First scan host-provided hardware information to assess if the address\r
803 // space is already known. If so, guest must use those values.\r
10460942 804 //\r
e0375304 805 Status = PlatformScanHostProvided64BitPciMmioEnd (&PlatformInfoHob->FirstNonAddress);\r
3497fd5c
NOL
806\r
807 if (EFI_ERROR (Status)) {\r
808 //\r
809 // If the host did not provide valid hardware information leading to a\r
810 // hard-defined 64-bit MMIO end, fold back to calculating the minimum range\r
811 // needed.\r
812 // As guest-physical memory size grows, the permanent PEI RAM requirements\r
813 // are dominated by the identity-mapping page tables built by the DXE IPL.\r
814 // The DXL IPL keys off of the physical address bits advertized in the CPU\r
815 // HOB. To conserve memory, we calculate the minimum address width here.\r
816 //\r
e0375304 817 PlatformGetFirstNonAddress (PlatformInfoHob);\r
3497fd5c
NOL
818 }\r
819\r
bbda386d
GH
820 PlatformAddressWidthFromCpuid (PlatformInfoHob, TRUE);\r
821 if (PlatformInfoHob->PhysMemAddressWidth != 0) {\r
822 // physical address width is known\r
ecb778d0 823 PlatformDynamicMmioWindow (PlatformInfoHob);\r
bbda386d
GH
824 return;\r
825 }\r
826\r
827 //\r
828 // physical address width is NOT known\r
829 // -> do some guess work, mostly based on installed memory\r
830 // -> try be conservstibe to stay below the guaranteed minimum of\r
831 // 36 phys bits (aka 64 GB).\r
832 //\r
e0375304 833 PhysMemAddressWidth = (UINT8)HighBitSet64 (PlatformInfoHob->FirstNonAddress);\r
10460942
MX
834\r
835 //\r
836 // If FirstNonAddress is not an integral power of two, then we need an\r
837 // additional bit.\r
838 //\r
e0375304 839 if ((PlatformInfoHob->FirstNonAddress & (PlatformInfoHob->FirstNonAddress - 1)) != 0) {\r
10460942
MX
840 ++PhysMemAddressWidth;\r
841 }\r
842\r
843 //\r
844 // The minimum address width is 36 (covers up to and excluding 64 GB, which\r
845 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for\r
846 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We\r
847 // can simply assert that here, since 48 bits are good enough for 256 TB.\r
848 //\r
849 if (PhysMemAddressWidth <= 36) {\r
850 PhysMemAddressWidth = 36;\r
851 }\r
852\r
e23f8f52
MX
853 #if defined (MDE_CPU_X64)\r
854 if (TdIsEnabled ()) {\r
855 if (TdSharedPageMask () == (1ULL << 47)) {\r
856 PhysMemAddressWidth = 48;\r
857 } else {\r
858 PhysMemAddressWidth = 52;\r
859 }\r
860 }\r
861\r
862 ASSERT (PhysMemAddressWidth <= 52);\r
863 #else\r
10460942 864 ASSERT (PhysMemAddressWidth <= 48);\r
e23f8f52 865 #endif\r
10460942 866\r
10460942
MX
867 PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;\r
868}\r
869\r
870STATIC\r
871VOID\r
872QemuInitializeRamBelow1gb (\r
873 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
874 )\r
875{\r
876 if (PlatformInfoHob->SmmSmramRequire && PlatformInfoHob->Q35SmramAtDefaultSmbase) {\r
877 PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);\r
878 PlatformAddReservedMemoryBaseSizeHob (\r
879 SMM_DEFAULT_SMBASE,\r
880 MCH_DEFAULT_SMBASE_SIZE,\r
881 TRUE /* Cacheable */\r
882 );\r
883 STATIC_ASSERT (\r
884 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,\r
885 "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"\r
886 );\r
887 PlatformAddMemoryRangeHob (\r
888 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,\r
889 BASE_512KB + BASE_128KB\r
890 );\r
891 } else {\r
892 PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);\r
893 }\r
894}\r
895\r
896/**\r
897 Peform Memory Detection for QEMU / KVM\r
898\r
899**/\r
900VOID\r
901EFIAPI\r
902PlatformQemuInitializeRam (\r
903 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
904 )\r
905{\r
10460942
MX
906 UINT64 UpperMemorySize;\r
907 MTRR_SETTINGS MtrrSettings;\r
908 EFI_STATUS Status;\r
909\r
910 DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));\r
911\r
912 //\r
913 // Determine total memory size available\r
914 //\r
124b7650 915 PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);\r
10460942
MX
916\r
917 if (PlatformInfoHob->BootMode == BOOT_ON_S3_RESUME) {\r
918 //\r
919 // Create the following memory HOB as an exception on the S3 boot path.\r
920 //\r
921 // Normally we'd create memory HOBs only on the normal boot path. However,\r
922 // CpuMpPei specifically needs such a low-memory HOB on the S3 path as\r
923 // well, for "borrowing" a subset of it temporarily, for the AP startup\r
924 // vector.\r
925 //\r
926 // CpuMpPei saves the original contents of the borrowed area in permanent\r
927 // PEI RAM, in a backup buffer allocated with the normal PEI services.\r
928 // CpuMpPei restores the original contents ("returns" the borrowed area) at\r
929 // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before\r
930 // transferring control to the OS's wakeup vector in the FACS.\r
931 //\r
932 // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to\r
933 // restore the original contents. Furthermore, we expect all such PEIMs\r
934 // (CpuMpPei included) to claim the borrowed areas by producing memory\r
935 // allocation HOBs, and to honor preexistent memory allocation HOBs when\r
936 // looking for an area to borrow.\r
937 //\r
938 QemuInitializeRamBelow1gb (PlatformInfoHob);\r
939 } else {\r
940 //\r
941 // Create memory HOBs\r
942 //\r
943 QemuInitializeRamBelow1gb (PlatformInfoHob);\r
944\r
945 if (PlatformInfoHob->SmmSmramRequire) {\r
946 UINT32 TsegSize;\r
947\r
948 TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;\r
124b7650 949 PlatformAddMemoryRangeHob (BASE_1MB, PlatformInfoHob->LowMemory - TsegSize);\r
10460942 950 PlatformAddReservedMemoryBaseSizeHob (\r
124b7650 951 PlatformInfoHob->LowMemory - TsegSize,\r
10460942
MX
952 TsegSize,\r
953 TRUE\r
954 );\r
955 } else {\r
124b7650 956 PlatformAddMemoryRangeHob (BASE_1MB, PlatformInfoHob->LowMemory);\r
10460942
MX
957 }\r
958\r
959 //\r
960 // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM\r
961 // entries. Otherwise, create a single memory HOB with the flat >=4GB\r
962 // memory size read from the CMOS.\r
963 //\r
328076cf 964 Status = PlatformScanE820 (PlatformAddHobCB, PlatformInfoHob);\r
10460942
MX
965 if (EFI_ERROR (Status)) {\r
966 UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb ();\r
967 if (UpperMemorySize != 0) {\r
968 PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);\r
969 }\r
970 }\r
971 }\r
972\r
973 //\r
974 // We'd like to keep the following ranges uncached:\r
975 // - [640 KB, 1 MB)\r
85fd05ab 976 // - [Uc32Base, 4 GB)\r
10460942
MX
977 //\r
978 // Everything else should be WB. Unfortunately, programming the inverse (ie.\r
979 // keeping the default UC, and configuring the complement set of the above as\r
980 // WB) is not reliable in general, because the end of the upper RAM can have\r
981 // practically any alignment, and we may not have enough variable MTRRs to\r
982 // cover it exactly.\r
983 //\r
984 if (IsMtrrSupported () && (PlatformInfoHob->HostBridgeDevId != CLOUDHV_DEVICE_ID)) {\r
985 MtrrGetAllMtrrs (&MtrrSettings);\r
986\r
987 //\r
988 // MTRRs disabled, fixed MTRRs disabled, default type is uncached\r
989 //\r
990 ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);\r
991 ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);\r
992 ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);\r
993\r
994 //\r
995 // flip default type to writeback\r
996 //\r
997 SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);\r
998 ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);\r
999 MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;\r
1000 MtrrSetAllMtrrs (&MtrrSettings);\r
1001\r
1002 //\r
1003 // Set memory range from 640KB to 1MB to uncacheable\r
1004 //\r
1005 Status = MtrrSetMemoryAttribute (\r
1006 BASE_512KB + BASE_128KB,\r
1007 BASE_1MB - (BASE_512KB + BASE_128KB),\r
1008 CacheUncacheable\r
1009 );\r
1010 ASSERT_EFI_ERROR (Status);\r
1011\r
1012 //\r
1013 // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI\r
1014 // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.\r
1015 //\r
1016 Status = MtrrSetMemoryAttribute (\r
1017 PlatformInfoHob->Uc32Base,\r
1018 SIZE_4GB - PlatformInfoHob->Uc32Base,\r
1019 CacheUncacheable\r
1020 );\r
1021 ASSERT_EFI_ERROR (Status);\r
1022 }\r
1023}\r
1024\r
1025VOID\r
1026EFIAPI\r
1027PlatformQemuInitializeRamForS3 (\r
1028 IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob\r
1029 )\r
1030{\r
1031 if (PlatformInfoHob->S3Supported && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {\r
1032 //\r
1033 // This is the memory range that will be used for PEI on S3 resume\r
1034 //\r
1035 BuildMemoryAllocationHob (\r
1036 PlatformInfoHob->S3AcpiReservedMemoryBase,\r
1037 PlatformInfoHob->S3AcpiReservedMemorySize,\r
1038 EfiACPIMemoryNVS\r
1039 );\r
1040\r
1041 //\r
1042 // Cover the initial RAM area used as stack and temporary PEI heap.\r
1043 //\r
1044 // This is reserved as ACPI NVS so it can be used on S3 resume.\r
1045 //\r
1046 BuildMemoryAllocationHob (\r
1047 PcdGet32 (PcdOvmfSecPeiTempRamBase),\r
1048 PcdGet32 (PcdOvmfSecPeiTempRamSize),\r
1049 EfiACPIMemoryNVS\r
1050 );\r
1051\r
1052 //\r
1053 // SEC stores its table of GUIDed section handlers here.\r
1054 //\r
1055 BuildMemoryAllocationHob (\r
1056 PcdGet64 (PcdGuidedExtractHandlerTableAddress),\r
1057 PcdGet32 (PcdGuidedExtractHandlerTableSize),\r
1058 EfiACPIMemoryNVS\r
1059 );\r
1060\r
1061 #ifdef MDE_CPU_X64\r
1062 //\r
1063 // Reserve the initial page tables built by the reset vector code.\r
1064 //\r
1065 // Since this memory range will be used by the Reset Vector on S3\r
1066 // resume, it must be reserved as ACPI NVS.\r
1067 //\r
1068 BuildMemoryAllocationHob (\r
1069 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase),\r
1070 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecPageTablesSize),\r
1071 EfiACPIMemoryNVS\r
1072 );\r
1073\r
1074 if (PlatformInfoHob->SevEsIsEnabled) {\r
1075 //\r
1076 // If SEV-ES is enabled, reserve the GHCB-related memory area. This\r
1077 // includes the extra page table used to break down the 2MB page\r
1078 // mapping into 4KB page entries where the GHCB resides and the\r
1079 // GHCB area itself.\r
1080 //\r
1081 // Since this memory range will be used by the Reset Vector on S3\r
1082 // resume, it must be reserved as ACPI NVS.\r
1083 //\r
1084 BuildMemoryAllocationHob (\r
1085 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableBase),\r
1086 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableSize),\r
1087 EfiACPIMemoryNVS\r
1088 );\r
1089 BuildMemoryAllocationHob (\r
1090 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase),\r
1091 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbSize),\r
1092 EfiACPIMemoryNVS\r
1093 );\r
1094 BuildMemoryAllocationHob (\r
1095 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase),\r
1096 (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupSize),\r
1097 EfiACPIMemoryNVS\r
1098 );\r
1099 }\r
1100\r
1101 #endif\r
1102 }\r
1103\r
1104 if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {\r
1105 if (!PlatformInfoHob->SmmSmramRequire) {\r
1106 //\r
1107 // Reserve the lock box storage area\r
1108 //\r
1109 // Since this memory range will be used on S3 resume, it must be\r
1110 // reserved as ACPI NVS.\r
1111 //\r
1112 // If S3 is unsupported, then various drivers might still write to the\r
1113 // LockBox area. We ought to prevent DXE from serving allocation requests\r
1114 // such that they would overlap the LockBox storage.\r
1115 //\r
1116 ZeroMem (\r
1117 (VOID *)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),\r
1118 (UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize)\r
1119 );\r
1120 BuildMemoryAllocationHob (\r
1121 (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),\r
1122 (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),\r
1123 PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData\r
1124 );\r
1125 }\r
1126\r
1127 if (PlatformInfoHob->SmmSmramRequire) {\r
1128 UINT32 TsegSize;\r
1129\r
1130 //\r
1131 // Make sure the TSEG area that we reported as a reserved memory resource\r
1132 // cannot be used for reserved memory allocations.\r
1133 //\r
124b7650 1134 PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);\r
10460942
MX
1135 TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;\r
1136 BuildMemoryAllocationHob (\r
124b7650 1137 PlatformInfoHob->LowMemory - TsegSize,\r
10460942
MX
1138 TsegSize,\r
1139 EfiReservedMemoryType\r
1140 );\r
1141 //\r
1142 // Similarly, allocate away the (already reserved) SMRAM at the default\r
1143 // SMBASE, if it exists.\r
1144 //\r
1145 if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {\r
1146 BuildMemoryAllocationHob (\r
1147 SMM_DEFAULT_SMBASE,\r
1148 MCH_DEFAULT_SMBASE_SIZE,\r
1149 EfiReservedMemoryType\r
1150 );\r
1151 }\r
1152 }\r
1153\r
1154 #ifdef MDE_CPU_X64\r
1155 if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {\r
1156 //\r
1157 // Reserve the work area.\r
1158 //\r
1159 // Since this memory range will be used by the Reset Vector on S3\r
1160 // resume, it must be reserved as ACPI NVS.\r
1161 //\r
1162 // If S3 is unsupported, then various drivers might still write to the\r
1163 // work area. We ought to prevent DXE from serving allocation requests\r
1164 // such that they would overlap the work area.\r
1165 //\r
1166 BuildMemoryAllocationHob (\r
1167 (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),\r
1168 (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),\r
1169 PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData\r
1170 );\r
1171 }\r
1172\r
1173 #endif\r
1174 }\r
1175}\r