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