]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformPei/Platform.c
UefiPayloadPkg: Fix build error
[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 <OvmfPlatforms.h>
40
41 #include "Platform.h"
42 #include "Cmos.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 (CmosRead8 (0xF) == 0xFE) {
509 mBootMode = BOOT_ON_S3_RESUME;
510 }
511
512 CmosWrite8 (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 DebugDumpCmos (
551 VOID
552 )
553 {
554 UINT32 Loop;
555
556 DEBUG ((DEBUG_INFO, "CMOS:\n"));
557
558 for (Loop = 0; Loop < 0x80; Loop++) {
559 if ((Loop % 0x10) == 0) {
560 DEBUG ((DEBUG_INFO, "%02x:", Loop));
561 }
562
563 DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
564 if ((Loop % 0x10) == 0xf) {
565 DEBUG ((DEBUG_INFO, "\n"));
566 }
567 }
568 }
569
570 VOID
571 S3Verification (
572 VOID
573 )
574 {
575 #if defined (MDE_CPU_X64)
576 if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {
577 DEBUG ((
578 DEBUG_ERROR,
579 "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",
580 __FUNCTION__
581 ));
582 DEBUG ((
583 DEBUG_ERROR,
584 "%a: Please disable S3 on the QEMU command line (see the README),\n",
585 __FUNCTION__
586 ));
587 DEBUG ((
588 DEBUG_ERROR,
589 "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n",
590 __FUNCTION__
591 ));
592 ASSERT (FALSE);
593 CpuDeadLoop ();
594 }
595
596 #endif
597 }
598
599 VOID
600 Q35BoardVerification (
601 VOID
602 )
603 {
604 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
605 return;
606 }
607
608 DEBUG ((
609 DEBUG_ERROR,
610 "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
611 "only DID=0x%04x (Q35) is supported\n",
612 __FUNCTION__,
613 mHostBridgeDevId,
614 INTEL_Q35_MCH_DEVICE_ID
615 ));
616 ASSERT (FALSE);
617 CpuDeadLoop ();
618 }
619
620 /**
621 Fetch the boot CPU count and the possible CPU count from QEMU, and expose
622 them to UefiCpuPkg modules. Set the mMaxCpuCount variable.
623 **/
624 VOID
625 MaxCpuCountInitialization (
626 VOID
627 )
628 {
629 UINT16 BootCpuCount;
630 RETURN_STATUS PcdStatus;
631
632 //
633 // Try to fetch the boot CPU count.
634 //
635 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
636 BootCpuCount = QemuFwCfgRead16 ();
637 if (BootCpuCount == 0) {
638 //
639 // QEMU doesn't report the boot CPU count. (BootCpuCount == 0) will let
640 // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or
641 // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reached
642 // first).
643 //
644 DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));
645 mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
646 } else {
647 //
648 // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to
649 // (BootCpuCount - 1) precisely, regardless of timeout.
650 //
651 // Now try to fetch the possible CPU count.
652 //
653 UINTN CpuHpBase;
654 UINT32 CmdData2;
655
656 CpuHpBase = ((mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
657 ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);
658
659 //
660 // If only legacy mode is available in the CPU hotplug register block, or
661 // the register block is completely missing, then the writes below are
662 // no-ops.
663 //
664 // 1. Switch the hotplug register block to modern mode.
665 //
666 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
667 //
668 // 2. Select a valid CPU for deterministic reading of
669 // QEMU_CPUHP_R_CMD_DATA2.
670 //
671 // CPU#0 is always valid; it is the always present and non-removable
672 // BSP.
673 //
674 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
675 //
676 // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to
677 // read as zero, and which does not invalidate the selector. (The
678 // selector may change, but it must not become invalid.)
679 //
680 // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later.
681 //
682 IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING);
683 //
684 // 4. Read QEMU_CPUHP_R_CMD_DATA2.
685 //
686 // If the register block is entirely missing, then this is an unassigned
687 // IO read, returning all-bits-one.
688 //
689 // If only legacy mode is available, then bit#0 stands for CPU#0 in the
690 // "CPU present bitmap". CPU#0 is always present.
691 //
692 // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (returning
693 // all-bits-zero), or it is specified to read as zero after the above
694 // steps. Both cases confirm modern mode.
695 //
696 CmdData2 = IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2);
697 DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=0x%x\n", __FUNCTION__, CmdData2));
698 if (CmdData2 != 0) {
699 //
700 // QEMU doesn't support the modern CPU hotplug interface. Assume that the
701 // possible CPU count equals the boot CPU count (precluding hotplug).
702 //
703 DEBUG ((
704 DEBUG_WARN,
705 "%a: modern CPU hotplug interface unavailable\n",
706 __FUNCTION__
707 ));
708 mMaxCpuCount = BootCpuCount;
709 } else {
710 //
711 // Grab the possible CPU count from the modern CPU hotplug interface.
712 //
713 UINT32 Present, Possible, Selected;
714
715 Present = 0;
716 Possible = 0;
717
718 //
719 // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures
720 // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However,
721 // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pending
722 // hotplug events; therefore, select CPU#0 forcibly.
723 //
724 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
725
726 do {
727 UINT8 CpuStatus;
728
729 //
730 // Read the status of the currently selected CPU. This will help with a
731 // sanity check against "BootCpuCount".
732 //
733 CpuStatus = IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT);
734 if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) != 0) {
735 ++Present;
736 }
737
738 //
739 // Attempt to select the next CPU.
740 //
741 ++Possible;
742 IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
743 //
744 // If the selection is successful, then the following read will return
745 // the selector (which we know is positive at this point). Otherwise,
746 // the read will return 0.
747 //
748 Selected = IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA);
749 ASSERT (Selected == Possible || Selected == 0);
750 } while (Selected > 0);
751
752 //
753 // Sanity check: fw_cfg and the modern CPU hotplug interface should
754 // return the same boot CPU count.
755 //
756 if (BootCpuCount != Present) {
757 DEBUG ((
758 DEBUG_WARN,
759 "%a: QEMU v2.7 reset bug: BootCpuCount=%d "
760 "Present=%u\n",
761 __FUNCTION__,
762 BootCpuCount,
763 Present
764 ));
765 //
766 // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug plus
767 // platform reset (including S3), was corrected in QEMU commit
768 // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device added
769 // CPUs", 2016-11-16), part of release v2.8.0.
770 //
771 BootCpuCount = (UINT16)Present;
772 }
773
774 mMaxCpuCount = Possible;
775 }
776 }
777
778 DEBUG ((
779 DEBUG_INFO,
780 "%a: BootCpuCount=%d mMaxCpuCount=%u\n",
781 __FUNCTION__,
782 BootCpuCount,
783 mMaxCpuCount
784 ));
785 ASSERT (BootCpuCount <= mMaxCpuCount);
786
787 PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, BootCpuCount);
788 ASSERT_RETURN_ERROR (PcdStatus);
789 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, mMaxCpuCount);
790 ASSERT_RETURN_ERROR (PcdStatus);
791 }
792
793 /**
794 Perform Platform PEI initialization.
795
796 @param FileHandle Handle of the file being invoked.
797 @param PeiServices Describes the list of possible PEI Services.
798
799 @return EFI_SUCCESS The PEIM initialized successfully.
800
801 **/
802 EFI_STATUS
803 EFIAPI
804 InitializePlatform (
805 IN EFI_PEI_FILE_HANDLE FileHandle,
806 IN CONST EFI_PEI_SERVICES **PeiServices
807 )
808 {
809 EFI_STATUS Status;
810
811 DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
812
813 DebugDumpCmos ();
814
815 if (QemuFwCfgS3Enabled ()) {
816 DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
817 mS3Supported = TRUE;
818 Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
819 ASSERT_EFI_ERROR (Status);
820 }
821
822 S3Verification ();
823 BootModeInitialization ();
824 AddressWidthInitialization ();
825
826 //
827 // Query Host Bridge DID
828 //
829 mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
830
831 MaxCpuCountInitialization ();
832
833 if (FeaturePcdGet (PcdSmmSmramRequire)) {
834 Q35BoardVerification ();
835 Q35TsegMbytesInitialization ();
836 Q35SmramAtDefaultSmbaseInitialization ();
837 }
838
839 PublishPeiMemory ();
840
841 QemuUc32BaseInitialization ();
842
843 InitializeRamRegions ();
844
845 if (mBootMode != BOOT_ON_S3_RESUME) {
846 if (!FeaturePcdGet (PcdSmmSmramRequire)) {
847 ReserveEmuVariableNvStore ();
848 }
849
850 PeiFvInitialization ();
851 MemTypeInfoInitialization ();
852 MemMapInitialization ();
853 NoexecDxeInitialization ();
854 }
855
856 InstallClearCacheCallback ();
857 AmdSevInitialize ();
858 MiscInitialization ();
859 InstallFeatureControlCallback ();
860
861 return EFI_SUCCESS;
862 }