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