OvmfPkg/PlatformPei: take VCPU count from QEMU and configure MpInitLib

These settings will allow CpuMpPei and CpuDxe to wait for the initial AP
check-ins exactly as long as necessary.

It is safe to set PcdCpuMaxLogicalProcessorNumber and
PcdCpuApInitTimeOutInMicroSeconds in OvmfPkg/PlatformPei.
OvmfPkg/PlatformPei installs the permanent PEI RAM, producing
gEfiPeiMemoryDiscoveredPpiGuid, and UefiCpuPkg/CpuMpPei has a depex on
gEfiPeiMemoryDiscoveredPpiGuid.

It is safe to read the fw_cfg item QemuFwCfgItemSmpCpuCount (0x0005). It
was added to QEMU in 2008 as key FW_CFG_NB_CPUS, in commit 905fdcb5264c
("Add common keys to firmware configuration"). Even if the key is
unavailable (or if fw_cfg is entirely unavailable, for example on Xen),
QemuFwCfgRead16() will return 0, and then we stick with the current
behavior.

Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index ed43c45..d913030 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -488,6 +488,10 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE

   gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable|FALSE

 

+  # UefiCpuPkg PCDs related to initial AP bringup and general AP management.

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000

+

 ################################################################################

 #

 # Components Section - list of all EDK II Modules needed by this Platform.

diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index ccd156d..8143ea9 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -496,6 +496,10 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE

   gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable|FALSE

 

+  # UefiCpuPkg PCDs related to initial AP bringup and general AP management.

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000

+

 ################################################################################

 #

 # Components Section - list of all EDK II Modules needed by this Platform.

diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 012ce85..d48d603 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -495,6 +495,10 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE

   gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable|FALSE

 

+  # UefiCpuPkg PCDs related to initial AP bringup and general AP management.

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000

+

 ################################################################################

 #

 # Components Section - list of all EDK II Modules needed by this Platform.

diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d00a570..af96a04 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -358,7 +358,7 @@
   //

   if (mS3Supported) {

     mS3AcpiReservedMemorySize = SIZE_512KB +

-      PcdGet32 (PcdCpuMaxLogicalProcessorNumber) *

+      mMaxCpuCount *

       PcdGet32 (PcdCpuApStackSize);

     mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;

     LowerMemorySize = mS3AcpiReservedMemoryBase;

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index c6e1106..0be8672 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -68,6 +68,7 @@
 

 BOOLEAN mS3Supported = FALSE;

 

+UINT32 mMaxCpuCount;

 

 VOID

 AddIoMemoryBaseSizeHob (

@@ -568,6 +569,47 @@
 

 

 /**

+  Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.

+  Set the mMaxCpuCount variable.

+**/

+VOID

+MaxCpuCountInitialization (

+  VOID

+  )

+{

+  UINT16        ProcessorCount;

+  RETURN_STATUS PcdStatus;

+

+  QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);

+  ProcessorCount = QemuFwCfgRead16 ();

+  //

+  // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount

+  // from the PCD default. No change to PCDs.

+  //

+  if (ProcessorCount == 0) {

+    mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);

+    return;

+  }

+  //

+  // Otherwise, set mMaxCpuCount to the value reported by QEMU.

+  //

+  mMaxCpuCount = ProcessorCount;

+  //

+  // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b)

+  // to wait, in the initial AP bringup, exactly as long as it takes for all of

+  // the APs to report in. For this, we set the longest representable timeout

+  // (approx. 71 minutes).

+  //

+  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount);

+  ASSERT_RETURN_ERROR (PcdStatus);

+  PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);

+  ASSERT_RETURN_ERROR (PcdStatus);

+  DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__,

+    ProcessorCount));

+}

+

+

+/**

   Perform Platform PEI initialization.

 

   @param  FileHandle      Handle of the file being invoked.

@@ -601,6 +643,7 @@
   S3Verification ();

   BootModeInitialization ();

   AddressWidthInitialization ();

+  MaxCpuCountInitialization ();

 

   PublishPeiMemory ();

 

diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index eda765b..18f42c3 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -101,4 +101,6 @@
 

 extern UINT8 mPhysMemAddressWidth;

 

+extern UINT32 mMaxCpuCount;

+

 #endif // _PLATFORM_PEI_H_INCLUDED_

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 776a4ab..fbaed31 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -95,6 +95,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable

   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress

   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds

   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize

 

 [FixedPcd]