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