]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformPei/Platform.c
OvmfPkg: Apply uncrustify changes
[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 UINT16 mHostBridgeDevId;
52
53 EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
54
55 BOOLEAN mS3Supported = FALSE;
56
57 UINT32 mMaxCpuCount;
58
59 VOID
60 AddIoMemoryBaseSizeHob (
61 EFI_PHYSICAL_ADDRESS MemoryBase,
62 UINT64 MemorySize
63 )
64 {
65 BuildResourceDescriptorHob (
66 EFI_RESOURCE_MEMORY_MAPPED_IO,
67 EFI_RESOURCE_ATTRIBUTE_PRESENT |
68 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
69 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
70 EFI_RESOURCE_ATTRIBUTE_TESTED,
71 MemoryBase,
72 MemorySize
73 );
74 }
75
76 VOID
77 AddReservedMemoryBaseSizeHob (
78 EFI_PHYSICAL_ADDRESS MemoryBase,
79 UINT64 MemorySize,
80 BOOLEAN Cacheable
81 )
82 {
83 BuildResourceDescriptorHob (
84 EFI_RESOURCE_MEMORY_RESERVED,
85 EFI_RESOURCE_ATTRIBUTE_PRESENT |
86 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
87 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
88 (Cacheable ?
89 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
90 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
91 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
92 0
93 ) |
94 EFI_RESOURCE_ATTRIBUTE_TESTED,
95 MemoryBase,
96 MemorySize
97 );
98 }
99
100 VOID
101 AddIoMemoryRangeHob (
102 EFI_PHYSICAL_ADDRESS MemoryBase,
103 EFI_PHYSICAL_ADDRESS MemoryLimit
104 )
105 {
106 AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
107 }
108
109 VOID
110 AddMemoryBaseSizeHob (
111 EFI_PHYSICAL_ADDRESS MemoryBase,
112 UINT64 MemorySize
113 )
114 {
115 BuildResourceDescriptorHob (
116 EFI_RESOURCE_SYSTEM_MEMORY,
117 EFI_RESOURCE_ATTRIBUTE_PRESENT |
118 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
119 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
120 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
121 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
122 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
123 EFI_RESOURCE_ATTRIBUTE_TESTED,
124 MemoryBase,
125 MemorySize
126 );
127 }
128
129 VOID
130 AddMemoryRangeHob (
131 EFI_PHYSICAL_ADDRESS MemoryBase,
132 EFI_PHYSICAL_ADDRESS MemoryLimit
133 )
134 {
135 AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
136 }
137
138 VOID
139 MemMapInitialization (
140 VOID
141 )
142 {
143 UINT64 PciIoBase;
144 UINT64 PciIoSize;
145 RETURN_STATUS PcdStatus;
146 UINT32 TopOfLowRam;
147 UINT64 PciExBarBase;
148 UINT32 PciBase;
149 UINT32 PciSize;
150
151 PciIoBase = 0xC000;
152 PciIoSize = 0x4000;
153
154 //
155 // Video memory + Legacy BIOS region
156 //
157 AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
158
159 if (mHostBridgeDevId == 0xffff /* microvm */) {
160 AddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
161 AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
162 AddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
163 return;
164 }
165
166 TopOfLowRam = GetSystemMemorySizeBelow4gb ();
167 PciExBarBase = 0;
168 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
169 //
170 // The MMCONFIG area is expected to fall between the top of low RAM and
171 // the base of the 32-bit PCI host aperture.
172 //
173 PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
174 ASSERT (TopOfLowRam <= PciExBarBase);
175 ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
176 PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
177 } else {
178 ASSERT (TopOfLowRam <= mQemuUc32Base);
179 PciBase = mQemuUc32Base;
180 }
181
182 //
183 // address purpose size
184 // ------------ -------- -------------------------
185 // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)
186 // 0xFC000000 gap 44 MB
187 // 0xFEC00000 IO-APIC 4 KB
188 // 0xFEC01000 gap 1020 KB
189 // 0xFED00000 HPET 1 KB
190 // 0xFED00400 gap 111 KB
191 // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB
192 // 0xFED20000 gap 896 KB
193 // 0xFEE00000 LAPIC 1 MB
194 //
195 PciSize = 0xFC000000 - PciBase;
196 AddIoMemoryBaseSizeHob (PciBase, PciSize);
197 PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
198 ASSERT_RETURN_ERROR (PcdStatus);
199 PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
200 ASSERT_RETURN_ERROR (PcdStatus);
201
202 AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
203 AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
204 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
205 AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
206 //
207 // Note: there should be an
208 //
209 // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
210 //
211 // call below, just like the one above for RCBA. However, Linux insists
212 // that the MMCONFIG area be marked in the E820 or UEFI memory map as
213 // "reserved memory" -- Linux does not content itself with a simple gap
214 // in the memory map wherever the MCFG ACPI table points to.
215 //
216 // This appears to be a safety measure. The PCI Firmware Specification
217 // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
218 // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
219 // [...]". (Emphasis added here.)
220 //
221 // Normally we add memory resource descriptor HOBs in
222 // QemuInitializeRam(), and pre-allocate from those with memory
223 // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
224 // is most definitely not RAM; so, as an exception, cover it with
225 // uncacheable reserved memory right here.
226 //
227 AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
228 BuildMemoryAllocationHob (
229 PciExBarBase,
230 SIZE_256MB,
231 EfiReservedMemoryType
232 );
233 }
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 (
372 PcdOvmfHostBridgePciDevId,
373 MICROVM_PSEUDO_DEVICE_ID
374 );
375 ASSERT_RETURN_ERROR (PcdStatus);
376 return;
377 default:
378 DEBUG ((
379 DEBUG_ERROR,
380 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
381 __FUNCTION__,
382 mHostBridgeDevId
383 ));
384 ASSERT (FALSE);
385 return;
386 }
387
388 PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
389 ASSERT_RETURN_ERROR (PcdStatus);
390
391 //
392 // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has
393 // been configured and skip the setup here. This matches the logic in
394 // AcpiTimerLibConstructor ().
395 //
396 if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
397 //
398 // The PEI phase should be exited with fully accessibe ACPI PM IO space:
399 // 1. set PMBA
400 //
401 PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
402
403 //
404 // 2. set PCICMD/IOSE
405 //
406 PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
407
408 //
409 // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
410 //
411 PciOr8 (AcpiCtlReg, AcpiEnBit);
412 }
413
414 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
415 //
416 // Set Root Complex Register Block BAR
417 //
418 PciWrite32 (
419 POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
420 ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
421 );
422
423 //
424 // Set PCI Express Register Range Base Address
425 //
426 PciExBarInitialization ();
427 }
428 }
429
430 VOID
431 BootModeInitialization (
432 VOID
433 )
434 {
435 EFI_STATUS Status;
436
437 if (CmosRead8 (0xF) == 0xFE) {
438 mBootMode = BOOT_ON_S3_RESUME;
439 }
440
441 CmosWrite8 (0xF, 0x00);
442
443 Status = PeiServicesSetBootMode (mBootMode);
444 ASSERT_EFI_ERROR (Status);
445
446 Status = PeiServicesInstallPpi (mPpiBootMode);
447 ASSERT_EFI_ERROR (Status);
448 }
449
450 VOID
451 ReserveEmuVariableNvStore (
452 )
453 {
454 EFI_PHYSICAL_ADDRESS VariableStore;
455 RETURN_STATUS PcdStatus;
456
457 //
458 // Allocate storage for NV variables early on so it will be
459 // at a consistent address. Since VM memory is preserved
460 // across reboots, this allows the NV variable storage to survive
461 // a VM reboot.
462 //
463 VariableStore =
464 (EFI_PHYSICAL_ADDRESS)(UINTN)
465 AllocateRuntimePages (
466 EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
467 );
468 DEBUG ((
469 DEBUG_INFO,
470 "Reserved variable store memory: 0x%lX; size: %dkb\n",
471 VariableStore,
472 (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
473 ));
474 PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
475 ASSERT_RETURN_ERROR (PcdStatus);
476 }
477
478 VOID
479 DebugDumpCmos (
480 VOID
481 )
482 {
483 UINT32 Loop;
484
485 DEBUG ((DEBUG_INFO, "CMOS:\n"));
486
487 for (Loop = 0; Loop < 0x80; Loop++) {
488 if ((Loop % 0x10) == 0) {
489 DEBUG ((DEBUG_INFO, "%02x:", Loop));
490 }
491
492 DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
493 if ((Loop % 0x10) == 0xf) {
494 DEBUG ((DEBUG_INFO, "\n"));
495 }
496 }
497 }
498
499 VOID
500 S3Verification (
501 VOID
502 )
503 {
504 #if defined (MDE_CPU_X64)
505 if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {
506 DEBUG ((
507 DEBUG_ERROR,
508 "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",
509 __FUNCTION__
510 ));
511 DEBUG ((
512 DEBUG_ERROR,
513 "%a: Please disable S3 on the QEMU command line (see the README),\n",
514 __FUNCTION__
515 ));
516 DEBUG ((
517 DEBUG_ERROR,
518 "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n",
519 __FUNCTION__
520 ));
521 ASSERT (FALSE);
522 CpuDeadLoop ();
523 }
524
525 #endif
526 }
527
528 VOID
529 Q35BoardVerification (
530 VOID
531 )
532 {
533 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
534 return;
535 }
536
537 DEBUG ((
538 DEBUG_ERROR,
539 "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
540 "only DID=0x%04x (Q35) is supported\n",
541 __FUNCTION__,
542 mHostBridgeDevId,
543 INTEL_Q35_MCH_DEVICE_ID
544 ));
545 ASSERT (FALSE);
546 CpuDeadLoop ();
547 }
548
549 /**
550 Fetch the boot CPU count and the possible CPU count from QEMU, and expose
551 them to UefiCpuPkg modules. Set the mMaxCpuCount variable.
552 **/
553 VOID
554 MaxCpuCountInitialization (
555 VOID
556 )
557 {
558 UINT16 BootCpuCount;
559 RETURN_STATUS PcdStatus;
560
561 //
562 // Try to fetch the boot CPU count.
563 //
564 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
565 BootCpuCount = QemuFwCfgRead16 ();
566 if (BootCpuCount == 0) {
567 //
568 // QEMU doesn't report the boot CPU count. (BootCpuCount == 0) will let
569 // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or
570 // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reached
571 // first).
572 //
573 DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));
574 mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
575 } else {
576 //
577 // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to
578 // (BootCpuCount - 1) precisely, regardless of timeout.
579 //
580 // Now try to fetch the possible CPU count.
581 //
582 UINTN CpuHpBase;
583 UINT32 CmdData2;
584
585 CpuHpBase = ((mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
586 ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);
587
588 //
589 // If only legacy mode is available in the CPU hotplug register block, or
590 // the register block is completely missing, then the writes below are
591 // no-ops.
592 //
593 // 1. Switch the hotplug register block to modern mode.
594 //
595 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
596 //
597 // 2. Select a valid CPU for deterministic reading of
598 // QEMU_CPUHP_R_CMD_DATA2.
599 //
600 // CPU#0 is always valid; it is the always present and non-removable
601 // BSP.
602 //
603 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
604 //
605 // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to
606 // read as zero, and which does not invalidate the selector. (The
607 // selector may change, but it must not become invalid.)
608 //
609 // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later.
610 //
611 IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING);
612 //
613 // 4. Read QEMU_CPUHP_R_CMD_DATA2.
614 //
615 // If the register block is entirely missing, then this is an unassigned
616 // IO read, returning all-bits-one.
617 //
618 // If only legacy mode is available, then bit#0 stands for CPU#0 in the
619 // "CPU present bitmap". CPU#0 is always present.
620 //
621 // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (returning
622 // all-bits-zero), or it is specified to read as zero after the above
623 // steps. Both cases confirm modern mode.
624 //
625 CmdData2 = IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2);
626 DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=0x%x\n", __FUNCTION__, CmdData2));
627 if (CmdData2 != 0) {
628 //
629 // QEMU doesn't support the modern CPU hotplug interface. Assume that the
630 // possible CPU count equals the boot CPU count (precluding hotplug).
631 //
632 DEBUG ((
633 DEBUG_WARN,
634 "%a: modern CPU hotplug interface unavailable\n",
635 __FUNCTION__
636 ));
637 mMaxCpuCount = BootCpuCount;
638 } else {
639 //
640 // Grab the possible CPU count from the modern CPU hotplug interface.
641 //
642 UINT32 Present, Possible, Selected;
643
644 Present = 0;
645 Possible = 0;
646
647 //
648 // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures
649 // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However,
650 // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pending
651 // hotplug events; therefore, select CPU#0 forcibly.
652 //
653 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
654
655 do {
656 UINT8 CpuStatus;
657
658 //
659 // Read the status of the currently selected CPU. This will help with a
660 // sanity check against "BootCpuCount".
661 //
662 CpuStatus = IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT);
663 if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) != 0) {
664 ++Present;
665 }
666
667 //
668 // Attempt to select the next CPU.
669 //
670 ++Possible;
671 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
672 //
673 // If the selection is successful, then the following read will return
674 // the selector (which we know is positive at this point). Otherwise,
675 // the read will return 0.
676 //
677 Selected = IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA);
678 ASSERT (Selected == Possible || Selected == 0);
679 } while (Selected > 0);
680
681 //
682 // Sanity check: fw_cfg and the modern CPU hotplug interface should
683 // return the same boot CPU count.
684 //
685 if (BootCpuCount != Present) {
686 DEBUG ((
687 DEBUG_WARN,
688 "%a: QEMU v2.7 reset bug: BootCpuCount=%d "
689 "Present=%u\n",
690 __FUNCTION__,
691 BootCpuCount,
692 Present
693 ));
694 //
695 // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug plus
696 // platform reset (including S3), was corrected in QEMU commit
697 // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device added
698 // CPUs", 2016-11-16), part of release v2.8.0.
699 //
700 BootCpuCount = (UINT16)Present;
701 }
702
703 mMaxCpuCount = Possible;
704 }
705 }
706
707 DEBUG ((
708 DEBUG_INFO,
709 "%a: BootCpuCount=%d mMaxCpuCount=%u\n",
710 __FUNCTION__,
711 BootCpuCount,
712 mMaxCpuCount
713 ));
714 ASSERT (BootCpuCount <= mMaxCpuCount);
715
716 PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, BootCpuCount);
717 ASSERT_RETURN_ERROR (PcdStatus);
718 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, mMaxCpuCount);
719 ASSERT_RETURN_ERROR (PcdStatus);
720 }
721
722 /**
723 Perform Platform PEI initialization.
724
725 @param FileHandle Handle of the file being invoked.
726 @param PeiServices Describes the list of possible PEI Services.
727
728 @return EFI_SUCCESS The PEIM initialized successfully.
729
730 **/
731 EFI_STATUS
732 EFIAPI
733 InitializePlatform (
734 IN EFI_PEI_FILE_HANDLE FileHandle,
735 IN CONST EFI_PEI_SERVICES **PeiServices
736 )
737 {
738 EFI_STATUS Status;
739
740 DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
741
742 DebugDumpCmos ();
743
744 if (QemuFwCfgS3Enabled ()) {
745 DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
746 mS3Supported = TRUE;
747 Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
748 ASSERT_EFI_ERROR (Status);
749 }
750
751 S3Verification ();
752 BootModeInitialization ();
753 AddressWidthInitialization ();
754
755 //
756 // Query Host Bridge DID
757 //
758 mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
759
760 MaxCpuCountInitialization ();
761
762 if (FeaturePcdGet (PcdSmmSmramRequire)) {
763 Q35BoardVerification ();
764 Q35TsegMbytesInitialization ();
765 Q35SmramAtDefaultSmbaseInitialization ();
766 }
767
768 PublishPeiMemory ();
769
770 QemuUc32BaseInitialization ();
771
772 InitializeRamRegions ();
773
774 if (mBootMode != BOOT_ON_S3_RESUME) {
775 if (!FeaturePcdGet (PcdSmmSmramRequire)) {
776 ReserveEmuVariableNvStore ();
777 }
778
779 PeiFvInitialization ();
780 MemTypeInfoInitialization ();
781 MemMapInitialization ();
782 NoexecDxeInitialization ();
783 }
784
785 InstallClearCacheCallback ();
786 AmdSevInitialize ();
787 MiscInitialization ();
788 InstallFeatureControlCallback ();
789
790 return EFI_SUCCESS;
791 }