• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 //
18 // The package level header files this module uses
19 //
20 #include <PiPei.h>
21 
22 //
23 // The Library classes this module consumes
24 //
25 #include <Library/BaseLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/HobLib.h>
28 #include <Library/IoLib.h>
29 #include <Library/MemoryAllocationLib.h>
30 #include <Library/PcdLib.h>
31 #include <Library/PciLib.h>
32 #include <Library/PeimEntryPoint.h>
33 #include <Library/PeiServicesLib.h>
34 #include <Library/QemuFwCfgLib.h>
35 #include <Library/ResourcePublicationLib.h>
36 #include <Guid/MemoryTypeInformation.h>
37 #include <Ppi/MasterBootMode.h>
38 #include <IndustryStandard/Pci22.h>
39 #include <OvmfPlatforms.h>
40 
41 #include "Platform.h"
42 #include "Cmos.h"
43 
44 EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
45   { EfiACPIMemoryNVS,       0x004 },
46   { EfiACPIReclaimMemory,   0x008 },
47   { EfiReservedMemoryType,  0x004 },
48   { EfiRuntimeServicesData, 0x024 },
49   { EfiRuntimeServicesCode, 0x030 },
50   { EfiBootServicesCode,    0x180 },
51   { EfiBootServicesData,    0xF00 },
52   { EfiMaxMemoryType,       0x000 }
53 };
54 
55 
56 EFI_PEI_PPI_DESCRIPTOR   mPpiBootMode[] = {
57   {
58     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
59     &gEfiPeiMasterBootModePpiGuid,
60     NULL
61   }
62 };
63 
64 
65 UINT16 mHostBridgeDevId;
66 
67 EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
68 
69 BOOLEAN mS3Supported = FALSE;
70 
71 UINT32 mMaxCpuCount;
72 
73 VOID
AddIoMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize)74 AddIoMemoryBaseSizeHob (
75   EFI_PHYSICAL_ADDRESS        MemoryBase,
76   UINT64                      MemorySize
77   )
78 {
79   BuildResourceDescriptorHob (
80     EFI_RESOURCE_MEMORY_MAPPED_IO,
81       EFI_RESOURCE_ATTRIBUTE_PRESENT     |
82       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
83       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
84       EFI_RESOURCE_ATTRIBUTE_TESTED,
85     MemoryBase,
86     MemorySize
87     );
88 }
89 
90 VOID
AddReservedMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize,BOOLEAN Cacheable)91 AddReservedMemoryBaseSizeHob (
92   EFI_PHYSICAL_ADDRESS        MemoryBase,
93   UINT64                      MemorySize,
94   BOOLEAN                     Cacheable
95   )
96 {
97   BuildResourceDescriptorHob (
98     EFI_RESOURCE_MEMORY_RESERVED,
99       EFI_RESOURCE_ATTRIBUTE_PRESENT     |
100       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
101       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
102       (Cacheable ?
103        EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
104        EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
105        EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
106        0
107        ) |
108       EFI_RESOURCE_ATTRIBUTE_TESTED,
109     MemoryBase,
110     MemorySize
111     );
112 }
113 
114 VOID
AddIoMemoryRangeHob(EFI_PHYSICAL_ADDRESS MemoryBase,EFI_PHYSICAL_ADDRESS MemoryLimit)115 AddIoMemoryRangeHob (
116   EFI_PHYSICAL_ADDRESS        MemoryBase,
117   EFI_PHYSICAL_ADDRESS        MemoryLimit
118   )
119 {
120   AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
121 }
122 
123 
124 VOID
AddMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize)125 AddMemoryBaseSizeHob (
126   EFI_PHYSICAL_ADDRESS        MemoryBase,
127   UINT64                      MemorySize
128   )
129 {
130   BuildResourceDescriptorHob (
131     EFI_RESOURCE_SYSTEM_MEMORY,
132       EFI_RESOURCE_ATTRIBUTE_PRESENT |
133       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
134       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
135       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
136       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
137       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
138       EFI_RESOURCE_ATTRIBUTE_TESTED,
139     MemoryBase,
140     MemorySize
141     );
142 }
143 
144 
145 VOID
AddMemoryRangeHob(EFI_PHYSICAL_ADDRESS MemoryBase,EFI_PHYSICAL_ADDRESS MemoryLimit)146 AddMemoryRangeHob (
147   EFI_PHYSICAL_ADDRESS        MemoryBase,
148   EFI_PHYSICAL_ADDRESS        MemoryLimit
149   )
150 {
151   AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
152 }
153 
154 
155 VOID
MemMapInitialization(VOID)156 MemMapInitialization (
157   VOID
158   )
159 {
160   UINT64        PciIoBase;
161   UINT64        PciIoSize;
162   RETURN_STATUS PcdStatus;
163 
164   PciIoBase = 0xC000;
165   PciIoSize = 0x4000;
166 
167   //
168   // Create Memory Type Information HOB
169   //
170   BuildGuidDataHob (
171     &gEfiMemoryTypeInformationGuid,
172     mDefaultMemoryTypeInformation,
173     sizeof(mDefaultMemoryTypeInformation)
174     );
175 
176   //
177   // Video memory + Legacy BIOS region
178   //
179   AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
180 
181   if (!mXen) {
182     UINT32  TopOfLowRam;
183     UINT64  PciExBarBase;
184     UINT32  PciBase;
185     UINT32  PciSize;
186 
187     TopOfLowRam = GetSystemMemorySizeBelow4gb ();
188     PciExBarBase = 0;
189     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
190       //
191       // The MMCONFIG area is expected to fall between the top of low RAM and
192       // the base of the 32-bit PCI host aperture.
193       //
194       PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
195       ASSERT (TopOfLowRam <= PciExBarBase);
196       ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
197       PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
198     } else {
199       PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
200     }
201 
202     //
203     // address       purpose   size
204     // ------------  --------  -------------------------
205     // max(top, 2g)  PCI MMIO  0xFC000000 - max(top, 2g)
206     // 0xFC000000    gap                           44 MB
207     // 0xFEC00000    IO-APIC                        4 KB
208     // 0xFEC01000    gap                         1020 KB
209     // 0xFED00000    HPET                           1 KB
210     // 0xFED00400    gap                          111 KB
211     // 0xFED1C000    gap (PIIX4) / RCRB (ICH9)     16 KB
212     // 0xFED20000    gap                          896 KB
213     // 0xFEE00000    LAPIC                          1 MB
214     //
215     PciSize = 0xFC000000 - PciBase;
216     AddIoMemoryBaseSizeHob (PciBase, PciSize);
217     PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
218     ASSERT_RETURN_ERROR (PcdStatus);
219     PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
220     ASSERT_RETURN_ERROR (PcdStatus);
221 
222     AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
223     AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
224     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
225       AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
226       //
227       // Note: there should be an
228       //
229       //   AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
230       //
231       // call below, just like the one above for RCBA. However, Linux insists
232       // that the MMCONFIG area be marked in the E820 or UEFI memory map as
233       // "reserved memory" -- Linux does not content itself with a simple gap
234       // in the memory map wherever the MCFG ACPI table points to.
235       //
236       // This appears to be a safety measure. The PCI Firmware Specification
237       // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
238       // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
239       // [...]". (Emphasis added here.)
240       //
241       // Normally we add memory resource descriptor HOBs in
242       // QemuInitializeRam(), and pre-allocate from those with memory
243       // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
244       // is most definitely not RAM; so, as an exception, cover it with
245       // uncacheable reserved memory right here.
246       //
247       AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
248       BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,
249         EfiReservedMemoryType);
250     }
251     AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);
252 
253     //
254     // On Q35, the IO Port space is available for PCI resource allocations from
255     // 0x6000 up.
256     //
257     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
258       PciIoBase = 0x6000;
259       PciIoSize = 0xA000;
260       ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
261     }
262   }
263 
264   //
265   // Add PCI IO Port space available for PCI resource allocations.
266   //
267   BuildResourceDescriptorHob (
268     EFI_RESOURCE_IO,
269     EFI_RESOURCE_ATTRIBUTE_PRESENT     |
270     EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
271     PciIoBase,
272     PciIoSize
273     );
274   PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
275   ASSERT_RETURN_ERROR (PcdStatus);
276   PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
277   ASSERT_RETURN_ERROR (PcdStatus);
278 }
279 
280 EFI_STATUS
GetNamedFwCfgBoolean(IN CHAR8 * FwCfgFileName,OUT BOOLEAN * Setting)281 GetNamedFwCfgBoolean (
282   IN  CHAR8   *FwCfgFileName,
283   OUT BOOLEAN *Setting
284   )
285 {
286   EFI_STATUS           Status;
287   FIRMWARE_CONFIG_ITEM FwCfgItem;
288   UINTN                FwCfgSize;
289   UINT8                Value[3];
290 
291   Status = QemuFwCfgFindFile (FwCfgFileName, &FwCfgItem, &FwCfgSize);
292   if (EFI_ERROR (Status)) {
293     return Status;
294   }
295   if (FwCfgSize > sizeof Value) {
296     return EFI_BAD_BUFFER_SIZE;
297   }
298   QemuFwCfgSelectItem (FwCfgItem);
299   QemuFwCfgReadBytes (FwCfgSize, Value);
300 
301   if ((FwCfgSize == 1) ||
302       (FwCfgSize == 2 && Value[1] == '\n') ||
303       (FwCfgSize == 3 && Value[1] == '\r' && Value[2] == '\n')) {
304     switch (Value[0]) {
305       case '0':
306       case 'n':
307       case 'N':
308         *Setting = FALSE;
309         return EFI_SUCCESS;
310 
311       case '1':
312       case 'y':
313       case 'Y':
314         *Setting = TRUE;
315         return EFI_SUCCESS;
316 
317       default:
318         break;
319     }
320   }
321   return EFI_PROTOCOL_ERROR;
322 }
323 
324 #define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName)                   \
325           do {                                                      \
326             BOOLEAN       Setting;                                  \
327             RETURN_STATUS PcdStatus;                                \
328                                                                     \
329             if (!EFI_ERROR (GetNamedFwCfgBoolean (                  \
330                               "opt/ovmf/" #TokenName, &Setting))) { \
331               PcdStatus = PcdSetBoolS (TokenName, Setting);         \
332               ASSERT_RETURN_ERROR (PcdStatus);                      \
333             }                                                       \
334           } while (0)
335 
336 VOID
NoexecDxeInitialization(VOID)337 NoexecDxeInitialization (
338   VOID
339   )
340 {
341   UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdPropertiesTableEnable);
342   UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);
343 }
344 
345 VOID
PciExBarInitialization(VOID)346 PciExBarInitialization (
347   VOID
348   )
349 {
350   union {
351     UINT64 Uint64;
352     UINT32 Uint32[2];
353   } PciExBarBase;
354 
355   //
356   // We only support the 256MB size for the MMCONFIG area:
357   // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
358   //
359   // The masks used below enforce the Q35 requirements that the MMCONFIG area
360   // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
361   //
362   // Note that (b) also ensures that the minimum address width we have
363   // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
364   // for DXE's page tables to cover the MMCONFIG area.
365   //
366   PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
367   ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
368   ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
369 
370   //
371   // Clear the PCIEXBAREN bit first, before programming the high register.
372   //
373   PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
374 
375   //
376   // Program the high register. Then program the low register, setting the
377   // MMCONFIG area size and enabling decoding at once.
378   //
379   PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
380   PciWrite32 (
381     DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
382     PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
383     );
384 }
385 
386 VOID
MiscInitialization(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     default:
432       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
433         __FUNCTION__, mHostBridgeDevId));
434       ASSERT (FALSE);
435       return;
436   }
437   PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
438   ASSERT_RETURN_ERROR (PcdStatus);
439 
440   //
441   // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
442   // has been configured (e.g., by Xen) and skip the setup here.
443   // This matches the logic in AcpiTimerLibConstructor ().
444   //
445   if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
446     //
447     // The PEI phase should be exited with fully accessibe ACPI PM IO space:
448     // 1. set PMBA
449     //
450     PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
451 
452     //
453     // 2. set PCICMD/IOSE
454     //
455     PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
456 
457     //
458     // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
459     //
460     PciOr8 (AcpiCtlReg, AcpiEnBit);
461   }
462 
463   if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
464     //
465     // Set Root Complex Register Block BAR
466     //
467     PciWrite32 (
468       POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
469       ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
470       );
471 
472     //
473     // Set PCI Express Register Range Base Address
474     //
475     PciExBarInitialization ();
476   }
477 }
478 
479 
480 VOID
BootModeInitialization(VOID)481 BootModeInitialization (
482   VOID
483   )
484 {
485   EFI_STATUS    Status;
486 
487   if (CmosRead8 (0xF) == 0xFE) {
488     mBootMode = BOOT_ON_S3_RESUME;
489   }
490   CmosWrite8 (0xF, 0x00);
491 
492   Status = PeiServicesSetBootMode (mBootMode);
493   ASSERT_EFI_ERROR (Status);
494 
495   Status = PeiServicesInstallPpi (mPpiBootMode);
496   ASSERT_EFI_ERROR (Status);
497 }
498 
499 
500 VOID
ReserveEmuVariableNvStore()501 ReserveEmuVariableNvStore (
502   )
503 {
504   EFI_PHYSICAL_ADDRESS VariableStore;
505   RETURN_STATUS        PcdStatus;
506 
507   //
508   // Allocate storage for NV variables early on so it will be
509   // at a consistent address.  Since VM memory is preserved
510   // across reboots, this allows the NV variable storage to survive
511   // a VM reboot.
512   //
513   VariableStore =
514     (EFI_PHYSICAL_ADDRESS)(UINTN)
515       AllocateAlignedRuntimePages (
516         EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)),
517         PcdGet32 (PcdFlashNvStorageFtwSpareSize)
518         );
519   DEBUG ((EFI_D_INFO,
520           "Reserved variable store memory: 0x%lX; size: %dkb\n",
521           VariableStore,
522           (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
523         ));
524   PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
525   ASSERT_RETURN_ERROR (PcdStatus);
526 }
527 
528 
529 VOID
DebugDumpCmos(VOID)530 DebugDumpCmos (
531   VOID
532   )
533 {
534   UINT32 Loop;
535 
536   DEBUG ((EFI_D_INFO, "CMOS:\n"));
537 
538   for (Loop = 0; Loop < 0x80; Loop++) {
539     if ((Loop % 0x10) == 0) {
540       DEBUG ((EFI_D_INFO, "%02x:", Loop));
541     }
542     DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop)));
543     if ((Loop % 0x10) == 0xf) {
544       DEBUG ((EFI_D_INFO, "\n"));
545     }
546   }
547 }
548 
549 
550 VOID
S3Verification(VOID)551 S3Verification (
552   VOID
553   )
554 {
555 #if defined (MDE_CPU_X64)
556   if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {
557     DEBUG ((EFI_D_ERROR,
558       "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n", __FUNCTION__));
559     DEBUG ((EFI_D_ERROR,
560       "%a: Please disable S3 on the QEMU command line (see the README),\n",
561       __FUNCTION__));
562     DEBUG ((EFI_D_ERROR,
563       "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n", __FUNCTION__));
564     ASSERT (FALSE);
565     CpuDeadLoop ();
566   }
567 #endif
568 }
569 
570 
571 /**
572   Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.
573   Set the mMaxCpuCount variable.
574 **/
575 VOID
MaxCpuCountInitialization(VOID)576 MaxCpuCountInitialization (
577   VOID
578   )
579 {
580   UINT16        ProcessorCount;
581   RETURN_STATUS PcdStatus;
582 
583   QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
584   ProcessorCount = QemuFwCfgRead16 ();
585   //
586   // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount
587   // from the PCD default. No change to PCDs.
588   //
589   if (ProcessorCount == 0) {
590     mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
591     return;
592   }
593   //
594   // Otherwise, set mMaxCpuCount to the value reported by QEMU.
595   //
596   mMaxCpuCount = ProcessorCount;
597   //
598   // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b)
599   // to wait, in the initial AP bringup, exactly as long as it takes for all of
600   // the APs to report in. For this, we set the longest representable timeout
601   // (approx. 71 minutes).
602   //
603   PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount);
604   ASSERT_RETURN_ERROR (PcdStatus);
605   PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);
606   ASSERT_RETURN_ERROR (PcdStatus);
607   DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__,
608     ProcessorCount));
609 }
610 
611 
612 /**
613   Perform Platform PEI initialization.
614 
615   @param  FileHandle      Handle of the file being invoked.
616   @param  PeiServices     Describes the list of possible PEI Services.
617 
618   @return EFI_SUCCESS     The PEIM initialized successfully.
619 
620 **/
621 EFI_STATUS
622 EFIAPI
InitializePlatform(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)623 InitializePlatform (
624   IN       EFI_PEI_FILE_HANDLE  FileHandle,
625   IN CONST EFI_PEI_SERVICES     **PeiServices
626   )
627 {
628   EFI_STATUS    Status;
629 
630   DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));
631 
632   DebugDumpCmos ();
633 
634   XenDetect ();
635 
636   if (QemuFwCfgS3Enabled ()) {
637     DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n"));
638     mS3Supported = TRUE;
639     Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
640     ASSERT_EFI_ERROR (Status);
641   }
642 
643   S3Verification ();
644   BootModeInitialization ();
645   AddressWidthInitialization ();
646   MaxCpuCountInitialization ();
647 
648   PublishPeiMemory ();
649 
650   InitializeRamRegions ();
651 
652   if (mXen) {
653     DEBUG ((EFI_D_INFO, "Xen was detected\n"));
654     InitializeXen ();
655   }
656 
657   //
658   // Query Host Bridge DID
659   //
660   mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
661 
662   if (mBootMode != BOOT_ON_S3_RESUME) {
663     ReserveEmuVariableNvStore ();
664     PeiFvInitialization ();
665     MemMapInitialization ();
666     NoexecDxeInitialization ();
667   }
668 
669   MiscInitialization ();
670   InstallFeatureControlCallback ();
671 
672   return EFI_SUCCESS;
673 }
674