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