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