]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PlatformPei/Platform.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / PlatformPei / Platform.c
CommitLineData
49ba9447 1/**@file\r
2 Platform PEI driver\r
3\r
a1726e30 4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
eec7d420 5 Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
49ba9447 8\r
9**/\r
10\r
11//\r
12// The package level header files this module uses\r
13//\r
14#include <PiPei.h>\r
15\r
16//\r
17// The Library classes this module consumes\r
18//\r
5133d1f1 19#include <Library/BaseLib.h>\r
49ba9447 20#include <Library/DebugLib.h>\r
21#include <Library/HobLib.h>\r
22#include <Library/IoLib.h>\r
77ba993c 23#include <Library/MemoryAllocationLib.h>\r
24#include <Library/PcdLib.h>\r
49ba9447 25#include <Library/PciLib.h>\r
26#include <Library/PeimEntryPoint.h>\r
9ed65b10 27#include <Library/PeiServicesLib.h>\r
7cdba634 28#include <Library/QemuFwCfgLib.h>\r
687f7521 29#include <Library/QemuFwCfgS3Lib.h>\r
b3c1bc1c 30#include <Library/QemuFwCfgSimpleParserLib.h>\r
49ba9447 31#include <Library/ResourcePublicationLib.h>\r
9ed65b10 32#include <Ppi/MasterBootMode.h>\r
83357313 33#include <IndustryStandard/I440FxPiix4.h>\r
bf02d73e 34#include <IndustryStandard/Microvm.h>\r
931a0c74 35#include <IndustryStandard/Pci22.h>\r
83357313
LE
36#include <IndustryStandard/Q35MchIch9.h>\r
37#include <IndustryStandard/QemuCpuHotplug.h>\r
97380beb 38#include <OvmfPlatforms.h>\r
49ba9447 39\r
40#include "Platform.h"\r
3ca15914 41#include "Cmos.h"\r
49ba9447 42\r
ac0a286f 43EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {\r
9ed65b10 44 {\r
45 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
46 &gEfiPeiMasterBootModePpiGuid,\r
47 NULL\r
48 }\r
49};\r
50\r
ac0a286f 51UINT16 mHostBridgeDevId;\r
9ed65b10 52\r
ac0a286f 53EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;\r
589756c7 54\r
ac0a286f 55BOOLEAN mS3Supported = FALSE;\r
979420df 56\r
ac0a286f 57UINT32 mMaxCpuCount;\r
979420df 58\r
49ba9447 59VOID\r
60AddIoMemoryBaseSizeHob (\r
ac0a286f
MK
61 EFI_PHYSICAL_ADDRESS MemoryBase,\r
62 UINT64 MemorySize\r
49ba9447 63 )\r
64{\r
991d9563 65 BuildResourceDescriptorHob (\r
66 EFI_RESOURCE_MEMORY_MAPPED_IO,\r
ac0a286f
MK
67 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
68 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
69 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
70 EFI_RESOURCE_ATTRIBUTE_TESTED,\r
49ba9447 71 MemoryBase,\r
72 MemorySize\r
73 );\r
74}\r
75\r
eec7d420 76VOID\r
77AddReservedMemoryBaseSizeHob (\r
ac0a286f
MK
78 EFI_PHYSICAL_ADDRESS MemoryBase,\r
79 UINT64 MemorySize,\r
80 BOOLEAN Cacheable\r
eec7d420 81 )\r
82{\r
83 BuildResourceDescriptorHob (\r
84 EFI_RESOURCE_MEMORY_RESERVED,\r
ac0a286f
MK
85 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
86 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
87 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
88 (Cacheable ?\r
89 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
90 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
91 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :\r
92 0\r
93 ) |\r
94 EFI_RESOURCE_ATTRIBUTE_TESTED,\r
eec7d420 95 MemoryBase,\r
96 MemorySize\r
97 );\r
98}\r
49ba9447 99\r
100VOID\r
101AddIoMemoryRangeHob (\r
ac0a286f
MK
102 EFI_PHYSICAL_ADDRESS MemoryBase,\r
103 EFI_PHYSICAL_ADDRESS MemoryLimit\r
49ba9447 104 )\r
105{\r
106 AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));\r
107}\r
108\r
49ba9447 109VOID\r
110AddMemoryBaseSizeHob (\r
ac0a286f
MK
111 EFI_PHYSICAL_ADDRESS MemoryBase,\r
112 UINT64 MemorySize\r
49ba9447 113 )\r
114{\r
991d9563 115 BuildResourceDescriptorHob (\r
116 EFI_RESOURCE_SYSTEM_MEMORY,\r
ac0a286f
MK
117 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
118 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
119 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
120 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
121 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
122 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |\r
123 EFI_RESOURCE_ATTRIBUTE_TESTED,\r
49ba9447 124 MemoryBase,\r
125 MemorySize\r
126 );\r
127}\r
128\r
49ba9447 129VOID\r
130AddMemoryRangeHob (\r
ac0a286f
MK
131 EFI_PHYSICAL_ADDRESS MemoryBase,\r
132 EFI_PHYSICAL_ADDRESS MemoryLimit\r
49ba9447 133 )\r
134{\r
135 AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));\r
136}\r
137\r
bb6a9a93 138VOID\r
4b455f7b 139MemMapInitialization (\r
bb6a9a93
WL
140 VOID\r
141 )\r
142{\r
ac0a286f
MK
143 UINT64 PciIoBase;\r
144 UINT64 PciIoSize;\r
145 RETURN_STATUS PcdStatus;\r
146 UINT32 TopOfLowRam;\r
147 UINT64 PciExBarBase;\r
148 UINT32 PciBase;\r
149 UINT32 PciSize;\r
c4df7fd0
LE
150\r
151 PciIoBase = 0xC000;\r
152 PciIoSize = 0x4000;\r
153\r
bb6a9a93
WL
154 //\r
155 // Video memory + Legacy BIOS region\r
156 //\r
157 AddIoMemoryRangeHob (0x0A0000, BASE_1MB);\r
158\r
8583b57c 159 if (mHostBridgeDevId == 0xffff /* microvm */) {\r
1d3e89f3 160 AddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);\r
8583b57c
GH
161 AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */\r
162 AddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */\r
163 return;\r
164 }\r
165\r
ac0a286f 166 TopOfLowRam = GetSystemMemorySizeBelow4gb ();\r
d06eb2d1
LE
167 PciExBarBase = 0;\r
168 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
169 //\r
170 // The MMCONFIG area is expected to fall between the top of low RAM and\r
171 // the base of the 32-bit PCI host aperture.\r
172 //\r
173 PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);\r
174 ASSERT (TopOfLowRam <= PciExBarBase);\r
175 ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);\r
176 PciBase = (UINT32)(PciExBarBase + SIZE_256MB);\r
177 } else {\r
178 ASSERT (TopOfLowRam <= mQemuUc32Base);\r
179 PciBase = mQemuUc32Base;\r
180 }\r
c68d3a69 181\r
d06eb2d1
LE
182 //\r
183 // address purpose size\r
184 // ------------ -------- -------------------------\r
185 // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)\r
186 // 0xFC000000 gap 44 MB\r
187 // 0xFEC00000 IO-APIC 4 KB\r
188 // 0xFEC01000 gap 1020 KB\r
189 // 0xFED00000 HPET 1 KB\r
190 // 0xFED00400 gap 111 KB\r
191 // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB\r
192 // 0xFED20000 gap 896 KB\r
193 // 0xFEE00000 LAPIC 1 MB\r
194 //\r
195 PciSize = 0xFC000000 - PciBase;\r
196 AddIoMemoryBaseSizeHob (PciBase, PciSize);\r
197 PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);\r
198 ASSERT_RETURN_ERROR (PcdStatus);\r
199 PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);\r
200 ASSERT_RETURN_ERROR (PcdStatus);\r
49ba9447 201\r
d06eb2d1
LE
202 AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);\r
203 AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);\r
204 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
205 AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);\r
4b455f7b 206 //\r
d06eb2d1 207 // Note: there should be an\r
bba734ab 208 //\r
d06eb2d1 209 // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);\r
bba734ab 210 //\r
d06eb2d1
LE
211 // call below, just like the one above for RCBA. However, Linux insists\r
212 // that the MMCONFIG area be marked in the E820 or UEFI memory map as\r
213 // "reserved memory" -- Linux does not content itself with a simple gap\r
214 // in the memory map wherever the MCFG ACPI table points to.\r
215 //\r
216 // This appears to be a safety measure. The PCI Firmware Specification\r
217 // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can\r
218 // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory\r
219 // [...]". (Emphasis added here.)\r
220 //\r
221 // Normally we add memory resource descriptor HOBs in\r
222 // QemuInitializeRam(), and pre-allocate from those with memory\r
223 // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area\r
224 // is most definitely not RAM; so, as an exception, cover it with\r
225 // uncacheable reserved memory right here.\r
226 //\r
227 AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);\r
ac0a286f
MK
228 BuildMemoryAllocationHob (\r
229 PciExBarBase,\r
230 SIZE_256MB,\r
231 EfiReservedMemoryType\r
232 );\r
d06eb2d1 233 }\r
ac0a286f
MK
234\r
235 AddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);\r
d06eb2d1
LE
236\r
237 //\r
238 // On Q35, the IO Port space is available for PCI resource allocations from\r
239 // 0x6000 up.\r
240 //\r
241 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
242 PciIoBase = 0x6000;\r
243 PciIoSize = 0xA000;\r
244 ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);\r
4b455f7b 245 }\r
c4df7fd0
LE
246\r
247 //\r
248 // Add PCI IO Port space available for PCI resource allocations.\r
249 //\r
250 BuildResourceDescriptorHob (\r
251 EFI_RESOURCE_IO,\r
252 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
253 EFI_RESOURCE_ATTRIBUTE_INITIALIZED,\r
254 PciIoBase,\r
255 PciIoSize\r
256 );\r
32e083c7
LE
257 PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);\r
258 ASSERT_RETURN_ERROR (PcdStatus);\r
259 PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);\r
260 ASSERT_RETURN_ERROR (PcdStatus);\r
49ba9447 261}\r
262\r
ab081a50
LE
263#define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName) \\r
264 do { \\r
32e083c7
LE
265 BOOLEAN Setting; \\r
266 RETURN_STATUS PcdStatus; \\r
ab081a50 267 \\r
b3c1bc1c 268 if (!RETURN_ERROR (QemuFwCfgParseBool ( \\r
ab081a50 269 "opt/ovmf/" #TokenName, &Setting))) { \\r
32e083c7
LE
270 PcdStatus = PcdSetBoolS (TokenName, Setting); \\r
271 ASSERT_RETURN_ERROR (PcdStatus); \\r
ab081a50
LE
272 } \\r
273 } while (0)\r
274\r
275VOID\r
276NoexecDxeInitialization (\r
277 VOID\r
278 )\r
279{\r
ab081a50
LE
280 UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);\r
281}\r
49ba9447 282\r
7b8fe635
LE
283VOID\r
284PciExBarInitialization (\r
285 VOID\r
286 )\r
287{\r
288 union {\r
ac0a286f
MK
289 UINT64 Uint64;\r
290 UINT32 Uint32[2];\r
7b8fe635
LE
291 } PciExBarBase;\r
292\r
293 //\r
294 // We only support the 256MB size for the MMCONFIG area:\r
295 // 256 buses * 32 devices * 8 functions * 4096 bytes config space.\r
296 //\r
297 // The masks used below enforce the Q35 requirements that the MMCONFIG area\r
298 // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.\r
299 //\r
300 // Note that (b) also ensures that the minimum address width we have\r
301 // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice\r
302 // for DXE's page tables to cover the MMCONFIG area.\r
303 //\r
304 PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);\r
305 ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);\r
306 ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);\r
307\r
308 //\r
309 // Clear the PCIEXBAREN bit first, before programming the high register.\r
310 //\r
311 PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);\r
312\r
313 //\r
314 // Program the high register. Then program the low register, setting the\r
315 // MMCONFIG area size and enabling decoding at once.\r
316 //\r
317 PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);\r
318 PciWrite32 (\r
319 DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),\r
320 PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN\r
321 );\r
322}\r
323\r
49ba9447 324VOID\r
325MiscInitialization (\r
0e20a186 326 VOID\r
49ba9447 327 )\r
328{\r
ac0a286f
MK
329 UINTN PmCmd;\r
330 UINTN Pmba;\r
331 UINT32 PmbaAndVal;\r
332 UINT32 PmbaOrVal;\r
333 UINTN AcpiCtlReg;\r
334 UINT8 AcpiEnBit;\r
335 RETURN_STATUS PcdStatus;\r
97380beb 336\r
49ba9447 337 //\r
338 // Disable A20 Mask\r
339 //\r
55cdb67a 340 IoOr8 (0x92, BIT1);\r
49ba9447 341\r
342 //\r
86a14b0a
LE
343 // Build the CPU HOB with guest RAM size dependent address width and 16-bits\r
344 // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during\r
345 // S3 resume as well, so we build it unconditionally.)\r
49ba9447 346 //\r
86a14b0a 347 BuildCpuHob (mPhysMemAddressWidth, 16);\r
c756b2ab 348\r
97380beb 349 //\r
589756c7 350 // Determine platform type and save Host Bridge DID to PCD\r
97380beb 351 //\r
589756c7 352 switch (mHostBridgeDevId) {\r
97380beb 353 case INTEL_82441_DEVICE_ID:\r
e2ab3f81 354 PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);\r
da372167 355 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
1466b76f
LE
356 PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;\r
357 PmbaOrVal = PIIX4_PMBA_VALUE;\r
da372167
LE
358 AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);\r
359 AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;\r
97380beb
GS
360 break;\r
361 case INTEL_Q35_MCH_DEVICE_ID:\r
e2ab3f81 362 PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);\r
bc9d05d6 363 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
1466b76f
LE
364 PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;\r
365 PmbaOrVal = ICH9_PMBASE_VALUE;\r
bc9d05d6
LE
366 AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);\r
367 AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;\r
97380beb 368 break;\r
bf02d73e
GH
369 case 0xffff: /* microvm */\r
370 DEBUG ((DEBUG_INFO, "%a: microvm\n", __FUNCTION__));\r
ac0a286f
MK
371 PcdStatus = PcdSet16S (\r
372 PcdOvmfHostBridgePciDevId,\r
373 MICROVM_PSEUDO_DEVICE_ID\r
374 );\r
bf02d73e
GH
375 ASSERT_RETURN_ERROR (PcdStatus);\r
376 return;\r
97380beb 377 default:\r
ac0a286f
MK
378 DEBUG ((\r
379 DEBUG_ERROR,\r
380 "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
381 __FUNCTION__,\r
382 mHostBridgeDevId\r
383 ));\r
97380beb
GS
384 ASSERT (FALSE);\r
385 return;\r
386 }\r
ac0a286f 387\r
32e083c7
LE
388 PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);\r
389 ASSERT_RETURN_ERROR (PcdStatus);\r
97380beb 390\r
0e20a186 391 //\r
d06eb2d1
LE
392 // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has\r
393 // been configured and skip the setup here. This matches the logic in\r
394 // AcpiTimerLibConstructor ().\r
0e20a186 395 //\r
e2ab3f81 396 if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {\r
eec7d420 397 //\r
e2ab3f81 398 // The PEI phase should be exited with fully accessibe ACPI PM IO space:\r
931a0c74 399 // 1. set PMBA\r
eec7d420 400 //\r
1466b76f 401 PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);\r
931a0c74 402\r
403 //\r
404 // 2. set PCICMD/IOSE\r
405 //\r
97380beb 406 PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);\r
931a0c74 407\r
408 //\r
e2ab3f81 409 // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)\r
931a0c74 410 //\r
e2ab3f81 411 PciOr8 (AcpiCtlReg, AcpiEnBit);\r
eec7d420 412 }\r
90721ba5
PA
413\r
414 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
415 //\r
416 // Set Root Complex Register Block BAR\r
417 //\r
418 PciWrite32 (\r
419 POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),\r
420 ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN\r
421 );\r
7b8fe635
LE
422\r
423 //\r
424 // Set PCI Express Register Range Base Address\r
425 //\r
426 PciExBarInitialization ();\r
90721ba5 427 }\r
49ba9447 428}\r
429\r
9ed65b10 430VOID\r
431BootModeInitialization (\r
8f5ca05b 432 VOID\r
9ed65b10 433 )\r
434{\r
ac0a286f 435 EFI_STATUS Status;\r
8f5ca05b
LE
436\r
437 if (CmosRead8 (0xF) == 0xFE) {\r
979420df 438 mBootMode = BOOT_ON_S3_RESUME;\r
8f5ca05b 439 }\r
ac0a286f 440\r
9be75189 441 CmosWrite8 (0xF, 0x00);\r
667bf1e4 442\r
979420df 443 Status = PeiServicesSetBootMode (mBootMode);\r
667bf1e4 444 ASSERT_EFI_ERROR (Status);\r
445\r
446 Status = PeiServicesInstallPpi (mPpiBootMode);\r
447 ASSERT_EFI_ERROR (Status);\r
9ed65b10 448}\r
449\r
77ba993c 450VOID\r
451ReserveEmuVariableNvStore (\r
452 )\r
453{\r
ac0a286f
MK
454 EFI_PHYSICAL_ADDRESS VariableStore;\r
455 RETURN_STATUS PcdStatus;\r
77ba993c 456\r
457 //\r
458 // Allocate storage for NV variables early on so it will be\r
459 // at a consistent address. Since VM memory is preserved\r
460 // across reboots, this allows the NV variable storage to survive\r
461 // a VM reboot.\r
462 //\r
463 VariableStore =\r
464 (EFI_PHYSICAL_ADDRESS)(UINTN)\r
ac0a286f
MK
465 AllocateRuntimePages (\r
466 EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))\r
467 );\r
468 DEBUG ((\r
469 DEBUG_INFO,\r
470 "Reserved variable store memory: 0x%lX; size: %dkb\n",\r
471 VariableStore,\r
472 (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024\r
473 ));\r
32e083c7
LE
474 PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);\r
475 ASSERT_RETURN_ERROR (PcdStatus);\r
77ba993c 476}\r
477\r
3ca15914 478VOID\r
479DebugDumpCmos (\r
480 VOID\r
481 )\r
482{\r
ac0a286f 483 UINT32 Loop;\r
3ca15914 484\r
70d5086c 485 DEBUG ((DEBUG_INFO, "CMOS:\n"));\r
3ca15914 486\r
487 for (Loop = 0; Loop < 0x80; Loop++) {\r
488 if ((Loop % 0x10) == 0) {\r
70d5086c 489 DEBUG ((DEBUG_INFO, "%02x:", Loop));\r
3ca15914 490 }\r
ac0a286f 491\r
70d5086c 492 DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));\r
3ca15914 493 if ((Loop % 0x10) == 0xf) {\r
70d5086c 494 DEBUG ((DEBUG_INFO, "\n"));\r
3ca15914 495 }\r
496 }\r
497}\r
498\r
5133d1f1
LE
499VOID\r
500S3Verification (\r
501 VOID\r
502 )\r
503{\r
ac0a286f 504 #if defined (MDE_CPU_X64)\r
5133d1f1 505 if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {\r
ac0a286f
MK
506 DEBUG ((\r
507 DEBUG_ERROR,\r
508 "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",\r
509 __FUNCTION__\r
510 ));\r
511 DEBUG ((\r
512 DEBUG_ERROR,\r
5133d1f1 513 "%a: Please disable S3 on the QEMU command line (see the README),\n",\r
ac0a286f
MK
514 __FUNCTION__\r
515 ));\r
516 DEBUG ((\r
517 DEBUG_ERROR,\r
518 "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n",\r
519 __FUNCTION__\r
520 ));\r
5133d1f1
LE
521 ASSERT (FALSE);\r
522 CpuDeadLoop ();\r
523 }\r
5133d1f1 524\r
ac0a286f
MK
525 #endif\r
526}\r
5133d1f1 527\r
e0ed7a9b
LE
528VOID\r
529Q35BoardVerification (\r
530 VOID\r
531 )\r
532{\r
533 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
534 return;\r
535 }\r
536\r
537 DEBUG ((\r
538 DEBUG_ERROR,\r
539 "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "\r
540 "only DID=0x%04x (Q35) is supported\n",\r
541 __FUNCTION__,\r
542 mHostBridgeDevId,\r
543 INTEL_Q35_MCH_DEVICE_ID\r
544 ));\r
545 ASSERT (FALSE);\r
546 CpuDeadLoop ();\r
547}\r
548\r
45a70db3 549/**\r
83357313
LE
550 Fetch the boot CPU count and the possible CPU count from QEMU, and expose\r
551 them to UefiCpuPkg modules. Set the mMaxCpuCount variable.\r
45a70db3
LE
552**/\r
553VOID\r
554MaxCpuCountInitialization (\r
555 VOID\r
556 )\r
557{\r
ac0a286f
MK
558 UINT16 BootCpuCount;\r
559 RETURN_STATUS PcdStatus;\r
45a70db3 560\r
45a70db3 561 //\r
83357313 562 // Try to fetch the boot CPU count.\r
45a70db3 563 //\r
83357313
LE
564 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);\r
565 BootCpuCount = QemuFwCfgRead16 ();\r
566 if (BootCpuCount == 0) {\r
567 //\r
568 // QEMU doesn't report the boot CPU count. (BootCpuCount == 0) will let\r
569 // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or\r
570 // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reached\r
571 // first).\r
572 //\r
573 DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));\r
45a70db3 574 mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
83357313
LE
575 } else {\r
576 //\r
577 // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to\r
578 // (BootCpuCount - 1) precisely, regardless of timeout.\r
579 //\r
580 // Now try to fetch the possible CPU count.\r
581 //\r
ac0a286f
MK
582 UINTN CpuHpBase;\r
583 UINT32 CmdData2;\r
83357313
LE
584\r
585 CpuHpBase = ((mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?\r
586 ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);\r
587\r
588 //\r
589 // If only legacy mode is available in the CPU hotplug register block, or\r
590 // the register block is completely missing, then the writes below are\r
591 // no-ops.\r
592 //\r
593 // 1. Switch the hotplug register block to modern mode.\r
594 //\r
595 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);\r
596 //\r
597 // 2. Select a valid CPU for deterministic reading of\r
598 // QEMU_CPUHP_R_CMD_DATA2.\r
599 //\r
600 // CPU#0 is always valid; it is the always present and non-removable\r
601 // BSP.\r
602 //\r
603 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);\r
604 //\r
605 // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to\r
606 // read as zero, and which does not invalidate the selector. (The\r
607 // selector may change, but it must not become invalid.)\r
608 //\r
609 // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later.\r
610 //\r
611 IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING);\r
612 //\r
613 // 4. Read QEMU_CPUHP_R_CMD_DATA2.\r
614 //\r
615 // If the register block is entirely missing, then this is an unassigned\r
616 // IO read, returning all-bits-one.\r
617 //\r
618 // If only legacy mode is available, then bit#0 stands for CPU#0 in the\r
619 // "CPU present bitmap". CPU#0 is always present.\r
620 //\r
621 // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (returning\r
622 // all-bits-zero), or it is specified to read as zero after the above\r
623 // steps. Both cases confirm modern mode.\r
624 //\r
625 CmdData2 = IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2);\r
626 DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=0x%x\n", __FUNCTION__, CmdData2));\r
627 if (CmdData2 != 0) {\r
628 //\r
629 // QEMU doesn't support the modern CPU hotplug interface. Assume that the\r
630 // possible CPU count equals the boot CPU count (precluding hotplug).\r
631 //\r
ac0a286f
MK
632 DEBUG ((\r
633 DEBUG_WARN,\r
634 "%a: modern CPU hotplug interface unavailable\n",\r
635 __FUNCTION__\r
636 ));\r
83357313
LE
637 mMaxCpuCount = BootCpuCount;\r
638 } else {\r
639 //\r
640 // Grab the possible CPU count from the modern CPU hotplug interface.\r
641 //\r
ac0a286f 642 UINT32 Present, Possible, Selected;\r
83357313 643\r
ac0a286f 644 Present = 0;\r
83357313
LE
645 Possible = 0;\r
646\r
647 //\r
648 // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures\r
649 // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However,\r
650 // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pending\r
651 // hotplug events; therefore, select CPU#0 forcibly.\r
652 //\r
653 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);\r
654\r
655 do {\r
ac0a286f 656 UINT8 CpuStatus;\r
83357313
LE
657\r
658 //\r
659 // Read the status of the currently selected CPU. This will help with a\r
660 // sanity check against "BootCpuCount".\r
661 //\r
662 CpuStatus = IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT);\r
663 if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) != 0) {\r
664 ++Present;\r
665 }\r
ac0a286f 666\r
83357313
LE
667 //\r
668 // Attempt to select the next CPU.\r
669 //\r
670 ++Possible;\r
671 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);\r
672 //\r
673 // If the selection is successful, then the following read will return\r
674 // the selector (which we know is positive at this point). Otherwise,\r
675 // the read will return 0.\r
676 //\r
677 Selected = IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA);\r
678 ASSERT (Selected == Possible || Selected == 0);\r
679 } while (Selected > 0);\r
680\r
681 //\r
682 // Sanity check: fw_cfg and the modern CPU hotplug interface should\r
683 // return the same boot CPU count.\r
684 //\r
685 if (BootCpuCount != Present) {\r
ac0a286f
MK
686 DEBUG ((\r
687 DEBUG_WARN,\r
688 "%a: QEMU v2.7 reset bug: BootCpuCount=%d "\r
689 "Present=%u\n",\r
690 __FUNCTION__,\r
691 BootCpuCount,\r
692 Present\r
693 ));\r
83357313
LE
694 //\r
695 // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug plus\r
696 // platform reset (including S3), was corrected in QEMU commit\r
697 // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device added\r
698 // CPUs", 2016-11-16), part of release v2.8.0.\r
699 //\r
700 BootCpuCount = (UINT16)Present;\r
701 }\r
702\r
703 mMaxCpuCount = Possible;\r
704 }\r
45a70db3 705 }\r
83357313 706\r
ac0a286f
MK
707 DEBUG ((\r
708 DEBUG_INFO,\r
709 "%a: BootCpuCount=%d mMaxCpuCount=%u\n",\r
710 __FUNCTION__,\r
711 BootCpuCount,\r
712 mMaxCpuCount\r
713 ));\r
83357313
LE
714 ASSERT (BootCpuCount <= mMaxCpuCount);\r
715\r
716 PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, BootCpuCount);\r
45a70db3 717 ASSERT_RETURN_ERROR (PcdStatus);\r
83357313 718 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, mMaxCpuCount);\r
45a70db3 719 ASSERT_RETURN_ERROR (PcdStatus);\r
45a70db3
LE
720}\r
721\r
49ba9447 722/**\r
723 Perform Platform PEI initialization.\r
724\r
725 @param FileHandle Handle of the file being invoked.\r
726 @param PeiServices Describes the list of possible PEI Services.\r
727\r
728 @return EFI_SUCCESS The PEIM initialized successfully.\r
729\r
730**/\r
731EFI_STATUS\r
732EFIAPI\r
733InitializePlatform (\r
734 IN EFI_PEI_FILE_HANDLE FileHandle,\r
735 IN CONST EFI_PEI_SERVICES **PeiServices\r
736 )\r
737{\r
ac0a286f 738 EFI_STATUS Status;\r
a1726e30 739\r
7707c9fd 740 DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));\r
49ba9447 741\r
3ca15914 742 DebugDumpCmos ();\r
743\r
7cdba634 744 if (QemuFwCfgS3Enabled ()) {\r
70d5086c 745 DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));\r
7cdba634 746 mS3Supported = TRUE;\r
ac0a286f 747 Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);\r
a1726e30 748 ASSERT_EFI_ERROR (Status);\r
7cdba634
JJ
749 }\r
750\r
5133d1f1 751 S3Verification ();\r
869b17cc 752 BootModeInitialization ();\r
bc89fe48 753 AddressWidthInitialization ();\r
869b17cc 754\r
d5e06444
LE
755 //\r
756 // Query Host Bridge DID\r
757 //\r
758 mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);\r
759\r
83357313
LE
760 MaxCpuCountInitialization ();\r
761\r
23bfb5c0 762 if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
e0ed7a9b 763 Q35BoardVerification ();\r
23bfb5c0 764 Q35TsegMbytesInitialization ();\r
73974f80 765 Q35SmramAtDefaultSmbaseInitialization ();\r
23bfb5c0
LE
766 }\r
767\r
f76e9eba
JJ
768 PublishPeiMemory ();\r
769\r
49edde15
LE
770 QemuUc32BaseInitialization ();\r
771\r
2818c158 772 InitializeRamRegions ();\r
49ba9447 773\r
bd386eaf 774 if (mBootMode != BOOT_ON_S3_RESUME) {\r
5e167d7e
LE
775 if (!FeaturePcdGet (PcdSmmSmramRequire)) {\r
776 ReserveEmuVariableNvStore ();\r
777 }\r
ac0a286f 778\r
bd386eaf 779 PeiFvInitialization ();\r
d42fdd6f 780 MemTypeInfoInitialization ();\r
bd386eaf 781 MemMapInitialization ();\r
ab081a50 782 NoexecDxeInitialization ();\r
bd386eaf 783 }\r
49ba9447 784\r
d20ae95a 785 InstallClearCacheCallback ();\r
13b5d743 786 AmdSevInitialize ();\r
0e20a186 787 MiscInitialization ();\r
dbab9949 788 InstallFeatureControlCallback ();\r
49ba9447 789\r
790 return EFI_SUCCESS;\r
791}\r