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