public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
@ 2020-02-26 22:11 Laszlo Ersek
  2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
                   ` (18 more replies)
  0 siblings, 19 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney,
	Philippe Mathieu-Daudé, Ray Ni

Supersedes: <20200223172537.28464-1-lersek@redhat.com>
Bugzilla:   https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Repo:       https://github.com/lersek/edk2.git
Branch:     vcpu_hotplug_smm_bz_1512_v2

V1 was posted at:

* [edk2-devel] [PATCH 00/16]
  OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE

  https://edk2.groups.io/g/devel/message/54734
  http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com

New in v2:

- Document (in patch#11) and implement (in patch#12) the "combined"
  approach described here:

  http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
  https://edk2.groups.io/g/devel/message/54754

  The idea is basically to make the SMM Monarch wait not just until the
  hot-added CPU hits the normal RAM Post-SMM Pen (which is safe wrt.
  ordering, but can be attacked by the OS), but *also* until the
  hot-added CPU is just about to execute RSM first (which is a bit less
  safe wrt. ordering, but cannot be attacked by the OS).

- Pick up Ard's conditional A-b for the other patches, which have not
  been modified.

- Rebase to master, and retest.

See the Notes sections on the individual patches.

I wanted to get v2 out on the list before having to ask Intel folks to
do an incremental review.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>

Thanks,
Laszlo

Laszlo Ersek (16):
  MdeModulePkg/PiSmmCore: log SMM image start failure
  UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
  OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg
  OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm
  OvmfPkg: enable CPU hotplug support in PiSmmCpuDxeSmm
  OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver
  OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions
  OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro
  OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events
  OvmfPkg/CpuHotplugSmm: collect CPUs with events
  OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs
  OvmfPkg/CpuHotplugSmm: introduce First SMI Handler for hot-added CPUs
  OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug
  OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg
  OvmfPkg/CpuS3DataDxe: superficial cleanups
  OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug

 MdeModulePkg/Core/PiSmmCore/Dispatcher.c                                                                                                              |   6 +
 OvmfPkg/CpuHotplugSmm/ApicId.h                                                                                                                        |  23 ++
 OvmfPkg/CpuHotplugSmm/CpuHotplug.c                                                                                                                    | 426 ++++++++++++++++++++
 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf                                                                                                               |  64 +++
 OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm                                                                                                            | 154 +++++++
 OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h                                                                                                        |  47 +++
 OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm                                                                                                                 | 151 +++++++
 OvmfPkg/CpuHotplugSmm/QemuCpuhp.c                                                                                                                     | 301 ++++++++++++++
 OvmfPkg/CpuHotplugSmm/QemuCpuhp.h                                                                                                                     |  61 +++
 OvmfPkg/CpuHotplugSmm/Smbase.c                                                                                                                        | 267 ++++++++++++
 OvmfPkg/CpuHotplugSmm/Smbase.h                                                                                                                        |  46 +++
 OvmfPkg/Include/IndustryStandard/Q35MchIch9.h                                                                                                         |   5 +-
 OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h                                                                                                     |   3 +
 OvmfPkg/OvmfPkgIa32.dsc                                                                                                                               |   7 +-
 OvmfPkg/OvmfPkgIa32.fdf                                                                                                                               |   3 +-
 OvmfPkg/OvmfPkgIa32X64.dsc                                                                                                                            |   7 +-
 OvmfPkg/OvmfPkgIa32X64.fdf                                                                                                                            |   3 +-
 OvmfPkg/OvmfPkgX64.dsc                                                                                                                                |   7 +-
 OvmfPkg/OvmfPkgX64.fdf                                                                                                                                |   3 +-
 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c     |  45 ++-
 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf |  24 +-
 UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c                                                                                                                     |  14 +-
 {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c                                                                                                      |  99 +++--
 {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf                                                                                                 |  30 +-
 24 files changed, 1707 insertions(+), 89 deletions(-)
 copy UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c (61%)
 copy UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf (43%)
 copy {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c (77%)
 copy {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf (69%)
 create mode 100644 OvmfPkg/CpuHotplugSmm/ApicId.h
 create mode 100644 OvmfPkg/CpuHotplugSmm/CpuHotplug.c
 create mode 100644 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 create mode 100644 OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm
 create mode 100644 OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h
 create mode 100644 OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm
 create mode 100644 OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
 create mode 100644 OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
 create mode 100644 OvmfPkg/CpuHotplugSmm/Smbase.c
 create mode 100644 OvmfPkg/CpuHotplugSmm/Smbase.h


base-commit: edfe16a6d9f8c6830d7ad93ee7616225fe4e9c13
-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 12:47   ` [edk2-devel] " Laszlo Ersek
                     ` (2 more replies)
  2020-02-26 22:11 ` [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug Laszlo Ersek
                   ` (17 subsequent siblings)
  18 siblings, 3 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney,
	Philippe Mathieu-Daudé, Ray Ni

In the CoreStartImage() function [MdeModulePkg/Core/Dxe/Image/Image.c], if
the image entry point returns a failure code, then the DXE Core logs a
helpful DEBUG_ERROR message, with the following format string:

  "Error: Image at %11p start failed: %r\n"

Do similarly in the SMM Core (update the message slightly).

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
index 9bec731e5312..76ee9e0b89cc 100644
--- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
+++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
@@ -883,44 +883,50 @@ SmmDispatcher (
       RemoveEntryList (&DriverEntry->ScheduledLink);
 
       REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
         EFI_PROGRESS_CODE,
         EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
         &DriverEntry->ImageHandle,
         sizeof (DriverEntry->ImageHandle)
         );
 
       //
       // Cache state of SmmEntryPointRegistered before calling entry point
       //
       PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
 
       //
       // For each SMM driver, pass NULL as ImageHandle
       //
       RegisterSmramProfileImage (DriverEntry, TRUE);
       PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
       Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
       PERF_START_IMAGE_END (DriverEntry->ImageHandle);
       if (EFI_ERROR(Status)){
+        DEBUG ((
+          DEBUG_ERROR,
+          "Error: SMM image at %11p start failed: %r\n",
+          DriverEntry->SmmLoadedImage.ImageBase,
+          Status
+          ));
         UnregisterSmramProfileImage (DriverEntry, TRUE);
         SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
         //
         // Uninstall LoadedImage
         //
         Status = gBS->UninstallProtocolInterface (
                         DriverEntry->ImageHandle,
                         &gEfiLoadedImageProtocolGuid,
                         DriverEntry->LoadedImage
                         );
         if (!EFI_ERROR (Status)) {
           if (DriverEntry->LoadedImage->FilePath != NULL) {
             gBS->FreePool (DriverEntry->LoadedImage->FilePath);
           }
           gBS->FreePool (DriverEntry->LoadedImage);
         }
         Status = SmmUninstallProtocolInterface (
                    DriverEntry->SmmImageHandle,
                    &gEfiLoadedImageProtocolGuid,
                    &DriverEntry->SmmLoadedImage
                    );
         if (!EFI_ERROR(Status)) {
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
  2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-02-28  3:05   ` [edk2-devel] " Dong, Eric
  2020-02-26 22:11 ` [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg Laszlo Ersek
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Eric Dong, Igor Mammedov, Jiewen Yao,
	Jordan Justen, Michael Kinney, Philippe Mathieu-Daudé,
	Ray Ni

The "ACPI_CPU_DATA.NumberOfCpus" field is specified as follows, in
"UefiCpuPkg/Include/AcpiCpuData.h" (rewrapped for this commit message):

  //
  // The number of CPUs.  If a platform does not support hot plug CPUs,
  // then this is the number of CPUs detected when the platform is booted,
  // regardless of being enabled or disabled.  If a platform does support
  // hot plug CPUs, then this is the maximum number of CPUs that the
  // platform supports.
  //

The InitializeCpuBeforeRebase() and InitializeCpuAfterRebase() functions
in "UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c" try to restore CPU configuration on
the S3 Resume path for *all* CPUs accounted for in
"ACPI_CPU_DATA.NumberOfCpus". This is wrong, as with CPU hotplug, not all
of the possible CPUs may be present at the time of S3 Suspend / Resume.
The symptom is an infinite wait.

Instead, the "mNumberOfCpus" variable should be used, which is properly
maintained through the EFI_SMM_CPU_SERVICE_PROTOCOL implementation (see
SmmAddProcessor(), SmmRemoveProcessor(), SmmCpuUpdate() in
"UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c").

When CPU hotplug is disabled, "mNumberOfCpus" is constant, and equals
"ACPI_CPU_DATA.NumberOfCpus" at all times.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
index ba5cc0194c2d..1e0840119724 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
@@ -597,75 +597,85 @@ PrepareApStartupVector (
 }
 
 /**
   The function is invoked before SMBASE relocation in S3 path to restores CPU status.
 
   The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
   and restores MTRRs for both BSP and APs.
 
 **/
 VOID
 InitializeCpuBeforeRebase (
   VOID
   )
 {
   LoadMtrrData (mAcpiCpuData.MtrrTable);
 
   SetRegister (TRUE);
 
   ProgramVirtualWireMode ();
 
   PrepareApStartupVector (mAcpiCpuData.StartupVector);
 
-  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
+  if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+    ASSERT (mNumberOfCpus <= mAcpiCpuData.NumberOfCpus);
+  } else {
+    ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);
+  }
+  mNumberToFinish = mNumberOfCpus - 1;
   mExchangeInfo->ApFunction  = (VOID *) (UINTN) InitializeAp;
 
   //
   // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
   //
   mInitApsAfterSmmBaseReloc = FALSE;
 
   //
   // Send INIT IPI - SIPI to all APs
   //
   SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
 
   while (mNumberToFinish > 0) {
     CpuPause ();
   }
 }
 
 /**
   The function is invoked after SMBASE relocation in S3 path to restores CPU status.
 
   The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
   data saved by normal boot path for both BSP and APs.
 
 **/
 VOID
 InitializeCpuAfterRebase (
   VOID
   )
 {
-  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
+  if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+    ASSERT (mNumberOfCpus <= mAcpiCpuData.NumberOfCpus);
+  } else {
+    ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);
+  }
+  mNumberToFinish = mNumberOfCpus - 1;
 
   //
   // Signal that SMM base relocation is complete and to continue initialization for all APs.
   //
   mInitApsAfterSmmBaseReloc = TRUE;
 
   //
   // Must begin set register after all APs have continue their initialization.
   // This is a requirement to support semaphore mechanism in register table.
   // Because if semaphore's dependence type is package type, semaphore will wait
   // for all Aps in one package finishing their tasks before set next register
   // for all APs. If the Aps not begin its task during BSP doing its task, the
   // BSP thread will hang because it is waiting for other Aps in the same
   // package finishing their task.
   //
   SetRegister (FALSE);
 
   while (mNumberToFinish > 0) {
     CpuPause ();
   }
 }
 
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
  2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
  2020-02-26 22:11 ` [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:27   ` Ard Biesheuvel
  2020-03-02 13:49   ` Philippe Mathieu-Daudé
  2020-02-26 22:11 ` [PATCH v2 04/16] OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm Laszlo Ersek
                   ` (15 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Clone the Null instance of SmmCpuPlatformHookLib from UefiCpuPkg to
OvmfPkg. In this patch, customize the lib instance only with the following
no-op steps:

- Replace Null/NULL references in filenames and comments with Qemu/QEMU
  references.
- Update copyright notices.
- Clean up and rewrap comment blocks.
- Update INF_VERSION to the latest INF spec version (1.29).
- Update FILE_GUID.
- Drop the UNI file.

This patch is best reviewed with:

$ git show --find-copies=43 --find-copies-harder

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/OvmfPkgIa32.dsc                                                                                                                               |  2 +-
 OvmfPkg/OvmfPkgIa32X64.dsc                                                                                                                            |  2 +-
 OvmfPkg/OvmfPkgX64.dsc                                                                                                                                |  2 +-
 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf | 21 +++++-------
 UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c     | 36 ++++++++++++--------
 5 files changed, 32 insertions(+), 31 deletions(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 19728f20b34e..813995fefad8 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -858,45 +858,45 @@ [Components]
   UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
-      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
+      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
       SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   }
 
   #
   # Variable driver stack (SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
   #
   # Variable driver stack (non-SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
   OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
     <LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 3c0c229e3a72..a256c7084a7e 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -872,45 +872,45 @@ [Components.X64]
   UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
-      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
+      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
       SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   }
 
   #
   # Variable driver stack (SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
   #
   # Variable driver stack (non-SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
   OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
     <LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index f6c1d8d228c6..78079b9f8e13 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -870,45 +870,45 @@ [Components]
   UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
-      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
+      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
       SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   }
 
   #
   # Variable driver stack (SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
   #
   # Variable driver stack (non-SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
   OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
     <LibraryClasses>
diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
similarity index 43%
copy from UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
copy to OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
index fab6b30b7a3f..82edeca3d12d 100644
--- a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
+++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
@@ -1,34 +1,29 @@
 ## @file
-#  SMM CPU Platform Hook NULL library instance.
+#  SMM CPU Platform Hook library instance for QEMU.
 #
+#  Copyright (c) 2020, Red Hat, Inc.
 #  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
-#
 ##
 
-################################################################################
-#
-# Defines Section - statements that will be processed to create a Makefile.
-#
-################################################################################
 [Defines]
-  INF_VERSION                    = 0x00010005
-  BASE_NAME                      = SmmCpuPlatformHookLibNull
-  MODULE_UNI_FILE                = SmmCpuPlatformHookLibNull.uni
-  FILE_GUID                      = D6494E1B-E06F-4ab5-B64D-48B25AA9EB33
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = SmmCpuPlatformHookLibQemu
+  FILE_GUID                      = 154D6D26-54B8-45BC-BA3A-CBAA20C02A6A
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   LIBRARY_CLASS                  = SmmCpuPlatformHookLib
 
 #
-# The following information is for reference only and not required by the build tools.
+# The following information is for reference only and not required by the build
+# tools.
 #
 #  VALID_ARCHITECTURES           = IA32 X64
 #
 
 [Sources]
-  SmmCpuPlatformHookLibNull.c
+  SmmCpuPlatformHookLibQemu.c
 
 [Packages]
   MdePkg/MdePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
similarity index 67%
copy from UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
copy to OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
index 6c2010dc0a67..257e1d399cc6 100644
--- a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
+++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
@@ -1,102 +1,108 @@
 /** @file
-SMM CPU Platform Hook NULL library instance.
+SMM CPU Platform Hook library instance for QEMU.
 
+Copyright (c) 2020, Red Hat, Inc.
 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 #include <PiSmm.h>
 #include <Library/SmmCpuPlatformHookLib.h>
 
 /**
   Checks if platform produces a valid SMI.
 
   This function checks if platform produces a valid SMI. This function is
   called at SMM entry to detect if this is a spurious SMI. This function
   must be implemented in an MP safe way because it is called by multiple CPU
   threads.
 
   @retval TRUE              There is a valid SMI
   @retval FALSE             There is no valid SMI
 
 **/
 BOOLEAN
 EFIAPI
 PlatformValidSmi (
   VOID
   )
 {
   return TRUE;
 }
 
 /**
   Clears platform top level SMI status bit.
 
   This function clears platform top level SMI status bit.
 
   @retval TRUE              The platform top level SMI status is cleared.
-  @retval FALSE             The platform top level SMI status cannot be cleared.
+  @retval FALSE             The platform top level SMI status cannot be
+                            cleared.
 
 **/
 BOOLEAN
 EFIAPI
 ClearTopLevelSmiStatus (
   VOID
   )
 {
   return TRUE;
 }
 
 /**
   Performs platform specific way of SMM BSP election.
 
   This function performs platform specific way of SMM BSP election.
 
-  @param  IsBsp             Output parameter. TRUE: the CPU this function executes
-                            on is elected to be the SMM BSP. FALSE: the CPU this
-                            function executes on is to be SMM AP.
+  @param  IsBsp             Output parameter. TRUE: the CPU this function
+                            executes on is elected to be the SMM BSP. FALSE:
+                            the CPU this function executes on is to be SMM AP.
 
   @retval EFI_SUCCESS       The function executes successfully.
-  @retval EFI_NOT_READY     The function does not determine whether this CPU should be
-                            BSP or AP. This may occur if hardware init sequence to
-                            enable the determination is yet to be done, or the function
-                            chooses not to do BSP election and will let SMM CPU driver to
-                            use its default BSP election process.
-  @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU should be
-                            BSP or AP due to hardware error.
+  @retval EFI_NOT_READY     The function does not determine whether this CPU
+                            should be BSP or AP. This may occur if hardware
+                            init sequence to enable the determination is yet to
+                            be done, or the function chooses not to do BSP
+                            election and will let SMM CPU driver to use its
+                            default BSP election process.
+  @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU
+                            should be BSP or AP due to hardware error.
 
 **/
 EFI_STATUS
 EFIAPI
 PlatformSmmBspElection (
   OUT BOOLEAN     *IsBsp
   )
 {
   return EFI_NOT_READY;
 }
 
 /**
   Get platform page table attribute.
 
   This function gets page table attribute of platform.
 
-  @param  Address        Input parameter. Obtain the page table entries attribute on this address.
+  @param  Address        Input parameter. Obtain the page table entries
+                         attribute on this address.
   @param  PageSize       Output parameter. The size of the page.
   @param  NumOfPages     Output parameter. Number of page.
   @param  PageAttribute  Output parameter. Paging Attributes (WB, UC, etc).
 
-  @retval EFI_SUCCESS      The platform page table attribute from the address is determined.
-  @retval EFI_UNSUPPORTED  The platform does not support getting page table attribute for the address.
+  @retval EFI_SUCCESS      The platform page table attribute from the address
+                           is determined.
+  @retval EFI_UNSUPPORTED  The platform does not support getting page table
+                           attribute for the address.
 
 **/
 EFI_STATUS
 EFIAPI
 GetPlatformPageTableAttribute (
   IN  UINT64                Address,
   IN OUT SMM_PAGE_SIZE_TYPE *PageSize,
   IN OUT UINTN              *NumOfPages,
   IN OUT UINTN              *PageAttribute
   )
 {
   return EFI_UNSUPPORTED;
 }
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 04/16] OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (2 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:32   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 05/16] OvmfPkg: enable CPU hotplug support " Laszlo Ersek
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

With "PcdCpuSmmEnableBspElection" set to FALSE, PiSmmCpuDxeSmm always
considers the processor with index 0 to be the SMM Monarch (a.k.a. the SMM
BSP). The SMM Monarch handles the SMI for real, while the other CPUs wait
in their SMM loops.

In a subsequent patch, we want to set "PcdCpuHotPlugSupport" to TRUE. For
that, PiCpuSmmEntry() [UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c] forces
us with an ASSERT() to set "PcdCpuSmmEnableBspElection" to TRUE as well.
To satisfy that expectation, we can simply remove our current
"PcdCpuSmmEnableBspElection|FALSE" setting, and inherit the default TRUE
value from "UefiCpuPkg.dec".

This causes "mSmmMpSyncData->BspIndex" in PiSmmCpuDxeSmm to lose its
static zero value (standing for CPU#0); instead it becomes (-1) in
general, and the SMM Monarch is elected anew on every SMI.

The default SMM Monarch Election is basically a race -- whichever CPU can
flip "mSmmMpSyncData->BspIndex" from (-1) to its own index, becomes king,
for handling that SMI. Refer to SmiRendezvous()
[UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c].

I consider this non-determinism less than ideal on QEMU/KVM; it would be
nice to stick with a "mostly permanent" SMM Monarch even with the Election
enabled. We can do that by implementing the PlatformSmmBspElection() API
in the SmmCpuPlatformHookLibQemu instance:

The IA32 APIC Base MSR can be read on each CPU concurrently, and it will
report the BSP bit as set only on the current Boot Service Processor. QEMU
marks CPU#0 as the BSP, by default.

Elect the current BSP, as reported by QEMU, for the SMM Monarch role.

(Note that the QEMU commit history is not entirely consistent on whether
QEMU/KVM may mark a CPU with nonzero index as the BSP:

- At tag v4.2.0, "target/i386/cpu.c" has a comment saying "We hard-wire
  the BSP to the first CPU". This comment goes back to commit 6cb2996cef5e
  ("x86: Extend validity of bsp_to_cpu", 2010-03-04).

- Compare commit 9cb11fd7539b ("target-i386: clear bsp bit when
  designating bsp", 2015-04-02) though, especially considering KVM.

Either way, this OvmfPkg patch is *not* dependent on CPU index 0; it just
takes the race on every SMI out of the game.)

One benefit of using a "mostly permanent" SMM Monarch / BSP is that we can
continue testing the SMM CPU synchronization by deterministically entering
the firmware on the BSP, vs. on an AP, from Linux guests:

$ time taskset -c 0 efibootmgr
$ time taskset -c 1 efibootmgr

(See
<https://github.com/tianocore/tianocore.github.io/wiki/Testing-SMM-with-QEMU,-KVM-and-libvirt#uefi-variable-access-test>.)

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512#c5
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/OvmfPkgIa32.dsc                                                 | 1 -
 OvmfPkg/OvmfPkgIa32X64.dsc                                              | 1 -
 OvmfPkg/OvmfPkgX64.dsc                                                  | 1 -
 OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf | 3 +++
 OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c   | 9 ++++++++-
 5 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 813995fefad8..60d8af185b9c 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -414,45 +414,44 @@ [LibraryClasses.common.SMM_CORE]
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
 
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 !ifdef $(CSM_ENABLE)
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
 !endif
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
-  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
 !endif
 
 [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
 !endif
 !endif
 !if $(FD_SIZE_IN_KB) == 4096
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a256c7084a7e..be6bc7bd88a7 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -419,45 +419,44 @@ [LibraryClasses.common.SMM_CORE]
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
 
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 !ifdef $(CSM_ENABLE)
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
 !endif
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
-  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
 !endif
 
 [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
 !endif
 !endif
 !if $(FD_SIZE_IN_KB) == 4096
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 78079b9f8e13..e258c474b60d 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -419,45 +419,44 @@ [LibraryClasses.common.SMM_CORE]
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
 
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 !ifdef $(CSM_ENABLE)
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
 !endif
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
-  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
 !endif
 
 [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
 !endif
 !endif
 !if $(FD_SIZE_IN_KB) == 4096
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
 !endif
diff --git a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
index 82edeca3d12d..413c56fce6e1 100644
--- a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
+++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
@@ -8,22 +8,25 @@
 
 [Defines]
   INF_VERSION                    = 1.29
   BASE_NAME                      = SmmCpuPlatformHookLibQemu
   FILE_GUID                      = 154D6D26-54B8-45BC-BA3A-CBAA20C02A6A
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   LIBRARY_CLASS                  = SmmCpuPlatformHookLib
 
 #
 # The following information is for reference only and not required by the build
 # tools.
 #
 #  VALID_ARCHITECTURES           = IA32 X64
 #
 
 [Sources]
   SmmCpuPlatformHookLibQemu.c
 
 [Packages]
   MdePkg/MdePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  BaseLib
diff --git a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
index 257e1d399cc6..c88a95c6deff 100644
--- a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
+++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
@@ -1,31 +1,34 @@
 /** @file
 SMM CPU Platform Hook library instance for QEMU.
 
 Copyright (c) 2020, Red Hat, Inc.
 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
+#include <Library/BaseLib.h>                 // AsmReadMsr64()
 #include <PiSmm.h>
+#include <Register/Intel/ArchitecturalMsr.h> // MSR_IA32_APIC_BASE_REGISTER
+
 #include <Library/SmmCpuPlatformHookLib.h>
 
 /**
   Checks if platform produces a valid SMI.
 
   This function checks if platform produces a valid SMI. This function is
   called at SMM entry to detect if this is a spurious SMI. This function
   must be implemented in an MP safe way because it is called by multiple CPU
   threads.
 
   @retval TRUE              There is a valid SMI
   @retval FALSE             There is no valid SMI
 
 **/
 BOOLEAN
 EFIAPI
 PlatformValidSmi (
   VOID
   )
 {
   return TRUE;
 }
@@ -56,45 +59,49 @@ ClearTopLevelSmiStatus (
 
   @param  IsBsp             Output parameter. TRUE: the CPU this function
                             executes on is elected to be the SMM BSP. FALSE:
                             the CPU this function executes on is to be SMM AP.
 
   @retval EFI_SUCCESS       The function executes successfully.
   @retval EFI_NOT_READY     The function does not determine whether this CPU
                             should be BSP or AP. This may occur if hardware
                             init sequence to enable the determination is yet to
                             be done, or the function chooses not to do BSP
                             election and will let SMM CPU driver to use its
                             default BSP election process.
   @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU
                             should be BSP or AP due to hardware error.
 
 **/
 EFI_STATUS
 EFIAPI
 PlatformSmmBspElection (
   OUT BOOLEAN     *IsBsp
   )
 {
-  return EFI_NOT_READY;
+  MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+  *IsBsp = (BOOLEAN)(ApicBaseMsr.Bits.BSP == 1);
+  return EFI_SUCCESS;
 }
 
 /**
   Get platform page table attribute.
 
   This function gets page table attribute of platform.
 
   @param  Address        Input parameter. Obtain the page table entries
                          attribute on this address.
   @param  PageSize       Output parameter. The size of the page.
   @param  NumOfPages     Output parameter. Number of page.
   @param  PageAttribute  Output parameter. Paging Attributes (WB, UC, etc).
 
   @retval EFI_SUCCESS      The platform page table attribute from the address
                            is determined.
   @retval EFI_UNSUPPORTED  The platform does not support getting page table
                            attribute for the address.
 
 **/
 EFI_STATUS
 EFIAPI
 GetPlatformPageTableAttribute (
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 05/16] OvmfPkg: enable CPU hotplug support in PiSmmCpuDxeSmm
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (3 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 04/16] OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:33   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 06/16] OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver Laszlo Ersek
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Set "PcdCpuHotPlugSupport" to TRUE, when OVMF is built with SMM_REQUIRE.
Consequences:

(1) In PiCpuSmmEntry() [UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c],
    resources are allocated and populated in advance for all possible
    (i.e., potentially hot-added) processors, rather than only the
    processors present at boot.

    The possible count (called "mMaxNumberOfCpus") is set from
    "PcdCpuMaxLogicalProcessorNumber"; we set the latter in
    OvmfPkg/PlatformPei. (Refer to commit 83357313dd67,
    "OvmfPkg/PlatformPei: rewrite MaxCpuCountInitialization() for CPU
    hotplug", 2020-01-29).

(2) The AddProcessor() and RemoveProcessor() member functions of
    EFI_SMM_CPU_SERVICE_PROTOCOL, implemented in
    "UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c", are no longer
    short-circuited to EFI_UNSUPPORTED.

    We'll rely on these functions in the CPU hotplug SMI handler, in a
    subsequent patch.

(3) In PiCpuSmmEntry(), the address of the CPU_HOT_PLUG_DATA structure (in
    SMRAM) is exposed via the dynamic-only "PcdCpuHotPlugDataAddress".

    This structure is an information channel between the CPU hotplug SMI
    handler, and EFI_SMM_CPU_SERVICE_PROTOCOL. Namely, at the first
    "Index" where the following equality holds:

      CPU_HOT_PLUG_DATA.ApicId[Index] == INVALID_APIC_ID

    a hot-plugged CPU can be accepted, with the steps below:

(3.1) The hotplug SMI handler has to overwrite INVALID_APIC_ID with the
      new CPU's APIC ID.

(3.2) The new CPU's SMBASE has to be relocated to:

        CPU_HOT_PLUG_DATA.SmBase[Index]

      (which was precomputed in step (1) above).

(3.3) The hotplug SMI handler is supposed to call
      EFI_SMM_CPU_SERVICE_PROTOCOL.AddProcessor().

Note: we need not spell out "PcdCpuHotPlugDataAddress" in the
[PcdsDynamicDefault] sections of the OVMF DSC files, just so the PCD
become dynamically settable. That's because "UefiCpuPkg.dec" declares this
PCD with [PcdsDynamic, PcdsDynamicEx] access methods *only*.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/OvmfPkgIa32.dsc    | 1 +
 OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
 OvmfPkg/OvmfPkgX64.dsc     | 1 +
 3 files changed, 3 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 60d8af185b9c..8c065ca7cec9 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -414,44 +414,45 @@ [LibraryClasses.common.SMM_CORE]
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
 
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 !ifdef $(CSM_ENABLE)
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
 !endif
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
 !endif
 
 [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
 !endif
 !endif
 !if $(FD_SIZE_IN_KB) == 4096
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index be6bc7bd88a7..944b785e61a9 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -419,44 +419,45 @@ [LibraryClasses.common.SMM_CORE]
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
 
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 !ifdef $(CSM_ENABLE)
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
 !endif
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
 !endif
 
 [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
 !endif
 !endif
 !if $(FD_SIZE_IN_KB) == 4096
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index e258c474b60d..8de0f7179784 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -419,44 +419,45 @@ [LibraryClasses.common.SMM_CORE]
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
 
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
 [PcdsFeatureFlag]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 !ifdef $(CSM_ENABLE)
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
 !endif
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
 !endif
 
 [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
 !endif
 !endif
 !if $(FD_SIZE_IN_KB) == 4096
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
 !if $(NETWORK_TLS_ENABLE) == FALSE
   # match PcdFlashNvStorageVariableSize purely for convenience
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
 !endif
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 06/16] OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (4 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 05/16] OvmfPkg: enable CPU hotplug support " Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:44   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions Laszlo Ersek
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Add a new SMM driver skeleton that registers a root SMI handler, and
checks if the SMI control value (written to 0xB2) indicates a CPU hotplug
SMI.

QEMU's ACPI payload will cause the OS to raise a broadcast SMI when a CPU
hotplug event occurs, namely by writing value 4 to IO Port 0xB2. In other
words, control value 4 is now allocated for this purpose; introduce the
ICH9_APM_CNT_CPU_HOTPLUG macro for it.

The standard identifiers in this driver use the new MM (Management Mode)
terminology from the PI spec, not the earlier SMM (System Management Mode)
terms.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 OvmfPkg/OvmfPkgX64.dsc                        |   1 +
 OvmfPkg/OvmfPkgIa32.fdf                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.fdf                    |   1 +
 OvmfPkg/OvmfPkgX64.fdf                        |   1 +
 OvmfPkg/Include/IndustryStandard/Q35MchIch9.h |   5 +-
 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf       |  48 +++++
 OvmfPkg/CpuHotplugSmm/CpuHotplug.c            | 191 ++++++++++++++++++++
 9 files changed, 248 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 8c065ca7cec9..78310da44a5f 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -851,44 +851,45 @@ [Components]
 
   OvmfPkg/PlatformDxe/Platform.inf
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
   UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
+  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
       SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
       SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   }
 
   #
   # Variable driver stack (SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 944b785e61a9..428578a4f839 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -865,44 +865,45 @@ [Components.X64]
   OvmfPkg/PlatformDxe/Platform.inf
   OvmfPkg/AmdSevDxe/AmdSevDxe.inf
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
   UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
+  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
       SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
       SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   }
 
   #
   # Variable driver stack (SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 8de0f7179784..73b92f259201 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -863,44 +863,45 @@ [Components]
   OvmfPkg/PlatformDxe/Platform.inf
   OvmfPkg/AmdSevDxe/AmdSevDxe.inf
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
   UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
+  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
       SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
       SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   }
 
   #
   # Variable driver stack (SMM)
   #
   OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index 63607551ed75..61b891765c56 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -301,44 +301,45 @@ [FV.DXEFV]
 INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
 
 !ifdef $(CSM_ENABLE)
 INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
 INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
 INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
 !else
 INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
 !endif
 
 INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
 INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
 INF  OvmfPkg/PlatformDxe/Platform.inf
 INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
 INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
 INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
 INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
+INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
 INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
 INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
 
 #
 # Variable driver stack (SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
 #
 # Variable driver stack (non-SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 0488e5d95ffe..501b4fcb7b67 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -308,44 +308,45 @@ [FV.DXEFV]
 INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
 
 !ifdef $(CSM_ENABLE)
 INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
 INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
 INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
 !else
 INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
 !endif
 
 INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
 INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
 INF  OvmfPkg/PlatformDxe/Platform.inf
 INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
 INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
 INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
 INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
 INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
+INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
 INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
 INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
 
 #
 # Variable driver stack (SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
 #
 # Variable driver stack (non-SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 0488e5d95ffe..501b4fcb7b67 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -308,44 +308,45 @@ [FV.DXEFV]
 INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
 
 !ifdef $(CSM_ENABLE)
 INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
 INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
 INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
 !else
 INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
 !endif
 
 INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
 INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
 INF  OvmfPkg/PlatformDxe/Platform.inf
 INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
 INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
 INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
 INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
 INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
+INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
 INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
 INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
 
 #
 # Variable driver stack (SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
 #
 # Variable driver stack (non-SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
 !endif
diff --git a/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h b/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
index cb705fee92ca..73db4b59a111 100644
--- a/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
+++ b/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
@@ -90,37 +90,38 @@
 #define POWER_MGMT_REGISTER_Q35(Offset) \
   PCI_LIB_ADDRESS (0, 0x1f, 0, (Offset))
 
 #define POWER_MGMT_REGISTER_Q35_EFI_PCI_ADDRESS(Offset) \
   EFI_PCI_ADDRESS (0, 0x1f, 0, (Offset))
 
 #define ICH9_PMBASE               0x40
 #define ICH9_PMBASE_MASK            (BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | \
                                      BIT10 | BIT9  | BIT8  | BIT7)
 
 #define ICH9_ACPI_CNTL            0x44
 #define ICH9_ACPI_CNTL_ACPI_EN      BIT7
 
 #define ICH9_GEN_PMCON_1          0xA0
 #define ICH9_GEN_PMCON_1_SMI_LOCK   BIT4
 
 #define ICH9_RCBA                 0xF0
 #define ICH9_RCBA_EN                BIT0
 
 //
 // IO ports
 //
-#define ICH9_APM_CNT 0xB2
-#define ICH9_APM_STS 0xB3
+#define ICH9_APM_CNT              0xB2
+#define ICH9_APM_CNT_CPU_HOTPLUG    0x04
+#define ICH9_APM_STS              0xB3
 
 #define ICH9_CPU_HOTPLUG_BASE 0x0CD8
 
 //
 // IO ports relative to PMBASE
 //
 #define ICH9_PMBASE_OFS_SMI_EN 0x30
 #define ICH9_SMI_EN_APMC_EN      BIT5
 #define ICH9_SMI_EN_GBL_SMI_EN   BIT0
 
 #define ICH9_ROOT_COMPLEX_BASE 0xFED1C000
 
 #endif
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
new file mode 100644
index 000000000000..fa70858a8dab
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
@@ -0,0 +1,48 @@
+## @file
+# Root SMI handler for VCPU hotplug SMIs.
+#
+# Copyright (c) 2020, Red Hat, Inc.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                = 1.29
+  PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
+  BASE_NAME                  = CpuHotplugSmm
+  FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
+  MODULE_TYPE                = DXE_SMM_DRIVER
+  ENTRY_POINT                = CpuHotplugEntry
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES        = IA32 X64
+#
+
+[Sources]
+  CpuHotplug.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  MmServicesTableLib
+  PcdLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
+
+[FeaturePcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
+
+[Depex]
+  gEfiMmCpuIoProtocolGuid
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
new file mode 100644
index 000000000000..fd09403eabf3
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
@@ -0,0 +1,191 @@
+/** @file
+  Root SMI handler for VCPU hotplug SMIs.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
+#include <Library/BaseLib.h>                 // CpuDeadLoop()
+#include <Library/DebugLib.h>                // ASSERT()
+#include <Library/MmServicesTableLib.h>      // gMmst
+#include <Library/PcdLib.h>                  // PcdGetBool()
+#include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
+#include <Uefi/UefiBaseType.h>               // EFI_STATUS
+
+//
+// We use this protocol for accessing IO Ports.
+//
+STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
+//
+// Represents the registration of the CPU Hotplug MMI handler.
+//
+STATIC EFI_HANDLE mDispatchHandle;
+
+
+/**
+  CPU Hotplug MMI handler function.
+
+  This is a root MMI handler.
+
+  @param[in] DispatchHandle      The unique handle assigned to this handler by
+                                 EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
+
+  @param[in] Context             Context passed in by
+                                 EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
+                                 CpuHotplugMmi() being a root MMI handler,
+                                 Context is ASSERT()ed to be NULL.
+
+  @param[in,out] CommBuffer      Ignored, due to CpuHotplugMmi() being a root
+                                 MMI handler.
+
+  @param[in,out] CommBufferSize  Ignored, due to CpuHotplugMmi() being a root
+                                 MMI handler.
+
+  @retval EFI_SUCCESS                       The MMI was handled and the MMI
+                                            source was quiesced. When returned
+                                            by a non-root MMI handler,
+                                            EFI_SUCCESS terminates the
+                                            processing of MMI handlers in
+                                            EFI_MM_SYSTEM_TABLE.MmiManage().
+                                            For a root MMI handler (i.e., for
+                                            the present function too),
+                                            EFI_SUCCESS behaves identically to
+                                            EFI_WARN_INTERRUPT_SOURCE_QUIESCED,
+                                            as further root MMI handlers are
+                                            going to be called by
+                                            EFI_MM_SYSTEM_TABLE.MmiManage()
+                                            anyway.
+
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The MMI source has been quiesced,
+                                              but other handlers should still
+                                              be called.
+
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The MMI source is still pending,
+                                              and other handlers should still
+                                              be called.
+
+  @retval EFI_INTERRUPT_PENDING               The MMI source could not be
+                                              quiesced.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CpuHotplugMmi (
+  IN EFI_HANDLE DispatchHandle,
+  IN CONST VOID *Context        OPTIONAL,
+  IN OUT VOID   *CommBuffer     OPTIONAL,
+  IN OUT UINTN  *CommBufferSize OPTIONAL
+  )
+{
+  EFI_STATUS Status;
+  UINT8      ApmControl;
+
+  //
+  // Assert that we are entering this function due to our root MMI handler
+  // registration.
+  //
+  ASSERT (DispatchHandle == mDispatchHandle);
+  //
+  // When MmiManage() is invoked to process root MMI handlers, the caller (the
+  // MM Core) is expected to pass in a NULL Context. MmiManage() then passes
+  // the same NULL Context to individual handlers.
+  //
+  ASSERT (Context == NULL);
+  //
+  // Read the MMI command value from the APM Control Port, to see if this is an
+  // MMI we should care about.
+  //
+  Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,
+                          &ApmControl);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,
+      Status));
+    //
+    // We couldn't even determine if the MMI was for us or not.
+    //
+    goto Fatal;
+  }
+
+  if (ApmControl != ICH9_APM_CNT_CPU_HOTPLUG) {
+    //
+    // The MMI is not for us.
+    //
+    return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
+  }
+
+  //
+  // We've handled this MMI.
+  //
+  return EFI_SUCCESS;
+
+Fatal:
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+  //
+  // We couldn't handle this MMI.
+  //
+  return EFI_INTERRUPT_PENDING;
+}
+
+
+//
+// Entry point function of this driver.
+//
+EFI_STATUS
+EFIAPI
+CpuHotplugEntry (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // This module should only be included when SMM support is required.
+  //
+  ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
+  //
+  // This driver depends on the dynamically detected "SMRAM at default SMBASE"
+  // feature.
+  //
+  if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Errors from here on are fatal; we cannot allow the boot to proceed if we
+  // can't set up this driver to handle CPU hotplug.
+  //
+  // First, collect the protocols needed later. All of these protocols are
+  // listed in our module DEPEX.
+  //
+  Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
+                    NULL /* Registration */, (VOID **)&mMmCpuIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
+    goto Fatal;
+  }
+
+  //
+  // Register the handler for the CPU Hotplug MMI.
+  //
+  Status = gMmst->MmiHandlerRegister (
+                    CpuHotplugMmi,
+                    NULL,            // HandlerType: root MMI handler
+                    &mDispatchHandle
+                    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
+      Status));
+    goto Fatal;
+  }
+
+  return EFI_SUCCESS;
+
+Fatal:
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+  return Status;
+}
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (5 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 06/16] OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:24   ` Philippe Mathieu-Daudé
  2020-03-02 13:45   ` [edk2-devel] " Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro Laszlo Ersek
                   ` (11 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Add a handful of simple functions for accessing QEMU's hotplug registers
more conveniently. These functions thinly wrap some of the registers
described in "docs/specs/acpi_cpu_hotplug.txt" in the QEMU tree. The
functions hang (by design) if they encounter an internal failure.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   2 +
 OvmfPkg/CpuHotplugSmm/QemuCpuhp.h       |  47 +++++++
 OvmfPkg/CpuHotplugSmm/QemuCpuhp.c       | 136 ++++++++++++++++++++
 3 files changed, 185 insertions(+)

diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
index fa70858a8dab..ac4ca4c1f4f2 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
@@ -4,44 +4,46 @@
 # Copyright (c) 2020, Red Hat, Inc.
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
 
 [Defines]
   INF_VERSION                = 1.29
   PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
   BASE_NAME                  = CpuHotplugSmm
   FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
   MODULE_TYPE                = DXE_SMM_DRIVER
   ENTRY_POINT                = CpuHotplugEntry
 
 #
 # The following information is for reference only and not required by the build
 # tools.
 #
 # VALID_ARCHITECTURES        = IA32 X64
 #
 
 [Sources]
   CpuHotplug.c
+  QemuCpuhp.c
+  QemuCpuhp.h
 
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
   BaseLib
   DebugLib
   MmServicesTableLib
   PcdLib
   UefiDriverEntryPoint
 
 [Protocols]
   gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
 
 [Depex]
diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
new file mode 100644
index 000000000000..82f88f0b73bb
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
@@ -0,0 +1,47 @@
+/** @file
+  Simple wrapper functions that access QEMU's modern CPU hotplug register
+  block.
+
+  These functions thinly wrap some of the registers described in
+  "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
+  via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
+  return.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef QEMU_CPUHP_H_
+#define QEMU_CPUHP_H_
+
+#include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
+
+UINT32
+QemuCpuhpReadCommandData2 (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
+  );
+
+UINT8
+QemuCpuhpReadCpuStatus (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
+  );
+
+UINT32
+QemuCpuhpReadCommandData (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
+  );
+
+VOID
+QemuCpuhpWriteCpuSelector (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
+  IN UINT32                       Selector
+  );
+
+VOID
+QemuCpuhpWriteCommand (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
+  IN UINT8                        Command
+  );
+
+#endif // QEMU_CPUHP_H_
diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
new file mode 100644
index 000000000000..31e46f51934a
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
@@ -0,0 +1,136 @@
+/** @file
+  Simple wrapper functions that access QEMU's modern CPU hotplug register
+  block.
+
+  These functions thinly wrap some of the registers described in
+  "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
+  via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
+  return.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
+#include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
+#include <Library/BaseLib.h>                 // CpuDeadLoop()
+#include <Library/DebugLib.h>                // DEBUG()
+
+#include "QemuCpuhp.h"
+
+UINT32
+QemuCpuhpReadCommandData2 (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
+  )
+{
+  UINT32     CommandData2;
+  EFI_STATUS Status;
+
+  CommandData2 = 0;
+  Status = MmCpuIo->Io.Read (
+                         MmCpuIo,
+                         MM_IO_UINT32,
+                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_R_CMD_DATA2,
+                         1,
+                         &CommandData2
+                         );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+  return CommandData2;
+}
+
+UINT8
+QemuCpuhpReadCpuStatus (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
+  )
+{
+  UINT8      CpuStatus;
+  EFI_STATUS Status;
+
+  CpuStatus = 0;
+  Status = MmCpuIo->Io.Read (
+                         MmCpuIo,
+                         MM_IO_UINT8,
+                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_R_CPU_STAT,
+                         1,
+                         &CpuStatus
+                         );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+  return CpuStatus;
+}
+
+UINT32
+QemuCpuhpReadCommandData (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
+  )
+{
+  UINT32     CommandData;
+  EFI_STATUS Status;
+
+  CommandData = 0;
+  Status = MmCpuIo->Io.Read (
+                         MmCpuIo,
+                         MM_IO_UINT32,
+                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_RW_CMD_DATA,
+                         1,
+                         &CommandData
+                         );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+  return CommandData;
+}
+
+VOID
+QemuCpuhpWriteCpuSelector (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
+  IN UINT32                       Selector
+  )
+{
+  EFI_STATUS Status;
+
+  Status = MmCpuIo->Io.Write (
+                         MmCpuIo,
+                         MM_IO_UINT32,
+                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL,
+                         1,
+                         &Selector
+                         );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+}
+
+VOID
+QemuCpuhpWriteCommand (
+  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
+  IN UINT8                        Command
+  )
+{
+  EFI_STATUS Status;
+
+  Status = MmCpuIo->Io.Write (
+                         MmCpuIo,
+                         MM_IO_UINT8,
+                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
+                         1,
+                         &Command
+                         );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+}
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (6 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:22   ` Philippe Mathieu-Daudé
  2020-03-02 13:45   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events Laszlo Ersek
                   ` (10 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

QEMU commit 3a61c8db9d25 ("acpi: cpuhp: add CPHP_GET_CPU_ID_CMD command",
2020-01-22) introduced a new command in the modern CPU hotplug register
block that lets the firmware query the arch-specific IDs (on IA32/X64: the
APIC IDs) of CPUs. Add a macro for this command value, because we'll need
it later.

At the same time, add a sanity check for the modern hotplug interface to
CpuHotplugSmm.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |  1 +
 OvmfPkg/CpuHotplugSmm/CpuHotplug.c                | 35 ++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
index cf0745610f2c..3d013633501b 100644
--- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
+++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
@@ -20,24 +20,25 @@
 #define QEMU_CPU_HOTPLUG_H_
 
 #include <Base.h>
 
 //
 // Each register offset is:
 // - relative to the board-dependent IO base address of the register block,
 // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access modes of the
 //   register,
 // - followed by distinguished bitmasks or values in the register.
 //
 #define QEMU_CPUHP_R_CMD_DATA2               0x0
 
 #define QEMU_CPUHP_R_CPU_STAT                0x4
 #define QEMU_CPUHP_STAT_ENABLED                BIT0
 
 #define QEMU_CPUHP_RW_CMD_DATA               0x8
 
 #define QEMU_CPUHP_W_CPU_SEL                 0x0
 
 #define QEMU_CPUHP_W_CMD                     0x5
 #define QEMU_CPUHP_CMD_GET_PENDING             0x0
+#define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
 
 #endif // QEMU_CPU_HOTPLUG_H_
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
index fd09403eabf3..5df8c689c63a 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
@@ -1,38 +1,41 @@
 /** @file
   Root SMI handler for VCPU hotplug SMIs.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
+#include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
 #include <Library/BaseLib.h>                 // CpuDeadLoop()
 #include <Library/DebugLib.h>                // ASSERT()
 #include <Library/MmServicesTableLib.h>      // gMmst
 #include <Library/PcdLib.h>                  // PcdGetBool()
 #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
 #include <Uefi/UefiBaseType.h>               // EFI_STATUS
 
+#include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
+
 //
 // We use this protocol for accessing IO Ports.
 //
 STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
 //
 // Represents the registration of the CPU Hotplug MMI handler.
 //
 STATIC EFI_HANDLE mDispatchHandle;
 
 
 /**
   CPU Hotplug MMI handler function.
 
   This is a root MMI handler.
 
   @param[in] DispatchHandle      The unique handle assigned to this handler by
                                  EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
 
   @param[in] Context             Context passed in by
                                  EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
                                  CpuHotplugMmi() being a root MMI handler,
                                  Context is ASSERT()ed to be NULL.
@@ -149,43 +152,75 @@ CpuHotplugEntry (
   //
   // This driver depends on the dynamically detected "SMRAM at default SMBASE"
   // feature.
   //
   if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
     return EFI_UNSUPPORTED;
   }
 
   //
   // Errors from here on are fatal; we cannot allow the boot to proceed if we
   // can't set up this driver to handle CPU hotplug.
   //
   // First, collect the protocols needed later. All of these protocols are
   // listed in our module DEPEX.
   //
   Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
                     NULL /* Registration */, (VOID **)&mMmCpuIo);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
     goto Fatal;
   }
 
+  //
+  // Sanity-check the CPU hotplug interface.
+  //
+  // Both of the following features are part of QEMU 5.0, introduced primarily
+  // in commit range 3e08b2b9cb64..3a61c8db9d25:
+  //
+  // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
+  //     interface,
+  //
+  // (b) the "SMRAM at default SMBASE" feature.
+  //
+  // From these, (b) is restricted to 5.0+ machine type versions, while (a)
+  // does not depend on machine type version. Because we ensured the stricter
+  // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
+  // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
+  // can't verify the presence of precisely that command, we can still verify
+  // (sanity-check) that the modern interface is active, at least.
+  //
+  // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
+  // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
+  // following.
+  //
+  QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
+  QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
+  QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
+  if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
+    Status = EFI_NOT_FOUND;
+    DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
+      __FUNCTION__, Status));
+    goto Fatal;
+  }
+
   //
   // Register the handler for the CPU Hotplug MMI.
   //
   Status = gMmst->MmiHandlerRegister (
                     CpuHotplugMmi,
                     NULL,            // HandlerType: root MMI handler
                     &mDispatchHandle
                     );
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
       Status));
     goto Fatal;
   }
 
   return EFI_SUCCESS;
 
 Fatal:
   ASSERT (FALSE);
   CpuDeadLoop ();
   return Status;
 }
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (7 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:49   ` Ard Biesheuvel
  2020-03-02 20:34   ` Philippe Mathieu-Daudé
  2020-02-26 22:11 ` [PATCH v2 10/16] OvmfPkg/CpuHotplugSmm: collect " Laszlo Ersek
                   ` (9 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Add a function that collects the APIC IDs of CPUs that have just been
hot-plugged, or are about to be hot-unplugged.

Pending events are only located and never cleared; QEMU's AML needs the
firmware to leave the status bits intact in the hotplug register block.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |   2 +
 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf           |   1 +
 OvmfPkg/CpuHotplugSmm/ApicId.h                    |  23 +++
 OvmfPkg/CpuHotplugSmm/QemuCpuhp.h                 |  20 ++-
 OvmfPkg/CpuHotplugSmm/QemuCpuhp.c                 | 171 +++++++++++++++++++-
 5 files changed, 211 insertions(+), 6 deletions(-)

diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
index 3d013633501b..a34a6d3fae61 100644
--- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
+++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
@@ -13,32 +13,34 @@
     The new ("modern") hotplug interface appeared in QEMU v2.7.0.
 
     The macros in this header file map to the minimal subset of the modern
     interface that OVMF needs.
 **/
 
 #ifndef QEMU_CPU_HOTPLUG_H_
 #define QEMU_CPU_HOTPLUG_H_
 
 #include <Base.h>
 
 //
 // Each register offset is:
 // - relative to the board-dependent IO base address of the register block,
 // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access modes of the
 //   register,
 // - followed by distinguished bitmasks or values in the register.
 //
 #define QEMU_CPUHP_R_CMD_DATA2               0x0
 
 #define QEMU_CPUHP_R_CPU_STAT                0x4
 #define QEMU_CPUHP_STAT_ENABLED                BIT0
+#define QEMU_CPUHP_STAT_INSERT                 BIT1
+#define QEMU_CPUHP_STAT_REMOVE                 BIT2
 
 #define QEMU_CPUHP_RW_CMD_DATA               0x8
 
 #define QEMU_CPUHP_W_CPU_SEL                 0x0
 
 #define QEMU_CPUHP_W_CMD                     0x5
 #define QEMU_CPUHP_CMD_GET_PENDING             0x0
 #define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
 
 #endif // QEMU_CPU_HOTPLUG_H_
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
index ac4ca4c1f4f2..ab690a9e5e20 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
@@ -3,44 +3,45 @@
 #
 # Copyright (c) 2020, Red Hat, Inc.
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
 
 [Defines]
   INF_VERSION                = 1.29
   PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
   BASE_NAME                  = CpuHotplugSmm
   FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
   MODULE_TYPE                = DXE_SMM_DRIVER
   ENTRY_POINT                = CpuHotplugEntry
 
 #
 # The following information is for reference only and not required by the build
 # tools.
 #
 # VALID_ARCHITECTURES        = IA32 X64
 #
 
 [Sources]
+  ApicId.h
   CpuHotplug.c
   QemuCpuhp.c
   QemuCpuhp.h
 
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
   BaseLib
   DebugLib
   MmServicesTableLib
   PcdLib
   UefiDriverEntryPoint
 
 [Protocols]
   gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
 
 [FeaturePcd]
diff --git a/OvmfPkg/CpuHotplugSmm/ApicId.h b/OvmfPkg/CpuHotplugSmm/ApicId.h
new file mode 100644
index 000000000000..3c365148ed02
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/ApicId.h
@@ -0,0 +1,23 @@
+/** @file
+  Type and macro definitions for representing and printing APIC IDs, compatibly
+  with the LocalApicLib and PrintLib classes, respectively.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef APIC_ID_H_
+#define APIC_ID_H_
+
+//
+// The type that LocalApicLib represents an APIC ID with.
+//
+typedef UINT32 APIC_ID;
+
+//
+// The PrintLib conversion specification for formatting an APIC_ID.
+//
+#define FMT_APIC_ID "0x%08x"
+
+#endif // APIC_ID_H_
diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
index 82f88f0b73bb..8adaa0ad91f0 100644
--- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
+++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
@@ -1,47 +1,61 @@
 /** @file
-  Simple wrapper functions that access QEMU's modern CPU hotplug register
-  block.
+  Simple wrapper functions and utility functions that access QEMU's modern CPU
+  hotplug register block.
 
-  These functions thinly wrap some of the registers described in
+  These functions manipulate some of the registers described in
   "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
   via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
   return.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #ifndef QEMU_CPUHP_H_
 #define QEMU_CPUHP_H_
 
 #include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
+#include <Uefi/UefiBaseType.h> // EFI_STATUS
+
+#include "ApicId.h"            // APIC_ID
 
 UINT32
 QemuCpuhpReadCommandData2 (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
   );
 
 UINT8
 QemuCpuhpReadCpuStatus (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
   );
 
 UINT32
 QemuCpuhpReadCommandData (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
   );
 
 VOID
 QemuCpuhpWriteCpuSelector (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
   IN UINT32                       Selector
   );
 
 VOID
 QemuCpuhpWriteCommand (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
   IN UINT8                        Command
   );
 
+EFI_STATUS
+QemuCpuhpCollectApicIds (
+  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
+  IN  UINT32                       PossibleCpuCount,
+  IN  UINT32                       ApicIdCount,
+  OUT APIC_ID                      *PluggedApicIds,
+  OUT UINT32                       *PluggedCount,
+  OUT APIC_ID                      *ToUnplugApicIds,
+  OUT UINT32                       *ToUnplugCount
+  );
+
 #endif // QEMU_CPUHP_H_
diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
index 31e46f51934a..8d4a6693c8d6 100644
--- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
+++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
@@ -1,27 +1,27 @@
 /** @file
-  Simple wrapper functions that access QEMU's modern CPU hotplug register
-  block.
+  Simple wrapper functions and utility functions that access QEMU's modern CPU
+  hotplug register block.
 
-  These functions thinly wrap some of the registers described in
+  These functions manipulate some of the registers described in
   "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
   via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
   return.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
 #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
 #include <Library/BaseLib.h>                 // CpuDeadLoop()
 #include <Library/DebugLib.h>                // DEBUG()
 
 #include "QemuCpuhp.h"
 
 UINT32
 QemuCpuhpReadCommandData2 (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
   )
 {
   UINT32     CommandData2;
@@ -115,22 +115,187 @@ QemuCpuhpWriteCpuSelector (
 
 VOID
 QemuCpuhpWriteCommand (
   IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
   IN UINT8                        Command
   )
 {
   EFI_STATUS Status;
 
   Status = MmCpuIo->Io.Write (
                          MmCpuIo,
                          MM_IO_UINT8,
                          ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
                          1,
                          &Command
                          );
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
     ASSERT (FALSE);
     CpuDeadLoop ();
   }
 }
+
+/**
+  Collect the APIC IDs of
+  - the CPUs that have been hot-plugged,
+  - the CPUs that are about to be hot-unplugged.
+
+  This function only scans for events -- it does not modify them -- in the
+  hotplug registers.
+
+  On error, the contents of the output parameters are undefined.
+
+  @param[in] MmCpuIo           The EFI_MM_CPU_IO_PROTOCOL instance for
+                               accessing IO Ports.
+
+  @param[in] PossibleCpuCount  The number of possible CPUs in the system. Must
+                               be positive.
+
+  @param[in] ApicIdCount       The number of elements each one of the
+                               PluggedApicIds and ToUnplugApicIds arrays can
+                               accommodate. Must be positive.
+
+  @param[out] PluggedApicIds   The APIC IDs of the CPUs that have been
+                               hot-plugged.
+
+  @param[out] PluggedCount     The number of filled-in APIC IDs in
+                               PluggedApicIds.
+
+  @param[out] ToUnplugApicIds  The APIC IDs of the CPUs that are about to be
+                               hot-unplugged.
+
+  @param[out] ToUnplugCount    The number of filled-in APIC IDs in
+                               ToUnplugApicIds.
+
+  @retval EFI_INVALID_PARAMETER  PossibleCpuCount is zero, or ApicIdCount is
+                                 zero.
+
+  @retval EFI_PROTOCOL_ERROR     Invalid bitmap detected in the
+                                 QEMU_CPUHP_R_CPU_STAT register.
+
+  @retval EFI_BUFFER_TOO_SMALL   There was an attempt to place more than
+                                 ApicIdCount APIC IDs into one of the
+                                 PluggedApicIds and ToUnplugApicIds arrays.
+
+  @retval EFI_SUCCESS            Output parameters have been set successfully.
+**/
+EFI_STATUS
+QemuCpuhpCollectApicIds (
+  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
+  IN  UINT32                       PossibleCpuCount,
+  IN  UINT32                       ApicIdCount,
+  OUT APIC_ID                      *PluggedApicIds,
+  OUT UINT32                       *PluggedCount,
+  OUT APIC_ID                      *ToUnplugApicIds,
+  OUT UINT32                       *ToUnplugCount
+  )
+{
+  UINT32 CurrentSelector;
+
+  if (PossibleCpuCount == 0 || ApicIdCount == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *PluggedCount = 0;
+  *ToUnplugCount = 0;
+
+  CurrentSelector = 0;
+  do {
+    UINT32  PendingSelector;
+    UINT8   CpuStatus;
+    APIC_ID *ExtendIds;
+    UINT32  *ExtendCount;
+    APIC_ID NewApicId;
+
+    //
+    // Write CurrentSelector (which is valid) to the CPU selector register.
+    // Consequences:
+    //
+    // - Other register accesses will be permitted.
+    //
+    // - The QEMU_CPUHP_CMD_GET_PENDING command will start scanning for a CPU
+    //   with pending events at CurrentSelector (inclusive).
+    //
+    QemuCpuhpWriteCpuSelector (MmCpuIo, CurrentSelector);
+    //
+    // Write the QEMU_CPUHP_CMD_GET_PENDING command. Consequences
+    // (independently of each other):
+    //
+    // - If there is a CPU with pending events, starting at CurrentSelector
+    //   (inclusive), the CPU selector will be updated to that CPU. Note that
+    //   the scanning in QEMU may wrap around, because we must never clear the
+    //   event bits.
+    //
+    // - The QEMU_CPUHP_RW_CMD_DATA register will return the (possibly updated)
+    //   CPU selector value.
+    //
+    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
+    PendingSelector = QemuCpuhpReadCommandData (MmCpuIo);
+    if (PendingSelector < CurrentSelector) {
+      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u PendingSelector=%u: "
+        "wrap-around\n", __FUNCTION__, CurrentSelector, PendingSelector));
+      break;
+    }
+    CurrentSelector = PendingSelector;
+
+    //
+    // Check the known status / event bits for the currently selected CPU.
+    //
+    CpuStatus = QemuCpuhpReadCpuStatus (MmCpuIo);
+    if ((CpuStatus & QEMU_CPUHP_STAT_INSERT) != 0) {
+      //
+      // The "insert" event guarantees the "enabled" status; plus it excludes
+      // the "remove" event.
+      //
+      if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) == 0 ||
+          (CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
+        DEBUG ((DEBUG_ERROR, "%a: CurrentSelector=%u CpuStatus=0x%x: "
+          "inconsistent CPU status\n", __FUNCTION__, CurrentSelector,
+          CpuStatus));
+        return EFI_PROTOCOL_ERROR;
+      }
+
+      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: insert\n", __FUNCTION__,
+        CurrentSelector));
+
+      ExtendIds   = PluggedApicIds;
+      ExtendCount = PluggedCount;
+    } else if ((CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
+      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: remove\n", __FUNCTION__,
+        CurrentSelector));
+
+      ExtendIds   = ToUnplugApicIds;
+      ExtendCount = ToUnplugCount;
+    } else {
+      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: no event\n",
+        __FUNCTION__, CurrentSelector));
+      break;
+    }
+
+    //
+    // Save the APIC ID of the CPU with the pending event, to the corresponding
+    // APIC ID array.
+    //
+    if (*ExtendCount == ApicIdCount) {
+      DEBUG ((DEBUG_ERROR, "%a: APIC ID array too small\n", __FUNCTION__));
+      return EFI_BUFFER_TOO_SMALL;
+    }
+    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_ARCH_ID);
+    NewApicId = QemuCpuhpReadCommandData (MmCpuIo);
+    DEBUG ((DEBUG_VERBOSE, "%a: ApicId=" FMT_APIC_ID "\n", __FUNCTION__,
+      NewApicId));
+    ExtendIds[(*ExtendCount)++] = NewApicId;
+
+    //
+    // We've processed the CPU with (known) pending events, but we must never
+    // clear events. Therefore we need to advance past this CPU manually;
+    // otherwise, QEMU_CPUHP_CMD_GET_PENDING would stick to the currently
+    // selected CPU.
+    //
+    CurrentSelector++;
+  } while (CurrentSelector < PossibleCpuCount);
+
+  DEBUG ((DEBUG_VERBOSE, "%a: PluggedCount=%u ToUnplugCount=%u\n",
+    __FUNCTION__, *PluggedCount, *ToUnplugCount));
+  return EFI_SUCCESS;
+}
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 10/16] OvmfPkg/CpuHotplugSmm: collect CPUs with events
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (8 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:58   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 11/16] OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs Laszlo Ersek
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Call QemuCpuhpCollectApicIds() in the root MMI handler. The APIC IDs of
the hotplugged CPUs will be used for several purposes in subsequent
patches.

For calling QemuCpuhpCollectApicIds(), pre-allocate both of its output
arrays "PluggedApicIds" and "ToUnplugApicIds" in the driver's entry point
function. The allocation size is dictated by the possible CPU count, which
we fetch from "CPU_HOT_PLUG_DATA.ArrayLength".

The CPU_HOT_PLUG_DATA structure in SMRAM is an out-of-band information
channel between this driver and PiSmmCpuDxeSmm, underlying
EFI_SMM_CPU_SERVICE_PROTOCOL.

In order to consume "CPU_HOT_PLUG_DATA.ArrayLength", extend the driver's
DEPEX to EFI_SMM_CPU_SERVICE_PROTOCOL. PiSmmCpuDxeSmm stores the address
of CPU_HOT_PLUG_DATA to "PcdCpuHotPlugDataAddress", before it produces
EFI_SMM_CPU_SERVICE_PROTOCOL.

Stash the protocol at once, as it will be needed later.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   7 +-
 OvmfPkg/CpuHotplugSmm/CpuHotplug.c      | 111 +++++++++++++++++++-
 2 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
index ab690a9e5e20..31c1ee1c9f6d 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
@@ -11,41 +11,46 @@ [Defines]
   PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
   BASE_NAME                  = CpuHotplugSmm
   FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
   MODULE_TYPE                = DXE_SMM_DRIVER
   ENTRY_POINT                = CpuHotplugEntry
 
 #
 # The following information is for reference only and not required by the build
 # tools.
 #
 # VALID_ARCHITECTURES        = IA32 X64
 #
 
 [Sources]
   ApicId.h
   CpuHotplug.c
   QemuCpuhp.c
   QemuCpuhp.h
 
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
   DebugLib
   MmServicesTableLib
   PcdLib
+  SafeIntLib
   UefiDriverEntryPoint
 
 [Protocols]
   gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
+  gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES
 
 [Pcd]
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
 
 [Depex]
-  gEfiMmCpuIoProtocolGuid
+  gEfiMmCpuIoProtocolGuid AND
+  gEfiSmmCpuServiceProtocolGuid
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
index 5df8c689c63a..42e023cb85c0 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
@@ -1,46 +1,76 @@
 /** @file
   Root SMI handler for VCPU hotplug SMIs.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
+#include <CpuHotPlugData.h>                  // CPU_HOT_PLUG_DATA
 #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
 #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
 #include <Library/BaseLib.h>                 // CpuDeadLoop()
 #include <Library/DebugLib.h>                // ASSERT()
 #include <Library/MmServicesTableLib.h>      // gMmst
 #include <Library/PcdLib.h>                  // PcdGetBool()
+#include <Library/SafeIntLib.h>              // SafeUintnSub()
 #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
+#include <Protocol/SmmCpuService.h>          // EFI_SMM_CPU_SERVICE_PROTOCOL
 #include <Uefi/UefiBaseType.h>               // EFI_STATUS
 
+#include "ApicId.h"                          // APIC_ID
 #include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
 
 //
 // We use this protocol for accessing IO Ports.
 //
 STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
 //
+// The following protocol is used to report the addition or removal of a CPU to
+// the SMM CPU driver (PiSmmCpuDxeSmm).
+//
+STATIC EFI_SMM_CPU_SERVICE_PROTOCOL *mMmCpuService;
+//
+// This structure is a communication side-channel between the
+// EFI_SMM_CPU_SERVICE_PROTOCOL consumer (i.e., this driver) and provider
+// (i.e., PiSmmCpuDxeSmm).
+//
+STATIC CPU_HOT_PLUG_DATA *mCpuHotPlugData;
+//
+// SMRAM arrays for fetching the APIC IDs of processors with pending events (of
+// known event types), for the time of just one MMI.
+//
+// The lifetimes of these arrays match that of this driver only because we
+// don't want to allocate SMRAM at OS runtime, and potentially fail (or
+// fragment the SMRAM map).
+//
+// These arrays provide room for ("possible CPU count" minus one) APIC IDs
+// each, as we don't expect every possible CPU to appear, or disappear, in a
+// single MMI. The numbers of used (populated) elements in the arrays are
+// determined on every MMI separately.
+//
+STATIC APIC_ID *mPluggedApicIds;
+STATIC APIC_ID *mToUnplugApicIds;
+//
 // Represents the registration of the CPU Hotplug MMI handler.
 //
 STATIC EFI_HANDLE mDispatchHandle;
 
 
 /**
   CPU Hotplug MMI handler function.
 
   This is a root MMI handler.
 
   @param[in] DispatchHandle      The unique handle assigned to this handler by
                                  EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
 
   @param[in] Context             Context passed in by
                                  EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
                                  CpuHotplugMmi() being a root MMI handler,
                                  Context is ASSERT()ed to be NULL.
 
   @param[in,out] CommBuffer      Ignored, due to CpuHotplugMmi() being a root
                                  MMI handler.
 
   @param[in,out] CommBufferSize  Ignored, due to CpuHotplugMmi() being a root
@@ -65,162 +95,239 @@ STATIC EFI_HANDLE mDispatchHandle;
                                               but other handlers should still
                                               be called.
 
   @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The MMI source is still pending,
                                               and other handlers should still
                                               be called.
 
   @retval EFI_INTERRUPT_PENDING               The MMI source could not be
                                               quiesced.
 **/
 STATIC
 EFI_STATUS
 EFIAPI
 CpuHotplugMmi (
   IN EFI_HANDLE DispatchHandle,
   IN CONST VOID *Context        OPTIONAL,
   IN OUT VOID   *CommBuffer     OPTIONAL,
   IN OUT UINTN  *CommBufferSize OPTIONAL
   )
 {
   EFI_STATUS Status;
   UINT8      ApmControl;
+  UINT32     PluggedCount;
+  UINT32     ToUnplugCount;
 
   //
   // Assert that we are entering this function due to our root MMI handler
   // registration.
   //
   ASSERT (DispatchHandle == mDispatchHandle);
   //
   // When MmiManage() is invoked to process root MMI handlers, the caller (the
   // MM Core) is expected to pass in a NULL Context. MmiManage() then passes
   // the same NULL Context to individual handlers.
   //
   ASSERT (Context == NULL);
   //
   // Read the MMI command value from the APM Control Port, to see if this is an
   // MMI we should care about.
   //
   Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,
                           &ApmControl);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,
       Status));
     //
     // We couldn't even determine if the MMI was for us or not.
     //
     goto Fatal;
   }
 
   if (ApmControl != ICH9_APM_CNT_CPU_HOTPLUG) {
     //
     // The MMI is not for us.
     //
     return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
   }
 
+  //
+  // Collect the CPUs with pending events.
+  //
+  Status = QemuCpuhpCollectApicIds (
+             mMmCpuIo,
+             mCpuHotPlugData->ArrayLength,     // PossibleCpuCount
+             mCpuHotPlugData->ArrayLength - 1, // ApicIdCount
+             mPluggedApicIds,
+             &PluggedCount,
+             mToUnplugApicIds,
+             &ToUnplugCount
+             );
+  if (EFI_ERROR (Status)) {
+    goto Fatal;
+  }
+  if (ToUnplugCount > 0) {
+    DEBUG ((DEBUG_ERROR, "%a: hot-unplug is not supported yet\n",
+      __FUNCTION__));
+    goto Fatal;
+  }
+
   //
   // We've handled this MMI.
   //
   return EFI_SUCCESS;
 
 Fatal:
   ASSERT (FALSE);
   CpuDeadLoop ();
   //
   // We couldn't handle this MMI.
   //
   return EFI_INTERRUPT_PENDING;
 }
 
 
 //
 // Entry point function of this driver.
 //
 EFI_STATUS
 EFIAPI
 CpuHotplugEntry (
   IN EFI_HANDLE       ImageHandle,
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
   EFI_STATUS Status;
+  UINTN      Size;
 
   //
   // This module should only be included when SMM support is required.
   //
   ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
   //
   // This driver depends on the dynamically detected "SMRAM at default SMBASE"
   // feature.
   //
   if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
     return EFI_UNSUPPORTED;
   }
 
   //
   // Errors from here on are fatal; we cannot allow the boot to proceed if we
   // can't set up this driver to handle CPU hotplug.
   //
   // First, collect the protocols needed later. All of these protocols are
   // listed in our module DEPEX.
   //
   Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
                     NULL /* Registration */, (VOID **)&mMmCpuIo);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
     goto Fatal;
   }
+  Status = gMmst->MmLocateProtocol (&gEfiSmmCpuServiceProtocolGuid,
+                    NULL /* Registration */, (VOID **)&mMmCpuService);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: locate MmCpuService: %r\n", __FUNCTION__,
+      Status));
+    goto Fatal;
+  }
+
+  //
+  // Our DEPEX on EFI_SMM_CPU_SERVICE_PROTOCOL guarantees that PiSmmCpuDxeSmm
+  // has pointed PcdCpuHotPlugDataAddress to CPU_HOT_PLUG_DATA in SMRAM.
+  //
+  mCpuHotPlugData = (VOID *)(UINTN)PcdGet64 (PcdCpuHotPlugDataAddress);
+  if (mCpuHotPlugData == NULL) {
+    Status = EFI_NOT_FOUND;
+    DEBUG ((DEBUG_ERROR, "%a: CPU_HOT_PLUG_DATA: %r\n", __FUNCTION__, Status));
+    goto Fatal;
+  }
+  //
+  // If the possible CPU count is 1, there's nothing for this driver to do.
+  //
+  if (mCpuHotPlugData->ArrayLength == 1) {
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Allocate the data structures that depend on the possible CPU count.
+  //
+  if (RETURN_ERROR (SafeUintnSub (mCpuHotPlugData->ArrayLength, 1, &Size)) ||
+      RETURN_ERROR (SafeUintnMult (sizeof (APIC_ID), Size, &Size))) {
+    Status = EFI_ABORTED;
+    DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_PLUG_DATA\n", __FUNCTION__));
+    goto Fatal;
+  }
+  Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
+                    (VOID **)&mPluggedApicIds);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
+    goto Fatal;
+  }
+  Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
+                    (VOID **)&mToUnplugApicIds);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
+    goto ReleasePluggedApicIds;
+  }
 
   //
   // Sanity-check the CPU hotplug interface.
   //
   // Both of the following features are part of QEMU 5.0, introduced primarily
   // in commit range 3e08b2b9cb64..3a61c8db9d25:
   //
   // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
   //     interface,
   //
   // (b) the "SMRAM at default SMBASE" feature.
   //
   // From these, (b) is restricted to 5.0+ machine type versions, while (a)
   // does not depend on machine type version. Because we ensured the stricter
   // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
   // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
   // can't verify the presence of precisely that command, we can still verify
   // (sanity-check) that the modern interface is active, at least.
   //
   // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
   // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
   // following.
   //
   QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
   QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
   QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
   if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
     Status = EFI_NOT_FOUND;
     DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
       __FUNCTION__, Status));
-    goto Fatal;
+    goto ReleaseToUnplugApicIds;
   }
 
   //
   // Register the handler for the CPU Hotplug MMI.
   //
   Status = gMmst->MmiHandlerRegister (
                     CpuHotplugMmi,
                     NULL,            // HandlerType: root MMI handler
                     &mDispatchHandle
                     );
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
       Status));
-    goto Fatal;
+    goto ReleaseToUnplugApicIds;
   }
 
   return EFI_SUCCESS;
 
+ReleaseToUnplugApicIds:
+  gMmst->MmFreePool (mToUnplugApicIds);
+  mToUnplugApicIds = NULL;
+
+ReleasePluggedApicIds:
+  gMmst->MmFreePool (mPluggedApicIds);
+  mPluggedApicIds = NULL;
+
 Fatal:
   ASSERT (FALSE);
   CpuDeadLoop ();
   return Status;
 }
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 11/16] OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (9 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 10/16] OvmfPkg/CpuHotplugSmm: collect " Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 14:02   ` [edk2-devel] " Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler " Laszlo Ersek
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Once a hot-added CPU finishes the SMBASE relocation, we need to pen it in
a HLT loop. Add the NASM implementation (with just a handful of
instructions, but much documentation), and some C language helper
functions.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---

Notes:
    v2:
    
    - document the combined approach described here:
    
      http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
      https://edk2.groups.io/g/devel/message/54754
    
      by mentioning the "about to leave SMM" byte in SMRAM.

 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   4 +
 OvmfPkg/CpuHotplugSmm/Smbase.h          |  32 +++++
 OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm   | 151 ++++++++++++++++++++
 OvmfPkg/CpuHotplugSmm/Smbase.c          | 110 ++++++++++++++
 4 files changed, 297 insertions(+)

diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
index 31c1ee1c9f6d..bf4162299c7c 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
@@ -5,52 +5,56 @@
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
 
 [Defines]
   INF_VERSION                = 1.29
   PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
   BASE_NAME                  = CpuHotplugSmm
   FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
   MODULE_TYPE                = DXE_SMM_DRIVER
   ENTRY_POINT                = CpuHotplugEntry
 
 #
 # The following information is for reference only and not required by the build
 # tools.
 #
 # VALID_ARCHITECTURES        = IA32 X64
 #
 
 [Sources]
   ApicId.h
   CpuHotplug.c
+  PostSmmPen.nasm
   QemuCpuhp.c
   QemuCpuhp.h
+  Smbase.c
+  Smbase.h
 
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
+  BaseMemoryLib
   DebugLib
   MmServicesTableLib
   PcdLib
   SafeIntLib
   UefiDriverEntryPoint
 
 [Protocols]
   gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
   gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
 
 [Depex]
   gEfiMmCpuIoProtocolGuid AND
   gEfiSmmCpuServiceProtocolGuid
diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.h b/OvmfPkg/CpuHotplugSmm/Smbase.h
new file mode 100644
index 000000000000..cb5aed98cdd3
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/Smbase.h
@@ -0,0 +1,32 @@
+/** @file
+  SMBASE relocation for hot-plugged CPUs.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef SMBASE_H_
+#define SMBASE_H_
+
+#include <Uefi/UefiBaseType.h> // EFI_STATUS
+#include <Uefi/UefiSpec.h>     // EFI_BOOT_SERVICES
+
+EFI_STATUS
+SmbaseAllocatePostSmmPen (
+  OUT UINT32                  *PenAddress,
+  IN  CONST EFI_BOOT_SERVICES *BootServices
+  );
+
+VOID
+SmbaseReinstallPostSmmPen (
+  IN UINT32 PenAddress
+  );
+
+VOID
+SmbaseReleasePostSmmPen (
+  IN UINT32                  PenAddress,
+  IN CONST EFI_BOOT_SERVICES *BootServices
+  );
+
+#endif // SMBASE_H_
diff --git a/OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm b/OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm
new file mode 100644
index 000000000000..ef702689bdb5
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm
@@ -0,0 +1,151 @@
+;------------------------------------------------------------------------------
+; @file
+; Pen any hot-added CPU in a 16-bit, real mode HLT loop, after it leaves SMM by
+; executing the RSM instruction.
+;
+; Copyright (c) 2020, Red Hat, Inc.
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; The routine implemented here is stored into normal RAM, under 1MB, at the
+; beginning of a page that is allocated as EfiReservedMemoryType. On any
+; hot-added CPU, it is executed after *at least* the first RSM (i.e., after
+; SMBASE relocation).
+;
+; The first execution of this code occurs as follows:
+;
+; - The hot-added CPU is in RESET state.
+;
+; - The ACPI CPU hotplug event handler triggers a broadcast SMI, from the OS.
+;
+; - Existent CPUs (BSP and APs) enter SMM.
+;
+; - The hot-added CPU remains in RESET state, but an SMI is pending for it now.
+;   (See "SYSTEM MANAGEMENT INTERRUPT (SMI)" in the Intel SDM.)
+;
+; - In SMM, pre-existent CPUs that are not elected SMM Monarch, keep themselves
+;   busy with their wait loops.
+;
+; - From the root MMI handler, the SMM Monarch:
+;
+;   - places this routine in the reserved page,
+;
+;   - clears the "about to leave SMM" byte in SMRAM,
+;
+;   - clears the last byte of the reserved page,
+;
+;   - sends an INIT-SIPI-SIPI sequence to the hot-added CPU,
+;
+;   - un-gates the default SMI handler by APIC ID.
+;
+; - The startup vector in the SIPI that is sent by the SMM Monarch points to
+;   this code; i.e., to the reserved page. (Example: 0x9_F000.)
+;
+; - The SMM Monarch starts polling the "about to leave SMM" byte in SMRAM.
+;
+; - The hot-added CPU boots, and immediately enters SMM due to the pending SMI.
+;   It starts executing the default SMI handler.
+;
+; - Importantly, the SMRAM Save State Map captures the following information,
+;   when the hot-added CPU enters SMM:
+;
+;   - CS selector: assumes the 16 most significant bits of the 20-bit (i.e.,
+;     below 1MB) startup vector from the SIPI. (Example: 0x9F00.)
+;
+;   - CS attributes: Accessed, Readable, User (S=1), CodeSegment (bit#11),
+;     Present.
+;
+;   - CS limit: 0xFFFF.
+;
+;   - CS base: the CS selector value shifted left by 4 bits. That is, the CS
+;     base equals the SIPI startup vector. (Example: 0x9_F000.)
+;
+;   - IP: the least significant 4 bits from the SIPI startup vector. Because
+;     the routine is page-aligned, these bits are zero (hence IP is zero).
+;
+;   - ES, SS, DS, FS, GS selectors: 0.
+;
+;   - ES, SS, DS, FS, GS attributes: same as the CS attributes, minus
+;     CodeSegment (bit#11).
+;
+;   - ES, SS, DS, FS, GS limits: 0xFFFF.
+;
+;   - ES, SS, DS, FS, GS bases: 0.
+;
+; - The hot-added CPU sets its new SMBASE value in the SMRAM Save State Map.
+;
+; - The hot-added CPU sets the "about to leave SMM" byte in SMRAM, then
+;   executes the RSM instruction immediately after, leaving SMM.
+;
+; - The SMM Monarch notices that the "about to leave SMM" byte in SMRAM has
+;   been set, and starts polling the last byte in the reserved page.
+;
+; - The hot-added CPU jumps ("returns") to the code below (in the reserved
+;   page), according to the register state listed in the SMRAM Save State Map.
+;
+; - The hot-added CPU sets the last byte of the reserved page, then halts
+;   itself.
+;
+; - The SMM Monarch notices that the hot-added CPU is done with SMBASE
+;   relocation.
+;
+; Note that, if the OS is malicious and sends INIT-SIPI-SIPI to the hot-added
+; CPU before allowing the ACPI CPU hotplug event handler to trigger a broadcast
+; SMI, then said broadcast SMI will yank the hot-added CPU directly into SMM,
+; without becoming pending for it (as the hot-added CPU is no longer in RESET
+; state). This is OK, because:
+;
+; - The default SMI handler copes with this, as it is gated by APIC ID. The
+;   hot-added CPU won't start the actual SMBASE relocation until the SMM
+;   Monarch lets it.
+;
+; - The INIT-SIPI-SIPI sequence that the SMM Monarch sends to the hot-added CPU
+;   will be ignored in this sate (it won't even be latched). See "SMI HANDLER
+;   EXECUTION ENVIRONMENT" in the Intel SDM: "INIT operations are inhibited
+;   when the processor enters SMM".
+;
+; - When the hot-added CPU (e.g., CPU#1) executes the RSM (having relocated
+;   SMBASE), it returns to the OS. The OS can use CPU#1 to attack the last byte
+;   of the reserved page, while another CPU (e.g., CPU#2) is relocating SMBASE,
+;   in order to trick the SMM Monarch (e.g., CPU#0) to open the APIC ID gate
+;   for yet another CPU (e.g., CPU#3). However, the SMM Monarch won't look at
+;   the last byte of the reserved page, until CPU#2 sets the "about to leave
+;   SMM" byte in SMRAM. This leaves a very small window (just one instruction's
+;   worth before the RSM) for CPU#3 to "catch up" with CPU#2, and overwrite
+;   CPU#2's SMBASE with its own.
+;
+; In other words, we do not / need not prevent a malicious OS from booting the
+; hot-added CPU early; instead we provide benign OSes with a pen for hot-added
+; CPUs.
+;------------------------------------------------------------------------------
+
+SECTION .data
+BITS 16
+
+GLOBAL ASM_PFX (mPostSmmPen)     ; UINT8[]
+GLOBAL ASM_PFX (mPostSmmPenSize) ; UINT16
+
+ASM_PFX (mPostSmmPen):
+  ;
+  ; Point DS at the same reserved page.
+  ;
+  mov ax, cs
+  mov ds, ax
+
+  ;
+  ; Inform the SMM Monarch that we're done with SMBASE relocation, by setting
+  ; the last byte in the reserved page.
+  ;
+  mov byte [ds : word 0xFFF], 1
+
+  ;
+  ; Halt now, until we get woken by another SMI, or (more likely) the OS
+  ; reboots us with another INIT-SIPI-SIPI.
+  ;
+HltLoop:
+  cli
+  hlt
+  jmp HltLoop
+
+ASM_PFX (mPostSmmPenSize):
+  dw $ - ASM_PFX (mPostSmmPen)
diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.c b/OvmfPkg/CpuHotplugSmm/Smbase.c
new file mode 100644
index 000000000000..ea21153d9145
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/Smbase.c
@@ -0,0 +1,110 @@
+/** @file
+  SMBASE relocation for hot-plugged CPUs.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Base.h>                             // BASE_1MB
+#include <Library/BaseMemoryLib.h>            // CopyMem()
+#include <Library/DebugLib.h>                 // DEBUG()
+
+#include "Smbase.h"
+
+extern CONST UINT8 mPostSmmPen[];
+extern CONST UINT16 mPostSmmPenSize;
+
+/**
+  Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot-added
+  CPUs.
+
+  This function may only be called from the entry point function of the driver.
+
+  @param[out] PenAddress   The address of the allocated (normal RAM) reserved
+                           page.
+
+  @param[in] BootServices  Pointer to the UEFI boot services table. Used for
+                           allocating the normal RAM (not SMRAM) reserved page.
+
+  @retval EFI_SUCCESS          Allocation successful.
+
+  @retval EFI_BAD_BUFFER_SIZE  The Post-SMM Pen template is not smaller than
+                               EFI_PAGE_SIZE.
+
+  @return                      Error codes propagated from underlying services.
+                               DEBUG_ERROR messages have been logged. No
+                               resources have been allocated.
+**/
+EFI_STATUS
+SmbaseAllocatePostSmmPen (
+  OUT UINT32                  *PenAddress,
+  IN  CONST EFI_BOOT_SERVICES *BootServices
+  )
+{
+  EFI_STATUS           Status;
+  EFI_PHYSICAL_ADDRESS Address;
+
+  //
+  // The pen code must fit in one page, and the last byte must remain free for
+  // signaling the SMM Monarch.
+  //
+  if (mPostSmmPenSize >= EFI_PAGE_SIZE) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((DEBUG_ERROR, "%a: mPostSmmPenSize=%u: %r\n", __FUNCTION__,
+      mPostSmmPenSize, Status));
+    return Status;
+  }
+
+  Address = BASE_1MB - 1;
+  Status = BootServices->AllocatePages (AllocateMaxAddress,
+                           EfiReservedMemoryType, 1, &Address);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: AllocatePages(): %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: Post-SMM Pen at 0x%Lx\n", __FUNCTION__, Address));
+  *PenAddress = (UINT32)Address;
+  return EFI_SUCCESS;
+}
+
+/**
+  Copy the Post-SMM Pen template code into the reserved page allocated with
+  SmbaseAllocatePostSmmPen().
+
+  Note that this effects an "SMRAM to normal RAM" copy.
+
+  The SMM Monarch is supposed to call this function from the root MMI handler.
+
+  @param[in] PenAddress  The allocation address returned by
+                         SmbaseAllocatePostSmmPen().
+**/
+VOID
+SmbaseReinstallPostSmmPen (
+  IN UINT32 PenAddress
+  )
+{
+  CopyMem ((VOID *)(UINTN)PenAddress, mPostSmmPen, mPostSmmPenSize);
+}
+
+/**
+  Release the reserved page allocated with SmbaseAllocatePostSmmPen().
+
+  This function may only be called from the entry point function of the driver,
+  on the error path.
+
+  @param[in] PenAddress    The allocation address returned by
+                           SmbaseAllocatePostSmmPen().
+
+  @param[in] BootServices  Pointer to the UEFI boot services table. Used for
+                           releasing the normal RAM (not SMRAM) reserved page.
+**/
+VOID
+SmbaseReleasePostSmmPen (
+  IN UINT32                  PenAddress,
+  IN CONST EFI_BOOT_SERVICES *BootServices
+  )
+{
+  BootServices->FreePages (PenAddress, 1);
+}
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler for hot-added CPUs
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (10 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 11/16] OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 14:03   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 13/16] OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug Laszlo Ersek
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Implement the First SMI Handler for hot-added CPUs, in NASM.

Add the interfacing C-language function that the SMM Monarch calls. This
function launches and coordinates SMBASE relocation for a hot-added CPU.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---

Notes:
    v2:
    
    - implement the combined approach described here:
    
      http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
      https://edk2.groups.io/g/devel/message/54754
    
      by introducing "FIRST_SMI_HANDLER_CONTEXT.AboutToLeaveSmm".

 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf        |   4 +
 OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h |  47 ++++++
 OvmfPkg/CpuHotplugSmm/Smbase.h                 |  14 ++
 OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm     | 154 +++++++++++++++++++
 OvmfPkg/CpuHotplugSmm/Smbase.c                 | 157 ++++++++++++++++++++
 5 files changed, 376 insertions(+)

diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
index bf4162299c7c..04322b0d7855 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
@@ -5,56 +5,60 @@
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
 
 [Defines]
   INF_VERSION                = 1.29
   PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
   BASE_NAME                  = CpuHotplugSmm
   FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
   MODULE_TYPE                = DXE_SMM_DRIVER
   ENTRY_POINT                = CpuHotplugEntry
 
 #
 # The following information is for reference only and not required by the build
 # tools.
 #
 # VALID_ARCHITECTURES        = IA32 X64
 #
 
 [Sources]
   ApicId.h
   CpuHotplug.c
+  FirstSmiHandler.nasm
+  FirstSmiHandlerContext.h
   PostSmmPen.nasm
   QemuCpuhp.c
   QemuCpuhp.h
   Smbase.c
   Smbase.h
 
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
   BaseMemoryLib
   DebugLib
+  LocalApicLib
   MmServicesTableLib
   PcdLib
   SafeIntLib
+  SynchronizationLib
   UefiDriverEntryPoint
 
 [Protocols]
   gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
   gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
 
 [Depex]
   gEfiMmCpuIoProtocolGuid AND
   gEfiSmmCpuServiceProtocolGuid
diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h b/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h
new file mode 100644
index 000000000000..029de4cdea35
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h
@@ -0,0 +1,47 @@
+/** @file
+  Define the FIRST_SMI_HANDLER_CONTEXT structure, which is an exchange area
+  between the SMM Monarch and the hot-added CPU, for relocating the SMBASE of
+  the hot-added CPU.
+
+  Copyright (c) 2020, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef FIRST_SMI_HANDLER_CONTEXT_H_
+#define FIRST_SMI_HANDLER_CONTEXT_H_
+
+//
+// The following structure is used to communicate between the SMM Monarch
+// (running the root MMI handler) and the hot-added CPU (handling its first
+// SMI). It is placed at SMM_DEFAULT_SMBASE, which is in SMRAM under QEMU's
+// "SMRAM at default SMBASE" feature.
+//
+#pragma pack (1)
+typedef struct {
+  //
+  // When ApicIdGate is MAX_UINT64, then no hot-added CPU may proceed with
+  // SMBASE relocation.
+  //
+  // Otherwise, the hot-added CPU whose APIC ID equals ApicIdGate may proceed
+  // with SMBASE relocation.
+  //
+  // This field is intentionally wider than APIC_ID (UINT32) because we need a
+  // "gate locked" value that is different from all possible APIC_IDs.
+  //
+  UINT64 ApicIdGate;
+  //
+  // The new SMBASE value for the hot-added CPU to set in the SMRAM Save State
+  // Map, before leaving SMM with the RSM instruction.
+  //
+  UINT32 NewSmbase;
+  //
+  // The hot-added CPU sets this field to 1 right before executing the RSM
+  // instruction. This tells the SMM Monarch to proceed to polling the last
+  // byte of the normal RAM reserved page (Post-SMM Pen).
+  //
+  UINT8 AboutToLeaveSmm;
+} FIRST_SMI_HANDLER_CONTEXT;
+#pragma pack ()
+
+#endif // FIRST_SMI_HANDLER_CONTEXT_H_
diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.h b/OvmfPkg/CpuHotplugSmm/Smbase.h
index cb5aed98cdd3..e73730d19926 100644
--- a/OvmfPkg/CpuHotplugSmm/Smbase.h
+++ b/OvmfPkg/CpuHotplugSmm/Smbase.h
@@ -1,32 +1,46 @@
 /** @file
   SMBASE relocation for hot-plugged CPUs.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #ifndef SMBASE_H_
 #define SMBASE_H_
 
 #include <Uefi/UefiBaseType.h> // EFI_STATUS
 #include <Uefi/UefiSpec.h>     // EFI_BOOT_SERVICES
 
+#include "ApicId.h"            // APIC_ID
+
 EFI_STATUS
 SmbaseAllocatePostSmmPen (
   OUT UINT32                  *PenAddress,
   IN  CONST EFI_BOOT_SERVICES *BootServices
   );
 
 VOID
 SmbaseReinstallPostSmmPen (
   IN UINT32 PenAddress
   );
 
 VOID
 SmbaseReleasePostSmmPen (
   IN UINT32                  PenAddress,
   IN CONST EFI_BOOT_SERVICES *BootServices
   );
 
+VOID
+SmbaseInstallFirstSmiHandler (
+  VOID
+  );
+
+EFI_STATUS
+SmbaseRelocate (
+  IN APIC_ID ApicId,
+  IN UINTN   Smbase,
+  IN UINT32  PenAddress
+  );
+
 #endif // SMBASE_H_
diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm b/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm
new file mode 100644
index 000000000000..5399b5fa4387
--- /dev/null
+++ b/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm
@@ -0,0 +1,154 @@
+;------------------------------------------------------------------------------
+; @file
+; Relocate the SMBASE on a hot-added CPU when it services its first SMI.
+;
+; Copyright (c) 2020, Red Hat, Inc.
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; The routine runs on the hot-added CPU in the following "big real mode",
+; 16-bit environment; per "SMI HANDLER EXECUTION ENVIRONMENT" in the Intel SDM
+; (table "Processor Register Initialization in SMM"):
+;
+;  - CS selector: 0x3000 (most significant 16 bits of SMM_DEFAULT_SMBASE).
+;
+;  - CS limit: 0xFFFF_FFFF.
+;
+;  - CS base: SMM_DEFAULT_SMBASE (0x3_0000).
+;
+;  - IP: SMM_HANDLER_OFFSET (0x8000).
+;
+;  - ES, SS, DS, FS, GS selectors: 0.
+;
+;  - ES, SS, DS, FS, GS limits: 0xFFFF_FFFF.
+;
+;  - ES, SS, DS, FS, GS bases: 0.
+;
+;  - Operand-size and address-size override prefixes can be used to access the
+;    address space beyond 1MB.
+;------------------------------------------------------------------------------
+
+SECTION .data
+BITS 16
+
+;
+; Bring in SMM_DEFAULT_SMBASE from
+; "MdePkg/Include/Register/Intel/SmramSaveStateMap.h".
+;
+SMM_DEFAULT_SMBASE: equ 0x3_0000
+
+;
+; Field offsets in FIRST_SMI_HANDLER_CONTEXT, which resides at
+; SMM_DEFAULT_SMBASE.
+;
+ApicIdGate:      equ  0 ; UINT64
+NewSmbase:       equ  8 ; UINT32
+AboutToLeaveSmm: equ 12 ; UINT8
+
+;
+; SMRAM Save State Map field offsets, per the AMD (not Intel) layout that QEMU
+; implements. Relative to SMM_DEFAULT_SMBASE.
+;
+SaveStateRevId:    equ 0xFEFC ; UINT32
+SaveStateSmbase:   equ 0xFEF8 ; UINT32
+SaveStateSmbase64: equ 0xFF00 ; UINT32
+
+;
+; CPUID constants, from "MdePkg/Include/Register/Intel/Cpuid.h".
+;
+CPUID_SIGNATURE:         equ 0x00
+CPUID_EXTENDED_TOPOLOGY: equ 0x0B
+CPUID_VERSION_INFO:      equ 0x01
+
+GLOBAL ASM_PFX (mFirstSmiHandler)     ; UINT8[]
+GLOBAL ASM_PFX (mFirstSmiHandlerSize) ; UINT16
+
+ASM_PFX (mFirstSmiHandler):
+  ;
+  ; Get our own APIC ID first, so we can contend for ApicIdGate.
+  ;
+  ; This basically reimplements GetInitialApicId() from
+  ; "UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c".
+  ;
+  mov eax, CPUID_SIGNATURE
+  cpuid
+  cmp eax, CPUID_EXTENDED_TOPOLOGY
+  jb GetApicIdFromVersionInfo
+
+  mov eax, CPUID_EXTENDED_TOPOLOGY
+  mov ecx, 0
+  cpuid
+  test ebx, 0xFFFF
+  jz GetApicIdFromVersionInfo
+
+  ;
+  ; EDX has the APIC ID, save it to ESI.
+  ;
+  mov esi, edx
+  jmp KnockOnGate
+
+GetApicIdFromVersionInfo:
+  mov eax, CPUID_VERSION_INFO
+  cpuid
+  shr ebx, 24
+  ;
+  ; EBX has the APIC ID, save it to ESI.
+  ;
+  mov esi, ebx
+
+KnockOnGate:
+  ;
+  ; See if ApicIdGate shows our own APIC ID. If so, swap it to MAX_UINT64
+  ; (close the gate), and advance. Otherwise, keep knocking.
+  ;
+  ; InterlockedCompareExchange64():
+  ; - Value                   := &FIRST_SMI_HANDLER_CONTEXT.ApicIdGate
+  ; - CompareValue  (EDX:EAX) := APIC ID (from ESI)
+  ; - ExchangeValue (ECX:EBX) := MAX_UINT64
+  ;
+  mov edx, 0
+  mov eax, esi
+  mov ecx, 0xFFFF_FFFF
+  mov ebx, 0xFFFF_FFFF
+  lock cmpxchg8b [ds : dword (SMM_DEFAULT_SMBASE + ApicIdGate)]
+  jz ApicIdMatch
+  pause
+  jmp KnockOnGate
+
+ApicIdMatch:
+  ;
+  ; Update the SMBASE field in the SMRAM Save State Map.
+  ;
+  ; First, calculate the address of the SMBASE field, based on the SMM Revision
+  ; ID; store the result in EBX.
+  ;
+  mov eax, dword [ds : dword (SMM_DEFAULT_SMBASE + SaveStateRevId)]
+  test eax, 0xFFFF
+  jz LegacySaveStateMap
+
+  mov ebx, SMM_DEFAULT_SMBASE + SaveStateSmbase64
+  jmp UpdateSmbase
+
+LegacySaveStateMap:
+  mov ebx, SMM_DEFAULT_SMBASE + SaveStateSmbase
+
+UpdateSmbase:
+  ;
+  ; Load the new SMBASE value into EAX.
+  ;
+  mov eax, dword [ds : dword (SMM_DEFAULT_SMBASE + NewSmbase)]
+  ;
+  ; Save it to the SMBASE field whose address we calculated in EBX.
+  ;
+  mov dword [ds : dword ebx], eax
+  ;
+  ; Set AboutToLeaveSmm.
+  ;
+  mov byte [ds : dword (SMM_DEFAULT_SMBASE + AboutToLeaveSmm)], 1
+  ;
+  ; We're done; leave SMM and continue to the pen.
+  ;
+  rsm
+
+ASM_PFX (mFirstSmiHandlerSize):
+  dw $ - ASM_PFX (mFirstSmiHandler)
diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.c b/OvmfPkg/CpuHotplugSmm/Smbase.c
index ea21153d9145..170571221d84 100644
--- a/OvmfPkg/CpuHotplugSmm/Smbase.c
+++ b/OvmfPkg/CpuHotplugSmm/Smbase.c
@@ -1,38 +1,46 @@
 /** @file
   SMBASE relocation for hot-plugged CPUs.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include <Base.h>                             // BASE_1MB
+#include <Library/BaseLib.h>                  // CpuPause()
 #include <Library/BaseMemoryLib.h>            // CopyMem()
 #include <Library/DebugLib.h>                 // DEBUG()
+#include <Library/LocalApicLib.h>             // SendInitSipiSipi()
+#include <Library/SynchronizationLib.h>       // InterlockedCompareExchange64()
+#include <Register/Intel/SmramSaveStateMap.h> // SMM_DEFAULT_SMBASE
+
+#include "FirstSmiHandlerContext.h"           // FIRST_SMI_HANDLER_CONTEXT
 
 #include "Smbase.h"
 
 extern CONST UINT8 mPostSmmPen[];
 extern CONST UINT16 mPostSmmPenSize;
+extern CONST UINT8 mFirstSmiHandler[];
+extern CONST UINT16 mFirstSmiHandlerSize;
 
 /**
   Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot-added
   CPUs.
 
   This function may only be called from the entry point function of the driver.
 
   @param[out] PenAddress   The address of the allocated (normal RAM) reserved
                            page.
 
   @param[in] BootServices  Pointer to the UEFI boot services table. Used for
                            allocating the normal RAM (not SMRAM) reserved page.
 
   @retval EFI_SUCCESS          Allocation successful.
 
   @retval EFI_BAD_BUFFER_SIZE  The Post-SMM Pen template is not smaller than
                                EFI_PAGE_SIZE.
 
   @return                      Error codes propagated from underlying services.
                                DEBUG_ERROR messages have been logged. No
                                resources have been allocated.
 **/
@@ -89,22 +97,171 @@ SmbaseReinstallPostSmmPen (
 }
 
 /**
   Release the reserved page allocated with SmbaseAllocatePostSmmPen().
 
   This function may only be called from the entry point function of the driver,
   on the error path.
 
   @param[in] PenAddress    The allocation address returned by
                            SmbaseAllocatePostSmmPen().
 
   @param[in] BootServices  Pointer to the UEFI boot services table. Used for
                            releasing the normal RAM (not SMRAM) reserved page.
 **/
 VOID
 SmbaseReleasePostSmmPen (
   IN UINT32                  PenAddress,
   IN CONST EFI_BOOT_SERVICES *BootServices
   )
 {
   BootServices->FreePages (PenAddress, 1);
 }
+
+/**
+  Place the handler routine for the first SMIs of hot-added CPUs at
+  (SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET).
+
+  Note that this effects an "SMRAM to SMRAM" copy.
+
+  Additionally, shut the APIC ID gate in FIRST_SMI_HANDLER_CONTEXT.
+
+  This function may only be called from the entry point function of the driver,
+  and only after PcdQ35SmramAtDefaultSmbase has been determined to be TRUE.
+**/
+VOID
+SmbaseInstallFirstSmiHandler (
+  VOID
+  )
+{
+  FIRST_SMI_HANDLER_CONTEXT *Context;
+
+  CopyMem ((VOID *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET),
+    mFirstSmiHandler, mFirstSmiHandlerSize);
+
+  Context = (VOID *)(UINTN)SMM_DEFAULT_SMBASE;
+  Context->ApicIdGate = MAX_UINT64;
+}
+
+/**
+  Relocate the SMBASE on a hot-added CPU. Then pen the hot-added CPU in the
+  normal RAM reserved memory page, set up earlier with
+  SmbaseAllocatePostSmmPen() and SmbaseReinstallPostSmmPen().
+
+  The SMM Monarch is supposed to call this function from the root MMI handler.
+
+  The SMM Monarch is responsible for calling SmbaseInstallFirstSmiHandler(),
+  SmbaseAllocatePostSmmPen(), and SmbaseReinstallPostSmmPen() before calling
+  this function.
+
+  If the OS maliciously boots the hot-added CPU ahead of letting the ACPI CPU
+  hotplug event handler broadcast the CPU hotplug MMI, then the hot-added CPU
+  returns to the OS rather than to the pen, upon RSM. In that case, this
+  function will hang forever (unless the OS happens to signal back through the
+  last byte of the pen page).
+
+  @param[in] ApicId      The APIC ID of the hot-added CPU whose SMBASE should
+                         be relocated.
+
+  @param[in] Smbase      The new SMBASE address. The root MMI handler is
+                         responsible for passing in a free ("unoccupied")
+                         SMBASE address that was pre-configured by
+                         PiSmmCpuDxeSmm in CPU_HOT_PLUG_DATA.
+
+  @param[in] PenAddress  The address of the Post-SMM Pen for hot-added CPUs, as
+                         returned by SmbaseAllocatePostSmmPen(), and installed
+                         by SmbaseReinstallPostSmmPen().
+
+  @retval EFI_SUCCESS            The SMBASE of the hot-added CPU with APIC ID
+                                 ApicId has been relocated to Smbase. The
+                                 hot-added CPU has reported back about leaving
+                                 SMM.
+
+  @retval EFI_PROTOCOL_ERROR     Synchronization bug encountered around
+                                 FIRST_SMI_HANDLER_CONTEXT.ApicIdGate.
+
+  @retval EFI_INVALID_PARAMETER  Smbase does not fit in 32 bits. No relocation
+                                 has been attempted.
+**/
+EFI_STATUS
+SmbaseRelocate (
+  IN APIC_ID ApicId,
+  IN UINTN   Smbase,
+  IN UINT32  PenAddress
+  )
+{
+  EFI_STATUS                         Status;
+  volatile UINT8                     *SmmVacated;
+  volatile FIRST_SMI_HANDLER_CONTEXT *Context;
+  UINT64                             ExchangeResult;
+
+  if (Smbase > MAX_UINT32) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((DEBUG_ERROR, "%a: ApicId=" FMT_APIC_ID " Smbase=0x%Lx: %r\n",
+      __FUNCTION__, ApicId, (UINT64)Smbase, Status));
+    return Status;
+  }
+
+  SmmVacated = (UINT8 *)(UINTN)PenAddress + (EFI_PAGE_SIZE - 1);
+  Context = (VOID *)(UINTN)SMM_DEFAULT_SMBASE;
+
+  //
+  // Clear AboutToLeaveSmm, so we notice when the hot-added CPU is just about
+  // to reach RSM, and we can proceed to polling the last byte of the reserved
+  // page (which could be attacked by the OS).
+  //
+  Context->AboutToLeaveSmm = 0;
+
+  //
+  // Clear the last byte of the reserved page, so we notice when the hot-added
+  // CPU checks back in from the pen.
+  //
+  *SmmVacated = 0;
+
+  //
+  // Boot the hot-added CPU.
+  //
+  // If the OS is benign, and so the hot-added CPU is still in RESET state,
+  // then the broadcast SMI is still pending for it; it will now launch
+  // directly into SMM.
+  //
+  // If the OS is malicious, the hot-added CPU has been booted already, and so
+  // it is already spinning on the APIC ID gate. In that case, the
+  // INIT-SIPI-SIPI below will be ignored.
+  //
+  SendInitSipiSipi (ApicId, PenAddress);
+
+  //
+  // Expose the desired new SMBASE value to the hot-added CPU.
+  //
+  Context->NewSmbase = (UINT32)Smbase;
+
+  //
+  // Un-gate SMBASE relocation for the hot-added CPU whose APIC ID is ApicId.
+  //
+  ExchangeResult = InterlockedCompareExchange64 (&Context->ApicIdGate,
+                     MAX_UINT64, ApicId);
+  if (ExchangeResult != MAX_UINT64) {
+    Status = EFI_PROTOCOL_ERROR;
+    DEBUG ((DEBUG_ERROR, "%a: ApicId=" FMT_APIC_ID " ApicIdGate=0x%Lx: %r\n",
+      __FUNCTION__, ApicId, ExchangeResult, Status));
+    return Status;
+  }
+
+  //
+  // Wait until the hot-added CPU is just about to execute RSM.
+  //
+  while (Context->AboutToLeaveSmm == 0) {
+    CpuPause ();
+  }
+
+  //
+  // Now wait until the hot-added CPU reports back from the pen (or the OS
+  // attacks the last byte of the reserved page).
+  //
+  while (*SmmVacated == 0) {
+    CpuPause ();
+  }
+
+  Status = EFI_SUCCESS;
+  return Status;
+}
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 13/16] OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (11 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler " Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 14:05   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg Laszlo Ersek
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

With the help of the Post-SMM Pen and the SMBASE relocation functions
added in the previous patches, we can now complete the root MMI handler
for CPU hotplug.

In the driver's entry point function:

- allocate the pen (in a reserved page in normal RAM),

- install the default ("first") SMI handler for hot-added CPUs (which
  includes priming the exchange area between the MM Monarch and the
  hot-added CPUs, i.e., shutting the APIC ID gate).

In the root MMI handler, for each hot-added CPU:

- record the APIC ID of the new CPU in CPU_HOT_PLUG_DATA,

- relocate the SMBASE of the new CPU,

- inform PiSmmCpuDxeSmm by calling
  EFI_SMM_CPU_SERVICE_PROTOCOL.AddProcessor().

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)
    
    - repeat all the v1 tests
    
    v1:
    
    (1) At this stage, CPU hotplug with SMM works.
    
    Test CPU topology (libvirt domain XML snippet):
    
    >   <vcpus>
    >     <vcpu id='0' enabled='yes' hotpluggable='no'/>
    >     <vcpu id='1' enabled='no' hotpluggable='yes'/>
    >     <vcpu id='2' enabled='yes' hotpluggable='yes'/>
    >     <vcpu id='3' enabled='no' hotpluggable='yes'/>
    >   </vcpus>
    
    The firmware logs the following during normal boot:
    
    > SmbaseAllocatePostSmmPen: Post-SMM Pen at 0x9F000
    
    CPU hotplug command on the host side:
    
    > virsh setvcpu ovmf.fedora.q35 1 --enable --live
    
    Firmware log in response:
    
    > QemuCpuhpCollectApicIds: CurrentSelector=1: insert
    > QemuCpuhpCollectApicIds: ApicId=0x00000001
    > QemuCpuhpCollectApicIds: CurrentSelector=2 PendingSelector=1:
    >                          wrap-around
    > QemuCpuhpCollectApicIds: PluggedCount=1 ToUnplugCount=0
    > CpuHotplugMmi: hot-added APIC ID 0x00000001, SMBASE 0x7D082000,
    >                EFI_SMM_CPU_SERVICE_PROTOCOL assigned number 2
    
    Query the CPU register state on the host side (without onlining the
    hot-added CPU in the OS just yet):
    
    > virsh qemu-monitor-command ovmf.fedora.q35 --hmp 'info registers -a'
    
    Output, confirming penned status (pen at 0x9F000):
    
    > CPU#1
    > EAX=00009f00 EBX=00000000 ECX=00000000 EDX=00000600
    > ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
    > EIP=0000000c EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=1
    > ES =0000 00000000 0000ffff 00009300
    > CS =9f00 0009f000 0000ffff 00009b00
    > SS =0000 00000000 0000ffff 00009300
    > DS =9f00 0009f000 0000ffff 00009300
    > FS =0000 00000000 0000ffff 00009300
    > GS =0000 00000000 0000ffff 00009300
    > LDT=0000 00000000 0000ffff 00008200
    > TR =0000 00000000 0000ffff 00008b00
    > GDT=     00000000 0000ffff
    > IDT=     00000000 0000ffff
    > CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
    > DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000
    > DR3=0000000000000000
    > DR6=00000000ffff0ff0 DR7=0000000000000400
    > EFER=0000000000000000
    > FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
    > FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
    > FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
    > FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
    > FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
    > XMM00=00000000000000000000000000000000
    > XMM01=00000000000000000000000000000000
    > XMM02=00000000000000000000000000000000
    > XMM03=00000000000000000000000000000000
    > XMM04=00000000000000000000000000000000
    > XMM05=00000000000000000000000000000000
    > XMM06=00000000000000000000000000000000
    > XMM07=00000000000000000000000000000000
    
    Additionally, the dmesg in the Linux guest contains:
    
    > CPU2 has been hot-added
    
    We can now boot the hot-addad CPU in the Linux guest:
    
    > echo 1 > /sys/devices/system/cpu/cpu2/online
    
    Dmesg in response:
    
    > smpboot: Booting Node 0 Processor 2 APIC 0x1
    > kvm-clock: cpu 2, msr 6e01081, secondary cpu clock
    > KVM setup async PF for cpu 2
    > kvm-stealtime: cpu 2, msr 7b52a040
    > Will online and init hotplugged CPU: 2
    
    Still in the guest, call UEFI variable services on each CPU (including
    the hot-added one), per
    <https://github.com/tianocore/tianocore.github.io/wiki/Testing-SMM-with-QEMU,-KVM-and-libvirt#uefi-variable-access-test>:
    
    > taskset -c 0 efibootmgr
    > taskset -c 1 efibootmgr
    > taskset -c 2 efibootmgr
    
    No delays, no instability.
    
    Having booted the hot-added CPU in the Linux guest, the host-side
    command
    
    > virsh qemu-monitor-command ovmf.fedora.q35 --hmp 'info registers -a'
    
    now shows:
    
    > CPU#1
    > RAX=ffffffffb39e4b50 RBX=0000000000000002 RCX=0000000000000000
    > RDX=0000000000000002
    > RSI=0000000000000002 RDI=ffff932cbb51c520 RBP=0000000000000002
    > RSP=ffffbc5bc0083eb0
    > R8 =000000cd42e4dffb R9 =0000005a22502599 R10=0000005a22502599
    > R11=0000005a22502599
    > R12=ffff932cbae25dc0 R13=0000000000000000 R14=0000000000000000
    > R15=ffff932cbae25dc0
    > RIP=ffffffffb39e4f2e RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0
    > HLT=1
    > ES =0000 0000000000000000 ffffffff 00c00000
    > CS =0010 0000000000000000 ffffffff 00a09b00 DPL=0 CS64 [-RA]
    > SS =0018 0000000000000000 ffffffff 00c09300 DPL=0 DS   [-WA]
    > DS =0000 0000000000000000 ffffffff 00c00000
    > FS =0000 0000000000000000 ffffffff 00c00000
    > GS =0000 ffff932cbb500000 ffffffff 00c00000
    > LDT=0000 0000000000000000 000fffff 00000000
    > TR =0040 fffffe0000069000 0000206f 00008b00 DPL=0 TSS64-busy
    > GDT=     fffffe0000067000 0000007f
    > IDT=     fffffe0000000000 00000fff
    > CR0=80050033 CR2=00007f54893cbf20 CR3=0000000078418001 CR4=001606e0
    > DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000
    > DR3=0000000000000000
    > DR6=00000000ffff0ff0 DR7=0000000000000400
    > EFER=0000000000000d01
    > FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001fa0
    > FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
    > FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
    > FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
    > FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
    > XMM00=000000000000000040ed2be000000000
    > XMM01=0000000000000000404ddf1a9fbe76c9
    > XMM02=00000000000000000000000000000000
    > XMM03=00000000000000000000000000000000
    > XMM04=00000000000000003ff0000000000000
    > XMM05=00000000000000000000000000000000
    > XMM06=00000000000000004078002d0ac487b7
    > XMM07=0000000000000000404ddf1a9fbe76c9
    > XMM08=72223d444955412022746f6f72223d44
    > XMM09=00000000000000000000000000000000
    > XMM10=00000000000000000000000000000000
    > XMM11=00000000000000000000000000000000
    > XMM12=00000000000000000000000000000000
    > XMM13=00000000000000000000000000000000
    > XMM14=00000000000000000000000000000000
    > XMM15=00000000000000000000000000000000
    
    Hotplug another CPU:
    
    > virsh setvcpu ovmf.fedora.q35 3 --enable --live
    
    Firmware log in response:
    
    > QemuCpuhpCollectApicIds: CurrentSelector=3: insert
    > QemuCpuhpCollectApicIds: ApicId=0x00000003
    > QemuCpuhpCollectApicIds: PluggedCount=1 ToUnplugCount=0
    > CpuHotplugMmi: hot-added APIC ID 0x00000003, SMBASE 0x7D084000,
    >                EFI_SMM_CPU_SERVICE_PROTOCOL assigned number 3
    
    Online the hot-added CPU in the Linux guest:
    
    > echo 1 > /sys/devices/system/cpu/cpu3/online
    
    Guest dmesg in response:
    
    > smpboot: Booting Node 0 Processor 3 APIC 0x3
    > kvm-clock: cpu 3, msr 6e010c1, secondary cpu clock
    > KVM setup async PF for cpu 3
    > kvm-stealtime: cpu 3, msr 7b5aa040
    > Will online and init hotplugged CPU: 3
    
    (2) Alternative order of actions:
    
    Hotplug both CPUs first, on the host:
    
    > virsh setvcpu ovmf.fedora.q35 1 --enable --live
    > virsh setvcpu ovmf.fedora.q35 3 --enable --live
    
    *then* online both hot-added CPUs in the Linux guest:
    
    > echo 1 > /sys/devices/system/cpu/cpu2/online
    > echo 1 > /sys/devices/system/cpu/cpu3/online
    
    The only difference here is that the broadcast SMI for the second
    hotplug finds the first hotplugged CPU still in the pen (i.e., not
    onlined by Linux). There is no difference in observable behavior (beyond
    the matching log messages and register dumps).
    
    (3) What doesn't work yet:
    
    - CPU hotplug w/ SMM in SEV guests.
    
      See <https://bugzilla.tianocore.org/show_bug.cgi?id=1512#c14>.
    
      (NB. I'm uncertain if CPU hotplug works in SEV guests without
      SMM_REQUIRE to begin with.)
    
    - S3 resume w/ SMM after hot-adding a CPU.
    
      The remaining patches in the series take care of that. (Only in the
      absence of SEV; SEV+S3 looks broken regardless of hotplug.)
    
    - CPU hot-unplug w/ SMM.
    
      Needs separate investigation. EFI_SMM_REMOVE_PROCESSOR in
      "UefiCpuPkg/Include/Protocol/SmmCpuService.h" is documented as
      follows: "After this API is called, the removed processor must not
      respond to SMIs in the coherence domain". This could raise challenging
      ordering questions between QEMU, the firmware, and the OS.

 OvmfPkg/CpuHotplugSmm/CpuHotplug.c | 97 +++++++++++++++++++-
 1 file changed, 95 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
index 42e023cb85c0..20e6bec04f41 100644
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
@@ -1,76 +1,82 @@
 /** @file
   Root SMI handler for VCPU hotplug SMIs.
 
   Copyright (c) 2020, Red Hat, Inc.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include <CpuHotPlugData.h>                  // CPU_HOT_PLUG_DATA
 #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
 #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
 #include <Library/BaseLib.h>                 // CpuDeadLoop()
 #include <Library/DebugLib.h>                // ASSERT()
 #include <Library/MmServicesTableLib.h>      // gMmst
 #include <Library/PcdLib.h>                  // PcdGetBool()
 #include <Library/SafeIntLib.h>              // SafeUintnSub()
 #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
 #include <Protocol/SmmCpuService.h>          // EFI_SMM_CPU_SERVICE_PROTOCOL
 #include <Uefi/UefiBaseType.h>               // EFI_STATUS
 
 #include "ApicId.h"                          // APIC_ID
 #include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
+#include "Smbase.h"                          // SmbaseAllocatePostSmmPen()
 
 //
 // We use this protocol for accessing IO Ports.
 //
 STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
 //
 // The following protocol is used to report the addition or removal of a CPU to
 // the SMM CPU driver (PiSmmCpuDxeSmm).
 //
 STATIC EFI_SMM_CPU_SERVICE_PROTOCOL *mMmCpuService;
 //
 // This structure is a communication side-channel between the
 // EFI_SMM_CPU_SERVICE_PROTOCOL consumer (i.e., this driver) and provider
 // (i.e., PiSmmCpuDxeSmm).
 //
 STATIC CPU_HOT_PLUG_DATA *mCpuHotPlugData;
 //
 // SMRAM arrays for fetching the APIC IDs of processors with pending events (of
 // known event types), for the time of just one MMI.
 //
 // The lifetimes of these arrays match that of this driver only because we
 // don't want to allocate SMRAM at OS runtime, and potentially fail (or
 // fragment the SMRAM map).
 //
 // These arrays provide room for ("possible CPU count" minus one) APIC IDs
 // each, as we don't expect every possible CPU to appear, or disappear, in a
 // single MMI. The numbers of used (populated) elements in the arrays are
 // determined on every MMI separately.
 //
 STATIC APIC_ID *mPluggedApicIds;
 STATIC APIC_ID *mToUnplugApicIds;
 //
+// Address of the non-SMRAM reserved memory page that contains the Post-SMM Pen
+// for hot-added CPUs.
+//
+STATIC UINT32 mPostSmmPenAddress;
+//
 // Represents the registration of the CPU Hotplug MMI handler.
 //
 STATIC EFI_HANDLE mDispatchHandle;
 
 
 /**
   CPU Hotplug MMI handler function.
 
   This is a root MMI handler.
 
   @param[in] DispatchHandle      The unique handle assigned to this handler by
                                  EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
 
   @param[in] Context             Context passed in by
                                  EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
                                  CpuHotplugMmi() being a root MMI handler,
                                  Context is ASSERT()ed to be NULL.
 
   @param[in,out] CommBuffer      Ignored, due to CpuHotplugMmi() being a root
                                  MMI handler.
 
   @param[in,out] CommBufferSize  Ignored, due to CpuHotplugMmi() being a root
@@ -97,44 +103,46 @@ STATIC EFI_HANDLE mDispatchHandle;
 
   @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The MMI source is still pending,
                                               and other handlers should still
                                               be called.
 
   @retval EFI_INTERRUPT_PENDING               The MMI source could not be
                                               quiesced.
 **/
 STATIC
 EFI_STATUS
 EFIAPI
 CpuHotplugMmi (
   IN EFI_HANDLE DispatchHandle,
   IN CONST VOID *Context        OPTIONAL,
   IN OUT VOID   *CommBuffer     OPTIONAL,
   IN OUT UINTN  *CommBufferSize OPTIONAL
   )
 {
   EFI_STATUS Status;
   UINT8      ApmControl;
   UINT32     PluggedCount;
   UINT32     ToUnplugCount;
+  UINT32     PluggedIdx;
+  UINT32     NewSlot;
 
   //
   // Assert that we are entering this function due to our root MMI handler
   // registration.
   //
   ASSERT (DispatchHandle == mDispatchHandle);
   //
   // When MmiManage() is invoked to process root MMI handlers, the caller (the
   // MM Core) is expected to pass in a NULL Context. MmiManage() then passes
   // the same NULL Context to individual handlers.
   //
   ASSERT (Context == NULL);
   //
   // Read the MMI command value from the APM Control Port, to see if this is an
   // MMI we should care about.
   //
   Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,
                           &ApmControl);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,
       Status));
     //
@@ -152,49 +160,116 @@ CpuHotplugMmi (
 
   //
   // Collect the CPUs with pending events.
   //
   Status = QemuCpuhpCollectApicIds (
              mMmCpuIo,
              mCpuHotPlugData->ArrayLength,     // PossibleCpuCount
              mCpuHotPlugData->ArrayLength - 1, // ApicIdCount
              mPluggedApicIds,
              &PluggedCount,
              mToUnplugApicIds,
              &ToUnplugCount
              );
   if (EFI_ERROR (Status)) {
     goto Fatal;
   }
   if (ToUnplugCount > 0) {
     DEBUG ((DEBUG_ERROR, "%a: hot-unplug is not supported yet\n",
       __FUNCTION__));
     goto Fatal;
   }
 
+  //
+  // Process hot-added CPUs.
+  //
+  // The Post-SMM Pen need not be reinstalled multiple times within a single
+  // root MMI handling. Even reinstalling once per root MMI is only prudence;
+  // in theory installing the pen in the driver's entry point function should
+  // suffice.
+  //
+  SmbaseReinstallPostSmmPen (mPostSmmPenAddress);
+
+  PluggedIdx = 0;
+  NewSlot = 0;
+  while (PluggedIdx < PluggedCount) {
+    APIC_ID NewApicId;
+    UINTN   NewProcessorNumberByProtocol;
+
+    NewApicId = mPluggedApicIds[PluggedIdx];
+    //
+    // Find the first empty slot in CPU_HOT_PLUG_DATA.
+    //
+    while (NewSlot < mCpuHotPlugData->ArrayLength &&
+           mCpuHotPlugData->ApicId[NewSlot] != MAX_UINT64) {
+      NewSlot++;
+    }
+    if (NewSlot == mCpuHotPlugData->ArrayLength) {
+      DEBUG ((DEBUG_ERROR, "%a: no room for APIC ID " FMT_APIC_ID "\n",
+        __FUNCTION__, NewApicId));
+      goto Fatal;
+    }
+
+    //
+    // Store the APIC ID of the new processor to the slot.
+    //
+    mCpuHotPlugData->ApicId[NewSlot] = NewApicId;
+
+    //
+    // Relocate the SMBASE of the new CPU.
+    //
+    Status = SmbaseRelocate (NewApicId, mCpuHotPlugData->SmBase[NewSlot],
+               mPostSmmPenAddress);
+    if (EFI_ERROR (Status)) {
+      goto RevokeNewSlot;
+    }
+
+    //
+    // Add the new CPU with EFI_SMM_CPU_SERVICE_PROTOCOL.
+    //
+    Status = mMmCpuService->AddProcessor (mMmCpuService, NewApicId,
+                              &NewProcessorNumberByProtocol);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: AddProcessor(" FMT_APIC_ID "): %r\n",
+        __FUNCTION__, NewApicId, Status));
+      goto RevokeNewSlot;
+    }
+
+    DEBUG ((DEBUG_INFO, "%a: hot-added APIC ID " FMT_APIC_ID ", SMBASE 0x%Lx, "
+      "EFI_SMM_CPU_SERVICE_PROTOCOL assigned number %Lu\n", __FUNCTION__,
+      NewApicId, (UINT64)mCpuHotPlugData->SmBase[NewSlot],
+      (UINT64)NewProcessorNumberByProtocol));
+
+    NewSlot++;
+    PluggedIdx++;
+  }
+
   //
   // We've handled this MMI.
   //
   return EFI_SUCCESS;
 
+RevokeNewSlot:
+  mCpuHotPlugData->ApicId[NewSlot] = MAX_UINT64;
+
 Fatal:
   ASSERT (FALSE);
   CpuDeadLoop ();
   //
   // We couldn't handle this MMI.
   //
   return EFI_INTERRUPT_PENDING;
 }
 
 
 //
 // Entry point function of this driver.
 //
 EFI_STATUS
 EFIAPI
 CpuHotplugEntry (
   IN EFI_HANDLE       ImageHandle,
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
   EFI_STATUS Status;
   UINTN      Size;
@@ -251,83 +326,101 @@ CpuHotplugEntry (
   //
   // Allocate the data structures that depend on the possible CPU count.
   //
   if (RETURN_ERROR (SafeUintnSub (mCpuHotPlugData->ArrayLength, 1, &Size)) ||
       RETURN_ERROR (SafeUintnMult (sizeof (APIC_ID), Size, &Size))) {
     Status = EFI_ABORTED;
     DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_PLUG_DATA\n", __FUNCTION__));
     goto Fatal;
   }
   Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
                     (VOID **)&mPluggedApicIds);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
     goto Fatal;
   }
   Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
                     (VOID **)&mToUnplugApicIds);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
     goto ReleasePluggedApicIds;
   }
 
+  //
+  // Allocate the Post-SMM Pen for hot-added CPUs.
+  //
+  Status = SmbaseAllocatePostSmmPen (&mPostSmmPenAddress,
+             SystemTable->BootServices);
+  if (EFI_ERROR (Status)) {
+    goto ReleaseToUnplugApicIds;
+  }
+
   //
   // Sanity-check the CPU hotplug interface.
   //
   // Both of the following features are part of QEMU 5.0, introduced primarily
   // in commit range 3e08b2b9cb64..3a61c8db9d25:
   //
   // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
   //     interface,
   //
   // (b) the "SMRAM at default SMBASE" feature.
   //
   // From these, (b) is restricted to 5.0+ machine type versions, while (a)
   // does not depend on machine type version. Because we ensured the stricter
   // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
   // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
   // can't verify the presence of precisely that command, we can still verify
   // (sanity-check) that the modern interface is active, at least.
   //
   // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
   // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
   // following.
   //
   QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
   QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
   QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
   if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
     Status = EFI_NOT_FOUND;
     DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
       __FUNCTION__, Status));
-    goto ReleaseToUnplugApicIds;
+    goto ReleasePostSmmPen;
   }
 
   //
   // Register the handler for the CPU Hotplug MMI.
   //
   Status = gMmst->MmiHandlerRegister (
                     CpuHotplugMmi,
                     NULL,            // HandlerType: root MMI handler
                     &mDispatchHandle
                     );
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
       Status));
-    goto ReleaseToUnplugApicIds;
+    goto ReleasePostSmmPen;
   }
 
+  //
+  // Install the handler for the hot-added CPUs' first SMI.
+  //
+  SmbaseInstallFirstSmiHandler ();
+
   return EFI_SUCCESS;
 
+ReleasePostSmmPen:
+  SmbaseReleasePostSmmPen (mPostSmmPenAddress, SystemTable->BootServices);
+  mPostSmmPenAddress = 0;
+
 ReleaseToUnplugApicIds:
   gMmst->MmFreePool (mToUnplugApicIds);
   mToUnplugApicIds = NULL;
 
 ReleasePluggedApicIds:
   gMmst->MmFreePool (mPluggedApicIds);
   mPluggedApicIds = NULL;
 
 Fatal:
   ASSERT (FALSE);
   CpuDeadLoop ();
   return Status;
 }
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (12 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 13/16] OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:44   ` Philippe Mathieu-Daudé
  2020-03-02 14:06   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups Laszlo Ersek
                   ` (4 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

The @file comments in UefiCpuPkg/CpuS3DataDxe say,

  [...] It also only supports the number of CPUs reported by the MP
  Services Protocol, so this module does not support hot plug CPUs.  This
  module can be copied into a CPU specific package and customized if these
  additional features are required. [...]

The driver is so small that the simplest way to extend it with hotplug
support is indeed to clone it at first. In this patch, customize the
driver only with the following no-op steps:

- Update copyright notices.
- Update INF_VERSION to the latest INF spec version (1.29).
- Update FILE_GUID.
- Drop the UNI files.
- Replace EFI_D_VERBOSE with DEBUG_VERBOSE, to appease "PatchCheck.py".

This patch is best reviewed with:

$ git show --find-copies-harder

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/OvmfPkgIa32.dsc                               |  2 +-
 OvmfPkg/OvmfPkgIa32X64.dsc                            |  2 +-
 OvmfPkg/OvmfPkgX64.dsc                                |  2 +-
 OvmfPkg/OvmfPkgIa32.fdf                               |  2 +-
 OvmfPkg/OvmfPkgIa32X64.fdf                            |  2 +-
 OvmfPkg/OvmfPkgX64.fdf                                |  2 +-
 {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf | 10 +++-------
 {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c      |  4 ++--
 8 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 78310da44a5f..8d8ca746ba03 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -836,45 +836,45 @@ [Components]
 !endif
       HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
       PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
       BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
 
     <PcdsFixedAtBuild>
       gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
       gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
       gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
   }
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
   OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
-  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
   OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 428578a4f839..acba1f80a431 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -850,45 +850,45 @@ [Components.X64]
       HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
       PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
       BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
 
     <PcdsFixedAtBuild>
       gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
       gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
       gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
   }
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
   OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
   OvmfPkg/AmdSevDxe/AmdSevDxe.inf
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
-  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
   OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 73b92f259201..621b27f80d4b 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -848,45 +848,45 @@ [Components]
       HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
       PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
       BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
 
     <PcdsFixedAtBuild>
       gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
       gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
       gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
   }
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
   OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
   OvmfPkg/AmdSevDxe/AmdSevDxe.inf
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
-  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 
   #
   # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 
   #
   # SMM_CORE
   #
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 
   #
   # Privileged drivers (DXE_SMM_DRIVER modules)
   #
   OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
   UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
   MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
     <LibraryClasses>
       LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
   }
   UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
     <LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index 61b891765c56..004aa318b222 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -298,45 +298,45 @@ [FV.DXEFV]
 INF  MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
 INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
 
 !ifdef $(CSM_ENABLE)
 INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
 INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
 INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
 !else
 INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
 !endif
 
 INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
 INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
 INF  OvmfPkg/PlatformDxe/Platform.inf
 INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
 INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
 INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
-INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
 INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
 INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
 
 #
 # Variable driver stack (SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
 #
 # Variable driver stack (non-SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 501b4fcb7b67..13da8b9dbe65 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -305,45 +305,45 @@ [FV.DXEFV]
 INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
 
 !ifdef $(CSM_ENABLE)
 INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
 INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
 INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
 !else
 INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
 !endif
 
 INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
 INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
 INF  OvmfPkg/PlatformDxe/Platform.inf
 INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
 INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
 INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
 INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
-INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
 INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
 INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
 
 #
 # Variable driver stack (SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
 #
 # Variable driver stack (non-SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 501b4fcb7b67..13da8b9dbe65 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -305,45 +305,45 @@ [FV.DXEFV]
 INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
 INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
 
 !ifdef $(CSM_ENABLE)
 INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
 INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
 INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
 !else
 INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
 !endif
 
 INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
 INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
 INF  OvmfPkg/PlatformDxe/Platform.inf
 INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
 INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
 INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
 INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
-INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
 INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
 INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
 INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
 INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
 INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
 
 #
 # Variable driver stack (SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
 INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
 INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
 
 !else
 
 #
 # Variable driver stack (non-SMM)
 #
 INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
 INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
similarity index 83%
copy from UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
copy to OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
index 510133a614ba..0ad8a0b35d25 100644
--- a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
@@ -1,65 +1,61 @@
 ## @file
 #  ACPI CPU Data initialization module
 #
 #  This module initializes the ACPI_CPU_DATA structure and registers the address
 #  of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
 #  version of this module.  It does not provide a machine check handler or CPU
 #  register initialization tables for ACPI S3 resume.  It also only supports the
 #  number of CPUs reported by the MP Services Protocol, so this module does not
 #  support hot plug CPUs.  This module can be copied into a CPU specific package
 #  and customized if these additional features are required.
 #
 #  Copyright (c) 2013-2016, Intel Corporation. All rights reserved.<BR>
-#  Copyright (c) 2015, Red Hat, Inc.
+#  Copyright (c) 2015-2020, Red Hat, Inc.
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
 
 [Defines]
-  INF_VERSION                    = 0x00010005
+  INF_VERSION                    = 1.29
   BASE_NAME                      = CpuS3DataDxe
-  MODULE_UNI_FILE                = CpuS3DataDxe.uni
-  FILE_GUID                      = 4D2E57EE-0E3F-44DD-93C4-D3B57E96945D
+  FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   ENTRY_POINT                    = CpuS3DataInitialize
 
 # The following information is for reference only and not required by the build
 # tools.
 #
 #  VALID_ARCHITECTURES           = IA32 X64
 
 [Sources]
   CpuS3Data.c
 
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   UefiDriverEntryPoint
   UefiBootServicesTableLib
   BaseMemoryLib
   DebugLib
   BaseLib
   MtrrLib
   MemoryAllocationLib
 
 [Guids]
   gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
 
 [Protocols]
   gEfiMpServiceProtocolGuid          ## CONSUMES
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize    ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress  ## PRODUCES
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
 
 [Depex]
   gEfiMpServiceProtocolGuid
-
-[UserExtensions.TianoCore."ExtraFiles"]
-  CpuS3DataDxeExtra.uni
diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
similarity index 96%
copy from UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
copy to OvmfPkg/CpuS3DataDxe/CpuS3Data.c
index 2be335d91903..2bb60d591b1e 100644
--- a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
+++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
@@ -1,35 +1,35 @@
 /** @file
 ACPI CPU Data initialization module
 
 This module initializes the ACPI_CPU_DATA structure and registers the address
 of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
 version of this module.  It does not provide a machine check handler or CPU
 register initialization tables for ACPI S3 resume.  It also only supports the
 number of CPUs reported by the MP Services Protocol, so this module does not
 support hot plug CPUs.  This module can be copied into a CPU specific package
 and customized if these additional features are required.
 
 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
-Copyright (c) 2015, Red Hat, Inc.
+Copyright (c) 2015 - 2020, Red Hat, Inc.
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
 #include <PiDxe.h>
 
 #include <AcpiCpuData.h>
 
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/DebugLib.h>
 #include <Library/MtrrLib.h>
 #include <Library/MemoryAllocationLib.h>
 
 #include <Protocol/MpService.h>
 #include <Guid/EventGroup.h>
 
 //
 // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
 //
@@ -107,45 +107,45 @@ VOID
 EFIAPI
 CpuS3DataOnEndOfDxe (
   IN  EFI_EVENT  Event,
   OUT VOID       *Context
   )
 {
   EFI_STATUS         Status;
   ACPI_CPU_DATA_EX   *AcpiCpuDataEx;
 
   AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context;
   //
   // Allocate a 4KB reserved page below 1MB
   //
   AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;
   Status = gBS->AllocatePages (
                   AllocateMaxAddress,
                   EfiReservedMemoryType,
                   1,
                   &AcpiCpuDataEx->AcpiCpuData.StartupVector
                   );
   ASSERT_EFI_ERROR (Status);
 
-  DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));
+  DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
   MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
 
   //
   // Close event, so it will not be invoked again.
   //
   gBS->CloseEvent (Event);
 }
 
 /**
    The entry function of the CpuS3Data driver.
 
    Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
    MTRR settings.  Register an event notification on gEfiEndOfDxeEventGroupGuid
    to capture the ACPI_CPU_DATA MTRR settings.  The PcdCpuS3DataAddress is set
    to the address that ACPI_CPU_DATA is allocated at.
 
    @param[in] ImageHandle  The firmware allocated handle for the EFI image.
    @param[in] SystemTable  A pointer to the EFI System Table.
 
    @retval EFI_SUCCESS     The entry point is executed successfully.
    @retval EFI_UNSUPPORTED Do not support ACPI S3.
    @retval other           Some error occurs when executing this entry point.
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (13 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 13:25   ` Philippe Mathieu-Daudé
  2020-03-02 14:06   ` Ard Biesheuvel
  2020-02-26 22:11 ` [PATCH v2 16/16] OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug Laszlo Ersek
                   ` (3 subsequent siblings)
  18 siblings, 2 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

Sort the [Packages], [LibraryClasses], and [Pcd] sections in the INF file.
Pad the usage notes (CONSUMES, PRODUCES) in the [Pcd] section.

Sort the Library #includes in the C file.

This patch is functionally a no-op.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf | 16 ++++++++--------
 OvmfPkg/CpuS3DataDxe/CpuS3Data.c      |  4 ++--
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
index 0ad8a0b35d25..f9679e0c33b3 100644
--- a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
@@ -14,48 +14,48 @@
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
 
 [Defines]
   INF_VERSION                    = 1.29
   BASE_NAME                      = CpuS3DataDxe
   FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   ENTRY_POINT                    = CpuS3DataInitialize
 
 # The following information is for reference only and not required by the build
 # tools.
 #
 #  VALID_ARCHITECTURES           = IA32 X64
 
 [Sources]
   CpuS3Data.c
 
 [Packages]
-  MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
-  UefiDriverEntryPoint
-  UefiBootServicesTableLib
+  BaseLib
   BaseMemoryLib
   DebugLib
-  BaseLib
-  MtrrLib
   MemoryAllocationLib
+  MtrrLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
 
 [Guids]
   gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
 
 [Protocols]
   gEfiMpServiceProtocolGuid          ## CONSUMES
 
 [Pcd]
-  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize    ## CONSUMES
-  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress  ## PRODUCES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable                    ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize                       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress                     ## PRODUCES
 
 [Depex]
   gEfiMpServiceProtocolGuid
diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
index 2bb60d591b1e..8bb9807cd501 100644
--- a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
+++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
@@ -3,48 +3,48 @@ ACPI CPU Data initialization module
 
 This module initializes the ACPI_CPU_DATA structure and registers the address
 of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
 version of this module.  It does not provide a machine check handler or CPU
 register initialization tables for ACPI S3 resume.  It also only supports the
 number of CPUs reported by the MP Services Protocol, so this module does not
 support hot plug CPUs.  This module can be copied into a CPU specific package
 and customized if these additional features are required.
 
 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
 Copyright (c) 2015 - 2020, Red Hat, Inc.
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
 #include <PiDxe.h>
 
 #include <AcpiCpuData.h>
 
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
-#include <Library/UefiBootServicesTableLib.h>
 #include <Library/DebugLib.h>
-#include <Library/MtrrLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/UefiBootServicesTableLib.h>
 
 #include <Protocol/MpService.h>
 #include <Guid/EventGroup.h>
 
 //
 // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
 //
 typedef struct {
   ACPI_CPU_DATA             AcpiCpuData;
   MTRR_SETTINGS             MtrrTable;
   IA32_DESCRIPTOR           GdtrProfile;
   IA32_DESCRIPTOR           IdtrProfile;
 } ACPI_CPU_DATA_EX;
 
 /**
   Allocate EfiACPIMemoryNVS memory.
 
   @param[in] Size   Size of memory to allocate.
 
   @return       Allocated address for output.
 
 **/
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 16/16] OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (14 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups Laszlo Ersek
@ 2020-02-26 22:11 ` Laszlo Ersek
  2020-03-02 14:16   ` Ard Biesheuvel
  2020-03-02 15:46 ` [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Boris Ostrovsky
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-26 22:11 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

During normal boot, CpuS3DataDxe allocates

- an empty CPU_REGISTER_TABLE entry in the
  "ACPI_CPU_DATA.PreSmmInitRegisterTable" array, and

- an empty CPU_REGISTER_TABLE entry in the "ACPI_CPU_DATA.RegisterTable"
  array,

for every CPU whose APIC ID CpuS3DataDxe can learn.

Currently EFI_MP_SERVICES_PROTOCOL is used for both determining the number
of CPUs -- the protocol reports the present-at-boot CPU count --, and for
retrieving the APIC IDs of those CPUs.

Consequently, if a CPU is hot-plugged at OS runtime, then S3 resume
breaks. That's because PiSmmCpuDxeSmm will not find the hot-added CPU's
APIC ID associated with any CPU_REGISTER_TABLE object, in the SMRAM copies
of either of the "RegisterTable" and "PreSmmInitRegisterTable" arrays. The
failure to match the hot-added CPU's APIC ID trips the ASSERT() in
SetRegister() [UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c].

If "PcdQ35SmramAtDefaultSmbase" is TRUE, then:

- prepare CPU_REGISTER_TABLE objects for all possible CPUs, not just the
  present-at-boot CPUs (PlatformPei stored the possible CPU count to
  "PcdCpuMaxLogicalProcessorNumber");

- use QEMU_CPUHP_CMD_GET_ARCH_ID for filling in the "InitialApicId" fields
  of the CPU_REGISTER_TABLE objects.

This provides full APIC ID coverage for PiSmmCpuDxeSmm during S3 resume,
accommodating CPUs hot-added at OS runtime.

This patch is best reviewed with

$ git show -b

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf |  4 +
 OvmfPkg/CpuS3DataDxe/CpuS3Data.c      | 91 ++++++++++++++------
 2 files changed, 70 insertions(+), 25 deletions(-)

diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
index f9679e0c33b3..ceae1d4078c7 100644
--- a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
+++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
@@ -16,46 +16,50 @@
 #
 ##
 
 [Defines]
   INF_VERSION                    = 1.29
   BASE_NAME                      = CpuS3DataDxe
   FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   ENTRY_POINT                    = CpuS3DataInitialize
 
 # The following information is for reference only and not required by the build
 # tools.
 #
 #  VALID_ARCHITECTURES           = IA32 X64
 
 [Sources]
   CpuS3Data.c
 
 [Packages]
   MdeModulePkg/MdeModulePkg.dec
   MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
   BaseMemoryLib
   DebugLib
+  IoLib
   MemoryAllocationLib
   MtrrLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
 
 [Guids]
   gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
 
 [Protocols]
   gEfiMpServiceProtocolGuid          ## CONSUMES
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable                    ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize                       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress                     ## PRODUCES
+  gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
 
 [Depex]
   gEfiMpServiceProtocolGuid
diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
index 8bb9807cd501..bac7285aa2f3 100644
--- a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
+++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
@@ -4,51 +4,55 @@ ACPI CPU Data initialization module
 This module initializes the ACPI_CPU_DATA structure and registers the address
 of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
 version of this module.  It does not provide a machine check handler or CPU
 register initialization tables for ACPI S3 resume.  It also only supports the
 number of CPUs reported by the MP Services Protocol, so this module does not
 support hot plug CPUs.  This module can be copied into a CPU specific package
 and customized if these additional features are required.
 
 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
 Copyright (c) 2015 - 2020, Red Hat, Inc.
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
 #include <PiDxe.h>
 
 #include <AcpiCpuData.h>
 
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
+#include <Library/IoLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/MtrrLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 
 #include <Protocol/MpService.h>
 #include <Guid/EventGroup.h>
 
+#include <IndustryStandard/Q35MchIch9.h>
+#include <IndustryStandard/QemuCpuHotplug.h>
+
 //
 // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
 //
 typedef struct {
   ACPI_CPU_DATA             AcpiCpuData;
   MTRR_SETTINGS             MtrrTable;
   IA32_DESCRIPTOR           GdtrProfile;
   IA32_DESCRIPTOR           IdtrProfile;
 } ACPI_CPU_DATA_EX;
 
 /**
   Allocate EfiACPIMemoryNVS memory.
 
   @param[in] Size   Size of memory to allocate.
 
   @return       Allocated address for output.
 
 **/
 VOID *
 AllocateAcpiNvsMemory (
   IN UINTN  Size
   )
@@ -144,89 +148,101 @@ CpuS3DataOnEndOfDxe (
    to the address that ACPI_CPU_DATA is allocated at.
 
    @param[in] ImageHandle  The firmware allocated handle for the EFI image.
    @param[in] SystemTable  A pointer to the EFI System Table.
 
    @retval EFI_SUCCESS     The entry point is executed successfully.
    @retval EFI_UNSUPPORTED Do not support ACPI S3.
    @retval other           Some error occurs when executing this entry point.
 
 **/
 EFI_STATUS
 EFIAPI
 CpuS3DataInitialize (
   IN EFI_HANDLE        ImageHandle,
   IN EFI_SYSTEM_TABLE  *SystemTable
   )
 {
   EFI_STATUS                 Status;
   ACPI_CPU_DATA_EX           *AcpiCpuDataEx;
   ACPI_CPU_DATA              *AcpiCpuData;
   EFI_MP_SERVICES_PROTOCOL   *MpServices;
   UINTN                      NumberOfCpus;
-  UINTN                      NumberOfEnabledProcessors;
   VOID                       *Stack;
   UINTN                      TableSize;
   CPU_REGISTER_TABLE         *RegisterTable;
   UINTN                      Index;
   EFI_PROCESSOR_INFORMATION  ProcessorInfoBuffer;
   UINTN                      GdtSize;
   UINTN                      IdtSize;
   VOID                       *Gdt;
   VOID                       *Idt;
   EFI_EVENT                  Event;
   ACPI_CPU_DATA              *OldAcpiCpuData;
+  BOOLEAN                    FetchPossibleApicIds;
 
   if (!PcdGetBool (PcdAcpiS3Enable)) {
     return EFI_UNSUPPORTED;
   }
 
   //
   // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
   //
   OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);
 
   AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));
   ASSERT (AcpiCpuDataEx != NULL);
   AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;
 
   //
-  // Get MP Services Protocol
+  // The "SMRAM at default SMBASE" feature guarantees that
+  // QEMU_CPUHP_CMD_GET_ARCH_ID too is available.
   //
-  Status = gBS->LocateProtocol (
-                  &gEfiMpServiceProtocolGuid,
-                  NULL,
-                  (VOID **)&MpServices
-                  );
-  ASSERT_EFI_ERROR (Status);
+  FetchPossibleApicIds = PcdGetBool (PcdQ35SmramAtDefaultSmbase);
 
-  //
-  // Get the number of CPUs
-  //
-  Status = MpServices->GetNumberOfProcessors (
-                         MpServices,
-                         &NumberOfCpus,
-                         &NumberOfEnabledProcessors
-                         );
-  ASSERT_EFI_ERROR (Status);
+  if (FetchPossibleApicIds) {
+    NumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+  } else {
+    UINTN NumberOfEnabledProcessors;
+
+    //
+    // Get MP Services Protocol
+    //
+    Status = gBS->LocateProtocol (
+                    &gEfiMpServiceProtocolGuid,
+                    NULL,
+                    (VOID **)&MpServices
+                    );
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // Get the number of CPUs
+    //
+    Status = MpServices->GetNumberOfProcessors (
+                           MpServices,
+                           &NumberOfCpus,
+                           &NumberOfEnabledProcessors
+                           );
+    ASSERT_EFI_ERROR (Status);
+  }
   AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;
 
   //
   // Initialize ACPI_CPU_DATA fields
   //
   AcpiCpuData->StackSize                 = PcdGet32 (PcdCpuApStackSize);
   AcpiCpuData->ApMachineCheckHandlerBase = 0;
   AcpiCpuData->ApMachineCheckHandlerSize = 0;
   AcpiCpuData->GdtrProfile  = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;
   AcpiCpuData->IdtrProfile  = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;
   AcpiCpuData->MtrrTable    = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;
 
   //
   // Allocate stack space for all CPUs.
   // Use ACPI NVS memory type because this data will be directly used by APs
   // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
   // will only be used as scratch space. i.e. we won't read anything from it
   // before we write to it, in PiSmmCpuDxeSmm.
   //
   Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);
   ASSERT (Stack != NULL);
   AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;
@@ -244,58 +260,83 @@ CpuS3DataInitialize (
   IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;
   Gdt = AllocateZeroPages (GdtSize + IdtSize);
   ASSERT (Gdt != NULL);
   Idt = (VOID *)((UINTN)Gdt + GdtSize);
   CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);
   CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);
   AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;
   AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;
 
   if (OldAcpiCpuData != NULL) {
     AcpiCpuData->RegisterTable           = OldAcpiCpuData->RegisterTable;
     AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;
     AcpiCpuData->ApLocation              = OldAcpiCpuData->ApLocation;
     CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));
   } else {
     //
     // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs
     //
     TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);
     RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize);
     ASSERT (RegisterTable != NULL);
 
+    if (FetchPossibleApicIds) {
+      //
+      // Write a valid selector so that other hotplug registers can be
+      // accessed.
+      //
+      IoWrite32 (ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL, 0);
+      //
+      // We'll be fetching the APIC IDs.
+      //
+      IoWrite8 (ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
+        QEMU_CPUHP_CMD_GET_ARCH_ID);
+    }
     for (Index = 0; Index < NumberOfCpus; Index++) {
-      Status = MpServices->GetProcessorInfo (
-                           MpServices,
-                           Index,
-                           &ProcessorInfoBuffer
-                           );
-      ASSERT_EFI_ERROR (Status);
+      UINT32 InitialApicId;
 
-      RegisterTable[Index].InitialApicId      = (UINT32)ProcessorInfoBuffer.ProcessorId;
+      if (FetchPossibleApicIds) {
+        IoWrite32 (ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL,
+          (UINT32)Index);
+        InitialApicId = IoRead32 (
+                          ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_RW_CMD_DATA);
+      } else {
+        Status = MpServices->GetProcessorInfo (
+                             MpServices,
+                             Index,
+                             &ProcessorInfoBuffer
+                             );
+        ASSERT_EFI_ERROR (Status);
+        InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;
+      }
+
+      DEBUG ((DEBUG_VERBOSE, "%a: Index=%05Lu ApicId=0x%08x\n", __FUNCTION__,
+        (UINT64)Index, InitialApicId));
+
+      RegisterTable[Index].InitialApicId      = InitialApicId;
       RegisterTable[Index].TableLength        = 0;
       RegisterTable[Index].AllocatedSize      = 0;
       RegisterTable[Index].RegisterTableEntry = 0;
 
-      RegisterTable[NumberOfCpus + Index].InitialApicId      = (UINT32)ProcessorInfoBuffer.ProcessorId;
+      RegisterTable[NumberOfCpus + Index].InitialApicId      = InitialApicId;
       RegisterTable[NumberOfCpus + Index].TableLength        = 0;
       RegisterTable[NumberOfCpus + Index].AllocatedSize      = 0;
       RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;
     }
     AcpiCpuData->RegisterTable           = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;
     AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);
   }
 
   //
   // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
   //
   Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
   ASSERT_EFI_ERROR (Status);
 
   //
   // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
   // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
   //
   Status = gBS->CreateEventEx (
                   EVT_NOTIFY_SIGNAL,
                   TPL_CALLBACK,
                   CpuS3DataOnEndOfDxe,
-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
  2020-02-26 22:11 ` [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug Laszlo Ersek
@ 2020-02-28  3:05   ` Dong, Eric
  2020-02-28 10:50     ` Laszlo Ersek
  2020-03-04 12:23     ` Laszlo Ersek
  0 siblings, 2 replies; 53+ messages in thread
From: Dong, Eric @ 2020-02-28  3:05 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com
  Cc: Ard Biesheuvel, Igor Mammedov, Yao, Jiewen, Justen, Jordan L,
	Kinney, Michael D, Philippe Mathieu-Daudé, Ni, Ray

Hi Laszlo,

Thanks for your patch. The change make sense base on the comments in the data structure header file.

I also checked all the code related to this data structure. The inputs for this data structure are CpuS3DataDxe and RegisterCpuFeaturesLib. Both these two drivers not support CPU hot plug feature, so the real inputs for mAcpiCpuData.NumberOfCpus is the enabled CPU number in this system. So before and after your code change, the CPU values are same. But the data structure comments said it can support CPU hot plug, so I agree your code change.

Reviewed-by: Eric Dong <eric.dong@intel.com>

Thanks,
Eric

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Laszlo Ersek
Sent: Thursday, February 27, 2020 6:12 AM
To: edk2-devel-groups-io <devel@edk2.groups.io>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Dong, Eric <eric.dong@intel.com>; Igor Mammedov <imammedo@redhat.com>; Yao, Jiewen <jiewen.yao@intel.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>
Subject: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug

The "ACPI_CPU_DATA.NumberOfCpus" field is specified as follows, in "UefiCpuPkg/Include/AcpiCpuData.h" (rewrapped for this commit message):

  //
  // The number of CPUs.  If a platform does not support hot plug CPUs,
  // then this is the number of CPUs detected when the platform is booted,
  // regardless of being enabled or disabled.  If a platform does support
  // hot plug CPUs, then this is the maximum number of CPUs that the
  // platform supports.
  //

The InitializeCpuBeforeRebase() and InitializeCpuAfterRebase() functions in "UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c" try to restore CPU configuration on the S3 Resume path for *all* CPUs accounted for in "ACPI_CPU_DATA.NumberOfCpus". This is wrong, as with CPU hotplug, not all of the possible CPUs may be present at the time of S3 Suspend / Resume.
The symptom is an infinite wait.

Instead, the "mNumberOfCpus" variable should be used, which is properly maintained through the EFI_SMM_CPU_SERVICE_PROTOCOL implementation (see SmmAddProcessor(), SmmRemoveProcessor(), SmmCpuUpdate() in "UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c").

When CPU hotplug is disabled, "mNumberOfCpus" is constant, and equals "ACPI_CPU_DATA.NumberOfCpus" at all times.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

Notes:
    v2:
    
    - Pick up Ard's Acked-by, which is conditional on approval from Intel
      reviewers on Cc. (I'd like to save Ard the churn of re-acking
      unmodified patches.)

 UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
index ba5cc0194c2d..1e0840119724 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
@@ -597,75 +597,85 @@ PrepareApStartupVector (  }
 
 /**
   The function is invoked before SMBASE relocation in S3 path to restores CPU status.
 
   The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
   and restores MTRRs for both BSP and APs.
 
 **/
 VOID
 InitializeCpuBeforeRebase (
   VOID
   )
 {
   LoadMtrrData (mAcpiCpuData.MtrrTable);
 
   SetRegister (TRUE);
 
   ProgramVirtualWireMode ();
 
   PrepareApStartupVector (mAcpiCpuData.StartupVector);
 
-  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
+  if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+    ASSERT (mNumberOfCpus <= mAcpiCpuData.NumberOfCpus);  } else {
+    ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);  }  
+ mNumberToFinish = mNumberOfCpus - 1;
   mExchangeInfo->ApFunction  = (VOID *) (UINTN) InitializeAp;
 
   //
   // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
   //
   mInitApsAfterSmmBaseReloc = FALSE;
 
   //
   // Send INIT IPI - SIPI to all APs
   //
   SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
 
   while (mNumberToFinish > 0) {
     CpuPause ();
   }
 }
 
 /**
   The function is invoked after SMBASE relocation in S3 path to restores CPU status.
 
   The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
   data saved by normal boot path for both BSP and APs.
 
 **/
 VOID
 InitializeCpuAfterRebase (
   VOID
   )
 {
-  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
+  if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+    ASSERT (mNumberOfCpus <= mAcpiCpuData.NumberOfCpus);  } else {
+    ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);  }  
+ mNumberToFinish = mNumberOfCpus - 1;
 
   //
   // Signal that SMM base relocation is complete and to continue initialization for all APs.
   //
   mInitApsAfterSmmBaseReloc = TRUE;
 
   //
   // Must begin set register after all APs have continue their initialization.
   // This is a requirement to support semaphore mechanism in register table.
   // Because if semaphore's dependence type is package type, semaphore will wait
   // for all Aps in one package finishing their tasks before set next register
   // for all APs. If the Aps not begin its task during BSP doing its task, the
   // BSP thread will hang because it is waiting for other Aps in the same
   // package finishing their task.
   //
   SetRegister (FALSE);
 
   while (mNumberToFinish > 0) {
     CpuPause ();
   }
 }
 
--
2.19.1.3.g30247aa5d201






^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
  2020-02-28  3:05   ` [edk2-devel] " Dong, Eric
@ 2020-02-28 10:50     ` Laszlo Ersek
  2020-03-04 12:23     ` Laszlo Ersek
  1 sibling, 0 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-02-28 10:50 UTC (permalink / raw)
  To: Dong, Eric, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Igor Mammedov, Yao, Jiewen, Justen, Jordan L,
	Kinney, Michael D, Philippe Mathieu-Daudé, Ni, Ray

On 02/28/20 04:05, Dong, Eric wrote:
> Hi Laszlo,
> 
> Thanks for your patch. The change make sense base on the comments in the data structure header file.
> 
> I also checked all the code related to this data structure. The inputs for this data structure are CpuS3DataDxe and RegisterCpuFeaturesLib. Both these two drivers not support CPU hot plug feature, so the real inputs for mAcpiCpuData.NumberOfCpus is the enabled CPU number in this system. So before and after your code change, the CPU values are same. But the data structure comments said it can support CPU hot plug, so I agree your code change.
> 
> Reviewed-by: Eric Dong <eric.dong@intel.com>

Thank you!

Please allow me one additional comment on CpuS3DataDxe however:

According to the comments in UefiCpuPkg/CpuS3DataDxe:

    [...] this module does not support hot plug CPUs.  This module can
    be copied into a CPU specific package and customized if these
    additional features are required [...]

in the last three patches of the series, I clone CpuS3DataDxe for
OvmfPkg, and extend it for CPU hotplug:

  [edk2-devel] [PATCH v2 14/16]
  OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg

  [edk2-devel] [PATCH v2 15/16]
  OvmfPkg/CpuS3DataDxe: superficial cleanups

  [edk2-devel] [PATCH v2 16/16]
  OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug

(This extension occurs in a QEMU-specific way -- in other words,
OvmfPkg/CpuS3DataDxe is really a platform driver.)

What I'm trying to say is: the PiSmmCpuDxeSmm changes from the present
patch *are* utilized in a CPU hotplug situation too.

In other words, PiSmmCpuDxeSmm is really exposed to a situation where
the following expression is TRUE:

  (FeaturePcdGet (PcdCpuHotPlugSupport) &&
   mNumberOfCpus < mAcpiCpuData.NumberOfCpus)

It is testable with OVMF, after this series is applied.

Thanks
Laszlo

> 
> Thanks,
> Eric
> 
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Laszlo Ersek
> Sent: Thursday, February 27, 2020 6:12 AM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Dong, Eric <eric.dong@intel.com>; Igor Mammedov <imammedo@redhat.com>; Yao, Jiewen <jiewen.yao@intel.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>
> Subject: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
> 
> The "ACPI_CPU_DATA.NumberOfCpus" field is specified as follows, in "UefiCpuPkg/Include/AcpiCpuData.h" (rewrapped for this commit message):
> 
>   //
>   // The number of CPUs.  If a platform does not support hot plug CPUs,
>   // then this is the number of CPUs detected when the platform is booted,
>   // regardless of being enabled or disabled.  If a platform does support
>   // hot plug CPUs, then this is the maximum number of CPUs that the
>   // platform supports.
>   //
> 
> The InitializeCpuBeforeRebase() and InitializeCpuAfterRebase() functions in "UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c" try to restore CPU configuration on the S3 Resume path for *all* CPUs accounted for in "ACPI_CPU_DATA.NumberOfCpus". This is wrong, as with CPU hotplug, not all of the possible CPUs may be present at the time of S3 Suspend / Resume.
> The symptom is an infinite wait.
> 
> Instead, the "mNumberOfCpus" variable should be used, which is properly maintained through the EFI_SMM_CPU_SERVICE_PROTOCOL implementation (see SmmAddProcessor(), SmmRemoveProcessor(), SmmCpuUpdate() in "UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c").
> 
> When CPU hotplug is disabled, "mNumberOfCpus" is constant, and equals "ACPI_CPU_DATA.NumberOfCpus" at all times.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>     v2:
>     
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
> 
>  UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> index ba5cc0194c2d..1e0840119724 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> @@ -597,75 +597,85 @@ PrepareApStartupVector (  }
>
>  /**
>    The function is invoked before SMBASE relocation in S3 path to restores CPU status.
>
>    The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
>    and restores MTRRs for both BSP and APs.
>
>  **/
>  VOID
>  InitializeCpuBeforeRebase (
>    VOID
>    )
>  {
>    LoadMtrrData (mAcpiCpuData.MtrrTable);
>
>    SetRegister (TRUE);
>
>    ProgramVirtualWireMode ();
>
>    PrepareApStartupVector (mAcpiCpuData.StartupVector);
>
> -  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
> +  if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
> +    ASSERT (mNumberOfCpus <= mAcpiCpuData.NumberOfCpus);  } else {
> +    ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);  }
> + mNumberToFinish = mNumberOfCpus - 1;
>    mExchangeInfo->ApFunction  = (VOID *) (UINTN) InitializeAp;
>
>    //
>    // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
>    //
>    mInitApsAfterSmmBaseReloc = FALSE;
>
>    //
>    // Send INIT IPI - SIPI to all APs
>    //
>    SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
>
>    while (mNumberToFinish > 0) {
>      CpuPause ();
>    }
>  }
>
>  /**
>    The function is invoked after SMBASE relocation in S3 path to restores CPU status.
>
>    The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
>    data saved by normal boot path for both BSP and APs.
>
>  **/
>  VOID
>  InitializeCpuAfterRebase (
>    VOID
>    )
>  {
> -  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
> +  if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
> +    ASSERT (mNumberOfCpus <= mAcpiCpuData.NumberOfCpus);  } else {
> +    ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);  }
> + mNumberToFinish = mNumberOfCpus - 1;
>
>    //
>    // Signal that SMM base relocation is complete and to continue initialization for all APs.
>    //
>    mInitApsAfterSmmBaseReloc = TRUE;
>
>    //
>    // Must begin set register after all APs have continue their initialization.
>    // This is a requirement to support semaphore mechanism in register table.
>    // Because if semaphore's dependence type is package type, semaphore will wait
>    // for all Aps in one package finishing their tasks before set next register
>    // for all APs. If the Aps not begin its task during BSP doing its task, the
>    // BSP thread will hang because it is waiting for other Aps in the same
>    // package finishing their task.
>    //
>    SetRegister (FALSE);
>
>    while (mNumberToFinish > 0) {
>      CpuPause ();
>    }
>  }
>
> --
> 2.19.1.3.g30247aa5d201
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure
  2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
@ 2020-03-02 12:47   ` Laszlo Ersek
  2020-03-02 12:55     ` Liming Gao
  2020-03-02 13:46   ` Philippe Mathieu-Daudé
  2020-03-03  0:46   ` Dong, Eric
  2 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-02 12:47 UTC (permalink / raw)
  To: Eric Dong, Hao A Wu, Jian J Wang, Ray Ni
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Igor Mammedov, Jiewen Yao,
	Jordan Justen, Michael Kinney, Philippe Mathieu-Daudé

Jian, Hao, Eric, Ray,

this patch is trivial; can one of you please ACK it?

Thanks
Laszlo

On 02/26/20 23:11, Laszlo Ersek wrote:
> In the CoreStartImage() function [MdeModulePkg/Core/Dxe/Image/Image.c], if
> the image entry point returns a failure code, then the DXE Core logs a
> helpful DEBUG_ERROR message, with the following format string:
> 
>   "Error: Image at %11p start failed: %r\n"
> 
> Do similarly in the SMM Core (update the message slightly).
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>     v2:
>     
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
> 
>  MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> index 9bec731e5312..76ee9e0b89cc 100644
> --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> @@ -883,44 +883,50 @@ SmmDispatcher (
>        RemoveEntryList (&DriverEntry->ScheduledLink);
>  
>        REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
>          EFI_PROGRESS_CODE,
>          EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
>          &DriverEntry->ImageHandle,
>          sizeof (DriverEntry->ImageHandle)
>          );
>  
>        //
>        // Cache state of SmmEntryPointRegistered before calling entry point
>        //
>        PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
>  
>        //
>        // For each SMM driver, pass NULL as ImageHandle
>        //
>        RegisterSmramProfileImage (DriverEntry, TRUE);
>        PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
>        Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
>        PERF_START_IMAGE_END (DriverEntry->ImageHandle);
>        if (EFI_ERROR(Status)){
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "Error: SMM image at %11p start failed: %r\n",
> +          DriverEntry->SmmLoadedImage.ImageBase,
> +          Status
> +          ));
>          UnregisterSmramProfileImage (DriverEntry, TRUE);
>          SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
>          //
>          // Uninstall LoadedImage
>          //
>          Status = gBS->UninstallProtocolInterface (
>                          DriverEntry->ImageHandle,
>                          &gEfiLoadedImageProtocolGuid,
>                          DriverEntry->LoadedImage
>                          );
>          if (!EFI_ERROR (Status)) {
>            if (DriverEntry->LoadedImage->FilePath != NULL) {
>              gBS->FreePool (DriverEntry->LoadedImage->FilePath);
>            }
>            gBS->FreePool (DriverEntry->LoadedImage);
>          }
>          Status = SmmUninstallProtocolInterface (
>                     DriverEntry->SmmImageHandle,
>                     &gEfiLoadedImageProtocolGuid,
>                     &DriverEntry->SmmLoadedImage
>                     );
>          if (!EFI_ERROR(Status)) {
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure
  2020-03-02 12:47   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-02 12:55     ` Liming Gao
  0 siblings, 0 replies; 53+ messages in thread
From: Liming Gao @ 2020-03-02 12:55 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com, Dong, Eric, Wu, Hao A,
	Wang, Jian J, Ni, Ray
  Cc: Ard Biesheuvel, Igor Mammedov, Yao, Jiewen, Justen, Jordan L,
	Kinney, Michael D, Philippe Mathieu-Daudé

Laszlo:
  The change refers to the same logic in DxeMain logic. So, it makes sense. Reviewed-by: Liming Gao <liming.gao@intel.com>

Thanks
Liming
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Laszlo Ersek
> Sent: Monday, March 2, 2020 8:47 PM
> To: Dong, Eric <eric.dong@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>; Ni, Ray
> <ray.ni@intel.com>
> Cc: edk2-devel-groups-io <devel@edk2.groups.io>; Ard Biesheuvel <ard.biesheuvel@linaro.org>; Igor Mammedov
> <imammedo@redhat.com>; Yao, Jiewen <jiewen.yao@intel.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Philippe Mathieu-Daudé <philmd@redhat.com>
> Subject: Re: [edk2-devel] [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure
> 
> Jian, Hao, Eric, Ray,
> 
> this patch is trivial; can one of you please ACK it?
> 
> Thanks
> Laszlo
> 
> On 02/26/20 23:11, Laszlo Ersek wrote:
> > In the CoreStartImage() function [MdeModulePkg/Core/Dxe/Image/Image.c], if
> > the image entry point returns a failure code, then the DXE Core logs a
> > helpful DEBUG_ERROR message, with the following format string:
> >
> >   "Error: Image at %11p start failed: %r\n"
> >
> > Do similarly in the SMM Core (update the message slightly).
> >
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Eric Dong <eric.dong@intel.com>
> > Cc: Hao A Wu <hao.a.wu@intel.com>
> > Cc: Igor Mammedov <imammedo@redhat.com>
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Jordan Justen <jordan.l.justen@intel.com>
> > Cc: Michael Kinney <michael.d.kinney@intel.com>
> > Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> > Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> > Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> > Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > ---
> >
> > Notes:
> >     v2:
> >
> >     - Pick up Ard's Acked-by, which is conditional on approval from Intel
> >       reviewers on Cc. (I'd like to save Ard the churn of re-acking
> >       unmodified patches.)
> >
> >  MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 6 ++++++
> >  1 file changed, 6 insertions(+)
> >
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> > index 9bec731e5312..76ee9e0b89cc 100644
> > --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> > +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> > @@ -883,44 +883,50 @@ SmmDispatcher (
> >        RemoveEntryList (&DriverEntry->ScheduledLink);
> >
> >        REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> >          EFI_PROGRESS_CODE,
> >          EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
> >          &DriverEntry->ImageHandle,
> >          sizeof (DriverEntry->ImageHandle)
> >          );
> >
> >        //
> >        // Cache state of SmmEntryPointRegistered before calling entry point
> >        //
> >        PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
> >
> >        //
> >        // For each SMM driver, pass NULL as ImageHandle
> >        //
> >        RegisterSmramProfileImage (DriverEntry, TRUE);
> >        PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
> >        Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
> >        PERF_START_IMAGE_END (DriverEntry->ImageHandle);
> >        if (EFI_ERROR(Status)){
> > +        DEBUG ((
> > +          DEBUG_ERROR,
> > +          "Error: SMM image at %11p start failed: %r\n",
> > +          DriverEntry->SmmLoadedImage.ImageBase,
> > +          Status
> > +          ));
> >          UnregisterSmramProfileImage (DriverEntry, TRUE);
> >          SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
> >          //
> >          // Uninstall LoadedImage
> >          //
> >          Status = gBS->UninstallProtocolInterface (
> >                          DriverEntry->ImageHandle,
> >                          &gEfiLoadedImageProtocolGuid,
> >                          DriverEntry->LoadedImage
> >                          );
> >          if (!EFI_ERROR (Status)) {
> >            if (DriverEntry->LoadedImage->FilePath != NULL) {
> >              gBS->FreePool (DriverEntry->LoadedImage->FilePath);
> >            }
> >            gBS->FreePool (DriverEntry->LoadedImage);
> >          }
> >          Status = SmmUninstallProtocolInterface (
> >                     DriverEntry->SmmImageHandle,
> >                     &gEfiLoadedImageProtocolGuid,
> >                     &DriverEntry->SmmLoadedImage
> >                     );
> >          if (!EFI_ERROR(Status)) {
> >
> 
> 
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro
  2020-02-26 22:11 ` [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro Laszlo Ersek
@ 2020-03-02 13:22   ` Philippe Mathieu-Daudé
  2020-03-02 13:45   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 13:22 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> QEMU commit 3a61c8db9d25 ("acpi: cpuhp: add CPHP_GET_CPU_ID_CMD command",
> 2020-01-22) introduced a new command in the modern CPU hotplug register
> block that lets the firmware query the arch-specific IDs (on IA32/X64: the
> APIC IDs) of CPUs. Add a macro for this command value, because we'll need
> it later.
> 
> At the same time, add a sanity check for the modern hotplug interface to
> CpuHotplugSmm.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |  1 +
>   OvmfPkg/CpuHotplugSmm/CpuHotplug.c                | 35 ++++++++++++++++++++
>   2 files changed, 36 insertions(+)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> index cf0745610f2c..3d013633501b 100644
> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> @@ -20,24 +20,25 @@
>   #define QEMU_CPU_HOTPLUG_H_
>   
>   #include <Base.h>
>   
>   //
>   // Each register offset is:
>   // - relative to the board-dependent IO base address of the register block,
>   // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access modes of the
>   //   register,
>   // - followed by distinguished bitmasks or values in the register.
>   //
>   #define QEMU_CPUHP_R_CMD_DATA2               0x0
>   
>   #define QEMU_CPUHP_R_CPU_STAT                0x4
>   #define QEMU_CPUHP_STAT_ENABLED                BIT0
>   
>   #define QEMU_CPUHP_RW_CMD_DATA               0x8
>   
>   #define QEMU_CPUHP_W_CPU_SEL                 0x0
>   
>   #define QEMU_CPUHP_W_CMD                     0x5
>   #define QEMU_CPUHP_CMD_GET_PENDING             0x0
> +#define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
>   
>   #endif // QEMU_CPU_HOTPLUG_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> index fd09403eabf3..5df8c689c63a 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> @@ -1,38 +1,41 @@
>   /** @file
>     Root SMI handler for VCPU hotplug SMIs.
>   
>     Copyright (c) 2020, Red Hat, Inc.
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
>   
>   #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
> +#include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
>   #include <Library/BaseLib.h>                 // CpuDeadLoop()
>   #include <Library/DebugLib.h>                // ASSERT()
>   #include <Library/MmServicesTableLib.h>      // gMmst
>   #include <Library/PcdLib.h>                  // PcdGetBool()
>   #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
>   #include <Uefi/UefiBaseType.h>               // EFI_STATUS
>   
> +#include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
> +
>   //
>   // We use this protocol for accessing IO Ports.
>   //
>   STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
>   //
>   // Represents the registration of the CPU Hotplug MMI handler.
>   //
>   STATIC EFI_HANDLE mDispatchHandle;
>   
>   
>   /**
>     CPU Hotplug MMI handler function.
>   
>     This is a root MMI handler.
>   
>     @param[in] DispatchHandle      The unique handle assigned to this handler by
>                                    EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
>   
>     @param[in] Context             Context passed in by
>                                    EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
>                                    CpuHotplugMmi() being a root MMI handler,
>                                    Context is ASSERT()ed to be NULL.
> @@ -149,43 +152,75 @@ CpuHotplugEntry (
>     //
>     // This driver depends on the dynamically detected "SMRAM at default SMBASE"
>     // feature.
>     //
>     if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
>       return EFI_UNSUPPORTED;
>     }
>   
>     //
>     // Errors from here on are fatal; we cannot allow the boot to proceed if we
>     // can't set up this driver to handle CPU hotplug.
>     //
>     // First, collect the protocols needed later. All of these protocols are
>     // listed in our module DEPEX.
>     //
>     Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
>                       NULL /* Registration */, (VOID **)&mMmCpuIo);
>     if (EFI_ERROR (Status)) {
>       DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
>       goto Fatal;
>     }
>   
> +  //
> +  // Sanity-check the CPU hotplug interface.
> +  //
> +  // Both of the following features are part of QEMU 5.0, introduced primarily
> +  // in commit range 3e08b2b9cb64..3a61c8db9d25:
> +  //
> +  // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
> +  //     interface,
> +  //
> +  // (b) the "SMRAM at default SMBASE" feature.
> +  //
> +  // From these, (b) is restricted to 5.0+ machine type versions, while (a)
> +  // does not depend on machine type version. Because we ensured the stricter
> +  // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
> +  // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
> +  // can't verify the presence of precisely that command, we can still verify
> +  // (sanity-check) that the modern interface is active, at least.
> +  //
> +  // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
> +  // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
> +  // following.
> +  //
> +  QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
> +  QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>

> +  QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
> +  if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
> +    Status = EFI_NOT_FOUND;
> +    DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
> +      __FUNCTION__, Status));
> +    goto Fatal;
> +  }
> +
>     //
>     // Register the handler for the CPU Hotplug MMI.
>     //
>     Status = gMmst->MmiHandlerRegister (
>                       CpuHotplugMmi,
>                       NULL,            // HandlerType: root MMI handler
>                       &mDispatchHandle
>                       );
>     if (EFI_ERROR (Status)) {
>       DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
>         Status));
>       goto Fatal;
>     }
>   
>     return EFI_SUCCESS;
>   
>   Fatal:
>     ASSERT (FALSE);
>     CpuDeadLoop ();
>     return Status;
>   }
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions
  2020-02-26 22:11 ` [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions Laszlo Ersek
@ 2020-03-02 13:24   ` Philippe Mathieu-Daudé
  2020-03-02 13:45   ` [edk2-devel] " Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 13:24 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> Add a handful of simple functions for accessing QEMU's hotplug registers
> more conveniently. These functions thinly wrap some of the registers
> described in "docs/specs/acpi_cpu_hotplug.txt" in the QEMU tree. The
> functions hang (by design) if they encounter an internal failure.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   2 +
>   OvmfPkg/CpuHotplugSmm/QemuCpuhp.h       |  47 +++++++
>   OvmfPkg/CpuHotplugSmm/QemuCpuhp.c       | 136 ++++++++++++++++++++
>   3 files changed, 185 insertions(+)
> 
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index fa70858a8dab..ac4ca4c1f4f2 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -4,44 +4,46 @@
>   # Copyright (c) 2020, Red Hat, Inc.
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   ##
>   
>   [Defines]
>     INF_VERSION                = 1.29
>     PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>     BASE_NAME                  = CpuHotplugSmm
>     FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>     MODULE_TYPE                = DXE_SMM_DRIVER
>     ENTRY_POINT                = CpuHotplugEntry
>   
>   #
>   # The following information is for reference only and not required by the build
>   # tools.
>   #
>   # VALID_ARCHITECTURES        = IA32 X64
>   #
>   
>   [Sources]
>     CpuHotplug.c
> +  QemuCpuhp.c
> +  QemuCpuhp.h
>   
>   [Packages]
>     MdePkg/MdePkg.dec
>     OvmfPkg/OvmfPkg.dec
>   
>   [LibraryClasses]
>     BaseLib
>     DebugLib
>     MmServicesTableLib
>     PcdLib
>     UefiDriverEntryPoint
>   
>   [Protocols]
>     gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
>   
>   [Pcd]
>     gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>   
>   [FeaturePcd]
>     gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
>   
>   [Depex]
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> new file mode 100644
> index 000000000000..82f88f0b73bb
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> @@ -0,0 +1,47 @@
> +/** @file
> +  Simple wrapper functions that access QEMU's modern CPU hotplug register
> +  block.
> +
> +  These functions thinly wrap some of the registers described in
> +  "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
> +  via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
> +  return.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef QEMU_CPUHP_H_
> +#define QEMU_CPUHP_H_
> +
> +#include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
> +
> +UINT32
> +QemuCpuhpReadCommandData2 (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  );
> +
> +UINT8
> +QemuCpuhpReadCpuStatus (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  );
> +
> +UINT32
> +QemuCpuhpReadCommandData (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  );
> +
> +VOID
> +QemuCpuhpWriteCpuSelector (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT32                       Selector
> +  );
> +
> +VOID
> +QemuCpuhpWriteCommand (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT8                        Command
> +  );
> +
> +#endif // QEMU_CPUHP_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> new file mode 100644
> index 000000000000..31e46f51934a
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> @@ -0,0 +1,136 @@
> +/** @file
> +  Simple wrapper functions that access QEMU's modern CPU hotplug register
> +  block.
> +
> +  These functions thinly wrap some of the registers described in
> +  "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
> +  via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
> +  return.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
> +#include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
> +#include <Library/BaseLib.h>                 // CpuDeadLoop()
> +#include <Library/DebugLib.h>                // DEBUG()
> +
> +#include "QemuCpuhp.h"
> +
> +UINT32
> +QemuCpuhpReadCommandData2 (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  )
> +{
> +  UINT32     CommandData2;
> +  EFI_STATUS Status;
> +
> +  CommandData2 = 0;
> +  Status = MmCpuIo->Io.Read (
> +                         MmCpuIo,
> +                         MM_IO_UINT32,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_R_CMD_DATA2,
> +                         1,
> +                         &CommandData2
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +  return CommandData2;
> +}
> +
> +UINT8
> +QemuCpuhpReadCpuStatus (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  )
> +{
> +  UINT8      CpuStatus;
> +  EFI_STATUS Status;
> +
> +  CpuStatus = 0;
> +  Status = MmCpuIo->Io.Read (
> +                         MmCpuIo,
> +                         MM_IO_UINT8,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_R_CPU_STAT,
> +                         1,
> +                         &CpuStatus
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +  return CpuStatus;
> +}
> +
> +UINT32
> +QemuCpuhpReadCommandData (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  )
> +{
> +  UINT32     CommandData;
> +  EFI_STATUS Status;
> +
> +  CommandData = 0;
> +  Status = MmCpuIo->Io.Read (
> +                         MmCpuIo,
> +                         MM_IO_UINT32,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_RW_CMD_DATA,
> +                         1,
> +                         &CommandData
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +  return CommandData;
> +}
> +
> +VOID
> +QemuCpuhpWriteCpuSelector (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT32                       Selector
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = MmCpuIo->Io.Write (
> +                         MmCpuIo,
> +                         MM_IO_UINT32,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL,
> +                         1,
> +                         &Selector
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +}
> +
> +VOID
> +QemuCpuhpWriteCommand (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT8                        Command
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = MmCpuIo->Io.Write (
> +                         MmCpuIo,
> +                         MM_IO_UINT8,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
> +                         1,
> +                         &Command
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +}
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups
  2020-02-26 22:11 ` [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups Laszlo Ersek
@ 2020-03-02 13:25   ` Philippe Mathieu-Daudé
  2020-03-02 14:06   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 13:25 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> Sort the [Packages], [LibraryClasses], and [Pcd] sections in the INF file.
> Pad the usage notes (CONSUMES, PRODUCES) in the [Pcd] section.
> 
> Sort the Library #includes in the C file.
> 
> This patch is functionally a no-op.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf | 16 ++++++++--------
>   OvmfPkg/CpuS3DataDxe/CpuS3Data.c      |  4 ++--
>   2 files changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> index 0ad8a0b35d25..f9679e0c33b3 100644
> --- a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> @@ -14,48 +14,48 @@
>   #
>   #  SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
>   ##
>   
>   [Defines]
>     INF_VERSION                    = 1.29
>     BASE_NAME                      = CpuS3DataDxe
>     FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
>     MODULE_TYPE                    = DXE_DRIVER
>     VERSION_STRING                 = 1.0
>     ENTRY_POINT                    = CpuS3DataInitialize
>   
>   # The following information is for reference only and not required by the build
>   # tools.
>   #
>   #  VALID_ARCHITECTURES           = IA32 X64
>   
>   [Sources]
>     CpuS3Data.c
>   
>   [Packages]
> -  MdePkg/MdePkg.dec
>     MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
>     UefiCpuPkg/UefiCpuPkg.dec
>   
>   [LibraryClasses]
> -  UefiDriverEntryPoint
> -  UefiBootServicesTableLib
> +  BaseLib
>     BaseMemoryLib
>     DebugLib
> -  BaseLib
> -  MtrrLib
>     MemoryAllocationLib
> +  MtrrLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
>   
>   [Guids]
>     gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
>   
>   [Protocols]
>     gEfiMpServiceProtocolGuid          ## CONSUMES
>   
>   [Pcd]
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize    ## CONSUMES
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress  ## PRODUCES
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable                    ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize                       ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress                     ## PRODUCES
>   
>   [Depex]
>     gEfiMpServiceProtocolGuid
> diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> index 2bb60d591b1e..8bb9807cd501 100644
> --- a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> @@ -3,48 +3,48 @@ ACPI CPU Data initialization module
>   
>   This module initializes the ACPI_CPU_DATA structure and registers the address
>   of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>   version of this module.  It does not provide a machine check handler or CPU
>   register initialization tables for ACPI S3 resume.  It also only supports the
>   number of CPUs reported by the MP Services Protocol, so this module does not
>   support hot plug CPUs.  This module can be copied into a CPU specific package
>   and customized if these additional features are required.
>   
>   Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
>   Copyright (c) 2015 - 2020, Red Hat, Inc.
>   
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   **/
>   
>   #include <PiDxe.h>
>   
>   #include <AcpiCpuData.h>
>   
>   #include <Library/BaseLib.h>
>   #include <Library/BaseMemoryLib.h>
> -#include <Library/UefiBootServicesTableLib.h>
>   #include <Library/DebugLib.h>
> -#include <Library/MtrrLib.h>
>   #include <Library/MemoryAllocationLib.h>
> +#include <Library/MtrrLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
>   
>   #include <Protocol/MpService.h>
>   #include <Guid/EventGroup.h>
>   
>   //
>   // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
>   //
>   typedef struct {
>     ACPI_CPU_DATA             AcpiCpuData;
>     MTRR_SETTINGS             MtrrTable;
>     IA32_DESCRIPTOR           GdtrProfile;
>     IA32_DESCRIPTOR           IdtrProfile;
>   } ACPI_CPU_DATA_EX;
>   
>   /**
>     Allocate EfiACPIMemoryNVS memory.
>   
>     @param[in] Size   Size of memory to allocate.
>   
>     @return       Allocated address for output.
>   
>   **/
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg
  2020-02-26 22:11 ` [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg Laszlo Ersek
@ 2020-03-02 13:27   ` Ard Biesheuvel
  2020-03-02 13:49   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:27 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Clone the Null instance of SmmCpuPlatformHookLib from UefiCpuPkg to
> OvmfPkg. In this patch, customize the lib instance only with the following
> no-op steps:
>
> - Replace Null/NULL references in filenames and comments with Qemu/QEMU
>   references.
> - Update copyright notices.
> - Clean up and rewrap comment blocks.
> - Update INF_VERSION to the latest INF spec version (1.29).
> - Update FILE_GUID.
> - Drop the UNI file.
>
> This patch is best reviewed with:
>
> $ git show --find-copies=43 --find-copies-harder
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/OvmfPkgIa32.dsc                                                                                                                               |  2 +-
>  OvmfPkg/OvmfPkgIa32X64.dsc                                                                                                                            |  2 +-
>  OvmfPkg/OvmfPkgX64.dsc                                                                                                                                |  2 +-
>  UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf | 21 +++++-------
>  UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c     | 36 ++++++++++++--------
>  5 files changed, 32 insertions(+), 31 deletions(-)
>
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 19728f20b34e..813995fefad8 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -858,45 +858,45 @@ [Components]
>    UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
> -      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>        SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    }
>
>    #
>    # Variable driver stack (SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>    }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>    #
>    # Variable driver stack (non-SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>    OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
>      <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 3c0c229e3a72..a256c7084a7e 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -872,45 +872,45 @@ [Components.X64]
>    UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
> -      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>        SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    }
>
>    #
>    # Variable driver stack (SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>    }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>    #
>    # Variable driver stack (non-SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>    OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
>      <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index f6c1d8d228c6..78079b9f8e13 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -870,45 +870,45 @@ [Components]
>    UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
> -      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>        SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    }
>
>    #
>    # Variable driver stack (SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>    }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>    #
>    # Variable driver stack (non-SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>    OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
>      <LibraryClasses>
> diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> similarity index 43%
> copy from UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> copy to OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> index fab6b30b7a3f..82edeca3d12d 100644
> --- a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> @@ -1,34 +1,29 @@
>  ## @file
> -#  SMM CPU Platform Hook NULL library instance.
> +#  SMM CPU Platform Hook library instance for QEMU.
>  #
> +#  Copyright (c) 2020, Red Hat, Inc.
>  #  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
>  ##
>
> -################################################################################
> -#
> -# Defines Section - statements that will be processed to create a Makefile.
> -#
> -################################################################################
>  [Defines]
> -  INF_VERSION                    = 0x00010005
> -  BASE_NAME                      = SmmCpuPlatformHookLibNull
> -  MODULE_UNI_FILE                = SmmCpuPlatformHookLibNull.uni
> -  FILE_GUID                      = D6494E1B-E06F-4ab5-B64D-48B25AA9EB33
> +  INF_VERSION                    = 1.29
> +  BASE_NAME                      = SmmCpuPlatformHookLibQemu
> +  FILE_GUID                      = 154D6D26-54B8-45BC-BA3A-CBAA20C02A6A
>    MODULE_TYPE                    = DXE_DRIVER
>    VERSION_STRING                 = 1.0
>    LIBRARY_CLASS                  = SmmCpuPlatformHookLib
>
>  #
> -# The following information is for reference only and not required by the build tools.
> +# The following information is for reference only and not required by the build
> +# tools.
>  #
>  #  VALID_ARCHITECTURES           = IA32 X64
>  #
>
>  [Sources]
> -  SmmCpuPlatformHookLibNull.c
> +  SmmCpuPlatformHookLibQemu.c
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
> diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> similarity index 67%
> copy from UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
> copy to OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> index 6c2010dc0a67..257e1d399cc6 100644
> --- a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
> +++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> @@ -1,102 +1,108 @@
>  /** @file
> -SMM CPU Platform Hook NULL library instance.
> +SMM CPU Platform Hook library instance for QEMU.
>
> +Copyright (c) 2020, Red Hat, Inc.
>  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  **/
>  #include <PiSmm.h>
>  #include <Library/SmmCpuPlatformHookLib.h>
>
>  /**
>    Checks if platform produces a valid SMI.
>
>    This function checks if platform produces a valid SMI. This function is
>    called at SMM entry to detect if this is a spurious SMI. This function
>    must be implemented in an MP safe way because it is called by multiple CPU
>    threads.
>
>    @retval TRUE              There is a valid SMI
>    @retval FALSE             There is no valid SMI
>
>  **/
>  BOOLEAN
>  EFIAPI
>  PlatformValidSmi (
>    VOID
>    )
>  {
>    return TRUE;
>  }
>
>  /**
>    Clears platform top level SMI status bit.
>
>    This function clears platform top level SMI status bit.
>
>    @retval TRUE              The platform top level SMI status is cleared.
> -  @retval FALSE             The platform top level SMI status cannot be cleared.
> +  @retval FALSE             The platform top level SMI status cannot be
> +                            cleared.
>
>  **/
>  BOOLEAN
>  EFIAPI
>  ClearTopLevelSmiStatus (
>    VOID
>    )
>  {
>    return TRUE;
>  }
>
>  /**
>    Performs platform specific way of SMM BSP election.
>
>    This function performs platform specific way of SMM BSP election.
>
> -  @param  IsBsp             Output parameter. TRUE: the CPU this function executes
> -                            on is elected to be the SMM BSP. FALSE: the CPU this
> -                            function executes on is to be SMM AP.
> +  @param  IsBsp             Output parameter. TRUE: the CPU this function
> +                            executes on is elected to be the SMM BSP. FALSE:
> +                            the CPU this function executes on is to be SMM AP.
>
>    @retval EFI_SUCCESS       The function executes successfully.
> -  @retval EFI_NOT_READY     The function does not determine whether this CPU should be
> -                            BSP or AP. This may occur if hardware init sequence to
> -                            enable the determination is yet to be done, or the function
> -                            chooses not to do BSP election and will let SMM CPU driver to
> -                            use its default BSP election process.
> -  @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU should be
> -                            BSP or AP due to hardware error.
> +  @retval EFI_NOT_READY     The function does not determine whether this CPU
> +                            should be BSP or AP. This may occur if hardware
> +                            init sequence to enable the determination is yet to
> +                            be done, or the function chooses not to do BSP
> +                            election and will let SMM CPU driver to use its
> +                            default BSP election process.
> +  @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU
> +                            should be BSP or AP due to hardware error.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  PlatformSmmBspElection (
>    OUT BOOLEAN     *IsBsp
>    )
>  {
>    return EFI_NOT_READY;
>  }
>
>  /**
>    Get platform page table attribute.
>
>    This function gets page table attribute of platform.
>
> -  @param  Address        Input parameter. Obtain the page table entries attribute on this address.
> +  @param  Address        Input parameter. Obtain the page table entries
> +                         attribute on this address.
>    @param  PageSize       Output parameter. The size of the page.
>    @param  NumOfPages     Output parameter. Number of page.
>    @param  PageAttribute  Output parameter. Paging Attributes (WB, UC, etc).
>
> -  @retval EFI_SUCCESS      The platform page table attribute from the address is determined.
> -  @retval EFI_UNSUPPORTED  The platform does not support getting page table attribute for the address.
> +  @retval EFI_SUCCESS      The platform page table attribute from the address
> +                           is determined.
> +  @retval EFI_UNSUPPORTED  The platform does not support getting page table
> +                           attribute for the address.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  GetPlatformPageTableAttribute (
>    IN  UINT64                Address,
>    IN OUT SMM_PAGE_SIZE_TYPE *PageSize,
>    IN OUT UINTN              *NumOfPages,
>    IN OUT UINTN              *PageAttribute
>    )
>  {
>    return EFI_UNSUPPORTED;
>  }
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 04/16] OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm
  2020-02-26 22:11 ` [PATCH v2 04/16] OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm Laszlo Ersek
@ 2020-03-02 13:32   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:32 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> With "PcdCpuSmmEnableBspElection" set to FALSE, PiSmmCpuDxeSmm always
> considers the processor with index 0 to be the SMM Monarch (a.k.a. the SMM
> BSP). The SMM Monarch handles the SMI for real, while the other CPUs wait
> in their SMM loops.
>
> In a subsequent patch, we want to set "PcdCpuHotPlugSupport" to TRUE. For
> that, PiCpuSmmEntry() [UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c] forces
> us with an ASSERT() to set "PcdCpuSmmEnableBspElection" to TRUE as well.
> To satisfy that expectation, we can simply remove our current
> "PcdCpuSmmEnableBspElection|FALSE" setting, and inherit the default TRUE
> value from "UefiCpuPkg.dec".
>
> This causes "mSmmMpSyncData->BspIndex" in PiSmmCpuDxeSmm to lose its
> static zero value (standing for CPU#0); instead it becomes (-1) in
> general, and the SMM Monarch is elected anew on every SMI.
>
> The default SMM Monarch Election is basically a race -- whichever CPU can
> flip "mSmmMpSyncData->BspIndex" from (-1) to its own index, becomes king,
> for handling that SMI. Refer to SmiRendezvous()
> [UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c].
>
> I consider this non-determinism less than ideal on QEMU/KVM; it would be
> nice to stick with a "mostly permanent" SMM Monarch even with the Election
> enabled. We can do that by implementing the PlatformSmmBspElection() API
> in the SmmCpuPlatformHookLibQemu instance:
>
> The IA32 APIC Base MSR can be read on each CPU concurrently, and it will
> report the BSP bit as set only on the current Boot Service Processor. QEMU
> marks CPU#0 as the BSP, by default.
>
> Elect the current BSP, as reported by QEMU, for the SMM Monarch role.
>
> (Note that the QEMU commit history is not entirely consistent on whether
> QEMU/KVM may mark a CPU with nonzero index as the BSP:
>
> - At tag v4.2.0, "target/i386/cpu.c" has a comment saying "We hard-wire
>   the BSP to the first CPU". This comment goes back to commit 6cb2996cef5e
>   ("x86: Extend validity of bsp_to_cpu", 2010-03-04).
>
> - Compare commit 9cb11fd7539b ("target-i386: clear bsp bit when
>   designating bsp", 2015-04-02) though, especially considering KVM.
>
> Either way, this OvmfPkg patch is *not* dependent on CPU index 0; it just
> takes the race on every SMI out of the game.)
>
> One benefit of using a "mostly permanent" SMM Monarch / BSP is that we can
> continue testing the SMM CPU synchronization by deterministically entering
> the firmware on the BSP, vs. on an AP, from Linux guests:
>
> $ time taskset -c 0 efibootmgr
> $ time taskset -c 1 efibootmgr
>
> (See
> <https://github.com/tianocore/tianocore.github.io/wiki/Testing-SMM-with-QEMU,-KVM-and-libvirt#uefi-variable-access-test>.)
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Suggested-by: Igor Mammedov <imammedo@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512#c5
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

(I checked the code below versus the intent below, which looks to me
to be in agreement.)

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/OvmfPkgIa32.dsc                                                 | 1 -
>  OvmfPkg/OvmfPkgIa32X64.dsc                                              | 1 -
>  OvmfPkg/OvmfPkgX64.dsc                                                  | 1 -
>  OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf | 3 +++
>  OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c   | 9 ++++++++-
>  5 files changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 813995fefad8..60d8af185b9c 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -414,45 +414,44 @@ [LibraryClasses.common.SMM_CORE]
>  !endif
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>
>  ################################################################################
>  #
>  # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
>  #
>  ################################################################################
>  [PcdsFeatureFlag]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
>  !ifdef $(CSM_ENABLE)
>    gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
>  !endif
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
>  !endif
>
>  [PcdsFixedAtBuild]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
>    gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
>    gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
>  !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
>  !endif
>  !endif
>  !if $(FD_SIZE_IN_KB) == 4096
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
>  !endif
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index a256c7084a7e..be6bc7bd88a7 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -419,45 +419,44 @@ [LibraryClasses.common.SMM_CORE]
>  !endif
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>
>  ################################################################################
>  #
>  # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
>  #
>  ################################################################################
>  [PcdsFeatureFlag]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
>  !ifdef $(CSM_ENABLE)
>    gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
>  !endif
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
>  !endif
>
>  [PcdsFixedAtBuild]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
>    gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
>    gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
>  !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
>  !endif
>  !endif
>  !if $(FD_SIZE_IN_KB) == 4096
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
>  !endif
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 78079b9f8e13..e258c474b60d 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -419,45 +419,44 @@ [LibraryClasses.common.SMM_CORE]
>  !endif
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>
>  ################################################################################
>  #
>  # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
>  #
>  ################################################################################
>  [PcdsFeatureFlag]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
>  !ifdef $(CSM_ENABLE)
>    gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
>  !endif
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
>  !endif
>
>  [PcdsFixedAtBuild]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
>    gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
>    gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
>  !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
>  !endif
>  !endif
>  !if $(FD_SIZE_IN_KB) == 4096
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
>  !endif
> diff --git a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> index 82edeca3d12d..413c56fce6e1 100644
> --- a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> +++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> @@ -8,22 +8,25 @@
>
>  [Defines]
>    INF_VERSION                    = 1.29
>    BASE_NAME                      = SmmCpuPlatformHookLibQemu
>    FILE_GUID                      = 154D6D26-54B8-45BC-BA3A-CBAA20C02A6A
>    MODULE_TYPE                    = DXE_DRIVER
>    VERSION_STRING                 = 1.0
>    LIBRARY_CLASS                  = SmmCpuPlatformHookLib
>
>  #
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  #  VALID_ARCHITECTURES           = IA32 X64
>  #
>
>  [Sources]
>    SmmCpuPlatformHookLibQemu.c
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> diff --git a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> index 257e1d399cc6..c88a95c6deff 100644
> --- a/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> +++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> @@ -1,31 +1,34 @@
>  /** @file
>  SMM CPU Platform Hook library instance for QEMU.
>
>  Copyright (c) 2020, Red Hat, Inc.
>  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  **/
> +#include <Library/BaseLib.h>                 // AsmReadMsr64()
>  #include <PiSmm.h>
> +#include <Register/Intel/ArchitecturalMsr.h> // MSR_IA32_APIC_BASE_REGISTER
> +
>  #include <Library/SmmCpuPlatformHookLib.h>
>
>  /**
>    Checks if platform produces a valid SMI.
>
>    This function checks if platform produces a valid SMI. This function is
>    called at SMM entry to detect if this is a spurious SMI. This function
>    must be implemented in an MP safe way because it is called by multiple CPU
>    threads.
>
>    @retval TRUE              There is a valid SMI
>    @retval FALSE             There is no valid SMI
>
>  **/
>  BOOLEAN
>  EFIAPI
>  PlatformValidSmi (
>    VOID
>    )
>  {
>    return TRUE;
>  }
> @@ -56,45 +59,49 @@ ClearTopLevelSmiStatus (
>
>    @param  IsBsp             Output parameter. TRUE: the CPU this function
>                              executes on is elected to be the SMM BSP. FALSE:
>                              the CPU this function executes on is to be SMM AP.
>
>    @retval EFI_SUCCESS       The function executes successfully.
>    @retval EFI_NOT_READY     The function does not determine whether this CPU
>                              should be BSP or AP. This may occur if hardware
>                              init sequence to enable the determination is yet to
>                              be done, or the function chooses not to do BSP
>                              election and will let SMM CPU driver to use its
>                              default BSP election process.
>    @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU
>                              should be BSP or AP due to hardware error.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  PlatformSmmBspElection (
>    OUT BOOLEAN     *IsBsp
>    )
>  {
> -  return EFI_NOT_READY;
> +  MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
> +
> +  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
> +  *IsBsp = (BOOLEAN)(ApicBaseMsr.Bits.BSP == 1);
> +  return EFI_SUCCESS;
>  }
>
>  /**
>    Get platform page table attribute.
>
>    This function gets page table attribute of platform.
>
>    @param  Address        Input parameter. Obtain the page table entries
>                           attribute on this address.
>    @param  PageSize       Output parameter. The size of the page.
>    @param  NumOfPages     Output parameter. Number of page.
>    @param  PageAttribute  Output parameter. Paging Attributes (WB, UC, etc).
>
>    @retval EFI_SUCCESS      The platform page table attribute from the address
>                             is determined.
>    @retval EFI_UNSUPPORTED  The platform does not support getting page table
>                             attribute for the address.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  GetPlatformPageTableAttribute (
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 05/16] OvmfPkg: enable CPU hotplug support in PiSmmCpuDxeSmm
  2020-02-26 22:11 ` [PATCH v2 05/16] OvmfPkg: enable CPU hotplug support " Laszlo Ersek
@ 2020-03-02 13:33   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:33 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Set "PcdCpuHotPlugSupport" to TRUE, when OVMF is built with SMM_REQUIRE.
> Consequences:
>
> (1) In PiCpuSmmEntry() [UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c],
>     resources are allocated and populated in advance for all possible
>     (i.e., potentially hot-added) processors, rather than only the
>     processors present at boot.
>
>     The possible count (called "mMaxNumberOfCpus") is set from
>     "PcdCpuMaxLogicalProcessorNumber"; we set the latter in
>     OvmfPkg/PlatformPei. (Refer to commit 83357313dd67,
>     "OvmfPkg/PlatformPei: rewrite MaxCpuCountInitialization() for CPU
>     hotplug", 2020-01-29).
>
> (2) The AddProcessor() and RemoveProcessor() member functions of
>     EFI_SMM_CPU_SERVICE_PROTOCOL, implemented in
>     "UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c", are no longer
>     short-circuited to EFI_UNSUPPORTED.
>
>     We'll rely on these functions in the CPU hotplug SMI handler, in a
>     subsequent patch.
>
> (3) In PiCpuSmmEntry(), the address of the CPU_HOT_PLUG_DATA structure (in
>     SMRAM) is exposed via the dynamic-only "PcdCpuHotPlugDataAddress".
>
>     This structure is an information channel between the CPU hotplug SMI
>     handler, and EFI_SMM_CPU_SERVICE_PROTOCOL. Namely, at the first
>     "Index" where the following equality holds:
>
>       CPU_HOT_PLUG_DATA.ApicId[Index] == INVALID_APIC_ID
>
>     a hot-plugged CPU can be accepted, with the steps below:
>
> (3.1) The hotplug SMI handler has to overwrite INVALID_APIC_ID with the
>       new CPU's APIC ID.
>
> (3.2) The new CPU's SMBASE has to be relocated to:
>
>         CPU_HOT_PLUG_DATA.SmBase[Index]
>
>       (which was precomputed in step (1) above).
>
> (3.3) The hotplug SMI handler is supposed to call
>       EFI_SMM_CPU_SERVICE_PROTOCOL.AddProcessor().
>
> Note: we need not spell out "PcdCpuHotPlugDataAddress" in the
> [PcdsDynamicDefault] sections of the OVMF DSC files, just so the PCD
> become dynamically settable. That's because "UefiCpuPkg.dec" declares this
> PCD with [PcdsDynamic, PcdsDynamicEx] access methods *only*.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/OvmfPkgIa32.dsc    | 1 +
>  OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
>  OvmfPkg/OvmfPkgX64.dsc     | 1 +
>  3 files changed, 3 insertions(+)
>
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 60d8af185b9c..8c065ca7cec9 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -414,44 +414,45 @@ [LibraryClasses.common.SMM_CORE]
>  !endif
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>
>  ################################################################################
>  #
>  # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
>  #
>  ################################################################################
>  [PcdsFeatureFlag]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
>  !ifdef $(CSM_ENABLE)
>    gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
>  !endif
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
>  !endif
>
>  [PcdsFixedAtBuild]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
>    gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
>    gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
>  !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
>  !endif
>  !endif
>  !if $(FD_SIZE_IN_KB) == 4096
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
>  !endif
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index be6bc7bd88a7..944b785e61a9 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -419,44 +419,45 @@ [LibraryClasses.common.SMM_CORE]
>  !endif
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>
>  ################################################################################
>  #
>  # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
>  #
>  ################################################################################
>  [PcdsFeatureFlag]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
>  !ifdef $(CSM_ENABLE)
>    gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
>  !endif
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
>  !endif
>
>  [PcdsFixedAtBuild]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
>    gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
>    gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
>  !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
>  !endif
>  !endif
>  !if $(FD_SIZE_IN_KB) == 4096
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
>  !endif
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index e258c474b60d..8de0f7179784 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -419,44 +419,45 @@ [LibraryClasses.common.SMM_CORE]
>  !endif
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>
>  ################################################################################
>  #
>  # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
>  #
>  ################################################################################
>  [PcdsFeatureFlag]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
>  !ifdef $(CSM_ENABLE)
>    gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable|TRUE
>  !endif
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|TRUE
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE
>  !endif
>
>  [PcdsFixedAtBuild]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
>    gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
>    gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
>  !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000
>  !endif
>  !endif
>  !if $(FD_SIZE_IN_KB) == 4096
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400
>  !if $(NETWORK_TLS_ENABLE) == FALSE
>    # match PcdFlashNvStorageVariableSize purely for convenience
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000
>  !endif
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 06/16] OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver
  2020-02-26 22:11 ` [PATCH v2 06/16] OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver Laszlo Ersek
@ 2020-03-02 13:44   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:44 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Add a new SMM driver skeleton that registers a root SMI handler, and
> checks if the SMI control value (written to 0xB2) indicates a CPU hotplug
> SMI.
>
> QEMU's ACPI payload will cause the OS to raise a broadcast SMI when a CPU
> hotplug event occurs, namely by writing value 4 to IO Port 0xB2. In other
> words, control value 4 is now allocated for this purpose; introduce the
> ICH9_APM_CNT_CPU_HOTPLUG macro for it.
>
> The standard identifiers in this driver use the new MM (Management Mode)
> terminology from the PI spec, not the earlier SMM (System Management Mode)
> terms.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>


Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
>  OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
>  OvmfPkg/OvmfPkgX64.dsc                        |   1 +
>  OvmfPkg/OvmfPkgIa32.fdf                       |   1 +
>  OvmfPkg/OvmfPkgIa32X64.fdf                    |   1 +
>  OvmfPkg/OvmfPkgX64.fdf                        |   1 +
>  OvmfPkg/Include/IndustryStandard/Q35MchIch9.h |   5 +-
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf       |  48 +++++
>  OvmfPkg/CpuHotplugSmm/CpuHotplug.c            | 191 ++++++++++++++++++++
>  9 files changed, 248 insertions(+), 2 deletions(-)
>
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 8c065ca7cec9..78310da44a5f 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -851,44 +851,45 @@ [Components]
>
>    OvmfPkg/PlatformDxe/Platform.inf
>    OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>    OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>    OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
>    UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
> +  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
>        SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>        SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    }
>
>    #
>    # Variable driver stack (SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>    }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 944b785e61a9..428578a4f839 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -865,44 +865,45 @@ [Components.X64]
>    OvmfPkg/PlatformDxe/Platform.inf
>    OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>    OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>    OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>    OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
>    UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
> +  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
>        SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>        SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    }
>
>    #
>    # Variable driver stack (SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>    }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 8de0f7179784..73b92f259201 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -863,44 +863,45 @@ [Components]
>    OvmfPkg/PlatformDxe/Platform.inf
>    OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>    OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>    OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>    OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
>    UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
> +  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
>        SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>        SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    }
>
>    #
>    # Variable driver stack (SMM)
>    #
>    OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>    }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
> diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
> index 63607551ed75..61b891765c56 100644
> --- a/OvmfPkg/OvmfPkgIa32.fdf
> +++ b/OvmfPkg/OvmfPkgIa32.fdf
> @@ -301,44 +301,45 @@ [FV.DXEFV]
>  INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>
>  !ifdef $(CSM_ENABLE)
>  INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>  INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>  INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !else
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>  !endif
>
>  INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>  INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>  INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
>  INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> +INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>  INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>  INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>
>  #
>  # Variable driver stack (SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>  #
>  # Variable driver stack (non-SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>  INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>  !endif
> diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
> index 0488e5d95ffe..501b4fcb7b67 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.fdf
> +++ b/OvmfPkg/OvmfPkgIa32X64.fdf
> @@ -308,44 +308,45 @@ [FV.DXEFV]
>  INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>
>  !ifdef $(CSM_ENABLE)
>  INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>  INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>  INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !else
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>  !endif
>
>  INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>  INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>  INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
>  INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> +INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>  INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>  INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>
>  #
>  # Variable driver stack (SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>  #
>  # Variable driver stack (non-SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>  INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>  !endif
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 0488e5d95ffe..501b4fcb7b67 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -308,44 +308,45 @@ [FV.DXEFV]
>  INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>
>  !ifdef $(CSM_ENABLE)
>  INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>  INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>  INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !else
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>  !endif
>
>  INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>  INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>  INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
>  INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> +INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>  INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>  INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>
>  #
>  # Variable driver stack (SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>  #
>  # Variable driver stack (non-SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>  INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>  !endif
> diff --git a/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h b/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
> index cb705fee92ca..73db4b59a111 100644
> --- a/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
> +++ b/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
> @@ -90,37 +90,38 @@
>  #define POWER_MGMT_REGISTER_Q35(Offset) \
>    PCI_LIB_ADDRESS (0, 0x1f, 0, (Offset))
>
>  #define POWER_MGMT_REGISTER_Q35_EFI_PCI_ADDRESS(Offset) \
>    EFI_PCI_ADDRESS (0, 0x1f, 0, (Offset))
>
>  #define ICH9_PMBASE               0x40
>  #define ICH9_PMBASE_MASK            (BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | \
>                                       BIT10 | BIT9  | BIT8  | BIT7)
>
>  #define ICH9_ACPI_CNTL            0x44
>  #define ICH9_ACPI_CNTL_ACPI_EN      BIT7
>
>  #define ICH9_GEN_PMCON_1          0xA0
>  #define ICH9_GEN_PMCON_1_SMI_LOCK   BIT4
>
>  #define ICH9_RCBA                 0xF0
>  #define ICH9_RCBA_EN                BIT0
>
>  //
>  // IO ports
>  //
> -#define ICH9_APM_CNT 0xB2
> -#define ICH9_APM_STS 0xB3
> +#define ICH9_APM_CNT              0xB2
> +#define ICH9_APM_CNT_CPU_HOTPLUG    0x04
> +#define ICH9_APM_STS              0xB3
>
>  #define ICH9_CPU_HOTPLUG_BASE 0x0CD8
>
>  //
>  // IO ports relative to PMBASE
>  //
>  #define ICH9_PMBASE_OFS_SMI_EN 0x30
>  #define ICH9_SMI_EN_APMC_EN      BIT5
>  #define ICH9_SMI_EN_GBL_SMI_EN   BIT0
>
>  #define ICH9_ROOT_COMPLEX_BASE 0xFED1C000
>
>  #endif
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> new file mode 100644
> index 000000000000..fa70858a8dab
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -0,0 +1,48 @@
> +## @file
> +# Root SMI handler for VCPU hotplug SMIs.
> +#
> +# Copyright (c) 2020, Red Hat, Inc.
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +  INF_VERSION                = 1.29
> +  PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
> +  BASE_NAME                  = CpuHotplugSmm
> +  FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
> +  MODULE_TYPE                = DXE_SMM_DRIVER
> +  ENTRY_POINT                = CpuHotplugEntry
> +
> +#
> +# The following information is for reference only and not required by the build
> +# tools.
> +#
> +# VALID_ARCHITECTURES        = IA32 X64
> +#
> +
> +[Sources]
> +  CpuHotplug.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  OvmfPkg/OvmfPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  DebugLib
> +  MmServicesTableLib
> +  PcdLib
> +  UefiDriverEntryPoint
> +
> +[Protocols]
> +  gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
> +
> +[Pcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
> +
> +[FeaturePcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
> +
> +[Depex]
> +  gEfiMmCpuIoProtocolGuid
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> new file mode 100644
> index 000000000000..fd09403eabf3
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> @@ -0,0 +1,191 @@
> +/** @file
> +  Root SMI handler for VCPU hotplug SMIs.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
> +#include <Library/BaseLib.h>                 // CpuDeadLoop()
> +#include <Library/DebugLib.h>                // ASSERT()
> +#include <Library/MmServicesTableLib.h>      // gMmst
> +#include <Library/PcdLib.h>                  // PcdGetBool()
> +#include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
> +#include <Uefi/UefiBaseType.h>               // EFI_STATUS
> +
> +//
> +// We use this protocol for accessing IO Ports.
> +//
> +STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
> +//
> +// Represents the registration of the CPU Hotplug MMI handler.
> +//
> +STATIC EFI_HANDLE mDispatchHandle;
> +
> +
> +/**
> +  CPU Hotplug MMI handler function.
> +
> +  This is a root MMI handler.
> +
> +  @param[in] DispatchHandle      The unique handle assigned to this handler by
> +                                 EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
> +
> +  @param[in] Context             Context passed in by
> +                                 EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
> +                                 CpuHotplugMmi() being a root MMI handler,
> +                                 Context is ASSERT()ed to be NULL.
> +
> +  @param[in,out] CommBuffer      Ignored, due to CpuHotplugMmi() being a root
> +                                 MMI handler.
> +
> +  @param[in,out] CommBufferSize  Ignored, due to CpuHotplugMmi() being a root
> +                                 MMI handler.
> +
> +  @retval EFI_SUCCESS                       The MMI was handled and the MMI
> +                                            source was quiesced. When returned
> +                                            by a non-root MMI handler,
> +                                            EFI_SUCCESS terminates the
> +                                            processing of MMI handlers in
> +                                            EFI_MM_SYSTEM_TABLE.MmiManage().
> +                                            For a root MMI handler (i.e., for
> +                                            the present function too),
> +                                            EFI_SUCCESS behaves identically to
> +                                            EFI_WARN_INTERRUPT_SOURCE_QUIESCED,
> +                                            as further root MMI handlers are
> +                                            going to be called by
> +                                            EFI_MM_SYSTEM_TABLE.MmiManage()
> +                                            anyway.
> +
> +  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The MMI source has been quiesced,
> +                                              but other handlers should still
> +                                              be called.
> +
> +  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The MMI source is still pending,
> +                                              and other handlers should still
> +                                              be called.
> +
> +  @retval EFI_INTERRUPT_PENDING               The MMI source could not be
> +                                              quiesced.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CpuHotplugMmi (
> +  IN EFI_HANDLE DispatchHandle,
> +  IN CONST VOID *Context        OPTIONAL,
> +  IN OUT VOID   *CommBuffer     OPTIONAL,
> +  IN OUT UINTN  *CommBufferSize OPTIONAL
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT8      ApmControl;
> +
> +  //
> +  // Assert that we are entering this function due to our root MMI handler
> +  // registration.
> +  //
> +  ASSERT (DispatchHandle == mDispatchHandle);
> +  //
> +  // When MmiManage() is invoked to process root MMI handlers, the caller (the
> +  // MM Core) is expected to pass in a NULL Context. MmiManage() then passes
> +  // the same NULL Context to individual handlers.
> +  //
> +  ASSERT (Context == NULL);
> +  //
> +  // Read the MMI command value from the APM Control Port, to see if this is an
> +  // MMI we should care about.
> +  //
> +  Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,
> +                          &ApmControl);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,
> +      Status));
> +    //
> +    // We couldn't even determine if the MMI was for us or not.
> +    //
> +    goto Fatal;
> +  }
> +
> +  if (ApmControl != ICH9_APM_CNT_CPU_HOTPLUG) {
> +    //
> +    // The MMI is not for us.
> +    //
> +    return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
> +  }
> +
> +  //
> +  // We've handled this MMI.
> +  //
> +  return EFI_SUCCESS;
> +
> +Fatal:
> +  ASSERT (FALSE);
> +  CpuDeadLoop ();
> +  //
> +  // We couldn't handle this MMI.
> +  //
> +  return EFI_INTERRUPT_PENDING;
> +}
> +
> +
> +//
> +// Entry point function of this driver.
> +//
> +EFI_STATUS
> +EFIAPI
> +CpuHotplugEntry (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  //
> +  // This module should only be included when SMM support is required.
> +  //
> +  ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
> +  //
> +  // This driver depends on the dynamically detected "SMRAM at default SMBASE"
> +  // feature.
> +  //
> +  if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Errors from here on are fatal; we cannot allow the boot to proceed if we
> +  // can't set up this driver to handle CPU hotplug.
> +  //
> +  // First, collect the protocols needed later. All of these protocols are
> +  // listed in our module DEPEX.
> +  //
> +  Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
> +                    NULL /* Registration */, (VOID **)&mMmCpuIo);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
> +    goto Fatal;
> +  }
> +
> +  //
> +  // Register the handler for the CPU Hotplug MMI.
> +  //
> +  Status = gMmst->MmiHandlerRegister (
> +                    CpuHotplugMmi,
> +                    NULL,            // HandlerType: root MMI handler
> +                    &mDispatchHandle
> +                    );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
> +      Status));
> +    goto Fatal;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +Fatal:
> +  ASSERT (FALSE);
> +  CpuDeadLoop ();
> +  return Status;
> +}
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg
  2020-02-26 22:11 ` [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg Laszlo Ersek
@ 2020-03-02 13:44   ` Philippe Mathieu-Daudé
  2020-03-02 14:06   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 13:44 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> The @file comments in UefiCpuPkg/CpuS3DataDxe say,
> 
>    [...] It also only supports the number of CPUs reported by the MP
>    Services Protocol, so this module does not support hot plug CPUs.  This
>    module can be copied into a CPU specific package and customized if these
>    additional features are required. [...]
> 
> The driver is so small that the simplest way to extend it with hotplug
> support is indeed to clone it at first. In this patch, customize the
> driver only with the following no-op steps:
> 
> - Update copyright notices.
> - Update INF_VERSION to the latest INF spec version (1.29).
> - Update FILE_GUID.
> - Drop the UNI files.
> - Replace EFI_D_VERBOSE with DEBUG_VERBOSE, to appease "PatchCheck.py".
> 
> This patch is best reviewed with:
> 
> $ git show --find-copies-harder
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   OvmfPkg/OvmfPkgIa32.dsc                               |  2 +-
>   OvmfPkg/OvmfPkgIa32X64.dsc                            |  2 +-
>   OvmfPkg/OvmfPkgX64.dsc                                |  2 +-
>   OvmfPkg/OvmfPkgIa32.fdf                               |  2 +-
>   OvmfPkg/OvmfPkgIa32X64.fdf                            |  2 +-
>   OvmfPkg/OvmfPkgX64.fdf                                |  2 +-
>   {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf | 10 +++-------
>   {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c      |  4 ++--
>   8 files changed, 11 insertions(+), 15 deletions(-)
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 78310da44a5f..8d8ca746ba03 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -836,45 +836,45 @@ [Components]
>   !endif
>         HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
>         PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
>         BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
>   
>       <PcdsFixedAtBuild>
>         gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
>         gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
>         gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
>     }
>   
>   !if $(SECURE_BOOT_ENABLE) == TRUE
>     SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
>     OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
>   !endif
>   
>     OvmfPkg/PlatformDxe/Platform.inf
>     OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>   
>   !if $(SMM_REQUIRE) == TRUE
>     OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>     OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   
>     #
>     # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   
>     #
>     # SMM_CORE
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   
>     #
>     # Privileged drivers (DXE_SMM_DRIVER modules)
>     #
>     OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>     UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>     MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>       <LibraryClasses>
>         LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>     }
>     UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>       <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 428578a4f839..acba1f80a431 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -850,45 +850,45 @@ [Components.X64]
>         HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
>         PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
>         BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
>   
>       <PcdsFixedAtBuild>
>         gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
>         gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
>         gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
>     }
>   
>   !if $(SECURE_BOOT_ENABLE) == TRUE
>     SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
>     OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
>   !endif
>   
>     OvmfPkg/PlatformDxe/Platform.inf
>     OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>     OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>   
>   !if $(SMM_REQUIRE) == TRUE
>     OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>     OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   
>     #
>     # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   
>     #
>     # SMM_CORE
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   
>     #
>     # Privileged drivers (DXE_SMM_DRIVER modules)
>     #
>     OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>     UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>     MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>       <LibraryClasses>
>         LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>     }
>     UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>       <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 73b92f259201..621b27f80d4b 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -848,45 +848,45 @@ [Components]
>         HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
>         PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
>         BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
>   
>       <PcdsFixedAtBuild>
>         gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
>         gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
>         gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
>     }
>   
>   !if $(SECURE_BOOT_ENABLE) == TRUE
>     SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
>     OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
>   !endif
>   
>     OvmfPkg/PlatformDxe/Platform.inf
>     OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>     OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>   
>   !if $(SMM_REQUIRE) == TRUE
>     OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>     OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   
>     #
>     # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   
>     #
>     # SMM_CORE
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   
>     #
>     # Privileged drivers (DXE_SMM_DRIVER modules)
>     #
>     OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>     UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>     MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>       <LibraryClasses>
>         LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>     }
>     UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>       <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
> index 61b891765c56..004aa318b222 100644
> --- a/OvmfPkg/OvmfPkgIa32.fdf
> +++ b/OvmfPkg/OvmfPkgIa32.fdf
> @@ -298,45 +298,45 @@ [FV.DXEFV]
>   INF  MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
>   INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>   
>   !ifdef $(CSM_ENABLE)
>   INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>   INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>   INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>   !else
>   INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>   !endif
>   
>   INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>   INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>   INF  OvmfPkg/PlatformDxe/Platform.inf
>   INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>   
>   !if $(SMM_REQUIRE) == TRUE
>   INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>   INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>   INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>   INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>   INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>   
>   #
>   # Variable driver stack (SMM)
>   #
>   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>   INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>   INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>   INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>   
>   !else
>   
>   #
>   # Variable driver stack (non-SMM)
>   #
>   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>   INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
> index 501b4fcb7b67..13da8b9dbe65 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.fdf
> +++ b/OvmfPkg/OvmfPkgIa32X64.fdf
> @@ -305,45 +305,45 @@ [FV.DXEFV]
>   INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>   
>   !ifdef $(CSM_ENABLE)
>   INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>   INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>   INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>   !else
>   INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>   !endif
>   
>   INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>   INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>   INF  OvmfPkg/PlatformDxe/Platform.inf
>   INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>   INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>   
>   !if $(SMM_REQUIRE) == TRUE
>   INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>   INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>   INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>   INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>   INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>   
>   #
>   # Variable driver stack (SMM)
>   #
>   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>   INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>   INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>   INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>   
>   !else
>   
>   #
>   # Variable driver stack (non-SMM)
>   #
>   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>   INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 501b4fcb7b67..13da8b9dbe65 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -305,45 +305,45 @@ [FV.DXEFV]
>   INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>   INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>   
>   !ifdef $(CSM_ENABLE)
>   INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>   INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>   INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>   !else
>   INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>   !endif
>   
>   INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>   INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>   INF  OvmfPkg/PlatformDxe/Platform.inf
>   INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>   INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>   
>   !if $(SMM_REQUIRE) == TRUE
>   INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>   INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>   INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>   INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>   INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>   
>   #
>   # Variable driver stack (SMM)
>   #
>   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>   INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>   INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>   INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>   
>   !else
>   
>   #
>   # Variable driver stack (non-SMM)
>   #
>   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>   INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
> diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> similarity index 83%
> copy from UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> copy to OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> index 510133a614ba..0ad8a0b35d25 100644
> --- a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> @@ -1,65 +1,61 @@
>   ## @file
>   #  ACPI CPU Data initialization module
>   #
>   #  This module initializes the ACPI_CPU_DATA structure and registers the address
>   #  of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>   #  version of this module.  It does not provide a machine check handler or CPU
>   #  register initialization tables for ACPI S3 resume.  It also only supports the
>   #  number of CPUs reported by the MP Services Protocol, so this module does not
>   #  support hot plug CPUs.  This module can be copied into a CPU specific package
>   #  and customized if these additional features are required.
>   #
>   #  Copyright (c) 2013-2016, Intel Corporation. All rights reserved.<BR>
> -#  Copyright (c) 2015, Red Hat, Inc.
> +#  Copyright (c) 2015-2020, Red Hat, Inc.
>   #
>   #  SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
>   ##
>   
>   [Defines]
> -  INF_VERSION                    = 0x00010005
> +  INF_VERSION                    = 1.29
>     BASE_NAME                      = CpuS3DataDxe
> -  MODULE_UNI_FILE                = CpuS3DataDxe.uni
> -  FILE_GUID                      = 4D2E57EE-0E3F-44DD-93C4-D3B57E96945D
> +  FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
>     MODULE_TYPE                    = DXE_DRIVER
>     VERSION_STRING                 = 1.0
>     ENTRY_POINT                    = CpuS3DataInitialize
>   
>   # The following information is for reference only and not required by the build
>   # tools.
>   #
>   #  VALID_ARCHITECTURES           = IA32 X64
>   
>   [Sources]
>     CpuS3Data.c
>   
>   [Packages]
>     MdePkg/MdePkg.dec
>     MdeModulePkg/MdeModulePkg.dec
>     UefiCpuPkg/UefiCpuPkg.dec
>   
>   [LibraryClasses]
>     UefiDriverEntryPoint
>     UefiBootServicesTableLib
>     BaseMemoryLib
>     DebugLib
>     BaseLib
>     MtrrLib
>     MemoryAllocationLib
>   
>   [Guids]
>     gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
>   
>   [Protocols]
>     gEfiMpServiceProtocolGuid          ## CONSUMES
>   
>   [Pcd]
>     gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize    ## CONSUMES
>     gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress  ## PRODUCES
>     gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
>   
>   [Depex]
>     gEfiMpServiceProtocolGuid
> -
> -[UserExtensions.TianoCore."ExtraFiles"]
> -  CpuS3DataDxeExtra.uni
> diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> similarity index 96%
> copy from UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
> copy to OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> index 2be335d91903..2bb60d591b1e 100644
> --- a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> @@ -1,35 +1,35 @@
>   /** @file
>   ACPI CPU Data initialization module
>   
>   This module initializes the ACPI_CPU_DATA structure and registers the address
>   of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>   version of this module.  It does not provide a machine check handler or CPU
>   register initialization tables for ACPI S3 resume.  It also only supports the
>   number of CPUs reported by the MP Services Protocol, so this module does not
>   support hot plug CPUs.  This module can be copied into a CPU specific package
>   and customized if these additional features are required.
>   
>   Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
> -Copyright (c) 2015, Red Hat, Inc.
> +Copyright (c) 2015 - 2020, Red Hat, Inc.
>   
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   **/
>   
>   #include <PiDxe.h>
>   
>   #include <AcpiCpuData.h>
>   
>   #include <Library/BaseLib.h>
>   #include <Library/BaseMemoryLib.h>
>   #include <Library/UefiBootServicesTableLib.h>
>   #include <Library/DebugLib.h>
>   #include <Library/MtrrLib.h>
>   #include <Library/MemoryAllocationLib.h>
>   
>   #include <Protocol/MpService.h>
>   #include <Guid/EventGroup.h>
>   
>   //
>   // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
>   //
> @@ -107,45 +107,45 @@ VOID
>   EFIAPI
>   CpuS3DataOnEndOfDxe (
>     IN  EFI_EVENT  Event,
>     OUT VOID       *Context
>     )
>   {
>     EFI_STATUS         Status;
>     ACPI_CPU_DATA_EX   *AcpiCpuDataEx;
>   
>     AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context;
>     //
>     // Allocate a 4KB reserved page below 1MB
>     //
>     AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;
>     Status = gBS->AllocatePages (
>                     AllocateMaxAddress,
>                     EfiReservedMemoryType,
>                     1,
>                     &AcpiCpuDataEx->AcpiCpuData.StartupVector
>                     );
>     ASSERT_EFI_ERROR (Status);
>   
> -  DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));
> +  DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
>     MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
>   
>     //
>     // Close event, so it will not be invoked again.
>     //
>     gBS->CloseEvent (Event);
>   }
>   
>   /**
>      The entry function of the CpuS3Data driver.
>   
>      Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
>      MTRR settings.  Register an event notification on gEfiEndOfDxeEventGroupGuid
>      to capture the ACPI_CPU_DATA MTRR settings.  The PcdCpuS3DataAddress is set
>      to the address that ACPI_CPU_DATA is allocated at.
>   
>      @param[in] ImageHandle  The firmware allocated handle for the EFI image.
>      @param[in] SystemTable  A pointer to the EFI System Table.
>   
>      @retval EFI_SUCCESS     The entry point is executed successfully.
>      @retval EFI_UNSUPPORTED Do not support ACPI S3.
>      @retval other           Some error occurs when executing this entry point.
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions
  2020-02-26 22:11 ` [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions Laszlo Ersek
  2020-03-02 13:24   ` Philippe Mathieu-Daudé
@ 2020-03-02 13:45   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:45 UTC (permalink / raw)
  To: edk2-devel-groups-io, Laszlo Ersek
  Cc: Igor Mammedov, Jiewen Yao, Jordan Justen, Michael Kinney,
	Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Add a handful of simple functions for accessing QEMU's hotplug registers
> more conveniently. These functions thinly wrap some of the registers
> described in "docs/specs/acpi_cpu_hotplug.txt" in the QEMU tree. The
> functions hang (by design) if they encounter an internal failure.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   2 +
>  OvmfPkg/CpuHotplugSmm/QemuCpuhp.h       |  47 +++++++
>  OvmfPkg/CpuHotplugSmm/QemuCpuhp.c       | 136 ++++++++++++++++++++
>  3 files changed, 185 insertions(+)
>
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index fa70858a8dab..ac4ca4c1f4f2 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -4,44 +4,46 @@
>  # Copyright (c) 2020, Red Hat, Inc.
>  #
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  ##
>
>  [Defines]
>    INF_VERSION                = 1.29
>    PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>    BASE_NAME                  = CpuHotplugSmm
>    FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>    MODULE_TYPE                = DXE_SMM_DRIVER
>    ENTRY_POINT                = CpuHotplugEntry
>
>  #
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  # VALID_ARCHITECTURES        = IA32 X64
>  #
>
>  [Sources]
>    CpuHotplug.c
> +  QemuCpuhp.c
> +  QemuCpuhp.h
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    OvmfPkg/OvmfPkg.dec
>
>  [LibraryClasses]
>    BaseLib
>    DebugLib
>    MmServicesTableLib
>    PcdLib
>    UefiDriverEntryPoint
>
>  [Protocols]
>    gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
>
>  [Pcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>
>  [FeaturePcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
>
>  [Depex]
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> new file mode 100644
> index 000000000000..82f88f0b73bb
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> @@ -0,0 +1,47 @@
> +/** @file
> +  Simple wrapper functions that access QEMU's modern CPU hotplug register
> +  block.
> +
> +  These functions thinly wrap some of the registers described in
> +  "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
> +  via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
> +  return.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef QEMU_CPUHP_H_
> +#define QEMU_CPUHP_H_
> +
> +#include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
> +
> +UINT32
> +QemuCpuhpReadCommandData2 (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  );
> +
> +UINT8
> +QemuCpuhpReadCpuStatus (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  );
> +
> +UINT32
> +QemuCpuhpReadCommandData (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  );
> +
> +VOID
> +QemuCpuhpWriteCpuSelector (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT32                       Selector
> +  );
> +
> +VOID
> +QemuCpuhpWriteCommand (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT8                        Command
> +  );
> +
> +#endif // QEMU_CPUHP_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> new file mode 100644
> index 000000000000..31e46f51934a
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> @@ -0,0 +1,136 @@
> +/** @file
> +  Simple wrapper functions that access QEMU's modern CPU hotplug register
> +  block.
> +
> +  These functions thinly wrap some of the registers described in
> +  "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
> +  via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
> +  return.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
> +#include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
> +#include <Library/BaseLib.h>                 // CpuDeadLoop()
> +#include <Library/DebugLib.h>                // DEBUG()
> +
> +#include "QemuCpuhp.h"
> +
> +UINT32
> +QemuCpuhpReadCommandData2 (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  )
> +{
> +  UINT32     CommandData2;
> +  EFI_STATUS Status;
> +
> +  CommandData2 = 0;
> +  Status = MmCpuIo->Io.Read (
> +                         MmCpuIo,
> +                         MM_IO_UINT32,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_R_CMD_DATA2,
> +                         1,
> +                         &CommandData2
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +  return CommandData2;
> +}
> +
> +UINT8
> +QemuCpuhpReadCpuStatus (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  )
> +{
> +  UINT8      CpuStatus;
> +  EFI_STATUS Status;
> +
> +  CpuStatus = 0;
> +  Status = MmCpuIo->Io.Read (
> +                         MmCpuIo,
> +                         MM_IO_UINT8,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_R_CPU_STAT,
> +                         1,
> +                         &CpuStatus
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +  return CpuStatus;
> +}
> +
> +UINT32
> +QemuCpuhpReadCommandData (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
> +  )
> +{
> +  UINT32     CommandData;
> +  EFI_STATUS Status;
> +
> +  CommandData = 0;
> +  Status = MmCpuIo->Io.Read (
> +                         MmCpuIo,
> +                         MM_IO_UINT32,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_RW_CMD_DATA,
> +                         1,
> +                         &CommandData
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +  return CommandData;
> +}
> +
> +VOID
> +QemuCpuhpWriteCpuSelector (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT32                       Selector
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = MmCpuIo->Io.Write (
> +                         MmCpuIo,
> +                         MM_IO_UINT32,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL,
> +                         1,
> +                         &Selector
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +}
> +
> +VOID
> +QemuCpuhpWriteCommand (
> +  IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN UINT8                        Command
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = MmCpuIo->Io.Write (
> +                         MmCpuIo,
> +                         MM_IO_UINT8,
> +                         ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
> +                         1,
> +                         &Command
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
> +    ASSERT (FALSE);
> +    CpuDeadLoop ();
> +  }
> +}
> --
> 2.19.1.3.g30247aa5d201
>
>
>
> 
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro
  2020-02-26 22:11 ` [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro Laszlo Ersek
  2020-03-02 13:22   ` Philippe Mathieu-Daudé
@ 2020-03-02 13:45   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:45 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> QEMU commit 3a61c8db9d25 ("acpi: cpuhp: add CPHP_GET_CPU_ID_CMD command",
> 2020-01-22) introduced a new command in the modern CPU hotplug register
> block that lets the firmware query the arch-specific IDs (on IA32/X64: the
> APIC IDs) of CPUs. Add a macro for this command value, because we'll need
> it later.
>
> At the same time, add a sanity check for the modern hotplug interface to
> CpuHotplugSmm.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |  1 +
>  OvmfPkg/CpuHotplugSmm/CpuHotplug.c                | 35 ++++++++++++++++++++
>  2 files changed, 36 insertions(+)
>
> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> index cf0745610f2c..3d013633501b 100644
> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> @@ -20,24 +20,25 @@
>  #define QEMU_CPU_HOTPLUG_H_
>
>  #include <Base.h>
>
>  //
>  // Each register offset is:
>  // - relative to the board-dependent IO base address of the register block,
>  // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access modes of the
>  //   register,
>  // - followed by distinguished bitmasks or values in the register.
>  //
>  #define QEMU_CPUHP_R_CMD_DATA2               0x0
>
>  #define QEMU_CPUHP_R_CPU_STAT                0x4
>  #define QEMU_CPUHP_STAT_ENABLED                BIT0
>
>  #define QEMU_CPUHP_RW_CMD_DATA               0x8
>
>  #define QEMU_CPUHP_W_CPU_SEL                 0x0
>
>  #define QEMU_CPUHP_W_CMD                     0x5
>  #define QEMU_CPUHP_CMD_GET_PENDING             0x0
> +#define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
>
>  #endif // QEMU_CPU_HOTPLUG_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> index fd09403eabf3..5df8c689c63a 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> @@ -1,38 +1,41 @@
>  /** @file
>    Root SMI handler for VCPU hotplug SMIs.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
>  #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
> +#include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
>  #include <Library/BaseLib.h>                 // CpuDeadLoop()
>  #include <Library/DebugLib.h>                // ASSERT()
>  #include <Library/MmServicesTableLib.h>      // gMmst
>  #include <Library/PcdLib.h>                  // PcdGetBool()
>  #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
>  #include <Uefi/UefiBaseType.h>               // EFI_STATUS
>
> +#include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
> +
>  //
>  // We use this protocol for accessing IO Ports.
>  //
>  STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
>  //
>  // Represents the registration of the CPU Hotplug MMI handler.
>  //
>  STATIC EFI_HANDLE mDispatchHandle;
>
>
>  /**
>    CPU Hotplug MMI handler function.
>
>    This is a root MMI handler.
>
>    @param[in] DispatchHandle      The unique handle assigned to this handler by
>                                   EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
>
>    @param[in] Context             Context passed in by
>                                   EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
>                                   CpuHotplugMmi() being a root MMI handler,
>                                   Context is ASSERT()ed to be NULL.
> @@ -149,43 +152,75 @@ CpuHotplugEntry (
>    //
>    // This driver depends on the dynamically detected "SMRAM at default SMBASE"
>    // feature.
>    //
>    if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
>      return EFI_UNSUPPORTED;
>    }
>
>    //
>    // Errors from here on are fatal; we cannot allow the boot to proceed if we
>    // can't set up this driver to handle CPU hotplug.
>    //
>    // First, collect the protocols needed later. All of these protocols are
>    // listed in our module DEPEX.
>    //
>    Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
>                      NULL /* Registration */, (VOID **)&mMmCpuIo);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
>      goto Fatal;
>    }
>
> +  //
> +  // Sanity-check the CPU hotplug interface.
> +  //
> +  // Both of the following features are part of QEMU 5.0, introduced primarily
> +  // in commit range 3e08b2b9cb64..3a61c8db9d25:
> +  //
> +  // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
> +  //     interface,
> +  //
> +  // (b) the "SMRAM at default SMBASE" feature.
> +  //
> +  // From these, (b) is restricted to 5.0+ machine type versions, while (a)
> +  // does not depend on machine type version. Because we ensured the stricter
> +  // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
> +  // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
> +  // can't verify the presence of precisely that command, we can still verify
> +  // (sanity-check) that the modern interface is active, at least.
> +  //
> +  // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
> +  // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
> +  // following.
> +  //
> +  QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
> +  QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
> +  QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
> +  if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
> +    Status = EFI_NOT_FOUND;
> +    DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
> +      __FUNCTION__, Status));
> +    goto Fatal;
> +  }
> +
>    //
>    // Register the handler for the CPU Hotplug MMI.
>    //
>    Status = gMmst->MmiHandlerRegister (
>                      CpuHotplugMmi,
>                      NULL,            // HandlerType: root MMI handler
>                      &mDispatchHandle
>                      );
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
>        Status));
>      goto Fatal;
>    }
>
>    return EFI_SUCCESS;
>
>  Fatal:
>    ASSERT (FALSE);
>    CpuDeadLoop ();
>    return Status;
>  }
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure
  2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
  2020-03-02 12:47   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-02 13:46   ` Philippe Mathieu-Daudé
  2020-03-03  0:46   ` Dong, Eric
  2 siblings, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 13:46 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney, Ray Ni

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> In the CoreStartImage() function [MdeModulePkg/Core/Dxe/Image/Image.c], if
> the image entry point returns a failure code, then the DXE Core logs a
> helpful DEBUG_ERROR message, with the following format string:
> 
>    "Error: Image at %11p start failed: %r\n"
> 
> Do similarly in the SMM Core (update the message slightly).
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> index 9bec731e5312..76ee9e0b89cc 100644
> --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> @@ -883,44 +883,50 @@ SmmDispatcher (
>         RemoveEntryList (&DriverEntry->ScheduledLink);
>   
>         REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
>           EFI_PROGRESS_CODE,
>           EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
>           &DriverEntry->ImageHandle,
>           sizeof (DriverEntry->ImageHandle)
>           );
>   
>         //
>         // Cache state of SmmEntryPointRegistered before calling entry point
>         //
>         PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
>   
>         //
>         // For each SMM driver, pass NULL as ImageHandle
>         //
>         RegisterSmramProfileImage (DriverEntry, TRUE);
>         PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
>         Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
>         PERF_START_IMAGE_END (DriverEntry->ImageHandle);
>         if (EFI_ERROR(Status)){
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "Error: SMM image at %11p start failed: %r\n",
> +          DriverEntry->SmmLoadedImage.ImageBase,
> +          Status
> +          ));
>           UnregisterSmramProfileImage (DriverEntry, TRUE);
>           SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
>           //
>           // Uninstall LoadedImage
>           //
>           Status = gBS->UninstallProtocolInterface (
>                           DriverEntry->ImageHandle,
>                           &gEfiLoadedImageProtocolGuid,
>                           DriverEntry->LoadedImage
>                           );
>           if (!EFI_ERROR (Status)) {
>             if (DriverEntry->LoadedImage->FilePath != NULL) {
>               gBS->FreePool (DriverEntry->LoadedImage->FilePath);
>             }
>             gBS->FreePool (DriverEntry->LoadedImage);
>           }
>           Status = SmmUninstallProtocolInterface (
>                      DriverEntry->SmmImageHandle,
>                      &gEfiLoadedImageProtocolGuid,
>                      &DriverEntry->SmmLoadedImage
>                      );
>           if (!EFI_ERROR(Status)) {
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg
  2020-02-26 22:11 ` [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg Laszlo Ersek
  2020-03-02 13:27   ` Ard Biesheuvel
@ 2020-03-02 13:49   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 13:49 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> Clone the Null instance of SmmCpuPlatformHookLib from UefiCpuPkg to
> OvmfPkg. In this patch, customize the lib instance only with the following
> no-op steps:
> 
> - Replace Null/NULL references in filenames and comments with Qemu/QEMU
>    references.
> - Update copyright notices.
> - Clean up and rewrap comment blocks.
> - Update INF_VERSION to the latest INF spec version (1.29).
> - Update FILE_GUID.
> - Drop the UNI file.
> 
> This patch is best reviewed with:
> 
> $ git show --find-copies=43 --find-copies-harder
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   OvmfPkg/OvmfPkgIa32.dsc                                                                                                                               |  2 +-
>   OvmfPkg/OvmfPkgIa32X64.dsc                                                                                                                            |  2 +-
>   OvmfPkg/OvmfPkgX64.dsc                                                                                                                                |  2 +-
>   UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf | 21 +++++-------
>   UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c     | 36 ++++++++++++--------
>   5 files changed, 32 insertions(+), 31 deletions(-)
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 19728f20b34e..813995fefad8 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -858,45 +858,45 @@ [Components]
>     UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   
>     #
>     # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   
>     #
>     # SMM_CORE
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   
>     #
>     # Privileged drivers (DXE_SMM_DRIVER modules)
>     #
>     UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>     MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>       <LibraryClasses>
>         LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>     }
>     UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>       <LibraryClasses>
> -      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>         SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>     }
>   
>     #
>     # Variable driver stack (SMM)
>     #
>     OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>     MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>       <LibraryClasses>
>         NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>     }
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>   
>   !else
>   
>     #
>     # Variable driver stack (non-SMM)
>     #
>     OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>     OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
>       <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 3c0c229e3a72..a256c7084a7e 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -872,45 +872,45 @@ [Components.X64]
>     UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   
>     #
>     # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   
>     #
>     # SMM_CORE
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   
>     #
>     # Privileged drivers (DXE_SMM_DRIVER modules)
>     #
>     UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>     MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>       <LibraryClasses>
>         LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>     }
>     UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>       <LibraryClasses>
> -      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>         SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>     }
>   
>     #
>     # Variable driver stack (SMM)
>     #
>     OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>     MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>       <LibraryClasses>
>         NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>     }
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>   
>   !else
>   
>     #
>     # Variable driver stack (non-SMM)
>     #
>     OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>     OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
>       <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index f6c1d8d228c6..78079b9f8e13 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -870,45 +870,45 @@ [Components]
>     UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>   
>     #
>     # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>   
>     #
>     # SMM_CORE
>     #
>     MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>   
>     #
>     # Privileged drivers (DXE_SMM_DRIVER modules)
>     #
>     UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>     MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>       <LibraryClasses>
>         LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>     }
>     UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>       <LibraryClasses>
> -      SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +      SmmCpuPlatformHookLib|OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
>         SmmCpuFeaturesLib|OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>     }
>   
>     #
>     # Variable driver stack (SMM)
>     #
>     OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>     MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
>       <LibraryClasses>
>         NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>     }
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>   
>   !else
>   
>     #
>     # Variable driver stack (non-SMM)
>     #
>     OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>     OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
>       <LibraryClasses>
> diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> similarity index 43%
> copy from UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> copy to OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> index fab6b30b7a3f..82edeca3d12d 100644
> --- a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
> +++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf
> @@ -1,34 +1,29 @@
>   ## @file
> -#  SMM CPU Platform Hook NULL library instance.
> +#  SMM CPU Platform Hook library instance for QEMU.
>   #
> +#  Copyright (c) 2020, Red Hat, Inc.
>   #  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
>   #  SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
>   ##
>   
> -################################################################################
> -#
> -# Defines Section - statements that will be processed to create a Makefile.
> -#
> -################################################################################
>   [Defines]
> -  INF_VERSION                    = 0x00010005
> -  BASE_NAME                      = SmmCpuPlatformHookLibNull
> -  MODULE_UNI_FILE                = SmmCpuPlatformHookLibNull.uni
> -  FILE_GUID                      = D6494E1B-E06F-4ab5-B64D-48B25AA9EB33
> +  INF_VERSION                    = 1.29
> +  BASE_NAME                      = SmmCpuPlatformHookLibQemu
> +  FILE_GUID                      = 154D6D26-54B8-45BC-BA3A-CBAA20C02A6A
>     MODULE_TYPE                    = DXE_DRIVER
>     VERSION_STRING                 = 1.0
>     LIBRARY_CLASS                  = SmmCpuPlatformHookLib
>   
>   #
> -# The following information is for reference only and not required by the build tools.
> +# The following information is for reference only and not required by the build
> +# tools.
>   #
>   #  VALID_ARCHITECTURES           = IA32 X64
>   #
>   
>   [Sources]
> -  SmmCpuPlatformHookLibNull.c
> +  SmmCpuPlatformHookLibQemu.c
>   
>   [Packages]
>     MdePkg/MdePkg.dec
>     UefiCpuPkg/UefiCpuPkg.dec
> diff --git a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> similarity index 67%
> copy from UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
> copy to OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> index 6c2010dc0a67..257e1d399cc6 100644
> --- a/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
> +++ b/OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c
> @@ -1,102 +1,108 @@
>   /** @file
> -SMM CPU Platform Hook NULL library instance.
> +SMM CPU Platform Hook library instance for QEMU.
>   
> +Copyright (c) 2020, Red Hat, Inc.
>   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   **/
>   #include <PiSmm.h>
>   #include <Library/SmmCpuPlatformHookLib.h>
>   
>   /**
>     Checks if platform produces a valid SMI.
>   
>     This function checks if platform produces a valid SMI. This function is
>     called at SMM entry to detect if this is a spurious SMI. This function
>     must be implemented in an MP safe way because it is called by multiple CPU
>     threads.
>   
>     @retval TRUE              There is a valid SMI
>     @retval FALSE             There is no valid SMI
>   
>   **/
>   BOOLEAN
>   EFIAPI
>   PlatformValidSmi (
>     VOID
>     )
>   {
>     return TRUE;
>   }
>   
>   /**
>     Clears platform top level SMI status bit.
>   
>     This function clears platform top level SMI status bit.
>   
>     @retval TRUE              The platform top level SMI status is cleared.
> -  @retval FALSE             The platform top level SMI status cannot be cleared.
> +  @retval FALSE             The platform top level SMI status cannot be
> +                            cleared.
>   
>   **/
>   BOOLEAN
>   EFIAPI
>   ClearTopLevelSmiStatus (
>     VOID
>     )
>   {
>     return TRUE;
>   }
>   
>   /**
>     Performs platform specific way of SMM BSP election.
>   
>     This function performs platform specific way of SMM BSP election.
>   
> -  @param  IsBsp             Output parameter. TRUE: the CPU this function executes
> -                            on is elected to be the SMM BSP. FALSE: the CPU this
> -                            function executes on is to be SMM AP.
> +  @param  IsBsp             Output parameter. TRUE: the CPU this function
> +                            executes on is elected to be the SMM BSP. FALSE:
> +                            the CPU this function executes on is to be SMM AP.
>   
>     @retval EFI_SUCCESS       The function executes successfully.
> -  @retval EFI_NOT_READY     The function does not determine whether this CPU should be
> -                            BSP or AP. This may occur if hardware init sequence to
> -                            enable the determination is yet to be done, or the function
> -                            chooses not to do BSP election and will let SMM CPU driver to
> -                            use its default BSP election process.
> -  @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU should be
> -                            BSP or AP due to hardware error.
> +  @retval EFI_NOT_READY     The function does not determine whether this CPU
> +                            should be BSP or AP. This may occur if hardware
> +                            init sequence to enable the determination is yet to
> +                            be done, or the function chooses not to do BSP
> +                            election and will let SMM CPU driver to use its
> +                            default BSP election process.
> +  @retval EFI_DEVICE_ERROR  The function cannot determine whether this CPU
> +                            should be BSP or AP due to hardware error.
>   
>   **/
>   EFI_STATUS
>   EFIAPI
>   PlatformSmmBspElection (
>     OUT BOOLEAN     *IsBsp
>     )
>   {
>     return EFI_NOT_READY;
>   }
>   
>   /**
>     Get platform page table attribute.
>   
>     This function gets page table attribute of platform.
>   
> -  @param  Address        Input parameter. Obtain the page table entries attribute on this address.
> +  @param  Address        Input parameter. Obtain the page table entries
> +                         attribute on this address.
>     @param  PageSize       Output parameter. The size of the page.
>     @param  NumOfPages     Output parameter. Number of page.
>     @param  PageAttribute  Output parameter. Paging Attributes (WB, UC, etc).
>   
> -  @retval EFI_SUCCESS      The platform page table attribute from the address is determined.
> -  @retval EFI_UNSUPPORTED  The platform does not support getting page table attribute for the address.
> +  @retval EFI_SUCCESS      The platform page table attribute from the address
> +                           is determined.
> +  @retval EFI_UNSUPPORTED  The platform does not support getting page table
> +                           attribute for the address.
>   
>   **/
>   EFI_STATUS
>   EFIAPI
>   GetPlatformPageTableAttribute (
>     IN  UINT64                Address,
>     IN OUT SMM_PAGE_SIZE_TYPE *PageSize,
>     IN OUT UINTN              *NumOfPages,
>     IN OUT UINTN              *PageAttribute
>     )
>   {
>     return EFI_UNSUPPORTED;
>   }
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events
  2020-02-26 22:11 ` [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events Laszlo Ersek
@ 2020-03-02 13:49   ` Ard Biesheuvel
  2020-03-02 20:34   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:49 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Add a function that collects the APIC IDs of CPUs that have just been
> hot-plugged, or are about to be hot-unplugged.
>
> Pending events are only located and never cleared; QEMU's AML needs the
> firmware to leave the status bits intact in the hotplug register block.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |   2 +
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf           |   1 +
>  OvmfPkg/CpuHotplugSmm/ApicId.h                    |  23 +++
>  OvmfPkg/CpuHotplugSmm/QemuCpuhp.h                 |  20 ++-
>  OvmfPkg/CpuHotplugSmm/QemuCpuhp.c                 | 171 +++++++++++++++++++-
>  5 files changed, 211 insertions(+), 6 deletions(-)
>
> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> index 3d013633501b..a34a6d3fae61 100644
> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> @@ -13,32 +13,34 @@
>      The new ("modern") hotplug interface appeared in QEMU v2.7.0.
>
>      The macros in this header file map to the minimal subset of the modern
>      interface that OVMF needs.
>  **/
>
>  #ifndef QEMU_CPU_HOTPLUG_H_
>  #define QEMU_CPU_HOTPLUG_H_
>
>  #include <Base.h>
>
>  //
>  // Each register offset is:
>  // - relative to the board-dependent IO base address of the register block,
>  // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access modes of the
>  //   register,
>  // - followed by distinguished bitmasks or values in the register.
>  //
>  #define QEMU_CPUHP_R_CMD_DATA2               0x0
>
>  #define QEMU_CPUHP_R_CPU_STAT                0x4
>  #define QEMU_CPUHP_STAT_ENABLED                BIT0
> +#define QEMU_CPUHP_STAT_INSERT                 BIT1
> +#define QEMU_CPUHP_STAT_REMOVE                 BIT2
>
>  #define QEMU_CPUHP_RW_CMD_DATA               0x8
>
>  #define QEMU_CPUHP_W_CPU_SEL                 0x0
>
>  #define QEMU_CPUHP_W_CMD                     0x5
>  #define QEMU_CPUHP_CMD_GET_PENDING             0x0
>  #define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
>
>  #endif // QEMU_CPU_HOTPLUG_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index ac4ca4c1f4f2..ab690a9e5e20 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -3,44 +3,45 @@
>  #
>  # Copyright (c) 2020, Red Hat, Inc.
>  #
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  ##
>
>  [Defines]
>    INF_VERSION                = 1.29
>    PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>    BASE_NAME                  = CpuHotplugSmm
>    FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>    MODULE_TYPE                = DXE_SMM_DRIVER
>    ENTRY_POINT                = CpuHotplugEntry
>
>  #
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  # VALID_ARCHITECTURES        = IA32 X64
>  #
>
>  [Sources]
> +  ApicId.h
>    CpuHotplug.c
>    QemuCpuhp.c
>    QemuCpuhp.h
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    OvmfPkg/OvmfPkg.dec
>
>  [LibraryClasses]
>    BaseLib
>    DebugLib
>    MmServicesTableLib
>    PcdLib
>    UefiDriverEntryPoint
>
>  [Protocols]
>    gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
>
>  [Pcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>
>  [FeaturePcd]
> diff --git a/OvmfPkg/CpuHotplugSmm/ApicId.h b/OvmfPkg/CpuHotplugSmm/ApicId.h
> new file mode 100644
> index 000000000000..3c365148ed02
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/ApicId.h
> @@ -0,0 +1,23 @@
> +/** @file
> +  Type and macro definitions for representing and printing APIC IDs, compatibly
> +  with the LocalApicLib and PrintLib classes, respectively.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef APIC_ID_H_
> +#define APIC_ID_H_
> +
> +//
> +// The type that LocalApicLib represents an APIC ID with.
> +//
> +typedef UINT32 APIC_ID;
> +
> +//
> +// The PrintLib conversion specification for formatting an APIC_ID.
> +//
> +#define FMT_APIC_ID "0x%08x"
> +
> +#endif // APIC_ID_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> index 82f88f0b73bb..8adaa0ad91f0 100644
> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> @@ -1,47 +1,61 @@
>  /** @file
> -  Simple wrapper functions that access QEMU's modern CPU hotplug register
> -  block.
> +  Simple wrapper functions and utility functions that access QEMU's modern CPU
> +  hotplug register block.
>
> -  These functions thinly wrap some of the registers described in
> +  These functions manipulate some of the registers described in
>    "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
>    via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
>    return.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
>  #ifndef QEMU_CPUHP_H_
>  #define QEMU_CPUHP_H_
>
>  #include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
> +#include <Uefi/UefiBaseType.h> // EFI_STATUS
> +
> +#include "ApicId.h"            // APIC_ID
>
>  UINT32
>  QemuCpuhpReadCommandData2 (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>    );
>
>  UINT8
>  QemuCpuhpReadCpuStatus (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>    );
>
>  UINT32
>  QemuCpuhpReadCommandData (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>    );
>
>  VOID
>  QemuCpuhpWriteCpuSelector (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>    IN UINT32                       Selector
>    );
>
>  VOID
>  QemuCpuhpWriteCommand (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>    IN UINT8                        Command
>    );
>
> +EFI_STATUS
> +QemuCpuhpCollectApicIds (
> +  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN  UINT32                       PossibleCpuCount,
> +  IN  UINT32                       ApicIdCount,
> +  OUT APIC_ID                      *PluggedApicIds,
> +  OUT UINT32                       *PluggedCount,
> +  OUT APIC_ID                      *ToUnplugApicIds,
> +  OUT UINT32                       *ToUnplugCount
> +  );
> +
>  #endif // QEMU_CPUHP_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> index 31e46f51934a..8d4a6693c8d6 100644
> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> @@ -1,27 +1,27 @@
>  /** @file
> -  Simple wrapper functions that access QEMU's modern CPU hotplug register
> -  block.
> +  Simple wrapper functions and utility functions that access QEMU's modern CPU
> +  hotplug register block.
>
> -  These functions thinly wrap some of the registers described in
> +  These functions manipulate some of the registers described in
>    "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
>    via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
>    return.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
>  #include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
>  #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
>  #include <Library/BaseLib.h>                 // CpuDeadLoop()
>  #include <Library/DebugLib.h>                // DEBUG()
>
>  #include "QemuCpuhp.h"
>
>  UINT32
>  QemuCpuhpReadCommandData2 (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>    )
>  {
>    UINT32     CommandData2;
> @@ -115,22 +115,187 @@ QemuCpuhpWriteCpuSelector (
>
>  VOID
>  QemuCpuhpWriteCommand (
>    IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>    IN UINT8                        Command
>    )
>  {
>    EFI_STATUS Status;
>
>    Status = MmCpuIo->Io.Write (
>                           MmCpuIo,
>                           MM_IO_UINT8,
>                           ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
>                           1,
>                           &Command
>                           );
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
>      ASSERT (FALSE);
>      CpuDeadLoop ();
>    }
>  }
> +
> +/**
> +  Collect the APIC IDs of
> +  - the CPUs that have been hot-plugged,
> +  - the CPUs that are about to be hot-unplugged.
> +
> +  This function only scans for events -- it does not modify them -- in the
> +  hotplug registers.
> +
> +  On error, the contents of the output parameters are undefined.
> +
> +  @param[in] MmCpuIo           The EFI_MM_CPU_IO_PROTOCOL instance for
> +                               accessing IO Ports.
> +
> +  @param[in] PossibleCpuCount  The number of possible CPUs in the system. Must
> +                               be positive.
> +
> +  @param[in] ApicIdCount       The number of elements each one of the
> +                               PluggedApicIds and ToUnplugApicIds arrays can
> +                               accommodate. Must be positive.
> +
> +  @param[out] PluggedApicIds   The APIC IDs of the CPUs that have been
> +                               hot-plugged.
> +
> +  @param[out] PluggedCount     The number of filled-in APIC IDs in
> +                               PluggedApicIds.
> +
> +  @param[out] ToUnplugApicIds  The APIC IDs of the CPUs that are about to be
> +                               hot-unplugged.
> +
> +  @param[out] ToUnplugCount    The number of filled-in APIC IDs in
> +                               ToUnplugApicIds.
> +
> +  @retval EFI_INVALID_PARAMETER  PossibleCpuCount is zero, or ApicIdCount is
> +                                 zero.
> +
> +  @retval EFI_PROTOCOL_ERROR     Invalid bitmap detected in the
> +                                 QEMU_CPUHP_R_CPU_STAT register.
> +
> +  @retval EFI_BUFFER_TOO_SMALL   There was an attempt to place more than
> +                                 ApicIdCount APIC IDs into one of the
> +                                 PluggedApicIds and ToUnplugApicIds arrays.
> +
> +  @retval EFI_SUCCESS            Output parameters have been set successfully.
> +**/
> +EFI_STATUS
> +QemuCpuhpCollectApicIds (
> +  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN  UINT32                       PossibleCpuCount,
> +  IN  UINT32                       ApicIdCount,
> +  OUT APIC_ID                      *PluggedApicIds,
> +  OUT UINT32                       *PluggedCount,
> +  OUT APIC_ID                      *ToUnplugApicIds,
> +  OUT UINT32                       *ToUnplugCount
> +  )
> +{
> +  UINT32 CurrentSelector;
> +
> +  if (PossibleCpuCount == 0 || ApicIdCount == 0) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *PluggedCount = 0;
> +  *ToUnplugCount = 0;
> +
> +  CurrentSelector = 0;
> +  do {
> +    UINT32  PendingSelector;
> +    UINT8   CpuStatus;
> +    APIC_ID *ExtendIds;
> +    UINT32  *ExtendCount;
> +    APIC_ID NewApicId;
> +
> +    //
> +    // Write CurrentSelector (which is valid) to the CPU selector register.
> +    // Consequences:
> +    //
> +    // - Other register accesses will be permitted.
> +    //
> +    // - The QEMU_CPUHP_CMD_GET_PENDING command will start scanning for a CPU
> +    //   with pending events at CurrentSelector (inclusive).
> +    //
> +    QemuCpuhpWriteCpuSelector (MmCpuIo, CurrentSelector);
> +    //
> +    // Write the QEMU_CPUHP_CMD_GET_PENDING command. Consequences
> +    // (independently of each other):
> +    //
> +    // - If there is a CPU with pending events, starting at CurrentSelector
> +    //   (inclusive), the CPU selector will be updated to that CPU. Note that
> +    //   the scanning in QEMU may wrap around, because we must never clear the
> +    //   event bits.
> +    //
> +    // - The QEMU_CPUHP_RW_CMD_DATA register will return the (possibly updated)
> +    //   CPU selector value.
> +    //
> +    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
> +    PendingSelector = QemuCpuhpReadCommandData (MmCpuIo);
> +    if (PendingSelector < CurrentSelector) {
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u PendingSelector=%u: "
> +        "wrap-around\n", __FUNCTION__, CurrentSelector, PendingSelector));
> +      break;
> +    }
> +    CurrentSelector = PendingSelector;
> +
> +    //
> +    // Check the known status / event bits for the currently selected CPU.
> +    //
> +    CpuStatus = QemuCpuhpReadCpuStatus (MmCpuIo);
> +    if ((CpuStatus & QEMU_CPUHP_STAT_INSERT) != 0) {
> +      //
> +      // The "insert" event guarantees the "enabled" status; plus it excludes
> +      // the "remove" event.
> +      //
> +      if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) == 0 ||
> +          (CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
> +        DEBUG ((DEBUG_ERROR, "%a: CurrentSelector=%u CpuStatus=0x%x: "
> +          "inconsistent CPU status\n", __FUNCTION__, CurrentSelector,
> +          CpuStatus));
> +        return EFI_PROTOCOL_ERROR;
> +      }
> +
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: insert\n", __FUNCTION__,
> +        CurrentSelector));
> +
> +      ExtendIds   = PluggedApicIds;
> +      ExtendCount = PluggedCount;
> +    } else if ((CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: remove\n", __FUNCTION__,
> +        CurrentSelector));
> +
> +      ExtendIds   = ToUnplugApicIds;
> +      ExtendCount = ToUnplugCount;
> +    } else {
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: no event\n",
> +        __FUNCTION__, CurrentSelector));
> +      break;
> +    }
> +
> +    //
> +    // Save the APIC ID of the CPU with the pending event, to the corresponding
> +    // APIC ID array.
> +    //
> +    if (*ExtendCount == ApicIdCount) {
> +      DEBUG ((DEBUG_ERROR, "%a: APIC ID array too small\n", __FUNCTION__));
> +      return EFI_BUFFER_TOO_SMALL;
> +    }
> +    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_ARCH_ID);
> +    NewApicId = QemuCpuhpReadCommandData (MmCpuIo);
> +    DEBUG ((DEBUG_VERBOSE, "%a: ApicId=" FMT_APIC_ID "\n", __FUNCTION__,
> +      NewApicId));
> +    ExtendIds[(*ExtendCount)++] = NewApicId;
> +
> +    //
> +    // We've processed the CPU with (known) pending events, but we must never
> +    // clear events. Therefore we need to advance past this CPU manually;
> +    // otherwise, QEMU_CPUHP_CMD_GET_PENDING would stick to the currently
> +    // selected CPU.
> +    //
> +    CurrentSelector++;
> +  } while (CurrentSelector < PossibleCpuCount);
> +
> +  DEBUG ((DEBUG_VERBOSE, "%a: PluggedCount=%u ToUnplugCount=%u\n",
> +    __FUNCTION__, *PluggedCount, *ToUnplugCount));
> +  return EFI_SUCCESS;
> +}
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 10/16] OvmfPkg/CpuHotplugSmm: collect CPUs with events
  2020-02-26 22:11 ` [PATCH v2 10/16] OvmfPkg/CpuHotplugSmm: collect " Laszlo Ersek
@ 2020-03-02 13:58   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 13:58 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Call QemuCpuhpCollectApicIds() in the root MMI handler. The APIC IDs of
> the hotplugged CPUs will be used for several purposes in subsequent
> patches.
>
> For calling QemuCpuhpCollectApicIds(), pre-allocate both of its output
> arrays "PluggedApicIds" and "ToUnplugApicIds" in the driver's entry point
> function. The allocation size is dictated by the possible CPU count, which
> we fetch from "CPU_HOT_PLUG_DATA.ArrayLength".
>
> The CPU_HOT_PLUG_DATA structure in SMRAM is an out-of-band information
> channel between this driver and PiSmmCpuDxeSmm, underlying
> EFI_SMM_CPU_SERVICE_PROTOCOL.
>
> In order to consume "CPU_HOT_PLUG_DATA.ArrayLength", extend the driver's
> DEPEX to EFI_SMM_CPU_SERVICE_PROTOCOL. PiSmmCpuDxeSmm stores the address
> of CPU_HOT_PLUG_DATA to "PcdCpuHotPlugDataAddress", before it produces
> EFI_SMM_CPU_SERVICE_PROTOCOL.
>
> Stash the protocol at once, as it will be needed later.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   7 +-
>  OvmfPkg/CpuHotplugSmm/CpuHotplug.c      | 111 +++++++++++++++++++-
>  2 files changed, 115 insertions(+), 3 deletions(-)
>
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index ab690a9e5e20..31c1ee1c9f6d 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -11,41 +11,46 @@ [Defines]
>    PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>    BASE_NAME                  = CpuHotplugSmm
>    FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>    MODULE_TYPE                = DXE_SMM_DRIVER
>    ENTRY_POINT                = CpuHotplugEntry
>
>  #
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  # VALID_ARCHITECTURES        = IA32 X64
>  #
>
>  [Sources]
>    ApicId.h
>    CpuHotplug.c
>    QemuCpuhp.c
>    QemuCpuhp.h
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    OvmfPkg/OvmfPkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
>
>  [LibraryClasses]
>    BaseLib
>    DebugLib
>    MmServicesTableLib
>    PcdLib
> +  SafeIntLib
>    UefiDriverEntryPoint
>
>  [Protocols]
>    gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
> +  gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES
>
>  [Pcd]
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>
>  [FeaturePcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
>
>  [Depex]
> -  gEfiMmCpuIoProtocolGuid
> +  gEfiMmCpuIoProtocolGuid AND
> +  gEfiSmmCpuServiceProtocolGuid
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> index 5df8c689c63a..42e023cb85c0 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> @@ -1,46 +1,76 @@
>  /** @file
>    Root SMI handler for VCPU hotplug SMIs.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
> +#include <CpuHotPlugData.h>                  // CPU_HOT_PLUG_DATA
>  #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
>  #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
>  #include <Library/BaseLib.h>                 // CpuDeadLoop()
>  #include <Library/DebugLib.h>                // ASSERT()
>  #include <Library/MmServicesTableLib.h>      // gMmst
>  #include <Library/PcdLib.h>                  // PcdGetBool()
> +#include <Library/SafeIntLib.h>              // SafeUintnSub()
>  #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
> +#include <Protocol/SmmCpuService.h>          // EFI_SMM_CPU_SERVICE_PROTOCOL
>  #include <Uefi/UefiBaseType.h>               // EFI_STATUS
>
> +#include "ApicId.h"                          // APIC_ID
>  #include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
>
>  //
>  // We use this protocol for accessing IO Ports.
>  //
>  STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
>  //
> +// The following protocol is used to report the addition or removal of a CPU to
> +// the SMM CPU driver (PiSmmCpuDxeSmm).
> +//
> +STATIC EFI_SMM_CPU_SERVICE_PROTOCOL *mMmCpuService;
> +//
> +// This structure is a communication side-channel between the
> +// EFI_SMM_CPU_SERVICE_PROTOCOL consumer (i.e., this driver) and provider
> +// (i.e., PiSmmCpuDxeSmm).
> +//
> +STATIC CPU_HOT_PLUG_DATA *mCpuHotPlugData;
> +//
> +// SMRAM arrays for fetching the APIC IDs of processors with pending events (of
> +// known event types), for the time of just one MMI.
> +//
> +// The lifetimes of these arrays match that of this driver only because we
> +// don't want to allocate SMRAM at OS runtime, and potentially fail (or
> +// fragment the SMRAM map).
> +//
> +// These arrays provide room for ("possible CPU count" minus one) APIC IDs
> +// each, as we don't expect every possible CPU to appear, or disappear, in a
> +// single MMI. The numbers of used (populated) elements in the arrays are
> +// determined on every MMI separately.
> +//
> +STATIC APIC_ID *mPluggedApicIds;
> +STATIC APIC_ID *mToUnplugApicIds;
> +//
>  // Represents the registration of the CPU Hotplug MMI handler.
>  //
>  STATIC EFI_HANDLE mDispatchHandle;
>
>
>  /**
>    CPU Hotplug MMI handler function.
>
>    This is a root MMI handler.
>
>    @param[in] DispatchHandle      The unique handle assigned to this handler by
>                                   EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
>
>    @param[in] Context             Context passed in by
>                                   EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
>                                   CpuHotplugMmi() being a root MMI handler,
>                                   Context is ASSERT()ed to be NULL.
>
>    @param[in,out] CommBuffer      Ignored, due to CpuHotplugMmi() being a root
>                                   MMI handler.
>
>    @param[in,out] CommBufferSize  Ignored, due to CpuHotplugMmi() being a root
> @@ -65,162 +95,239 @@ STATIC EFI_HANDLE mDispatchHandle;
>                                                but other handlers should still
>                                                be called.
>
>    @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The MMI source is still pending,
>                                                and other handlers should still
>                                                be called.
>
>    @retval EFI_INTERRUPT_PENDING               The MMI source could not be
>                                                quiesced.
>  **/
>  STATIC
>  EFI_STATUS
>  EFIAPI
>  CpuHotplugMmi (
>    IN EFI_HANDLE DispatchHandle,
>    IN CONST VOID *Context        OPTIONAL,
>    IN OUT VOID   *CommBuffer     OPTIONAL,
>    IN OUT UINTN  *CommBufferSize OPTIONAL
>    )
>  {
>    EFI_STATUS Status;
>    UINT8      ApmControl;
> +  UINT32     PluggedCount;
> +  UINT32     ToUnplugCount;
>
>    //
>    // Assert that we are entering this function due to our root MMI handler
>    // registration.
>    //
>    ASSERT (DispatchHandle == mDispatchHandle);
>    //
>    // When MmiManage() is invoked to process root MMI handlers, the caller (the
>    // MM Core) is expected to pass in a NULL Context. MmiManage() then passes
>    // the same NULL Context to individual handlers.
>    //
>    ASSERT (Context == NULL);
>    //
>    // Read the MMI command value from the APM Control Port, to see if this is an
>    // MMI we should care about.
>    //
>    Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,
>                            &ApmControl);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,
>        Status));
>      //
>      // We couldn't even determine if the MMI was for us or not.
>      //
>      goto Fatal;
>    }
>
>    if (ApmControl != ICH9_APM_CNT_CPU_HOTPLUG) {
>      //
>      // The MMI is not for us.
>      //
>      return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
>    }
>
> +  //
> +  // Collect the CPUs with pending events.
> +  //
> +  Status = QemuCpuhpCollectApicIds (
> +             mMmCpuIo,
> +             mCpuHotPlugData->ArrayLength,     // PossibleCpuCount
> +             mCpuHotPlugData->ArrayLength - 1, // ApicIdCount
> +             mPluggedApicIds,
> +             &PluggedCount,
> +             mToUnplugApicIds,
> +             &ToUnplugCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    goto Fatal;
> +  }
> +  if (ToUnplugCount > 0) {
> +    DEBUG ((DEBUG_ERROR, "%a: hot-unplug is not supported yet\n",
> +      __FUNCTION__));
> +    goto Fatal;
> +  }
> +
>    //
>    // We've handled this MMI.
>    //
>    return EFI_SUCCESS;
>
>  Fatal:
>    ASSERT (FALSE);
>    CpuDeadLoop ();
>    //
>    // We couldn't handle this MMI.
>    //
>    return EFI_INTERRUPT_PENDING;
>  }
>
>
>  //
>  // Entry point function of this driver.
>  //
>  EFI_STATUS
>  EFIAPI
>  CpuHotplugEntry (
>    IN EFI_HANDLE       ImageHandle,
>    IN EFI_SYSTEM_TABLE *SystemTable
>    )
>  {
>    EFI_STATUS Status;
> +  UINTN      Size;
>
>    //
>    // This module should only be included when SMM support is required.
>    //
>    ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
>    //
>    // This driver depends on the dynamically detected "SMRAM at default SMBASE"
>    // feature.
>    //
>    if (!PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
>      return EFI_UNSUPPORTED;
>    }
>
>    //
>    // Errors from here on are fatal; we cannot allow the boot to proceed if we
>    // can't set up this driver to handle CPU hotplug.
>    //
>    // First, collect the protocols needed later. All of these protocols are
>    // listed in our module DEPEX.
>    //
>    Status = gMmst->MmLocateProtocol (&gEfiMmCpuIoProtocolGuid,
>                      NULL /* Registration */, (VOID **)&mMmCpuIo);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));
>      goto Fatal;
>    }
> +  Status = gMmst->MmLocateProtocol (&gEfiSmmCpuServiceProtocolGuid,
> +                    NULL /* Registration */, (VOID **)&mMmCpuService);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: locate MmCpuService: %r\n", __FUNCTION__,
> +      Status));
> +    goto Fatal;
> +  }
> +
> +  //
> +  // Our DEPEX on EFI_SMM_CPU_SERVICE_PROTOCOL guarantees that PiSmmCpuDxeSmm
> +  // has pointed PcdCpuHotPlugDataAddress to CPU_HOT_PLUG_DATA in SMRAM.
> +  //
> +  mCpuHotPlugData = (VOID *)(UINTN)PcdGet64 (PcdCpuHotPlugDataAddress);
> +  if (mCpuHotPlugData == NULL) {
> +    Status = EFI_NOT_FOUND;
> +    DEBUG ((DEBUG_ERROR, "%a: CPU_HOT_PLUG_DATA: %r\n", __FUNCTION__, Status));
> +    goto Fatal;
> +  }
> +  //
> +  // If the possible CPU count is 1, there's nothing for this driver to do.
> +  //
> +  if (mCpuHotPlugData->ArrayLength == 1) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  //
> +  // Allocate the data structures that depend on the possible CPU count.
> +  //
> +  if (RETURN_ERROR (SafeUintnSub (mCpuHotPlugData->ArrayLength, 1, &Size)) ||
> +      RETURN_ERROR (SafeUintnMult (sizeof (APIC_ID), Size, &Size))) {
> +    Status = EFI_ABORTED;
> +    DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_PLUG_DATA\n", __FUNCTION__));
> +    goto Fatal;
> +  }
> +  Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
> +                    (VOID **)&mPluggedApicIds);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
> +    goto Fatal;
> +  }
> +  Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
> +                    (VOID **)&mToUnplugApicIds);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
> +    goto ReleasePluggedApicIds;
> +  }
>
>    //
>    // Sanity-check the CPU hotplug interface.
>    //
>    // Both of the following features are part of QEMU 5.0, introduced primarily
>    // in commit range 3e08b2b9cb64..3a61c8db9d25:
>    //
>    // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
>    //     interface,
>    //
>    // (b) the "SMRAM at default SMBASE" feature.
>    //
>    // From these, (b) is restricted to 5.0+ machine type versions, while (a)
>    // does not depend on machine type version. Because we ensured the stricter
>    // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
>    // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
>    // can't verify the presence of precisely that command, we can still verify
>    // (sanity-check) that the modern interface is active, at least.
>    //
>    // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
>    // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
>    // following.
>    //
>    QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
>    QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
>    QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
>    if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
>      Status = EFI_NOT_FOUND;
>      DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
>        __FUNCTION__, Status));
> -    goto Fatal;
> +    goto ReleaseToUnplugApicIds;
>    }
>
>    //
>    // Register the handler for the CPU Hotplug MMI.
>    //
>    Status = gMmst->MmiHandlerRegister (
>                      CpuHotplugMmi,
>                      NULL,            // HandlerType: root MMI handler
>                      &mDispatchHandle
>                      );
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
>        Status));
> -    goto Fatal;
> +    goto ReleaseToUnplugApicIds;
>    }
>
>    return EFI_SUCCESS;
>
> +ReleaseToUnplugApicIds:
> +  gMmst->MmFreePool (mToUnplugApicIds);
> +  mToUnplugApicIds = NULL;
> +
> +ReleasePluggedApicIds:
> +  gMmst->MmFreePool (mPluggedApicIds);
> +  mPluggedApicIds = NULL;
> +
>  Fatal:
>    ASSERT (FALSE);
>    CpuDeadLoop ();
>    return Status;
>  }
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 11/16] OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs
  2020-02-26 22:11 ` [PATCH v2 11/16] OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs Laszlo Ersek
@ 2020-03-02 14:02   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 14:02 UTC (permalink / raw)
  To: edk2-devel-groups-io, Laszlo Ersek
  Cc: Igor Mammedov, Jiewen Yao, Jordan Justen, Michael Kinney,
	Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Once a hot-added CPU finishes the SMBASE relocation, we need to pen it in
> a HLT loop. Add the NASM implementation (with just a handful of
> instructions, but much documentation), and some C language helper
> functions.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>

Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - document the combined approach described here:
>
>       http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>       https://edk2.groups.io/g/devel/message/54754
>
>       by mentioning the "about to leave SMM" byte in SMRAM.
>
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf |   4 +
>  OvmfPkg/CpuHotplugSmm/Smbase.h          |  32 +++++
>  OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm   | 151 ++++++++++++++++++++
>  OvmfPkg/CpuHotplugSmm/Smbase.c          | 110 ++++++++++++++
>  4 files changed, 297 insertions(+)
>
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index 31c1ee1c9f6d..bf4162299c7c 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -5,52 +5,56 @@
>  #
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  ##
>
>  [Defines]
>    INF_VERSION                = 1.29
>    PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>    BASE_NAME                  = CpuHotplugSmm
>    FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>    MODULE_TYPE                = DXE_SMM_DRIVER
>    ENTRY_POINT                = CpuHotplugEntry
>
>  #
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  # VALID_ARCHITECTURES        = IA32 X64
>  #
>
>  [Sources]
>    ApicId.h
>    CpuHotplug.c
> +  PostSmmPen.nasm
>    QemuCpuhp.c
>    QemuCpuhp.h
> +  Smbase.c
> +  Smbase.h
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    OvmfPkg/OvmfPkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
>
>  [LibraryClasses]
>    BaseLib
> +  BaseMemoryLib
>    DebugLib
>    MmServicesTableLib
>    PcdLib
>    SafeIntLib
>    UefiDriverEntryPoint
>
>  [Protocols]
>    gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
>    gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES
>
>  [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>
>  [FeaturePcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
>
>  [Depex]
>    gEfiMmCpuIoProtocolGuid AND
>    gEfiSmmCpuServiceProtocolGuid
> diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.h b/OvmfPkg/CpuHotplugSmm/Smbase.h
> new file mode 100644
> index 000000000000..cb5aed98cdd3
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/Smbase.h
> @@ -0,0 +1,32 @@
> +/** @file
> +  SMBASE relocation for hot-plugged CPUs.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef SMBASE_H_
> +#define SMBASE_H_
> +
> +#include <Uefi/UefiBaseType.h> // EFI_STATUS
> +#include <Uefi/UefiSpec.h>     // EFI_BOOT_SERVICES
> +
> +EFI_STATUS
> +SmbaseAllocatePostSmmPen (
> +  OUT UINT32                  *PenAddress,
> +  IN  CONST EFI_BOOT_SERVICES *BootServices
> +  );
> +
> +VOID
> +SmbaseReinstallPostSmmPen (
> +  IN UINT32 PenAddress
> +  );
> +
> +VOID
> +SmbaseReleasePostSmmPen (
> +  IN UINT32                  PenAddress,
> +  IN CONST EFI_BOOT_SERVICES *BootServices
> +  );
> +
> +#endif // SMBASE_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm b/OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm
> new file mode 100644
> index 000000000000..ef702689bdb5
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm
> @@ -0,0 +1,151 @@
> +;------------------------------------------------------------------------------
> +; @file
> +; Pen any hot-added CPU in a 16-bit, real mode HLT loop, after it leaves SMM by
> +; executing the RSM instruction.
> +;
> +; Copyright (c) 2020, Red Hat, Inc.
> +;
> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> +;
> +; The routine implemented here is stored into normal RAM, under 1MB, at the
> +; beginning of a page that is allocated as EfiReservedMemoryType. On any
> +; hot-added CPU, it is executed after *at least* the first RSM (i.e., after
> +; SMBASE relocation).
> +;
> +; The first execution of this code occurs as follows:
> +;
> +; - The hot-added CPU is in RESET state.
> +;
> +; - The ACPI CPU hotplug event handler triggers a broadcast SMI, from the OS.
> +;
> +; - Existent CPUs (BSP and APs) enter SMM.
> +;
> +; - The hot-added CPU remains in RESET state, but an SMI is pending for it now.
> +;   (See "SYSTEM MANAGEMENT INTERRUPT (SMI)" in the Intel SDM.)
> +;
> +; - In SMM, pre-existent CPUs that are not elected SMM Monarch, keep themselves
> +;   busy with their wait loops.
> +;
> +; - From the root MMI handler, the SMM Monarch:
> +;
> +;   - places this routine in the reserved page,
> +;
> +;   - clears the "about to leave SMM" byte in SMRAM,
> +;
> +;   - clears the last byte of the reserved page,
> +;
> +;   - sends an INIT-SIPI-SIPI sequence to the hot-added CPU,
> +;
> +;   - un-gates the default SMI handler by APIC ID.
> +;
> +; - The startup vector in the SIPI that is sent by the SMM Monarch points to
> +;   this code; i.e., to the reserved page. (Example: 0x9_F000.)
> +;
> +; - The SMM Monarch starts polling the "about to leave SMM" byte in SMRAM.
> +;
> +; - The hot-added CPU boots, and immediately enters SMM due to the pending SMI.
> +;   It starts executing the default SMI handler.
> +;
> +; - Importantly, the SMRAM Save State Map captures the following information,
> +;   when the hot-added CPU enters SMM:
> +;
> +;   - CS selector: assumes the 16 most significant bits of the 20-bit (i.e.,
> +;     below 1MB) startup vector from the SIPI. (Example: 0x9F00.)
> +;
> +;   - CS attributes: Accessed, Readable, User (S=1), CodeSegment (bit#11),
> +;     Present.
> +;
> +;   - CS limit: 0xFFFF.
> +;
> +;   - CS base: the CS selector value shifted left by 4 bits. That is, the CS
> +;     base equals the SIPI startup vector. (Example: 0x9_F000.)
> +;
> +;   - IP: the least significant 4 bits from the SIPI startup vector. Because
> +;     the routine is page-aligned, these bits are zero (hence IP is zero).
> +;
> +;   - ES, SS, DS, FS, GS selectors: 0.
> +;
> +;   - ES, SS, DS, FS, GS attributes: same as the CS attributes, minus
> +;     CodeSegment (bit#11).
> +;
> +;   - ES, SS, DS, FS, GS limits: 0xFFFF.
> +;
> +;   - ES, SS, DS, FS, GS bases: 0.
> +;
> +; - The hot-added CPU sets its new SMBASE value in the SMRAM Save State Map.
> +;
> +; - The hot-added CPU sets the "about to leave SMM" byte in SMRAM, then
> +;   executes the RSM instruction immediately after, leaving SMM.
> +;
> +; - The SMM Monarch notices that the "about to leave SMM" byte in SMRAM has
> +;   been set, and starts polling the last byte in the reserved page.
> +;
> +; - The hot-added CPU jumps ("returns") to the code below (in the reserved
> +;   page), according to the register state listed in the SMRAM Save State Map.
> +;
> +; - The hot-added CPU sets the last byte of the reserved page, then halts
> +;   itself.
> +;
> +; - The SMM Monarch notices that the hot-added CPU is done with SMBASE
> +;   relocation.
> +;
> +; Note that, if the OS is malicious and sends INIT-SIPI-SIPI to the hot-added
> +; CPU before allowing the ACPI CPU hotplug event handler to trigger a broadcast
> +; SMI, then said broadcast SMI will yank the hot-added CPU directly into SMM,
> +; without becoming pending for it (as the hot-added CPU is no longer in RESET
> +; state). This is OK, because:
> +;
> +; - The default SMI handler copes with this, as it is gated by APIC ID. The
> +;   hot-added CPU won't start the actual SMBASE relocation until the SMM
> +;   Monarch lets it.
> +;
> +; - The INIT-SIPI-SIPI sequence that the SMM Monarch sends to the hot-added CPU
> +;   will be ignored in this sate (it won't even be latched). See "SMI HANDLER
> +;   EXECUTION ENVIRONMENT" in the Intel SDM: "INIT operations are inhibited
> +;   when the processor enters SMM".
> +;
> +; - When the hot-added CPU (e.g., CPU#1) executes the RSM (having relocated
> +;   SMBASE), it returns to the OS. The OS can use CPU#1 to attack the last byte
> +;   of the reserved page, while another CPU (e.g., CPU#2) is relocating SMBASE,
> +;   in order to trick the SMM Monarch (e.g., CPU#0) to open the APIC ID gate
> +;   for yet another CPU (e.g., CPU#3). However, the SMM Monarch won't look at
> +;   the last byte of the reserved page, until CPU#2 sets the "about to leave
> +;   SMM" byte in SMRAM. This leaves a very small window (just one instruction's
> +;   worth before the RSM) for CPU#3 to "catch up" with CPU#2, and overwrite
> +;   CPU#2's SMBASE with its own.
> +;
> +; In other words, we do not / need not prevent a malicious OS from booting the
> +; hot-added CPU early; instead we provide benign OSes with a pen for hot-added
> +; CPUs.
> +;------------------------------------------------------------------------------
> +
> +SECTION .data
> +BITS 16
> +
> +GLOBAL ASM_PFX (mPostSmmPen)     ; UINT8[]
> +GLOBAL ASM_PFX (mPostSmmPenSize) ; UINT16
> +
> +ASM_PFX (mPostSmmPen):
> +  ;
> +  ; Point DS at the same reserved page.
> +  ;
> +  mov ax, cs
> +  mov ds, ax
> +
> +  ;
> +  ; Inform the SMM Monarch that we're done with SMBASE relocation, by setting
> +  ; the last byte in the reserved page.
> +  ;
> +  mov byte [ds : word 0xFFF], 1
> +
> +  ;
> +  ; Halt now, until we get woken by another SMI, or (more likely) the OS
> +  ; reboots us with another INIT-SIPI-SIPI.
> +  ;
> +HltLoop:
> +  cli
> +  hlt
> +  jmp HltLoop
> +
> +ASM_PFX (mPostSmmPenSize):
> +  dw $ - ASM_PFX (mPostSmmPen)
> diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.c b/OvmfPkg/CpuHotplugSmm/Smbase.c
> new file mode 100644
> index 000000000000..ea21153d9145
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/Smbase.c
> @@ -0,0 +1,110 @@
> +/** @file
> +  SMBASE relocation for hot-plugged CPUs.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>                             // BASE_1MB
> +#include <Library/BaseMemoryLib.h>            // CopyMem()
> +#include <Library/DebugLib.h>                 // DEBUG()
> +
> +#include "Smbase.h"
> +
> +extern CONST UINT8 mPostSmmPen[];
> +extern CONST UINT16 mPostSmmPenSize;
> +
> +/**
> +  Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot-added
> +  CPUs.
> +
> +  This function may only be called from the entry point function of the driver.
> +
> +  @param[out] PenAddress   The address of the allocated (normal RAM) reserved
> +                           page.
> +
> +  @param[in] BootServices  Pointer to the UEFI boot services table. Used for
> +                           allocating the normal RAM (not SMRAM) reserved page.
> +
> +  @retval EFI_SUCCESS          Allocation successful.
> +
> +  @retval EFI_BAD_BUFFER_SIZE  The Post-SMM Pen template is not smaller than
> +                               EFI_PAGE_SIZE.
> +
> +  @return                      Error codes propagated from underlying services.
> +                               DEBUG_ERROR messages have been logged. No
> +                               resources have been allocated.
> +**/
> +EFI_STATUS
> +SmbaseAllocatePostSmmPen (
> +  OUT UINT32                  *PenAddress,
> +  IN  CONST EFI_BOOT_SERVICES *BootServices
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EFI_PHYSICAL_ADDRESS Address;
> +
> +  //
> +  // The pen code must fit in one page, and the last byte must remain free for
> +  // signaling the SMM Monarch.
> +  //
> +  if (mPostSmmPenSize >= EFI_PAGE_SIZE) {
> +    Status = EFI_BAD_BUFFER_SIZE;
> +    DEBUG ((DEBUG_ERROR, "%a: mPostSmmPenSize=%u: %r\n", __FUNCTION__,
> +      mPostSmmPenSize, Status));
> +    return Status;
> +  }
> +
> +  Address = BASE_1MB - 1;
> +  Status = BootServices->AllocatePages (AllocateMaxAddress,
> +                           EfiReservedMemoryType, 1, &Address);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: AllocatePages(): %r\n", __FUNCTION__, Status));
> +    return Status;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "%a: Post-SMM Pen at 0x%Lx\n", __FUNCTION__, Address));
> +  *PenAddress = (UINT32)Address;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Copy the Post-SMM Pen template code into the reserved page allocated with
> +  SmbaseAllocatePostSmmPen().
> +
> +  Note that this effects an "SMRAM to normal RAM" copy.
> +
> +  The SMM Monarch is supposed to call this function from the root MMI handler.
> +
> +  @param[in] PenAddress  The allocation address returned by
> +                         SmbaseAllocatePostSmmPen().
> +**/
> +VOID
> +SmbaseReinstallPostSmmPen (
> +  IN UINT32 PenAddress
> +  )
> +{
> +  CopyMem ((VOID *)(UINTN)PenAddress, mPostSmmPen, mPostSmmPenSize);
> +}
> +
> +/**
> +  Release the reserved page allocated with SmbaseAllocatePostSmmPen().
> +
> +  This function may only be called from the entry point function of the driver,
> +  on the error path.
> +
> +  @param[in] PenAddress    The allocation address returned by
> +                           SmbaseAllocatePostSmmPen().
> +
> +  @param[in] BootServices  Pointer to the UEFI boot services table. Used for
> +                           releasing the normal RAM (not SMRAM) reserved page.
> +**/
> +VOID
> +SmbaseReleasePostSmmPen (
> +  IN UINT32                  PenAddress,
> +  IN CONST EFI_BOOT_SERVICES *BootServices
> +  )
> +{
> +  BootServices->FreePages (PenAddress, 1);
> +}
> --
> 2.19.1.3.g30247aa5d201
>
>
>
> 
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler for hot-added CPUs
  2020-02-26 22:11 ` [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler " Laszlo Ersek
@ 2020-03-02 14:03   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 14:03 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Implement the First SMI Handler for hot-added CPUs, in NASM.
>
> Add the interfacing C-language function that the SMM Monarch calls. This
> function launches and coordinates SMBASE relocation for a hot-added CPU.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>

Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - implement the combined approach described here:
>
>       http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>       https://edk2.groups.io/g/devel/message/54754
>
>       by introducing "FIRST_SMI_HANDLER_CONTEXT.AboutToLeaveSmm".
>
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf        |   4 +
>  OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h |  47 ++++++
>  OvmfPkg/CpuHotplugSmm/Smbase.h                 |  14 ++
>  OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm     | 154 +++++++++++++++++++
>  OvmfPkg/CpuHotplugSmm/Smbase.c                 | 157 ++++++++++++++++++++
>  5 files changed, 376 insertions(+)
>
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index bf4162299c7c..04322b0d7855 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -5,56 +5,60 @@
>  #
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  ##
>
>  [Defines]
>    INF_VERSION                = 1.29
>    PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>    BASE_NAME                  = CpuHotplugSmm
>    FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>    MODULE_TYPE                = DXE_SMM_DRIVER
>    ENTRY_POINT                = CpuHotplugEntry
>
>  #
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  # VALID_ARCHITECTURES        = IA32 X64
>  #
>
>  [Sources]
>    ApicId.h
>    CpuHotplug.c
> +  FirstSmiHandler.nasm
> +  FirstSmiHandlerContext.h
>    PostSmmPen.nasm
>    QemuCpuhp.c
>    QemuCpuhp.h
>    Smbase.c
>    Smbase.h
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    OvmfPkg/OvmfPkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
>
>  [LibraryClasses]
>    BaseLib
>    BaseMemoryLib
>    DebugLib
> +  LocalApicLib
>    MmServicesTableLib
>    PcdLib
>    SafeIntLib
> +  SynchronizationLib
>    UefiDriverEntryPoint
>
>  [Protocols]
>    gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
>    gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES
>
>  [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>
>  [FeaturePcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES
>
>  [Depex]
>    gEfiMmCpuIoProtocolGuid AND
>    gEfiSmmCpuServiceProtocolGuid
> diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h b/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h
> new file mode 100644
> index 000000000000..029de4cdea35
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h
> @@ -0,0 +1,47 @@
> +/** @file
> +  Define the FIRST_SMI_HANDLER_CONTEXT structure, which is an exchange area
> +  between the SMM Monarch and the hot-added CPU, for relocating the SMBASE of
> +  the hot-added CPU.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef FIRST_SMI_HANDLER_CONTEXT_H_
> +#define FIRST_SMI_HANDLER_CONTEXT_H_
> +
> +//
> +// The following structure is used to communicate between the SMM Monarch
> +// (running the root MMI handler) and the hot-added CPU (handling its first
> +// SMI). It is placed at SMM_DEFAULT_SMBASE, which is in SMRAM under QEMU's
> +// "SMRAM at default SMBASE" feature.
> +//
> +#pragma pack (1)
> +typedef struct {
> +  //
> +  // When ApicIdGate is MAX_UINT64, then no hot-added CPU may proceed with
> +  // SMBASE relocation.
> +  //
> +  // Otherwise, the hot-added CPU whose APIC ID equals ApicIdGate may proceed
> +  // with SMBASE relocation.
> +  //
> +  // This field is intentionally wider than APIC_ID (UINT32) because we need a
> +  // "gate locked" value that is different from all possible APIC_IDs.
> +  //
> +  UINT64 ApicIdGate;
> +  //
> +  // The new SMBASE value for the hot-added CPU to set in the SMRAM Save State
> +  // Map, before leaving SMM with the RSM instruction.
> +  //
> +  UINT32 NewSmbase;
> +  //
> +  // The hot-added CPU sets this field to 1 right before executing the RSM
> +  // instruction. This tells the SMM Monarch to proceed to polling the last
> +  // byte of the normal RAM reserved page (Post-SMM Pen).
> +  //
> +  UINT8 AboutToLeaveSmm;
> +} FIRST_SMI_HANDLER_CONTEXT;
> +#pragma pack ()
> +
> +#endif // FIRST_SMI_HANDLER_CONTEXT_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.h b/OvmfPkg/CpuHotplugSmm/Smbase.h
> index cb5aed98cdd3..e73730d19926 100644
> --- a/OvmfPkg/CpuHotplugSmm/Smbase.h
> +++ b/OvmfPkg/CpuHotplugSmm/Smbase.h
> @@ -1,32 +1,46 @@
>  /** @file
>    SMBASE relocation for hot-plugged CPUs.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
>  #ifndef SMBASE_H_
>  #define SMBASE_H_
>
>  #include <Uefi/UefiBaseType.h> // EFI_STATUS
>  #include <Uefi/UefiSpec.h>     // EFI_BOOT_SERVICES
>
> +#include "ApicId.h"            // APIC_ID
> +
>  EFI_STATUS
>  SmbaseAllocatePostSmmPen (
>    OUT UINT32                  *PenAddress,
>    IN  CONST EFI_BOOT_SERVICES *BootServices
>    );
>
>  VOID
>  SmbaseReinstallPostSmmPen (
>    IN UINT32 PenAddress
>    );
>
>  VOID
>  SmbaseReleasePostSmmPen (
>    IN UINT32                  PenAddress,
>    IN CONST EFI_BOOT_SERVICES *BootServices
>    );
>
> +VOID
> +SmbaseInstallFirstSmiHandler (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +SmbaseRelocate (
> +  IN APIC_ID ApicId,
> +  IN UINTN   Smbase,
> +  IN UINT32  PenAddress
> +  );
> +
>  #endif // SMBASE_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm b/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm
> new file mode 100644
> index 000000000000..5399b5fa4387
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm
> @@ -0,0 +1,154 @@
> +;------------------------------------------------------------------------------
> +; @file
> +; Relocate the SMBASE on a hot-added CPU when it services its first SMI.
> +;
> +; Copyright (c) 2020, Red Hat, Inc.
> +;
> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> +;
> +; The routine runs on the hot-added CPU in the following "big real mode",
> +; 16-bit environment; per "SMI HANDLER EXECUTION ENVIRONMENT" in the Intel SDM
> +; (table "Processor Register Initialization in SMM"):
> +;
> +;  - CS selector: 0x3000 (most significant 16 bits of SMM_DEFAULT_SMBASE).
> +;
> +;  - CS limit: 0xFFFF_FFFF.
> +;
> +;  - CS base: SMM_DEFAULT_SMBASE (0x3_0000).
> +;
> +;  - IP: SMM_HANDLER_OFFSET (0x8000).
> +;
> +;  - ES, SS, DS, FS, GS selectors: 0.
> +;
> +;  - ES, SS, DS, FS, GS limits: 0xFFFF_FFFF.
> +;
> +;  - ES, SS, DS, FS, GS bases: 0.
> +;
> +;  - Operand-size and address-size override prefixes can be used to access the
> +;    address space beyond 1MB.
> +;------------------------------------------------------------------------------
> +
> +SECTION .data
> +BITS 16
> +
> +;
> +; Bring in SMM_DEFAULT_SMBASE from
> +; "MdePkg/Include/Register/Intel/SmramSaveStateMap.h".
> +;
> +SMM_DEFAULT_SMBASE: equ 0x3_0000
> +
> +;
> +; Field offsets in FIRST_SMI_HANDLER_CONTEXT, which resides at
> +; SMM_DEFAULT_SMBASE.
> +;
> +ApicIdGate:      equ  0 ; UINT64
> +NewSmbase:       equ  8 ; UINT32
> +AboutToLeaveSmm: equ 12 ; UINT8
> +
> +;
> +; SMRAM Save State Map field offsets, per the AMD (not Intel) layout that QEMU
> +; implements. Relative to SMM_DEFAULT_SMBASE.
> +;
> +SaveStateRevId:    equ 0xFEFC ; UINT32
> +SaveStateSmbase:   equ 0xFEF8 ; UINT32
> +SaveStateSmbase64: equ 0xFF00 ; UINT32
> +
> +;
> +; CPUID constants, from "MdePkg/Include/Register/Intel/Cpuid.h".
> +;
> +CPUID_SIGNATURE:         equ 0x00
> +CPUID_EXTENDED_TOPOLOGY: equ 0x0B
> +CPUID_VERSION_INFO:      equ 0x01
> +
> +GLOBAL ASM_PFX (mFirstSmiHandler)     ; UINT8[]
> +GLOBAL ASM_PFX (mFirstSmiHandlerSize) ; UINT16
> +
> +ASM_PFX (mFirstSmiHandler):
> +  ;
> +  ; Get our own APIC ID first, so we can contend for ApicIdGate.
> +  ;
> +  ; This basically reimplements GetInitialApicId() from
> +  ; "UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c".
> +  ;
> +  mov eax, CPUID_SIGNATURE
> +  cpuid
> +  cmp eax, CPUID_EXTENDED_TOPOLOGY
> +  jb GetApicIdFromVersionInfo
> +
> +  mov eax, CPUID_EXTENDED_TOPOLOGY
> +  mov ecx, 0
> +  cpuid
> +  test ebx, 0xFFFF
> +  jz GetApicIdFromVersionInfo
> +
> +  ;
> +  ; EDX has the APIC ID, save it to ESI.
> +  ;
> +  mov esi, edx
> +  jmp KnockOnGate
> +
> +GetApicIdFromVersionInfo:
> +  mov eax, CPUID_VERSION_INFO
> +  cpuid
> +  shr ebx, 24
> +  ;
> +  ; EBX has the APIC ID, save it to ESI.
> +  ;
> +  mov esi, ebx
> +
> +KnockOnGate:
> +  ;
> +  ; See if ApicIdGate shows our own APIC ID. If so, swap it to MAX_UINT64
> +  ; (close the gate), and advance. Otherwise, keep knocking.
> +  ;
> +  ; InterlockedCompareExchange64():
> +  ; - Value                   := &FIRST_SMI_HANDLER_CONTEXT.ApicIdGate
> +  ; - CompareValue  (EDX:EAX) := APIC ID (from ESI)
> +  ; - ExchangeValue (ECX:EBX) := MAX_UINT64
> +  ;
> +  mov edx, 0
> +  mov eax, esi
> +  mov ecx, 0xFFFF_FFFF
> +  mov ebx, 0xFFFF_FFFF
> +  lock cmpxchg8b [ds : dword (SMM_DEFAULT_SMBASE + ApicIdGate)]
> +  jz ApicIdMatch
> +  pause
> +  jmp KnockOnGate
> +
> +ApicIdMatch:
> +  ;
> +  ; Update the SMBASE field in the SMRAM Save State Map.
> +  ;
> +  ; First, calculate the address of the SMBASE field, based on the SMM Revision
> +  ; ID; store the result in EBX.
> +  ;
> +  mov eax, dword [ds : dword (SMM_DEFAULT_SMBASE + SaveStateRevId)]
> +  test eax, 0xFFFF
> +  jz LegacySaveStateMap
> +
> +  mov ebx, SMM_DEFAULT_SMBASE + SaveStateSmbase64
> +  jmp UpdateSmbase
> +
> +LegacySaveStateMap:
> +  mov ebx, SMM_DEFAULT_SMBASE + SaveStateSmbase
> +
> +UpdateSmbase:
> +  ;
> +  ; Load the new SMBASE value into EAX.
> +  ;
> +  mov eax, dword [ds : dword (SMM_DEFAULT_SMBASE + NewSmbase)]
> +  ;
> +  ; Save it to the SMBASE field whose address we calculated in EBX.
> +  ;
> +  mov dword [ds : dword ebx], eax
> +  ;
> +  ; Set AboutToLeaveSmm.
> +  ;
> +  mov byte [ds : dword (SMM_DEFAULT_SMBASE + AboutToLeaveSmm)], 1
> +  ;
> +  ; We're done; leave SMM and continue to the pen.
> +  ;
> +  rsm
> +
> +ASM_PFX (mFirstSmiHandlerSize):
> +  dw $ - ASM_PFX (mFirstSmiHandler)
> diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.c b/OvmfPkg/CpuHotplugSmm/Smbase.c
> index ea21153d9145..170571221d84 100644
> --- a/OvmfPkg/CpuHotplugSmm/Smbase.c
> +++ b/OvmfPkg/CpuHotplugSmm/Smbase.c
> @@ -1,38 +1,46 @@
>  /** @file
>    SMBASE relocation for hot-plugged CPUs.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
>  #include <Base.h>                             // BASE_1MB
> +#include <Library/BaseLib.h>                  // CpuPause()
>  #include <Library/BaseMemoryLib.h>            // CopyMem()
>  #include <Library/DebugLib.h>                 // DEBUG()
> +#include <Library/LocalApicLib.h>             // SendInitSipiSipi()
> +#include <Library/SynchronizationLib.h>       // InterlockedCompareExchange64()
> +#include <Register/Intel/SmramSaveStateMap.h> // SMM_DEFAULT_SMBASE
> +
> +#include "FirstSmiHandlerContext.h"           // FIRST_SMI_HANDLER_CONTEXT
>
>  #include "Smbase.h"
>
>  extern CONST UINT8 mPostSmmPen[];
>  extern CONST UINT16 mPostSmmPenSize;
> +extern CONST UINT8 mFirstSmiHandler[];
> +extern CONST UINT16 mFirstSmiHandlerSize;
>
>  /**
>    Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot-added
>    CPUs.
>
>    This function may only be called from the entry point function of the driver.
>
>    @param[out] PenAddress   The address of the allocated (normal RAM) reserved
>                             page.
>
>    @param[in] BootServices  Pointer to the UEFI boot services table. Used for
>                             allocating the normal RAM (not SMRAM) reserved page.
>
>    @retval EFI_SUCCESS          Allocation successful.
>
>    @retval EFI_BAD_BUFFER_SIZE  The Post-SMM Pen template is not smaller than
>                                 EFI_PAGE_SIZE.
>
>    @return                      Error codes propagated from underlying services.
>                                 DEBUG_ERROR messages have been logged. No
>                                 resources have been allocated.
>  **/
> @@ -89,22 +97,171 @@ SmbaseReinstallPostSmmPen (
>  }
>
>  /**
>    Release the reserved page allocated with SmbaseAllocatePostSmmPen().
>
>    This function may only be called from the entry point function of the driver,
>    on the error path.
>
>    @param[in] PenAddress    The allocation address returned by
>                             SmbaseAllocatePostSmmPen().
>
>    @param[in] BootServices  Pointer to the UEFI boot services table. Used for
>                             releasing the normal RAM (not SMRAM) reserved page.
>  **/
>  VOID
>  SmbaseReleasePostSmmPen (
>    IN UINT32                  PenAddress,
>    IN CONST EFI_BOOT_SERVICES *BootServices
>    )
>  {
>    BootServices->FreePages (PenAddress, 1);
>  }
> +
> +/**
> +  Place the handler routine for the first SMIs of hot-added CPUs at
> +  (SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET).
> +
> +  Note that this effects an "SMRAM to SMRAM" copy.
> +
> +  Additionally, shut the APIC ID gate in FIRST_SMI_HANDLER_CONTEXT.
> +
> +  This function may only be called from the entry point function of the driver,
> +  and only after PcdQ35SmramAtDefaultSmbase has been determined to be TRUE.
> +**/
> +VOID
> +SmbaseInstallFirstSmiHandler (
> +  VOID
> +  )
> +{
> +  FIRST_SMI_HANDLER_CONTEXT *Context;
> +
> +  CopyMem ((VOID *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET),
> +    mFirstSmiHandler, mFirstSmiHandlerSize);
> +
> +  Context = (VOID *)(UINTN)SMM_DEFAULT_SMBASE;
> +  Context->ApicIdGate = MAX_UINT64;
> +}
> +
> +/**
> +  Relocate the SMBASE on a hot-added CPU. Then pen the hot-added CPU in the
> +  normal RAM reserved memory page, set up earlier with
> +  SmbaseAllocatePostSmmPen() and SmbaseReinstallPostSmmPen().
> +
> +  The SMM Monarch is supposed to call this function from the root MMI handler.
> +
> +  The SMM Monarch is responsible for calling SmbaseInstallFirstSmiHandler(),
> +  SmbaseAllocatePostSmmPen(), and SmbaseReinstallPostSmmPen() before calling
> +  this function.
> +
> +  If the OS maliciously boots the hot-added CPU ahead of letting the ACPI CPU
> +  hotplug event handler broadcast the CPU hotplug MMI, then the hot-added CPU
> +  returns to the OS rather than to the pen, upon RSM. In that case, this
> +  function will hang forever (unless the OS happens to signal back through the
> +  last byte of the pen page).
> +
> +  @param[in] ApicId      The APIC ID of the hot-added CPU whose SMBASE should
> +                         be relocated.
> +
> +  @param[in] Smbase      The new SMBASE address. The root MMI handler is
> +                         responsible for passing in a free ("unoccupied")
> +                         SMBASE address that was pre-configured by
> +                         PiSmmCpuDxeSmm in CPU_HOT_PLUG_DATA.
> +
> +  @param[in] PenAddress  The address of the Post-SMM Pen for hot-added CPUs, as
> +                         returned by SmbaseAllocatePostSmmPen(), and installed
> +                         by SmbaseReinstallPostSmmPen().
> +
> +  @retval EFI_SUCCESS            The SMBASE of the hot-added CPU with APIC ID
> +                                 ApicId has been relocated to Smbase. The
> +                                 hot-added CPU has reported back about leaving
> +                                 SMM.
> +
> +  @retval EFI_PROTOCOL_ERROR     Synchronization bug encountered around
> +                                 FIRST_SMI_HANDLER_CONTEXT.ApicIdGate.
> +
> +  @retval EFI_INVALID_PARAMETER  Smbase does not fit in 32 bits. No relocation
> +                                 has been attempted.
> +**/
> +EFI_STATUS
> +SmbaseRelocate (
> +  IN APIC_ID ApicId,
> +  IN UINTN   Smbase,
> +  IN UINT32  PenAddress
> +  )
> +{
> +  EFI_STATUS                         Status;
> +  volatile UINT8                     *SmmVacated;
> +  volatile FIRST_SMI_HANDLER_CONTEXT *Context;
> +  UINT64                             ExchangeResult;
> +
> +  if (Smbase > MAX_UINT32) {
> +    Status = EFI_INVALID_PARAMETER;
> +    DEBUG ((DEBUG_ERROR, "%a: ApicId=" FMT_APIC_ID " Smbase=0x%Lx: %r\n",
> +      __FUNCTION__, ApicId, (UINT64)Smbase, Status));
> +    return Status;
> +  }
> +
> +  SmmVacated = (UINT8 *)(UINTN)PenAddress + (EFI_PAGE_SIZE - 1);
> +  Context = (VOID *)(UINTN)SMM_DEFAULT_SMBASE;
> +
> +  //
> +  // Clear AboutToLeaveSmm, so we notice when the hot-added CPU is just about
> +  // to reach RSM, and we can proceed to polling the last byte of the reserved
> +  // page (which could be attacked by the OS).
> +  //
> +  Context->AboutToLeaveSmm = 0;
> +
> +  //
> +  // Clear the last byte of the reserved page, so we notice when the hot-added
> +  // CPU checks back in from the pen.
> +  //
> +  *SmmVacated = 0;
> +
> +  //
> +  // Boot the hot-added CPU.
> +  //
> +  // If the OS is benign, and so the hot-added CPU is still in RESET state,
> +  // then the broadcast SMI is still pending for it; it will now launch
> +  // directly into SMM.
> +  //
> +  // If the OS is malicious, the hot-added CPU has been booted already, and so
> +  // it is already spinning on the APIC ID gate. In that case, the
> +  // INIT-SIPI-SIPI below will be ignored.
> +  //
> +  SendInitSipiSipi (ApicId, PenAddress);
> +
> +  //
> +  // Expose the desired new SMBASE value to the hot-added CPU.
> +  //
> +  Context->NewSmbase = (UINT32)Smbase;
> +
> +  //
> +  // Un-gate SMBASE relocation for the hot-added CPU whose APIC ID is ApicId.
> +  //
> +  ExchangeResult = InterlockedCompareExchange64 (&Context->ApicIdGate,
> +                     MAX_UINT64, ApicId);
> +  if (ExchangeResult != MAX_UINT64) {
> +    Status = EFI_PROTOCOL_ERROR;
> +    DEBUG ((DEBUG_ERROR, "%a: ApicId=" FMT_APIC_ID " ApicIdGate=0x%Lx: %r\n",
> +      __FUNCTION__, ApicId, ExchangeResult, Status));
> +    return Status;
> +  }
> +
> +  //
> +  // Wait until the hot-added CPU is just about to execute RSM.
> +  //
> +  while (Context->AboutToLeaveSmm == 0) {
> +    CpuPause ();
> +  }
> +
> +  //
> +  // Now wait until the hot-added CPU reports back from the pen (or the OS
> +  // attacks the last byte of the reserved page).
> +  //
> +  while (*SmmVacated == 0) {
> +    CpuPause ();
> +  }
> +
> +  Status = EFI_SUCCESS;
> +  return Status;
> +}
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 13/16] OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug
  2020-02-26 22:11 ` [PATCH v2 13/16] OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug Laszlo Ersek
@ 2020-03-02 14:05   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 14:05 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> With the help of the Post-SMM Pen and the SMBASE relocation functions
> added in the previous patches, we can now complete the root MMI handler
> for CPU hotplug.
>
> In the driver's entry point function:
>
> - allocate the pen (in a reserved page in normal RAM),
>
> - install the default ("first") SMI handler for hot-added CPUs (which
>   includes priming the exchange area between the MM Monarch and the
>   hot-added CPUs, i.e., shutting the APIC ID gate).
>
> In the root MMI handler, for each hot-added CPU:
>
> - record the APIC ID of the new CPU in CPU_HOT_PLUG_DATA,
>
> - relocate the SMBASE of the new CPU,
>
> - inform PiSmmCpuDxeSmm by calling
>   EFI_SMM_CPU_SERVICE_PROTOCOL.AddProcessor().
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>     - repeat all the v1 tests
>
>     v1:
>
>     (1) At this stage, CPU hotplug with SMM works.
>
>     Test CPU topology (libvirt domain XML snippet):
>
>     >   <vcpus>
>     >     <vcpu id='0' enabled='yes' hotpluggable='no'/>
>     >     <vcpu id='1' enabled='no' hotpluggable='yes'/>
>     >     <vcpu id='2' enabled='yes' hotpluggable='yes'/>
>     >     <vcpu id='3' enabled='no' hotpluggable='yes'/>
>     >   </vcpus>
>
>     The firmware logs the following during normal boot:
>
>     > SmbaseAllocatePostSmmPen: Post-SMM Pen at 0x9F000
>
>     CPU hotplug command on the host side:
>
>     > virsh setvcpu ovmf.fedora.q35 1 --enable --live
>
>     Firmware log in response:
>
>     > QemuCpuhpCollectApicIds: CurrentSelector=1: insert
>     > QemuCpuhpCollectApicIds: ApicId=0x00000001
>     > QemuCpuhpCollectApicIds: CurrentSelector=2 PendingSelector=1:
>     >                          wrap-around
>     > QemuCpuhpCollectApicIds: PluggedCount=1 ToUnplugCount=0
>     > CpuHotplugMmi: hot-added APIC ID 0x00000001, SMBASE 0x7D082000,
>     >                EFI_SMM_CPU_SERVICE_PROTOCOL assigned number 2
>
>     Query the CPU register state on the host side (without onlining the
>     hot-added CPU in the OS just yet):
>
>     > virsh qemu-monitor-command ovmf.fedora.q35 --hmp 'info registers -a'
>
>     Output, confirming penned status (pen at 0x9F000):
>
>     > CPU#1
>     > EAX=00009f00 EBX=00000000 ECX=00000000 EDX=00000600
>     > ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
>     > EIP=0000000c EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=1
>     > ES =0000 00000000 0000ffff 00009300
>     > CS =9f00 0009f000 0000ffff 00009b00
>     > SS =0000 00000000 0000ffff 00009300
>     > DS =9f00 0009f000 0000ffff 00009300
>     > FS =0000 00000000 0000ffff 00009300
>     > GS =0000 00000000 0000ffff 00009300
>     > LDT=0000 00000000 0000ffff 00008200
>     > TR =0000 00000000 0000ffff 00008b00
>     > GDT=     00000000 0000ffff
>     > IDT=     00000000 0000ffff
>     > CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
>     > DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000
>     > DR3=0000000000000000
>     > DR6=00000000ffff0ff0 DR7=0000000000000400
>     > EFER=0000000000000000
>     > FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
>     > FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
>     > FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
>     > FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
>     > FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
>     > XMM00=00000000000000000000000000000000
>     > XMM01=00000000000000000000000000000000
>     > XMM02=00000000000000000000000000000000
>     > XMM03=00000000000000000000000000000000
>     > XMM04=00000000000000000000000000000000
>     > XMM05=00000000000000000000000000000000
>     > XMM06=00000000000000000000000000000000
>     > XMM07=00000000000000000000000000000000
>
>     Additionally, the dmesg in the Linux guest contains:
>
>     > CPU2 has been hot-added
>
>     We can now boot the hot-addad CPU in the Linux guest:
>
>     > echo 1 > /sys/devices/system/cpu/cpu2/online
>
>     Dmesg in response:
>
>     > smpboot: Booting Node 0 Processor 2 APIC 0x1
>     > kvm-clock: cpu 2, msr 6e01081, secondary cpu clock
>     > KVM setup async PF for cpu 2
>     > kvm-stealtime: cpu 2, msr 7b52a040
>     > Will online and init hotplugged CPU: 2
>
>     Still in the guest, call UEFI variable services on each CPU (including
>     the hot-added one), per
>     <https://github.com/tianocore/tianocore.github.io/wiki/Testing-SMM-with-QEMU,-KVM-and-libvirt#uefi-variable-access-test>:
>
>     > taskset -c 0 efibootmgr
>     > taskset -c 1 efibootmgr
>     > taskset -c 2 efibootmgr
>
>     No delays, no instability.
>
>     Having booted the hot-added CPU in the Linux guest, the host-side
>     command
>
>     > virsh qemu-monitor-command ovmf.fedora.q35 --hmp 'info registers -a'
>
>     now shows:
>
>     > CPU#1
>     > RAX=ffffffffb39e4b50 RBX=0000000000000002 RCX=0000000000000000
>     > RDX=0000000000000002
>     > RSI=0000000000000002 RDI=ffff932cbb51c520 RBP=0000000000000002
>     > RSP=ffffbc5bc0083eb0
>     > R8 =000000cd42e4dffb R9 =0000005a22502599 R10=0000005a22502599
>     > R11=0000005a22502599
>     > R12=ffff932cbae25dc0 R13=0000000000000000 R14=0000000000000000
>     > R15=ffff932cbae25dc0
>     > RIP=ffffffffb39e4f2e RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0
>     > HLT=1
>     > ES =0000 0000000000000000 ffffffff 00c00000
>     > CS =0010 0000000000000000 ffffffff 00a09b00 DPL=0 CS64 [-RA]
>     > SS =0018 0000000000000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>     > DS =0000 0000000000000000 ffffffff 00c00000
>     > FS =0000 0000000000000000 ffffffff 00c00000
>     > GS =0000 ffff932cbb500000 ffffffff 00c00000
>     > LDT=0000 0000000000000000 000fffff 00000000
>     > TR =0040 fffffe0000069000 0000206f 00008b00 DPL=0 TSS64-busy
>     > GDT=     fffffe0000067000 0000007f
>     > IDT=     fffffe0000000000 00000fff
>     > CR0=80050033 CR2=00007f54893cbf20 CR3=0000000078418001 CR4=001606e0
>     > DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000
>     > DR3=0000000000000000
>     > DR6=00000000ffff0ff0 DR7=0000000000000400
>     > EFER=0000000000000d01
>     > FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001fa0
>     > FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
>     > FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
>     > FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
>     > FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
>     > XMM00=000000000000000040ed2be000000000
>     > XMM01=0000000000000000404ddf1a9fbe76c9
>     > XMM02=00000000000000000000000000000000
>     > XMM03=00000000000000000000000000000000
>     > XMM04=00000000000000003ff0000000000000
>     > XMM05=00000000000000000000000000000000
>     > XMM06=00000000000000004078002d0ac487b7
>     > XMM07=0000000000000000404ddf1a9fbe76c9
>     > XMM08=72223d444955412022746f6f72223d44
>     > XMM09=00000000000000000000000000000000
>     > XMM10=00000000000000000000000000000000
>     > XMM11=00000000000000000000000000000000
>     > XMM12=00000000000000000000000000000000
>     > XMM13=00000000000000000000000000000000
>     > XMM14=00000000000000000000000000000000
>     > XMM15=00000000000000000000000000000000
>
>     Hotplug another CPU:
>
>     > virsh setvcpu ovmf.fedora.q35 3 --enable --live
>
>     Firmware log in response:
>
>     > QemuCpuhpCollectApicIds: CurrentSelector=3: insert
>     > QemuCpuhpCollectApicIds: ApicId=0x00000003
>     > QemuCpuhpCollectApicIds: PluggedCount=1 ToUnplugCount=0
>     > CpuHotplugMmi: hot-added APIC ID 0x00000003, SMBASE 0x7D084000,
>     >                EFI_SMM_CPU_SERVICE_PROTOCOL assigned number 3
>
>     Online the hot-added CPU in the Linux guest:
>
>     > echo 1 > /sys/devices/system/cpu/cpu3/online
>
>     Guest dmesg in response:
>
>     > smpboot: Booting Node 0 Processor 3 APIC 0x3
>     > kvm-clock: cpu 3, msr 6e010c1, secondary cpu clock
>     > KVM setup async PF for cpu 3
>     > kvm-stealtime: cpu 3, msr 7b5aa040
>     > Will online and init hotplugged CPU: 3
>
>     (2) Alternative order of actions:
>
>     Hotplug both CPUs first, on the host:
>
>     > virsh setvcpu ovmf.fedora.q35 1 --enable --live
>     > virsh setvcpu ovmf.fedora.q35 3 --enable --live
>
>     *then* online both hot-added CPUs in the Linux guest:
>
>     > echo 1 > /sys/devices/system/cpu/cpu2/online
>     > echo 1 > /sys/devices/system/cpu/cpu3/online
>
>     The only difference here is that the broadcast SMI for the second
>     hotplug finds the first hotplugged CPU still in the pen (i.e., not
>     onlined by Linux). There is no difference in observable behavior (beyond
>     the matching log messages and register dumps).
>
>     (3) What doesn't work yet:
>
>     - CPU hotplug w/ SMM in SEV guests.
>
>       See <https://bugzilla.tianocore.org/show_bug.cgi?id=1512#c14>.
>
>       (NB. I'm uncertain if CPU hotplug works in SEV guests without
>       SMM_REQUIRE to begin with.)
>
>     - S3 resume w/ SMM after hot-adding a CPU.
>
>       The remaining patches in the series take care of that. (Only in the
>       absence of SEV; SEV+S3 looks broken regardless of hotplug.)
>
>     - CPU hot-unplug w/ SMM.
>
>       Needs separate investigation. EFI_SMM_REMOVE_PROCESSOR in
>       "UefiCpuPkg/Include/Protocol/SmmCpuService.h" is documented as
>       follows: "After this API is called, the removed processor must not
>       respond to SMIs in the coherence domain". This could raise challenging
>       ordering questions between QEMU, the firmware, and the OS.
>
>  OvmfPkg/CpuHotplugSmm/CpuHotplug.c | 97 +++++++++++++++++++-
>  1 file changed, 95 insertions(+), 2 deletions(-)
>
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> index 42e023cb85c0..20e6bec04f41 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> @@ -1,76 +1,82 @@
>  /** @file
>    Root SMI handler for VCPU hotplug SMIs.
>
>    Copyright (c) 2020, Red Hat, Inc.
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>
>  #include <CpuHotPlugData.h>                  // CPU_HOT_PLUG_DATA
>  #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT
>  #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING
>  #include <Library/BaseLib.h>                 // CpuDeadLoop()
>  #include <Library/DebugLib.h>                // ASSERT()
>  #include <Library/MmServicesTableLib.h>      // gMmst
>  #include <Library/PcdLib.h>                  // PcdGetBool()
>  #include <Library/SafeIntLib.h>              // SafeUintnSub()
>  #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL
>  #include <Protocol/SmmCpuService.h>          // EFI_SMM_CPU_SERVICE_PROTOCOL
>  #include <Uefi/UefiBaseType.h>               // EFI_STATUS
>
>  #include "ApicId.h"                          // APIC_ID
>  #include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()
> +#include "Smbase.h"                          // SmbaseAllocatePostSmmPen()
>
>  //
>  // We use this protocol for accessing IO Ports.
>  //
>  STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;
>  //
>  // The following protocol is used to report the addition or removal of a CPU to
>  // the SMM CPU driver (PiSmmCpuDxeSmm).
>  //
>  STATIC EFI_SMM_CPU_SERVICE_PROTOCOL *mMmCpuService;
>  //
>  // This structure is a communication side-channel between the
>  // EFI_SMM_CPU_SERVICE_PROTOCOL consumer (i.e., this driver) and provider
>  // (i.e., PiSmmCpuDxeSmm).
>  //
>  STATIC CPU_HOT_PLUG_DATA *mCpuHotPlugData;
>  //
>  // SMRAM arrays for fetching the APIC IDs of processors with pending events (of
>  // known event types), for the time of just one MMI.
>  //
>  // The lifetimes of these arrays match that of this driver only because we
>  // don't want to allocate SMRAM at OS runtime, and potentially fail (or
>  // fragment the SMRAM map).
>  //
>  // These arrays provide room for ("possible CPU count" minus one) APIC IDs
>  // each, as we don't expect every possible CPU to appear, or disappear, in a
>  // single MMI. The numbers of used (populated) elements in the arrays are
>  // determined on every MMI separately.
>  //
>  STATIC APIC_ID *mPluggedApicIds;
>  STATIC APIC_ID *mToUnplugApicIds;
>  //
> +// Address of the non-SMRAM reserved memory page that contains the Post-SMM Pen
> +// for hot-added CPUs.
> +//
> +STATIC UINT32 mPostSmmPenAddress;
> +//
>  // Represents the registration of the CPU Hotplug MMI handler.
>  //
>  STATIC EFI_HANDLE mDispatchHandle;
>
>
>  /**
>    CPU Hotplug MMI handler function.
>
>    This is a root MMI handler.
>
>    @param[in] DispatchHandle      The unique handle assigned to this handler by
>                                   EFI_MM_SYSTEM_TABLE.MmiHandlerRegister().
>
>    @param[in] Context             Context passed in by
>                                   EFI_MM_SYSTEM_TABLE.MmiManage(). Due to
>                                   CpuHotplugMmi() being a root MMI handler,
>                                   Context is ASSERT()ed to be NULL.
>
>    @param[in,out] CommBuffer      Ignored, due to CpuHotplugMmi() being a root
>                                   MMI handler.
>
>    @param[in,out] CommBufferSize  Ignored, due to CpuHotplugMmi() being a root
> @@ -97,44 +103,46 @@ STATIC EFI_HANDLE mDispatchHandle;
>
>    @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The MMI source is still pending,
>                                                and other handlers should still
>                                                be called.
>
>    @retval EFI_INTERRUPT_PENDING               The MMI source could not be
>                                                quiesced.
>  **/
>  STATIC
>  EFI_STATUS
>  EFIAPI
>  CpuHotplugMmi (
>    IN EFI_HANDLE DispatchHandle,
>    IN CONST VOID *Context        OPTIONAL,
>    IN OUT VOID   *CommBuffer     OPTIONAL,
>    IN OUT UINTN  *CommBufferSize OPTIONAL
>    )
>  {
>    EFI_STATUS Status;
>    UINT8      ApmControl;
>    UINT32     PluggedCount;
>    UINT32     ToUnplugCount;
> +  UINT32     PluggedIdx;
> +  UINT32     NewSlot;
>
>    //
>    // Assert that we are entering this function due to our root MMI handler
>    // registration.
>    //
>    ASSERT (DispatchHandle == mDispatchHandle);
>    //
>    // When MmiManage() is invoked to process root MMI handlers, the caller (the
>    // MM Core) is expected to pass in a NULL Context. MmiManage() then passes
>    // the same NULL Context to individual handlers.
>    //
>    ASSERT (Context == NULL);
>    //
>    // Read the MMI command value from the APM Control Port, to see if this is an
>    // MMI we should care about.
>    //
>    Status = mMmCpuIo->Io.Read (mMmCpuIo, MM_IO_UINT8, ICH9_APM_CNT, 1,
>                            &ApmControl);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: failed to read ICH9_APM_CNT: %r\n", __FUNCTION__,
>        Status));
>      //
> @@ -152,49 +160,116 @@ CpuHotplugMmi (
>
>    //
>    // Collect the CPUs with pending events.
>    //
>    Status = QemuCpuhpCollectApicIds (
>               mMmCpuIo,
>               mCpuHotPlugData->ArrayLength,     // PossibleCpuCount
>               mCpuHotPlugData->ArrayLength - 1, // ApicIdCount
>               mPluggedApicIds,
>               &PluggedCount,
>               mToUnplugApicIds,
>               &ToUnplugCount
>               );
>    if (EFI_ERROR (Status)) {
>      goto Fatal;
>    }
>    if (ToUnplugCount > 0) {
>      DEBUG ((DEBUG_ERROR, "%a: hot-unplug is not supported yet\n",
>        __FUNCTION__));
>      goto Fatal;
>    }
>
> +  //
> +  // Process hot-added CPUs.
> +  //
> +  // The Post-SMM Pen need not be reinstalled multiple times within a single
> +  // root MMI handling. Even reinstalling once per root MMI is only prudence;
> +  // in theory installing the pen in the driver's entry point function should
> +  // suffice.
> +  //
> +  SmbaseReinstallPostSmmPen (mPostSmmPenAddress);
> +
> +  PluggedIdx = 0;
> +  NewSlot = 0;
> +  while (PluggedIdx < PluggedCount) {
> +    APIC_ID NewApicId;
> +    UINTN   NewProcessorNumberByProtocol;
> +
> +    NewApicId = mPluggedApicIds[PluggedIdx];
> +    //
> +    // Find the first empty slot in CPU_HOT_PLUG_DATA.
> +    //
> +    while (NewSlot < mCpuHotPlugData->ArrayLength &&
> +           mCpuHotPlugData->ApicId[NewSlot] != MAX_UINT64) {
> +      NewSlot++;
> +    }
> +    if (NewSlot == mCpuHotPlugData->ArrayLength) {
> +      DEBUG ((DEBUG_ERROR, "%a: no room for APIC ID " FMT_APIC_ID "\n",
> +        __FUNCTION__, NewApicId));
> +      goto Fatal;
> +    }
> +
> +    //
> +    // Store the APIC ID of the new processor to the slot.
> +    //
> +    mCpuHotPlugData->ApicId[NewSlot] = NewApicId;
> +
> +    //
> +    // Relocate the SMBASE of the new CPU.
> +    //
> +    Status = SmbaseRelocate (NewApicId, mCpuHotPlugData->SmBase[NewSlot],
> +               mPostSmmPenAddress);
> +    if (EFI_ERROR (Status)) {
> +      goto RevokeNewSlot;
> +    }
> +
> +    //
> +    // Add the new CPU with EFI_SMM_CPU_SERVICE_PROTOCOL.
> +    //
> +    Status = mMmCpuService->AddProcessor (mMmCpuService, NewApicId,
> +                              &NewProcessorNumberByProtocol);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: AddProcessor(" FMT_APIC_ID "): %r\n",
> +        __FUNCTION__, NewApicId, Status));
> +      goto RevokeNewSlot;
> +    }
> +
> +    DEBUG ((DEBUG_INFO, "%a: hot-added APIC ID " FMT_APIC_ID ", SMBASE 0x%Lx, "
> +      "EFI_SMM_CPU_SERVICE_PROTOCOL assigned number %Lu\n", __FUNCTION__,
> +      NewApicId, (UINT64)mCpuHotPlugData->SmBase[NewSlot],
> +      (UINT64)NewProcessorNumberByProtocol));
> +
> +    NewSlot++;
> +    PluggedIdx++;
> +  }
> +
>    //
>    // We've handled this MMI.
>    //
>    return EFI_SUCCESS;
>
> +RevokeNewSlot:
> +  mCpuHotPlugData->ApicId[NewSlot] = MAX_UINT64;
> +
>  Fatal:
>    ASSERT (FALSE);
>    CpuDeadLoop ();
>    //
>    // We couldn't handle this MMI.
>    //
>    return EFI_INTERRUPT_PENDING;
>  }
>
>
>  //
>  // Entry point function of this driver.
>  //
>  EFI_STATUS
>  EFIAPI
>  CpuHotplugEntry (
>    IN EFI_HANDLE       ImageHandle,
>    IN EFI_SYSTEM_TABLE *SystemTable
>    )
>  {
>    EFI_STATUS Status;
>    UINTN      Size;
> @@ -251,83 +326,101 @@ CpuHotplugEntry (
>    //
>    // Allocate the data structures that depend on the possible CPU count.
>    //
>    if (RETURN_ERROR (SafeUintnSub (mCpuHotPlugData->ArrayLength, 1, &Size)) ||
>        RETURN_ERROR (SafeUintnMult (sizeof (APIC_ID), Size, &Size))) {
>      Status = EFI_ABORTED;
>      DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_PLUG_DATA\n", __FUNCTION__));
>      goto Fatal;
>    }
>    Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
>                      (VOID **)&mPluggedApicIds);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
>      goto Fatal;
>    }
>    Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,
>                      (VOID **)&mToUnplugApicIds);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));
>      goto ReleasePluggedApicIds;
>    }
>
> +  //
> +  // Allocate the Post-SMM Pen for hot-added CPUs.
> +  //
> +  Status = SmbaseAllocatePostSmmPen (&mPostSmmPenAddress,
> +             SystemTable->BootServices);
> +  if (EFI_ERROR (Status)) {
> +    goto ReleaseToUnplugApicIds;
> +  }
> +
>    //
>    // Sanity-check the CPU hotplug interface.
>    //
>    // Both of the following features are part of QEMU 5.0, introduced primarily
>    // in commit range 3e08b2b9cb64..3a61c8db9d25:
>    //
>    // (a) the QEMU_CPUHP_CMD_GET_ARCH_ID command of the modern CPU hotplug
>    //     interface,
>    //
>    // (b) the "SMRAM at default SMBASE" feature.
>    //
>    // From these, (b) is restricted to 5.0+ machine type versions, while (a)
>    // does not depend on machine type version. Because we ensured the stricter
>    // condition (b) through PcdQ35SmramAtDefaultSmbase above, the (a)
>    // QEMU_CPUHP_CMD_GET_ARCH_ID command must now be available too. While we
>    // can't verify the presence of precisely that command, we can still verify
>    // (sanity-check) that the modern interface is active, at least.
>    //
>    // Consult the "Typical usecases | Detecting and enabling modern CPU hotplug
>    // interface" section in QEMU's "docs/specs/acpi_cpu_hotplug.txt", on the
>    // following.
>    //
>    QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
>    QemuCpuhpWriteCpuSelector (mMmCpuIo, 0);
>    QemuCpuhpWriteCommand (mMmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
>    if (QemuCpuhpReadCommandData2 (mMmCpuIo) != 0) {
>      Status = EFI_NOT_FOUND;
>      DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
>        __FUNCTION__, Status));
> -    goto ReleaseToUnplugApicIds;
> +    goto ReleasePostSmmPen;
>    }
>
>    //
>    // Register the handler for the CPU Hotplug MMI.
>    //
>    Status = gMmst->MmiHandlerRegister (
>                      CpuHotplugMmi,
>                      NULL,            // HandlerType: root MMI handler
>                      &mDispatchHandle
>                      );
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,
>        Status));
> -    goto ReleaseToUnplugApicIds;
> +    goto ReleasePostSmmPen;
>    }
>
> +  //
> +  // Install the handler for the hot-added CPUs' first SMI.
> +  //
> +  SmbaseInstallFirstSmiHandler ();
> +
>    return EFI_SUCCESS;
>
> +ReleasePostSmmPen:
> +  SmbaseReleasePostSmmPen (mPostSmmPenAddress, SystemTable->BootServices);
> +  mPostSmmPenAddress = 0;
> +
>  ReleaseToUnplugApicIds:
>    gMmst->MmFreePool (mToUnplugApicIds);
>    mToUnplugApicIds = NULL;
>
>  ReleasePluggedApicIds:
>    gMmst->MmFreePool (mPluggedApicIds);
>    mPluggedApicIds = NULL;
>
>  Fatal:
>    ASSERT (FALSE);
>    CpuDeadLoop ();
>    return Status;
>  }
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg
  2020-02-26 22:11 ` [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg Laszlo Ersek
  2020-03-02 13:44   ` Philippe Mathieu-Daudé
@ 2020-03-02 14:06   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 14:06 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> The @file comments in UefiCpuPkg/CpuS3DataDxe say,
>
>   [...] It also only supports the number of CPUs reported by the MP
>   Services Protocol, so this module does not support hot plug CPUs.  This
>   module can be copied into a CPU specific package and customized if these
>   additional features are required. [...]
>
> The driver is so small that the simplest way to extend it with hotplug
> support is indeed to clone it at first. In this patch, customize the
> driver only with the following no-op steps:
>
> - Update copyright notices.
> - Update INF_VERSION to the latest INF spec version (1.29).
> - Update FILE_GUID.
> - Drop the UNI files.
> - Replace EFI_D_VERBOSE with DEBUG_VERBOSE, to appease "PatchCheck.py".
>
> This patch is best reviewed with:
>
> $ git show --find-copies-harder
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/OvmfPkgIa32.dsc                               |  2 +-
>  OvmfPkg/OvmfPkgIa32X64.dsc                            |  2 +-
>  OvmfPkg/OvmfPkgX64.dsc                                |  2 +-
>  OvmfPkg/OvmfPkgIa32.fdf                               |  2 +-
>  OvmfPkg/OvmfPkgIa32X64.fdf                            |  2 +-
>  OvmfPkg/OvmfPkgX64.fdf                                |  2 +-
>  {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf | 10 +++-------
>  {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c      |  4 ++--
>  8 files changed, 11 insertions(+), 15 deletions(-)
>
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 78310da44a5f..8d8ca746ba03 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -836,45 +836,45 @@ [Components]
>  !endif
>        HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
>        PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
>        BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
>
>      <PcdsFixedAtBuild>
>        gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
>        gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
>        gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
>    }
>
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
>    OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
>  !endif
>
>    OvmfPkg/PlatformDxe/Platform.inf
>    OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>    OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>    OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
>    OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 428578a4f839..acba1f80a431 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -850,45 +850,45 @@ [Components.X64]
>        HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
>        PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
>        BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
>
>      <PcdsFixedAtBuild>
>        gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
>        gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
>        gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
>    }
>
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
>    OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
>  !endif
>
>    OvmfPkg/PlatformDxe/Platform.inf
>    OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>    OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>    OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>    OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
>    OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 73b92f259201..621b27f80d4b 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -848,45 +848,45 @@ [Components]
>        HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
>        PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
>        BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
>
>      <PcdsFixedAtBuild>
>        gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
>        gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
>        gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
>    }
>
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
>    OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf
>  !endif
>
>    OvmfPkg/PlatformDxe/Platform.inf
>    OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>    OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>    OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>    OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>
>    #
>    # SMM Initial Program Load (a DXE_RUNTIME_DRIVER)
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>
>    #
>    # SMM_CORE
>    #
>    MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>
>    #
>    # Privileged drivers (DXE_SMM_DRIVER modules)
>    #
>    OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>    UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>    MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
>      <LibraryClasses>
>        LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
>    }
>    UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf {
>      <LibraryClasses>
> diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
> index 61b891765c56..004aa318b222 100644
> --- a/OvmfPkg/OvmfPkgIa32.fdf
> +++ b/OvmfPkg/OvmfPkgIa32.fdf
> @@ -298,45 +298,45 @@ [FV.DXEFV]
>  INF  MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
>  INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>
>  !ifdef $(CSM_ENABLE)
>  INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>  INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>  INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !else
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>  !endif
>
>  INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>  INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>  INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>  INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>  INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>  INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>
>  #
>  # Variable driver stack (SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>  #
>  # Variable driver stack (non-SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>  INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
> index 501b4fcb7b67..13da8b9dbe65 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.fdf
> +++ b/OvmfPkg/OvmfPkgIa32X64.fdf
> @@ -305,45 +305,45 @@ [FV.DXEFV]
>  INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>
>  !ifdef $(CSM_ENABLE)
>  INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>  INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>  INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !else
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>  !endif
>
>  INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>  INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>  INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>  INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>  INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>  INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>
>  #
>  # Variable driver stack (SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>  #
>  # Variable driver stack (non-SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>  INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 501b4fcb7b67..13da8b9dbe65 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -305,45 +305,45 @@ [FV.DXEFV]
>  INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
>  INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
>
>  !ifdef $(CSM_ENABLE)
>  INF  OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
>  INF  OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
>  INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !else
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
>  !endif
>
>  INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
>
>  !if $(SMM_REQUIRE) == TRUE
>  INF  OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
>  INF  OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
> -INF  UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +INF  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
>  INF  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
>  INF  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  INF  UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
>  INF  MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
>  INF  UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
>
>  #
>  # Variable driver stack (SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf
>  INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
>  INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
>
>  !else
>
>  #
>  # Variable driver stack (non-SMM)
>  #
>  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>  INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
> diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> similarity index 83%
> copy from UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> copy to OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> index 510133a614ba..0ad8a0b35d25 100644
> --- a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> @@ -1,65 +1,61 @@
>  ## @file
>  #  ACPI CPU Data initialization module
>  #
>  #  This module initializes the ACPI_CPU_DATA structure and registers the address
>  #  of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>  #  version of this module.  It does not provide a machine check handler or CPU
>  #  register initialization tables for ACPI S3 resume.  It also only supports the
>  #  number of CPUs reported by the MP Services Protocol, so this module does not
>  #  support hot plug CPUs.  This module can be copied into a CPU specific package
>  #  and customized if these additional features are required.
>  #
>  #  Copyright (c) 2013-2016, Intel Corporation. All rights reserved.<BR>
> -#  Copyright (c) 2015, Red Hat, Inc.
> +#  Copyright (c) 2015-2020, Red Hat, Inc.
>  #
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
>  ##
>
>  [Defines]
> -  INF_VERSION                    = 0x00010005
> +  INF_VERSION                    = 1.29
>    BASE_NAME                      = CpuS3DataDxe
> -  MODULE_UNI_FILE                = CpuS3DataDxe.uni
> -  FILE_GUID                      = 4D2E57EE-0E3F-44DD-93C4-D3B57E96945D
> +  FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
>    MODULE_TYPE                    = DXE_DRIVER
>    VERSION_STRING                 = 1.0
>    ENTRY_POINT                    = CpuS3DataInitialize
>
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  #  VALID_ARCHITECTURES           = IA32 X64
>
>  [Sources]
>    CpuS3Data.c
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
>
>  [LibraryClasses]
>    UefiDriverEntryPoint
>    UefiBootServicesTableLib
>    BaseMemoryLib
>    DebugLib
>    BaseLib
>    MtrrLib
>    MemoryAllocationLib
>
>  [Guids]
>    gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
>
>  [Protocols]
>    gEfiMpServiceProtocolGuid          ## CONSUMES
>
>  [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize    ## CONSUMES
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress  ## PRODUCES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
>
>  [Depex]
>    gEfiMpServiceProtocolGuid
> -
> -[UserExtensions.TianoCore."ExtraFiles"]
> -  CpuS3DataDxeExtra.uni
> diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> similarity index 96%
> copy from UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
> copy to OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> index 2be335d91903..2bb60d591b1e 100644
> --- a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> @@ -1,35 +1,35 @@
>  /** @file
>  ACPI CPU Data initialization module
>
>  This module initializes the ACPI_CPU_DATA structure and registers the address
>  of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>  version of this module.  It does not provide a machine check handler or CPU
>  register initialization tables for ACPI S3 resume.  It also only supports the
>  number of CPUs reported by the MP Services Protocol, so this module does not
>  support hot plug CPUs.  This module can be copied into a CPU specific package
>  and customized if these additional features are required.
>
>  Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
> -Copyright (c) 2015, Red Hat, Inc.
> +Copyright (c) 2015 - 2020, Red Hat, Inc.
>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  **/
>
>  #include <PiDxe.h>
>
>  #include <AcpiCpuData.h>
>
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/MtrrLib.h>
>  #include <Library/MemoryAllocationLib.h>
>
>  #include <Protocol/MpService.h>
>  #include <Guid/EventGroup.h>
>
>  //
>  // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
>  //
> @@ -107,45 +107,45 @@ VOID
>  EFIAPI
>  CpuS3DataOnEndOfDxe (
>    IN  EFI_EVENT  Event,
>    OUT VOID       *Context
>    )
>  {
>    EFI_STATUS         Status;
>    ACPI_CPU_DATA_EX   *AcpiCpuDataEx;
>
>    AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context;
>    //
>    // Allocate a 4KB reserved page below 1MB
>    //
>    AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;
>    Status = gBS->AllocatePages (
>                    AllocateMaxAddress,
>                    EfiReservedMemoryType,
>                    1,
>                    &AcpiCpuDataEx->AcpiCpuData.StartupVector
>                    );
>    ASSERT_EFI_ERROR (Status);
>
> -  DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));
> +  DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));
>    MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
>
>    //
>    // Close event, so it will not be invoked again.
>    //
>    gBS->CloseEvent (Event);
>  }
>
>  /**
>     The entry function of the CpuS3Data driver.
>
>     Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
>     MTRR settings.  Register an event notification on gEfiEndOfDxeEventGroupGuid
>     to capture the ACPI_CPU_DATA MTRR settings.  The PcdCpuS3DataAddress is set
>     to the address that ACPI_CPU_DATA is allocated at.
>
>     @param[in] ImageHandle  The firmware allocated handle for the EFI image.
>     @param[in] SystemTable  A pointer to the EFI System Table.
>
>     @retval EFI_SUCCESS     The entry point is executed successfully.
>     @retval EFI_UNSUPPORTED Do not support ACPI S3.
>     @retval other           Some error occurs when executing this entry point.
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups
  2020-02-26 22:11 ` [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups Laszlo Ersek
  2020-03-02 13:25   ` Philippe Mathieu-Daudé
@ 2020-03-02 14:06   ` Ard Biesheuvel
  1 sibling, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 14:06 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Sort the [Packages], [LibraryClasses], and [Pcd] sections in the INF file.
> Pad the usage notes (CONSUMES, PRODUCES) in the [Pcd] section.
>
> Sort the Library #includes in the C file.
>
> This patch is functionally a no-op.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf | 16 ++++++++--------
>  OvmfPkg/CpuS3DataDxe/CpuS3Data.c      |  4 ++--
>  2 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> index 0ad8a0b35d25..f9679e0c33b3 100644
> --- a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> @@ -14,48 +14,48 @@
>  #
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
>  ##
>
>  [Defines]
>    INF_VERSION                    = 1.29
>    BASE_NAME                      = CpuS3DataDxe
>    FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
>    MODULE_TYPE                    = DXE_DRIVER
>    VERSION_STRING                 = 1.0
>    ENTRY_POINT                    = CpuS3DataInitialize
>
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  #  VALID_ARCHITECTURES           = IA32 X64
>
>  [Sources]
>    CpuS3Data.c
>
>  [Packages]
> -  MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
>
>  [LibraryClasses]
> -  UefiDriverEntryPoint
> -  UefiBootServicesTableLib
> +  BaseLib
>    BaseMemoryLib
>    DebugLib
> -  BaseLib
> -  MtrrLib
>    MemoryAllocationLib
> +  MtrrLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
>
>  [Guids]
>    gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
>
>  [Protocols]
>    gEfiMpServiceProtocolGuid          ## CONSUMES
>
>  [Pcd]
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize    ## CONSUMES
> -  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress  ## PRODUCES
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable                    ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize                       ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress                     ## PRODUCES
>
>  [Depex]
>    gEfiMpServiceProtocolGuid
> diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> index 2bb60d591b1e..8bb9807cd501 100644
> --- a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> @@ -3,48 +3,48 @@ ACPI CPU Data initialization module
>
>  This module initializes the ACPI_CPU_DATA structure and registers the address
>  of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>  version of this module.  It does not provide a machine check handler or CPU
>  register initialization tables for ACPI S3 resume.  It also only supports the
>  number of CPUs reported by the MP Services Protocol, so this module does not
>  support hot plug CPUs.  This module can be copied into a CPU specific package
>  and customized if these additional features are required.
>
>  Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
>  Copyright (c) 2015 - 2020, Red Hat, Inc.
>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  **/
>
>  #include <PiDxe.h>
>
>  #include <AcpiCpuData.h>
>
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
> -#include <Library/UefiBootServicesTableLib.h>
>  #include <Library/DebugLib.h>
> -#include <Library/MtrrLib.h>
>  #include <Library/MemoryAllocationLib.h>
> +#include <Library/MtrrLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
>
>  #include <Protocol/MpService.h>
>  #include <Guid/EventGroup.h>
>
>  //
>  // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
>  //
>  typedef struct {
>    ACPI_CPU_DATA             AcpiCpuData;
>    MTRR_SETTINGS             MtrrTable;
>    IA32_DESCRIPTOR           GdtrProfile;
>    IA32_DESCRIPTOR           IdtrProfile;
>  } ACPI_CPU_DATA_EX;
>
>  /**
>    Allocate EfiACPIMemoryNVS memory.
>
>    @param[in] Size   Size of memory to allocate.
>
>    @return       Allocated address for output.
>
>  **/
> --
> 2.19.1.3.g30247aa5d201
>
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 16/16] OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug
  2020-02-26 22:11 ` [PATCH v2 16/16] OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug Laszlo Ersek
@ 2020-03-02 14:16   ` Ard Biesheuvel
  0 siblings, 0 replies; 53+ messages in thread
From: Ard Biesheuvel @ 2020-03-02 14:16 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: edk2-devel-groups-io, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney, Philippe Mathieu-Daudé

On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek <lersek@redhat.com> wrote:
>
> During normal boot, CpuS3DataDxe allocates
>
> - an empty CPU_REGISTER_TABLE entry in the
>   "ACPI_CPU_DATA.PreSmmInitRegisterTable" array, and
>
> - an empty CPU_REGISTER_TABLE entry in the "ACPI_CPU_DATA.RegisterTable"
>   array,
>
> for every CPU whose APIC ID CpuS3DataDxe can learn.
>
> Currently EFI_MP_SERVICES_PROTOCOL is used for both determining the number
> of CPUs -- the protocol reports the present-at-boot CPU count --, and for
> retrieving the APIC IDs of those CPUs.
>
> Consequently, if a CPU is hot-plugged at OS runtime, then S3 resume
> breaks. That's because PiSmmCpuDxeSmm will not find the hot-added CPU's
> APIC ID associated with any CPU_REGISTER_TABLE object, in the SMRAM copies
> of either of the "RegisterTable" and "PreSmmInitRegisterTable" arrays. The
> failure to match the hot-added CPU's APIC ID trips the ASSERT() in
> SetRegister() [UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c].
>
> If "PcdQ35SmramAtDefaultSmbase" is TRUE, then:
>
> - prepare CPU_REGISTER_TABLE objects for all possible CPUs, not just the
>   present-at-boot CPUs (PlatformPei stored the possible CPU count to
>   "PcdCpuMaxLogicalProcessorNumber");
>
> - use QEMU_CPUHP_CMD_GET_ARCH_ID for filling in the "InitialApicId" fields
>   of the CPU_REGISTER_TABLE objects.
>
> This provides full APIC ID coverage for PiSmmCpuDxeSmm during S3 resume,
> accommodating CPUs hot-added at OS runtime.
>
> This patch is best reviewed with
>
> $ git show -b
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---
>
> Notes:
>     v2:
>
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
>
>  OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf |  4 +
>  OvmfPkg/CpuS3DataDxe/CpuS3Data.c      | 91 ++++++++++++++------
>  2 files changed, 70 insertions(+), 25 deletions(-)
>
> diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> index f9679e0c33b3..ceae1d4078c7 100644
> --- a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf
> @@ -16,46 +16,50 @@
>  #
>  ##
>
>  [Defines]
>    INF_VERSION                    = 1.29
>    BASE_NAME                      = CpuS3DataDxe
>    FILE_GUID                      = 229B7EFD-DA02-46B9-93F4-E20C009F94E9
>    MODULE_TYPE                    = DXE_DRIVER
>    VERSION_STRING                 = 1.0
>    ENTRY_POINT                    = CpuS3DataInitialize
>
>  # The following information is for reference only and not required by the build
>  # tools.
>  #
>  #  VALID_ARCHITECTURES           = IA32 X64
>
>  [Sources]
>    CpuS3Data.c
>
>  [Packages]
>    MdeModulePkg/MdeModulePkg.dec
>    MdePkg/MdePkg.dec
> +  OvmfPkg/OvmfPkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
>
>  [LibraryClasses]
>    BaseLib
>    BaseMemoryLib
>    DebugLib
> +  IoLib
>    MemoryAllocationLib
>    MtrrLib
>    UefiBootServicesTableLib
>    UefiDriverEntryPoint
>
>  [Guids]
>    gEfiEndOfDxeEventGroupGuid         ## CONSUMES   ## Event
>
>  [Protocols]
>    gEfiMpServiceProtocolGuid          ## CONSUMES
>
>  [Pcd]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable                    ## CONSUMES
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize                       ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber         ## CONSUMES
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress                     ## PRODUCES
> +  gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>
>  [Depex]
>    gEfiMpServiceProtocolGuid
> diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> index 8bb9807cd501..bac7285aa2f3 100644
> --- a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> +++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c
> @@ -4,51 +4,55 @@ ACPI CPU Data initialization module
>  This module initializes the ACPI_CPU_DATA structure and registers the address
>  of this structure in the PcdCpuS3DataAddress PCD.  This is a generic/simple
>  version of this module.  It does not provide a machine check handler or CPU
>  register initialization tables for ACPI S3 resume.  It also only supports the
>  number of CPUs reported by the MP Services Protocol, so this module does not
>  support hot plug CPUs.  This module can be copied into a CPU specific package
>  and customized if these additional features are required.
>
>  Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
>  Copyright (c) 2015 - 2020, Red Hat, Inc.
>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  **/
>
>  #include <PiDxe.h>
>
>  #include <AcpiCpuData.h>
>
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/MtrrLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>
>  #include <Protocol/MpService.h>
>  #include <Guid/EventGroup.h>
>
> +#include <IndustryStandard/Q35MchIch9.h>
> +#include <IndustryStandard/QemuCpuHotplug.h>
> +
>  //
>  // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
>  //
>  typedef struct {
>    ACPI_CPU_DATA             AcpiCpuData;
>    MTRR_SETTINGS             MtrrTable;
>    IA32_DESCRIPTOR           GdtrProfile;
>    IA32_DESCRIPTOR           IdtrProfile;
>  } ACPI_CPU_DATA_EX;
>
>  /**
>    Allocate EfiACPIMemoryNVS memory.
>
>    @param[in] Size   Size of memory to allocate.
>
>    @return       Allocated address for output.
>
>  **/
>  VOID *
>  AllocateAcpiNvsMemory (
>    IN UINTN  Size
>    )
> @@ -144,89 +148,101 @@ CpuS3DataOnEndOfDxe (
>     to the address that ACPI_CPU_DATA is allocated at.
>
>     @param[in] ImageHandle  The firmware allocated handle for the EFI image.
>     @param[in] SystemTable  A pointer to the EFI System Table.
>
>     @retval EFI_SUCCESS     The entry point is executed successfully.
>     @retval EFI_UNSUPPORTED Do not support ACPI S3.
>     @retval other           Some error occurs when executing this entry point.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  CpuS3DataInitialize (
>    IN EFI_HANDLE        ImageHandle,
>    IN EFI_SYSTEM_TABLE  *SystemTable
>    )
>  {
>    EFI_STATUS                 Status;
>    ACPI_CPU_DATA_EX           *AcpiCpuDataEx;
>    ACPI_CPU_DATA              *AcpiCpuData;
>    EFI_MP_SERVICES_PROTOCOL   *MpServices;
>    UINTN                      NumberOfCpus;
> -  UINTN                      NumberOfEnabledProcessors;
>    VOID                       *Stack;
>    UINTN                      TableSize;
>    CPU_REGISTER_TABLE         *RegisterTable;
>    UINTN                      Index;
>    EFI_PROCESSOR_INFORMATION  ProcessorInfoBuffer;
>    UINTN                      GdtSize;
>    UINTN                      IdtSize;
>    VOID                       *Gdt;
>    VOID                       *Idt;
>    EFI_EVENT                  Event;
>    ACPI_CPU_DATA              *OldAcpiCpuData;
> +  BOOLEAN                    FetchPossibleApicIds;
>
>    if (!PcdGetBool (PcdAcpiS3Enable)) {
>      return EFI_UNSUPPORTED;
>    }
>
>    //
>    // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
>    //
>    OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);
>
>    AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));
>    ASSERT (AcpiCpuDataEx != NULL);
>    AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;
>
>    //
> -  // Get MP Services Protocol
> +  // The "SMRAM at default SMBASE" feature guarantees that
> +  // QEMU_CPUHP_CMD_GET_ARCH_ID too is available.
>    //
> -  Status = gBS->LocateProtocol (
> -                  &gEfiMpServiceProtocolGuid,
> -                  NULL,
> -                  (VOID **)&MpServices
> -                  );
> -  ASSERT_EFI_ERROR (Status);
> +  FetchPossibleApicIds = PcdGetBool (PcdQ35SmramAtDefaultSmbase);
>
> -  //
> -  // Get the number of CPUs
> -  //
> -  Status = MpServices->GetNumberOfProcessors (
> -                         MpServices,
> -                         &NumberOfCpus,
> -                         &NumberOfEnabledProcessors
> -                         );
> -  ASSERT_EFI_ERROR (Status);
> +  if (FetchPossibleApicIds) {
> +    NumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
> +  } else {
> +    UINTN NumberOfEnabledProcessors;
> +
> +    //
> +    // Get MP Services Protocol
> +    //
> +    Status = gBS->LocateProtocol (
> +                    &gEfiMpServiceProtocolGuid,
> +                    NULL,
> +                    (VOID **)&MpServices
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    //
> +    // Get the number of CPUs
> +    //
> +    Status = MpServices->GetNumberOfProcessors (
> +                           MpServices,
> +                           &NumberOfCpus,
> +                           &NumberOfEnabledProcessors
> +                           );
> +    ASSERT_EFI_ERROR (Status);
> +  }
>    AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;
>
>    //
>    // Initialize ACPI_CPU_DATA fields
>    //
>    AcpiCpuData->StackSize                 = PcdGet32 (PcdCpuApStackSize);
>    AcpiCpuData->ApMachineCheckHandlerBase = 0;
>    AcpiCpuData->ApMachineCheckHandlerSize = 0;
>    AcpiCpuData->GdtrProfile  = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;
>    AcpiCpuData->IdtrProfile  = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;
>    AcpiCpuData->MtrrTable    = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;
>
>    //
>    // Allocate stack space for all CPUs.
>    // Use ACPI NVS memory type because this data will be directly used by APs
>    // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
>    // will only be used as scratch space. i.e. we won't read anything from it
>    // before we write to it, in PiSmmCpuDxeSmm.
>    //
>    Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);
>    ASSERT (Stack != NULL);
>    AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;
> @@ -244,58 +260,83 @@ CpuS3DataInitialize (
>    IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;
>    Gdt = AllocateZeroPages (GdtSize + IdtSize);
>    ASSERT (Gdt != NULL);
>    Idt = (VOID *)((UINTN)Gdt + GdtSize);
>    CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);
>    CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);
>    AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;
>    AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;
>
>    if (OldAcpiCpuData != NULL) {
>      AcpiCpuData->RegisterTable           = OldAcpiCpuData->RegisterTable;
>      AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;
>      AcpiCpuData->ApLocation              = OldAcpiCpuData->ApLocation;
>      CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));
>    } else {
>      //
>      // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs
>      //
>      TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);
>      RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize);
>      ASSERT (RegisterTable != NULL);
>
> +    if (FetchPossibleApicIds) {
> +      //
> +      // Write a valid selector so that other hotplug registers can be
> +      // accessed.
> +      //
> +      IoWrite32 (ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL, 0);
> +      //
> +      // We'll be fetching the APIC IDs.
> +      //
> +      IoWrite8 (ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
> +        QEMU_CPUHP_CMD_GET_ARCH_ID);
> +    }
>      for (Index = 0; Index < NumberOfCpus; Index++) {
> -      Status = MpServices->GetProcessorInfo (
> -                           MpServices,
> -                           Index,
> -                           &ProcessorInfoBuffer
> -                           );
> -      ASSERT_EFI_ERROR (Status);
> +      UINT32 InitialApicId;
>
> -      RegisterTable[Index].InitialApicId      = (UINT32)ProcessorInfoBuffer.ProcessorId;
> +      if (FetchPossibleApicIds) {
> +        IoWrite32 (ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CPU_SEL,
> +          (UINT32)Index);
> +        InitialApicId = IoRead32 (
> +                          ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_RW_CMD_DATA);
> +      } else {
> +        Status = MpServices->GetProcessorInfo (
> +                             MpServices,
> +                             Index,
> +                             &ProcessorInfoBuffer
> +                             );
> +        ASSERT_EFI_ERROR (Status);
> +        InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;
> +      }
> +
> +      DEBUG ((DEBUG_VERBOSE, "%a: Index=%05Lu ApicId=0x%08x\n", __FUNCTION__,
> +        (UINT64)Index, InitialApicId));
> +
> +      RegisterTable[Index].InitialApicId      = InitialApicId;
>        RegisterTable[Index].TableLength        = 0;
>        RegisterTable[Index].AllocatedSize      = 0;
>        RegisterTable[Index].RegisterTableEntry = 0;
>
> -      RegisterTable[NumberOfCpus + Index].InitialApicId      = (UINT32)ProcessorInfoBuffer.ProcessorId;
> +      RegisterTable[NumberOfCpus + Index].InitialApicId      = InitialApicId;
>        RegisterTable[NumberOfCpus + Index].TableLength        = 0;
>        RegisterTable[NumberOfCpus + Index].AllocatedSize      = 0;
>        RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;
>      }
>      AcpiCpuData->RegisterTable           = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;
>      AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);
>    }
>
>    //
>    // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
>    //
>    Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
>    ASSERT_EFI_ERROR (Status);
>
>    //
>    // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
>    // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
>    //
>    Status = gBS->CreateEventEx (
>                    EVT_NOTIFY_SIGNAL,
>                    TPL_CALLBACK,
>                    CpuS3DataOnEndOfDxe,
> --
> 2.19.1.3.g30247aa5d201
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (15 preceding siblings ...)
  2020-02-26 22:11 ` [PATCH v2 16/16] OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug Laszlo Ersek
@ 2020-03-02 15:46 ` Boris Ostrovsky
  2020-03-02 19:22   ` Laszlo Ersek
  2020-03-02 19:59 ` Laszlo Ersek
  2020-03-04 12:29 ` Laszlo Ersek
  18 siblings, 1 reply; 53+ messages in thread
From: Boris Ostrovsky @ 2020-03-02 15:46 UTC (permalink / raw)
  To: Laszlo Ersek, devel

[-- Attachment #1: Type: text/plain, Size: 564 bytes --]

On Wed, Feb 26, 2020 at 05:12 PM, Laszlo Ersek wrote:

> 
> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Repo: https://github.com/lersek/edk2.git
> Branch: vcpu_hotplug_smm_bz_1512_v2
> 
> V1 was posted at:
> 
> * [edk2-devel] [PATCH 00/16]
> OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
> 
> https://edk2.groups.io/g/devel/message/54734
> http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com

Tested-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>

[-- Attachment #2: Type: text/html, Size: 1006 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-03-02 15:46 ` [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Boris Ostrovsky
@ 2020-03-02 19:22   ` Laszlo Ersek
  0 siblings, 0 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-02 19:22 UTC (permalink / raw)
  To: Boris Ostrovsky, devel

On 03/02/20 16:46, Boris Ostrovsky wrote:
> On Wed, Feb 26, 2020 at 05:12 PM, Laszlo Ersek wrote:
> 
>>
>> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
>> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
>> Repo: https://github.com/lersek/edk2.git
>> Branch: vcpu_hotplug_smm_bz_1512_v2
>>
>> V1 was posted at:
>>
>> * [edk2-devel] [PATCH 00/16]
>> OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
>>
>> https://edk2.groups.io/g/devel/message/54734
>> http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com
> 
> Tested-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
> 

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (16 preceding siblings ...)
  2020-03-02 15:46 ` [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Boris Ostrovsky
@ 2020-03-02 19:59 ` Laszlo Ersek
  2020-03-04 13:29   ` Philippe Mathieu-Daudé
  2020-03-04 12:29 ` Laszlo Ersek
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-02 19:59 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Eric Dong, Hao A Wu,
	Igor Mammedov, Jian J Wang, Jiewen Yao, Jordan Justen,
	Michael Kinney, Ray Ni, Boris Ostrovsky

On 02/26/20 23:11, Laszlo Ersek wrote:
> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
> Bugzilla:   https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Repo:       https://github.com/lersek/edk2.git
> Branch:     vcpu_hotplug_smm_bz_1512_v2
> 
> V1 was posted at:
> 
> * [edk2-devel] [PATCH 00/16]
>   OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
> 
>   https://edk2.groups.io/g/devel/message/54734
>   http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com
> 
> New in v2:
> 
> - Document (in patch#11) and implement (in patch#12) the "combined"
>   approach described here:
> 
>   http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>   https://edk2.groups.io/g/devel/message/54754
> 
>   The idea is basically to make the SMM Monarch wait not just until the
>   hot-added CPU hits the normal RAM Post-SMM Pen (which is safe wrt.
>   ordering, but can be attacked by the OS), but *also* until the
>   hot-added CPU is just about to execute RSM first (which is a bit less
>   safe wrt. ordering, but cannot be attacked by the OS).
> 
> - Pick up Ard's conditional A-b for the other patches, which have not
>   been modified.
> 
> - Rebase to master, and retest.

Thanks everyone for the feedback!

I plan to push this series soon after the hard feature freeze ends, and
edk2-stable202002 is tagged. I have three questions / remarks regarding
that:

- Phil, please tell me if you'd like me to hold the series for longer.
(You seem to have reached the end of the series, and I'm unsure about
the skipped patches -- maybe you want to skip them, maybe you need more
time for them.)

- I've talked to Igor about ordering the merging of the firmware set vs.
the merging of the QEMU patches. Igor made the great point that in this
case, QEMU is the user / consumer (ACPI payload) of the firmware
feature, and so the firmware stuff should go in first. I hadn't thought
of that, but he convinced me. The QEMU PoC patch is available, Boris has
tested the patches against each other, and this OVMF set in itself does
not regress anything functional. (Note that, while several patches in
the series *do* affect code paths that are independent of CPU hotplug, I
also regression-tested those.)

- Once the set is "in", I'll mark TianoCore#1512 as one of the new
features (for the first stable tag *after* edk2-stable202002) at
<https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Release-Planning>.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events
  2020-02-26 22:11 ` [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events Laszlo Ersek
  2020-03-02 13:49   ` Ard Biesheuvel
@ 2020-03-02 20:34   ` Philippe Mathieu-Daudé
  2020-03-03 10:31     ` Laszlo Ersek
  1 sibling, 1 reply; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-02 20:34 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 2/26/20 11:11 PM, Laszlo Ersek wrote:
> Add a function that collects the APIC IDs of CPUs that have just been
> hot-plugged, or are about to be hot-unplugged.
> 
> Pending events are only located and never cleared; QEMU's AML needs the
> firmware to leave the status bits intact in the hotplug register block.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>      v2:
>      
>      - Pick up Ard's Acked-by, which is conditional on approval from Intel
>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>        unmodified patches.)
> 
>   OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |   2 +
>   OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf           |   1 +
>   OvmfPkg/CpuHotplugSmm/ApicId.h                    |  23 +++
>   OvmfPkg/CpuHotplugSmm/QemuCpuhp.h                 |  20 ++-
>   OvmfPkg/CpuHotplugSmm/QemuCpuhp.c                 | 171 +++++++++++++++++++-
>   5 files changed, 211 insertions(+), 6 deletions(-)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> index 3d013633501b..a34a6d3fae61 100644
> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> @@ -13,32 +13,34 @@
>       The new ("modern") hotplug interface appeared in QEMU v2.7.0.
>   
>       The macros in this header file map to the minimal subset of the modern
>       interface that OVMF needs.
>   **/
>   
>   #ifndef QEMU_CPU_HOTPLUG_H_
>   #define QEMU_CPU_HOTPLUG_H_
>   
>   #include <Base.h>
>   
>   //
>   // Each register offset is:
>   // - relative to the board-dependent IO base address of the register block,
>   // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access modes of the
>   //   register,
>   // - followed by distinguished bitmasks or values in the register.
>   //
>   #define QEMU_CPUHP_R_CMD_DATA2               0x0
>   
>   #define QEMU_CPUHP_R_CPU_STAT                0x4
>   #define QEMU_CPUHP_STAT_ENABLED                BIT0
> +#define QEMU_CPUHP_STAT_INSERT                 BIT1
> +#define QEMU_CPUHP_STAT_REMOVE                 BIT2
>   
>   #define QEMU_CPUHP_RW_CMD_DATA               0x8
>   
>   #define QEMU_CPUHP_W_CPU_SEL                 0x0
>   
>   #define QEMU_CPUHP_W_CMD                     0x5
>   #define QEMU_CPUHP_CMD_GET_PENDING             0x0
>   #define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
>   
>   #endif // QEMU_CPU_HOTPLUG_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> index ac4ca4c1f4f2..ab690a9e5e20 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
> @@ -3,44 +3,45 @@
>   #
>   # Copyright (c) 2020, Red Hat, Inc.
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   ##
>   
>   [Defines]
>     INF_VERSION                = 1.29
>     PI_SPECIFICATION_VERSION   = 0x00010046                            # PI-1.7.0
>     BASE_NAME                  = CpuHotplugSmm
>     FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>     MODULE_TYPE                = DXE_SMM_DRIVER
>     ENTRY_POINT                = CpuHotplugEntry
>   
>   #
>   # The following information is for reference only and not required by the build
>   # tools.
>   #
>   # VALID_ARCHITECTURES        = IA32 X64
>   #
>   
>   [Sources]
> +  ApicId.h
>     CpuHotplug.c
>     QemuCpuhp.c
>     QemuCpuhp.h
>   
>   [Packages]
>     MdePkg/MdePkg.dec
>     OvmfPkg/OvmfPkg.dec
>   
>   [LibraryClasses]
>     BaseLib
>     DebugLib
>     MmServicesTableLib
>     PcdLib
>     UefiDriverEntryPoint
>   
>   [Protocols]
>     gEfiMmCpuIoProtocolGuid                                           ## CONSUMES
>   
>   [Pcd]
>     gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES
>   
>   [FeaturePcd]
> diff --git a/OvmfPkg/CpuHotplugSmm/ApicId.h b/OvmfPkg/CpuHotplugSmm/ApicId.h
> new file mode 100644
> index 000000000000..3c365148ed02
> --- /dev/null
> +++ b/OvmfPkg/CpuHotplugSmm/ApicId.h
> @@ -0,0 +1,23 @@
> +/** @file
> +  Type and macro definitions for representing and printing APIC IDs, compatibly
> +  with the LocalApicLib and PrintLib classes, respectively.
> +
> +  Copyright (c) 2020, Red Hat, Inc.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef APIC_ID_H_
> +#define APIC_ID_H_
> +
> +//
> +// The type that LocalApicLib represents an APIC ID with.
> +//
> +typedef UINT32 APIC_ID;
> +
> +//
> +// The PrintLib conversion specification for formatting an APIC_ID.
> +//
> +#define FMT_APIC_ID "0x%08x"
> +
> +#endif // APIC_ID_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> index 82f88f0b73bb..8adaa0ad91f0 100644
> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
> @@ -1,47 +1,61 @@
>   /** @file
> -  Simple wrapper functions that access QEMU's modern CPU hotplug register
> -  block.
> +  Simple wrapper functions and utility functions that access QEMU's modern CPU
> +  hotplug register block.
>   
> -  These functions thinly wrap some of the registers described in
> +  These functions manipulate some of the registers described in
>     "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
>     via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
>     return.
>   
>     Copyright (c) 2020, Red Hat, Inc.
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
>   
>   #ifndef QEMU_CPUHP_H_
>   #define QEMU_CPUHP_H_
>   
>   #include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
> +#include <Uefi/UefiBaseType.h> // EFI_STATUS
> +
> +#include "ApicId.h"            // APIC_ID
>   
>   UINT32
>   QemuCpuhpReadCommandData2 (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>     );
>   
>   UINT8
>   QemuCpuhpReadCpuStatus (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>     );
>   
>   UINT32
>   QemuCpuhpReadCommandData (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>     );
>   
>   VOID
>   QemuCpuhpWriteCpuSelector (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>     IN UINT32                       Selector
>     );
>   
>   VOID
>   QemuCpuhpWriteCommand (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>     IN UINT8                        Command
>     );
>   
> +EFI_STATUS
> +QemuCpuhpCollectApicIds (
> +  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN  UINT32                       PossibleCpuCount,
> +  IN  UINT32                       ApicIdCount,
> +  OUT APIC_ID                      *PluggedApicIds,
> +  OUT UINT32                       *PluggedCount,
> +  OUT APIC_ID                      *ToUnplugApicIds,
> +  OUT UINT32                       *ToUnplugCount
> +  );
> +
>   #endif // QEMU_CPUHP_H_
> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> index 31e46f51934a..8d4a6693c8d6 100644
> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
> @@ -1,27 +1,27 @@
>   /** @file
> -  Simple wrapper functions that access QEMU's modern CPU hotplug register
> -  block.
> +  Simple wrapper functions and utility functions that access QEMU's modern CPU
> +  hotplug register block.
>   
> -  These functions thinly wrap some of the registers described in
> +  These functions manipulate some of the registers described in
>     "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are accessed
>     via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these functions don't
>     return.
>   
>     Copyright (c) 2020, Red Hat, Inc.
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
>   
>   #include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
>   #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
>   #include <Library/BaseLib.h>                 // CpuDeadLoop()
>   #include <Library/DebugLib.h>                // DEBUG()
>   
>   #include "QemuCpuhp.h"
>   
>   UINT32
>   QemuCpuhpReadCommandData2 (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>     )
>   {
>     UINT32     CommandData2;
> @@ -115,22 +115,187 @@ QemuCpuhpWriteCpuSelector (
>   
>   VOID
>   QemuCpuhpWriteCommand (
>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>     IN UINT8                        Command
>     )
>   {
>     EFI_STATUS Status;
>   
>     Status = MmCpuIo->Io.Write (
>                            MmCpuIo,
>                            MM_IO_UINT8,
>                            ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
>                            1,
>                            &Command
>                            );
>     if (EFI_ERROR (Status)) {
>       DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
>       ASSERT (FALSE);
>       CpuDeadLoop ();
>     }
>   }
> +
> +/**
> +  Collect the APIC IDs of
> +  - the CPUs that have been hot-plugged,
> +  - the CPUs that are about to be hot-unplugged.
> +
> +  This function only scans for events -- it does not modify them -- in the
> +  hotplug registers.
> +
> +  On error, the contents of the output parameters are undefined.
> +
> +  @param[in] MmCpuIo           The EFI_MM_CPU_IO_PROTOCOL instance for
> +                               accessing IO Ports.
> +
> +  @param[in] PossibleCpuCount  The number of possible CPUs in the system. Must
> +                               be positive.

Maybe nitpicking: "positive (non zero)"?

> +
> +  @param[in] ApicIdCount       The number of elements each one of the
> +                               PluggedApicIds and ToUnplugApicIds arrays can
> +                               accommodate. Must be positive.
> +
> +  @param[out] PluggedApicIds   The APIC IDs of the CPUs that have been
> +                               hot-plugged.
> +
> +  @param[out] PluggedCount     The number of filled-in APIC IDs in
> +                               PluggedApicIds.
> +
> +  @param[out] ToUnplugApicIds  The APIC IDs of the CPUs that are about to be
> +                               hot-unplugged.
> +
> +  @param[out] ToUnplugCount    The number of filled-in APIC IDs in
> +                               ToUnplugApicIds.
> +
> +  @retval EFI_INVALID_PARAMETER  PossibleCpuCount is zero, or ApicIdCount is
> +                                 zero.
> +
> +  @retval EFI_PROTOCOL_ERROR     Invalid bitmap detected in the
> +                                 QEMU_CPUHP_R_CPU_STAT register.
> +
> +  @retval EFI_BUFFER_TOO_SMALL   There was an attempt to place more than
> +                                 ApicIdCount APIC IDs into one of the
> +                                 PluggedApicIds and ToUnplugApicIds arrays.
> +
> +  @retval EFI_SUCCESS            Output parameters have been set successfully.
> +**/
> +EFI_STATUS
> +QemuCpuhpCollectApicIds (
> +  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
> +  IN  UINT32                       PossibleCpuCount,
> +  IN  UINT32                       ApicIdCount,
> +  OUT APIC_ID                      *PluggedApicIds,
> +  OUT UINT32                       *PluggedCount,
> +  OUT APIC_ID                      *ToUnplugApicIds,
> +  OUT UINT32                       *ToUnplugCount
> +  )
> +{
> +  UINT32 CurrentSelector;
> +
> +  if (PossibleCpuCount == 0 || ApicIdCount == 0) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *PluggedCount = 0;
> +  *ToUnplugCount = 0;
> +
> +  CurrentSelector = 0;
> +  do {
> +    UINT32  PendingSelector;
> +    UINT8   CpuStatus;
> +    APIC_ID *ExtendIds;
> +    UINT32  *ExtendCount;
> +    APIC_ID NewApicId;
> +
> +    //
> +    // Write CurrentSelector (which is valid) to the CPU selector register.
> +    // Consequences:
> +    //
> +    // - Other register accesses will be permitted.
> +    //
> +    // - The QEMU_CPUHP_CMD_GET_PENDING command will start scanning for a CPU
> +    //   with pending events at CurrentSelector (inclusive).
> +    //
> +    QemuCpuhpWriteCpuSelector (MmCpuIo, CurrentSelector);
> +    //
> +    // Write the QEMU_CPUHP_CMD_GET_PENDING command. Consequences
> +    // (independently of each other):
> +    //
> +    // - If there is a CPU with pending events, starting at CurrentSelector
> +    //   (inclusive), the CPU selector will be updated to that CPU. Note that
> +    //   the scanning in QEMU may wrap around, because we must never clear the
> +    //   event bits.
> +    //
> +    // - The QEMU_CPUHP_RW_CMD_DATA register will return the (possibly updated)
> +    //   CPU selector value.
> +    //
> +    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
> +    PendingSelector = QemuCpuhpReadCommandData (MmCpuIo);
> +    if (PendingSelector < CurrentSelector) {
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u PendingSelector=%u: "
> +        "wrap-around\n", __FUNCTION__, CurrentSelector, PendingSelector));
> +      break;
> +    }
> +    CurrentSelector = PendingSelector;
> +
> +    //
> +    // Check the known status / event bits for the currently selected CPU.
> +    //
> +    CpuStatus = QemuCpuhpReadCpuStatus (MmCpuIo);
> +    if ((CpuStatus & QEMU_CPUHP_STAT_INSERT) != 0) {
> +      //
> +      // The "insert" event guarantees the "enabled" status; plus it excludes
> +      // the "remove" event.
> +      //
> +      if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) == 0 ||
> +          (CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
> +        DEBUG ((DEBUG_ERROR, "%a: CurrentSelector=%u CpuStatus=0x%x: "
> +          "inconsistent CPU status\n", __FUNCTION__, CurrentSelector,
> +          CpuStatus));
> +        return EFI_PROTOCOL_ERROR;
> +      }
> +
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: insert\n", __FUNCTION__,
> +        CurrentSelector));
> +
> +      ExtendIds   = PluggedApicIds;
> +      ExtendCount = PluggedCount;
> +    } else if ((CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: remove\n", __FUNCTION__,
> +        CurrentSelector));
> +
> +      ExtendIds   = ToUnplugApicIds;
> +      ExtendCount = ToUnplugCount;
> +    } else {
> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: no event\n",
> +        __FUNCTION__, CurrentSelector));
> +      break;
> +    }
> +
> +    //
> +    // Save the APIC ID of the CPU with the pending event, to the corresponding
> +    // APIC ID array.
> +    //
> +    if (*ExtendCount == ApicIdCount) {
> +      DEBUG ((DEBUG_ERROR, "%a: APIC ID array too small\n", __FUNCTION__));
> +      return EFI_BUFFER_TOO_SMALL;
> +    }
> +    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_ARCH_ID);
> +    NewApicId = QemuCpuhpReadCommandData (MmCpuIo);
> +    DEBUG ((DEBUG_VERBOSE, "%a: ApicId=" FMT_APIC_ID "\n", __FUNCTION__,
> +      NewApicId));
> +    ExtendIds[(*ExtendCount)++] = NewApicId;
> +
> +    //
> +    // We've processed the CPU with (known) pending events, but we must never
> +    // clear events. Therefore we need to advance past this CPU manually;
> +    // otherwise, QEMU_CPUHP_CMD_GET_PENDING would stick to the currently
> +    // selected CPU.
> +    //
> +    CurrentSelector++;
> +  } while (CurrentSelector < PossibleCpuCount);
> +
> +  DEBUG ((DEBUG_VERBOSE, "%a: PluggedCount=%u ToUnplugCount=%u\n",
> +    __FUNCTION__, *PluggedCount, *ToUnplugCount));
> +  return EFI_SUCCESS;
> +}
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure
  2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
  2020-03-02 12:47   ` [edk2-devel] " Laszlo Ersek
  2020-03-02 13:46   ` Philippe Mathieu-Daudé
@ 2020-03-03  0:46   ` Dong, Eric
  2 siblings, 0 replies; 53+ messages in thread
From: Dong, Eric @ 2020-03-03  0:46 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Wu, Hao A, Igor Mammedov, Wang, Jian J,
	Yao, Jiewen, Justen, Jordan L, Kinney, Michael D,
	Philippe Mathieu-Daudé, Ni, Ray

Hi Laszlo,

Reviewed-by: Eric Dong <eric.dong@intel.com>

Thanks,
Eric
> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Thursday, February 27, 2020 6:12 AM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Dong, Eric
> <eric.dong@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Igor Mammedov
> <imammedo@redhat.com>; Wang, Jian J <jian.j.wang@intel.com>; Yao,
> Jiewen <jiewen.yao@intel.com>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Philippe Mathieu-Daudé
> <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>
> Subject: [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start
> failure
> 
> In the CoreStartImage() function
> [MdeModulePkg/Core/Dxe/Image/Image.c], if the image entry point returns
> a failure code, then the DXE Core logs a helpful DEBUG_ERROR message,
> with the following format string:
> 
>   "Error: Image at %11p start failed: %r\n"
> 
> Do similarly in the SMM Core (update the message slightly).
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> 
> Notes:
>     v2:
> 
>     - Pick up Ard's Acked-by, which is conditional on approval from Intel
>       reviewers on Cc. (I'd like to save Ard the churn of re-acking
>       unmodified patches.)
> 
>  MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> index 9bec731e5312..76ee9e0b89cc 100644
> --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
> @@ -883,44 +883,50 @@ SmmDispatcher (
>        RemoveEntryList (&DriverEntry->ScheduledLink);
> 
>        REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
>          EFI_PROGRESS_CODE,
>          EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
>          &DriverEntry->ImageHandle,
>          sizeof (DriverEntry->ImageHandle)
>          );
> 
>        //
>        // Cache state of SmmEntryPointRegistered before calling entry point
>        //
>        PreviousSmmEntryPointRegistered = gSmmCorePrivate-
> >SmmEntryPointRegistered;
> 
>        //
>        // For each SMM driver, pass NULL as ImageHandle
>        //
>        RegisterSmramProfileImage (DriverEntry, TRUE);
>        PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
>        Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry-
> >ImageEntryPoint)(DriverEntry->ImageHandle, gST);
>        PERF_START_IMAGE_END (DriverEntry->ImageHandle);
>        if (EFI_ERROR(Status)){
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "Error: SMM image at %11p start failed: %r\n",
> +          DriverEntry->SmmLoadedImage.ImageBase,
> +          Status
> +          ));
>          UnregisterSmramProfileImage (DriverEntry, TRUE);
>          SmmFreePages(DriverEntry->ImageBuffer, DriverEntry-
> >NumberOfPage);
>          //
>          // Uninstall LoadedImage
>          //
>          Status = gBS->UninstallProtocolInterface (
>                          DriverEntry->ImageHandle,
>                          &gEfiLoadedImageProtocolGuid,
>                          DriverEntry->LoadedImage
>                          );
>          if (!EFI_ERROR (Status)) {
>            if (DriverEntry->LoadedImage->FilePath != NULL) {
>              gBS->FreePool (DriverEntry->LoadedImage->FilePath);
>            }
>            gBS->FreePool (DriverEntry->LoadedImage);
>          }
>          Status = SmmUninstallProtocolInterface (
>                     DriverEntry->SmmImageHandle,
>                     &gEfiLoadedImageProtocolGuid,
>                     &DriverEntry->SmmLoadedImage
>                     );
>          if (!EFI_ERROR(Status)) {
> --
> 2.19.1.3.g30247aa5d201
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events
  2020-03-02 20:34   ` Philippe Mathieu-Daudé
@ 2020-03-03 10:31     ` Laszlo Ersek
  0 siblings, 0 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-03 10:31 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, edk2-devel-groups-io
  Cc: Ard Biesheuvel, Igor Mammedov, Jiewen Yao, Jordan Justen,
	Michael Kinney

On 03/02/20 21:34, Philippe Mathieu-Daudé wrote:
> On 2/26/20 11:11 PM, Laszlo Ersek wrote:
>> Add a function that collects the APIC IDs of CPUs that have just been
>> hot-plugged, or are about to be hot-unplugged.
>>
>> Pending events are only located and never cleared; QEMU's AML needs the
>> firmware to leave the status bits intact in the hotplug register block.
>>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Jiewen Yao <jiewen.yao@intel.com>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Michael Kinney <michael.d.kinney@intel.com>
>> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
>> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>
>> Notes:
>>      v2:
>>           - Pick up Ard's Acked-by, which is conditional on approval
>> from Intel
>>        reviewers on Cc. (I'd like to save Ard the churn of re-acking
>>        unmodified patches.)
>>
>>   OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |   2 +
>>   OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf           |   1 +
>>   OvmfPkg/CpuHotplugSmm/ApicId.h                    |  23 +++
>>   OvmfPkg/CpuHotplugSmm/QemuCpuhp.h                 |  20 ++-
>>   OvmfPkg/CpuHotplugSmm/QemuCpuhp.c                 | 171
>> +++++++++++++++++++-
>>   5 files changed, 211 insertions(+), 6 deletions(-)
>>
>> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
>> b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
>> index 3d013633501b..a34a6d3fae61 100644
>> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
>> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
>> @@ -13,32 +13,34 @@
>>       The new ("modern") hotplug interface appeared in QEMU v2.7.0.
>>         The macros in this header file map to the minimal subset of
>> the modern
>>       interface that OVMF needs.
>>   **/
>>     #ifndef QEMU_CPU_HOTPLUG_H_
>>   #define QEMU_CPU_HOTPLUG_H_
>>     #include <Base.h>
>>     //
>>   // Each register offset is:
>>   // - relative to the board-dependent IO base address of the register
>> block,
>>   // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible access
>> modes of the
>>   //   register,
>>   // - followed by distinguished bitmasks or values in the register.
>>   //
>>   #define QEMU_CPUHP_R_CMD_DATA2               0x0
>>     #define QEMU_CPUHP_R_CPU_STAT                0x4
>>   #define QEMU_CPUHP_STAT_ENABLED                BIT0
>> +#define QEMU_CPUHP_STAT_INSERT                 BIT1
>> +#define QEMU_CPUHP_STAT_REMOVE                 BIT2
>>     #define QEMU_CPUHP_RW_CMD_DATA               0x8
>>     #define QEMU_CPUHP_W_CPU_SEL                 0x0
>>     #define QEMU_CPUHP_W_CMD                     0x5
>>   #define QEMU_CPUHP_CMD_GET_PENDING             0x0
>>   #define QEMU_CPUHP_CMD_GET_ARCH_ID             0x3
>>     #endif // QEMU_CPU_HOTPLUG_H_
>> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>> b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>> index ac4ca4c1f4f2..ab690a9e5e20 100644
>> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>> @@ -3,44 +3,45 @@
>>   #
>>   # Copyright (c) 2020, Red Hat, Inc.
>>   #
>>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>>   ##
>>     [Defines]
>>     INF_VERSION                = 1.29
>>     PI_SPECIFICATION_VERSION   = 0x00010046                           
>> # PI-1.7.0
>>     BASE_NAME                  = CpuHotplugSmm
>>     FILE_GUID                  = 84EEA114-C6BE-4445-8F90-51D97863E363
>>     MODULE_TYPE                = DXE_SMM_DRIVER
>>     ENTRY_POINT                = CpuHotplugEntry
>>     #
>>   # The following information is for reference only and not required
>> by the build
>>   # tools.
>>   #
>>   # VALID_ARCHITECTURES        = IA32 X64
>>   #
>>     [Sources]
>> +  ApicId.h
>>     CpuHotplug.c
>>     QemuCpuhp.c
>>     QemuCpuhp.h
>>     [Packages]
>>     MdePkg/MdePkg.dec
>>     OvmfPkg/OvmfPkg.dec
>>     [LibraryClasses]
>>     BaseLib
>>     DebugLib
>>     MmServicesTableLib
>>     PcdLib
>>     UefiDriverEntryPoint
>>     [Protocols]
>>     gEfiMmCpuIoProtocolGuid                                          
>> ## CONSUMES
>>     [Pcd]
>>     gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase            
>> ## CONSUMES
>>     [FeaturePcd]
>> diff --git a/OvmfPkg/CpuHotplugSmm/ApicId.h
>> b/OvmfPkg/CpuHotplugSmm/ApicId.h
>> new file mode 100644
>> index 000000000000..3c365148ed02
>> --- /dev/null
>> +++ b/OvmfPkg/CpuHotplugSmm/ApicId.h
>> @@ -0,0 +1,23 @@
>> +/** @file
>> +  Type and macro definitions for representing and printing APIC IDs,
>> compatibly
>> +  with the LocalApicLib and PrintLib classes, respectively.
>> +
>> +  Copyright (c) 2020, Red Hat, Inc.
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef APIC_ID_H_
>> +#define APIC_ID_H_
>> +
>> +//
>> +// The type that LocalApicLib represents an APIC ID with.
>> +//
>> +typedef UINT32 APIC_ID;
>> +
>> +//
>> +// The PrintLib conversion specification for formatting an APIC_ID.
>> +//
>> +#define FMT_APIC_ID "0x%08x"
>> +
>> +#endif // APIC_ID_H_
>> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
>> b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
>> index 82f88f0b73bb..8adaa0ad91f0 100644
>> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
>> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
>> @@ -1,47 +1,61 @@
>>   /** @file
>> -  Simple wrapper functions that access QEMU's modern CPU hotplug
>> register
>> -  block.
>> +  Simple wrapper functions and utility functions that access QEMU's
>> modern CPU
>> +  hotplug register block.
>>   -  These functions thinly wrap some of the registers described in
>> +  These functions manipulate some of the registers described in
>>     "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are
>> accessed
>>     via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these
>> functions don't
>>     return.
>>       Copyright (c) 2020, Red Hat, Inc.
>>       SPDX-License-Identifier: BSD-2-Clause-Patent
>>   **/
>>     #ifndef QEMU_CPUHP_H_
>>   #define QEMU_CPUHP_H_
>>     #include <Protocol/MmCpuIo.h>  // EFI_MM_CPU_IO_PROTOCOL
>> +#include <Uefi/UefiBaseType.h> // EFI_STATUS
>> +
>> +#include "ApicId.h"            // APIC_ID
>>     UINT32
>>   QemuCpuhpReadCommandData2 (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>>     );
>>     UINT8
>>   QemuCpuhpReadCpuStatus (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>>     );
>>     UINT32
>>   QemuCpuhpReadCommandData (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>>     );
>>     VOID
>>   QemuCpuhpWriteCpuSelector (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>>     IN UINT32                       Selector
>>     );
>>     VOID
>>   QemuCpuhpWriteCommand (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>>     IN UINT8                        Command
>>     );
>>   +EFI_STATUS
>> +QemuCpuhpCollectApicIds (
>> +  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>> +  IN  UINT32                       PossibleCpuCount,
>> +  IN  UINT32                       ApicIdCount,
>> +  OUT APIC_ID                      *PluggedApicIds,
>> +  OUT UINT32                       *PluggedCount,
>> +  OUT APIC_ID                      *ToUnplugApicIds,
>> +  OUT UINT32                       *ToUnplugCount
>> +  );
>> +
>>   #endif // QEMU_CPUHP_H_
>> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
>> b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
>> index 31e46f51934a..8d4a6693c8d6 100644
>> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
>> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
>> @@ -1,27 +1,27 @@
>>   /** @file
>> -  Simple wrapper functions that access QEMU's modern CPU hotplug
>> register
>> -  block.
>> +  Simple wrapper functions and utility functions that access QEMU's
>> modern CPU
>> +  hotplug register block.
>>   -  These functions thinly wrap some of the registers described in
>> +  These functions manipulate some of the registers described in
>>     "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source. IO Ports are
>> accessed
>>     via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails, these
>> functions don't
>>     return.
>>       Copyright (c) 2020, Red Hat, Inc.
>>       SPDX-License-Identifier: BSD-2-Clause-Patent
>>   **/
>>     #include <IndustryStandard/Q35MchIch9.h>     // ICH9_CPU_HOTPLUG_BASE
>>   #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_R_CMD_DATA2
>>   #include <Library/BaseLib.h>                 // CpuDeadLoop()
>>   #include <Library/DebugLib.h>                // DEBUG()
>>     #include "QemuCpuhp.h"
>>     UINT32
>>   QemuCpuhpReadCommandData2 (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo
>>     )
>>   {
>>     UINT32     CommandData2;
>> @@ -115,22 +115,187 @@ QemuCpuhpWriteCpuSelector (
>>     VOID
>>   QemuCpuhpWriteCommand (
>>     IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>>     IN UINT8                        Command
>>     )
>>   {
>>     EFI_STATUS Status;
>>       Status = MmCpuIo->Io.Write (
>>                            MmCpuIo,
>>                            MM_IO_UINT8,
>>                            ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD,
>>                            1,
>>                            &Command
>>                            );
>>     if (EFI_ERROR (Status)) {
>>       DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
>>       ASSERT (FALSE);
>>       CpuDeadLoop ();
>>     }
>>   }
>> +
>> +/**
>> +  Collect the APIC IDs of
>> +  - the CPUs that have been hot-plugged,
>> +  - the CPUs that are about to be hot-unplugged.
>> +
>> +  This function only scans for events -- it does not modify them --
>> in the
>> +  hotplug registers.
>> +
>> +  On error, the contents of the output parameters are undefined.
>> +
>> +  @param[in] MmCpuIo           The EFI_MM_CPU_IO_PROTOCOL instance for
>> +                               accessing IO Ports.
>> +
>> +  @param[in] PossibleCpuCount  The number of possible CPUs in the
>> system. Must
>> +                               be positive.
> 
> Maybe nitpicking: "positive (non zero)"?

Zero is not positive, zero is zero. Positive implies nonzero. :)

Thanks
Laszlo

> 
>> +
>> +  @param[in] ApicIdCount       The number of elements each one of the
>> +                               PluggedApicIds and ToUnplugApicIds
>> arrays can
>> +                               accommodate. Must be positive.
>> +
>> +  @param[out] PluggedApicIds   The APIC IDs of the CPUs that have been
>> +                               hot-plugged.
>> +
>> +  @param[out] PluggedCount     The number of filled-in APIC IDs in
>> +                               PluggedApicIds.
>> +
>> +  @param[out] ToUnplugApicIds  The APIC IDs of the CPUs that are
>> about to be
>> +                               hot-unplugged.
>> +
>> +  @param[out] ToUnplugCount    The number of filled-in APIC IDs in
>> +                               ToUnplugApicIds.
>> +
>> +  @retval EFI_INVALID_PARAMETER  PossibleCpuCount is zero, or
>> ApicIdCount is
>> +                                 zero.
>> +
>> +  @retval EFI_PROTOCOL_ERROR     Invalid bitmap detected in the
>> +                                 QEMU_CPUHP_R_CPU_STAT register.
>> +
>> +  @retval EFI_BUFFER_TOO_SMALL   There was an attempt to place more than
>> +                                 ApicIdCount APIC IDs into one of the
>> +                                 PluggedApicIds and ToUnplugApicIds
>> arrays.
>> +
>> +  @retval EFI_SUCCESS            Output parameters have been set
>> successfully.
>> +**/
>> +EFI_STATUS
>> +QemuCpuhpCollectApicIds (
>> +  IN  CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo,
>> +  IN  UINT32                       PossibleCpuCount,
>> +  IN  UINT32                       ApicIdCount,
>> +  OUT APIC_ID                      *PluggedApicIds,
>> +  OUT UINT32                       *PluggedCount,
>> +  OUT APIC_ID                      *ToUnplugApicIds,
>> +  OUT UINT32                       *ToUnplugCount
>> +  )
>> +{
>> +  UINT32 CurrentSelector;
>> +
>> +  if (PossibleCpuCount == 0 || ApicIdCount == 0) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  *PluggedCount = 0;
>> +  *ToUnplugCount = 0;
>> +
>> +  CurrentSelector = 0;
>> +  do {
>> +    UINT32  PendingSelector;
>> +    UINT8   CpuStatus;
>> +    APIC_ID *ExtendIds;
>> +    UINT32  *ExtendCount;
>> +    APIC_ID NewApicId;
>> +
>> +    //
>> +    // Write CurrentSelector (which is valid) to the CPU selector
>> register.
>> +    // Consequences:
>> +    //
>> +    // - Other register accesses will be permitted.
>> +    //
>> +    // - The QEMU_CPUHP_CMD_GET_PENDING command will start scanning
>> for a CPU
>> +    //   with pending events at CurrentSelector (inclusive).
>> +    //
>> +    QemuCpuhpWriteCpuSelector (MmCpuIo, CurrentSelector);
>> +    //
>> +    // Write the QEMU_CPUHP_CMD_GET_PENDING command. Consequences
>> +    // (independently of each other):
>> +    //
>> +    // - If there is a CPU with pending events, starting at
>> CurrentSelector
>> +    //   (inclusive), the CPU selector will be updated to that CPU.
>> Note that
>> +    //   the scanning in QEMU may wrap around, because we must never
>> clear the
>> +    //   event bits.
>> +    //
>> +    // - The QEMU_CPUHP_RW_CMD_DATA register will return the
>> (possibly updated)
>> +    //   CPU selector value.
>> +    //
>> +    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_PENDING);
>> +    PendingSelector = QemuCpuhpReadCommandData (MmCpuIo);
>> +    if (PendingSelector < CurrentSelector) {
>> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u
>> PendingSelector=%u: "
>> +        "wrap-around\n", __FUNCTION__, CurrentSelector,
>> PendingSelector));
>> +      break;
>> +    }
>> +    CurrentSelector = PendingSelector;
>> +
>> +    //
>> +    // Check the known status / event bits for the currently selected
>> CPU.
>> +    //
>> +    CpuStatus = QemuCpuhpReadCpuStatus (MmCpuIo);
>> +    if ((CpuStatus & QEMU_CPUHP_STAT_INSERT) != 0) {
>> +      //
>> +      // The "insert" event guarantees the "enabled" status; plus it
>> excludes
>> +      // the "remove" event.
>> +      //
>> +      if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) == 0 ||
>> +          (CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
>> +        DEBUG ((DEBUG_ERROR, "%a: CurrentSelector=%u CpuStatus=0x%x: "
>> +          "inconsistent CPU status\n", __FUNCTION__, CurrentSelector,
>> +          CpuStatus));
>> +        return EFI_PROTOCOL_ERROR;
>> +      }
>> +
>> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: insert\n",
>> __FUNCTION__,
>> +        CurrentSelector));
>> +
>> +      ExtendIds   = PluggedApicIds;
>> +      ExtendCount = PluggedCount;
>> +    } else if ((CpuStatus & QEMU_CPUHP_STAT_REMOVE) != 0) {
>> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: remove\n",
>> __FUNCTION__,
>> +        CurrentSelector));
>> +
>> +      ExtendIds   = ToUnplugApicIds;
>> +      ExtendCount = ToUnplugCount;
>> +    } else {
>> +      DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelector=%u: no event\n",
>> +        __FUNCTION__, CurrentSelector));
>> +      break;
>> +    }
>> +
>> +    //
>> +    // Save the APIC ID of the CPU with the pending event, to the
>> corresponding
>> +    // APIC ID array.
>> +    //
>> +    if (*ExtendCount == ApicIdCount) {
>> +      DEBUG ((DEBUG_ERROR, "%a: APIC ID array too small\n",
>> __FUNCTION__));
>> +      return EFI_BUFFER_TOO_SMALL;
>> +    }
>> +    QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_ARCH_ID);
>> +    NewApicId = QemuCpuhpReadCommandData (MmCpuIo);
>> +    DEBUG ((DEBUG_VERBOSE, "%a: ApicId=" FMT_APIC_ID "\n", __FUNCTION__,
>> +      NewApicId));
>> +    ExtendIds[(*ExtendCount)++] = NewApicId;
>> +
>> +    //
>> +    // We've processed the CPU with (known) pending events, but we
>> must never
>> +    // clear events. Therefore we need to advance past this CPU
>> manually;
>> +    // otherwise, QEMU_CPUHP_CMD_GET_PENDING would stick to the
>> currently
>> +    // selected CPU.
>> +    //
>> +    CurrentSelector++;
>> +  } while (CurrentSelector < PossibleCpuCount);
>> +
>> +  DEBUG ((DEBUG_VERBOSE, "%a: PluggedCount=%u ToUnplugCount=%u\n",
>> +    __FUNCTION__, *PluggedCount, *ToUnplugCount));
>> +  return EFI_SUCCESS;
>> +}
>>
> 
> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
  2020-02-28  3:05   ` [edk2-devel] " Dong, Eric
  2020-02-28 10:50     ` Laszlo Ersek
@ 2020-03-04 12:23     ` Laszlo Ersek
  2020-03-04 14:36       ` Dong, Eric
  1 sibling, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-04 12:23 UTC (permalink / raw)
  To: devel, eric.dong
  Cc: Ard Biesheuvel, Igor Mammedov, Yao, Jiewen, Justen, Jordan L,
	Kinney, Michael D, Philippe Mathieu-Daudé, Ni, Ray,
	Boris Ostrovsky

Hi Eric,

On 02/28/20 04:05, Dong, Eric wrote:
> Hi Laszlo,
>
> Thanks for your patch. The change make sense base on the comments in
> the data structure header file.
>
> I also checked all the code related to this data structure. The inputs
> for this data structure are CpuS3DataDxe and RegisterCpuFeaturesLib.
> Both these two drivers not support CPU hot plug feature, so the real
> inputs for mAcpiCpuData.NumberOfCpus is the enabled CPU number in this
> system. So before and after your code change, the CPU values are same.
> But the data structure comments said it can support CPU hot plug, so I
> agree your code change.
>
> Reviewed-by: Eric Dong <eric.dong@intel.com>

while merging this patch, the edk2 CI system reported the following
build warning (in the "Windows VS2019 PR" check):

https://github.com/tianocore/edk2/pull/416/checks?check_run_id=484688972
https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=4568&view=logs&j=898a5c7a-7a49-5be1-c417-92a6761a8039&t=7c50f5c2-8a2c-50f9-5007-e26f12377af8&l=64

> 2020-03-04T11:06:29.7838532Z ERROR - Compiler #2220 from d:\a\1\s\UefiCpuPkg\PiSmmCpuDxeSmm\CpuS3.c(624):   the following warning is treated as an error
> 2020-03-04T11:06:29.7839570Z WARNING - Compiler #4244 from d:\a\1\s\UefiCpuPkg\PiSmmCpuDxeSmm\CpuS3.c(624):   '=': conversion from 'UINTN' to 'volatile UINT32', possible loss of data
> 2020-03-04T11:06:29.7841177Z WARNING - Compiler #4244 from d:\a\1\s\UefiCpuPkg\PiSmmCpuDxeSmm\CpuS3.c(659):   '=': conversion from 'UINTN' to 'volatile UINT32', possible loss of data

I've suppressed that by squashing the following hunks into the patch:

> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> index 1e0840119724..29e9ba92b453 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> @@ -621,7 +621,7 @@ InitializeCpuBeforeRebase (
>    } else {
>      ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);
>    }
> -  mNumberToFinish = mNumberOfCpus - 1;
> +  mNumberToFinish = (UINT32)(mNumberOfCpus - 1);
>    mExchangeInfo->ApFunction  = (VOID *) (UINTN) InitializeAp;
>
>    //
> @@ -656,7 +656,7 @@ InitializeCpuAfterRebase (
>    } else {
>      ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);
>    }
> -  mNumberToFinish = mNumberOfCpus - 1;
> +  mNumberToFinish = (UINT32)(mNumberOfCpus - 1);
>
>    //
>    // Signal that SMM base relocation is complete and to continue initialization for all APs.

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
                   ` (17 preceding siblings ...)
  2020-03-02 19:59 ` Laszlo Ersek
@ 2020-03-04 12:29 ` Laszlo Ersek
  2020-03-05  8:32   ` Laszlo Ersek
  18 siblings, 1 reply; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-04 12:29 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney,
	Philippe Mathieu-Daudé, Ray Ni

On 02/26/20 23:11, Laszlo Ersek wrote:
> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
> Bugzilla:   https://bugzilla.tianocore.org/show_bug.cgi?id=1512
> Repo:       https://github.com/lersek/edk2.git
> Branch:     vcpu_hotplug_smm_bz_1512_v2
> 
> V1 was posted at:
> 
> * [edk2-devel] [PATCH 00/16]
>   OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
> 
>   https://edk2.groups.io/g/devel/message/54734
>   http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com
> 
> New in v2:
> 
> - Document (in patch#11) and implement (in patch#12) the "combined"
>   approach described here:
> 
>   http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>   https://edk2.groups.io/g/devel/message/54754
> 
>   The idea is basically to make the SMM Monarch wait not just until the
>   hot-added CPU hits the normal RAM Post-SMM Pen (which is safe wrt.
>   ordering, but can be attacked by the OS), but *also* until the
>   hot-added CPU is just about to execute RSM first (which is a bit less
>   safe wrt. ordering, but cannot be attacked by the OS).
> 
> - Pick up Ard's conditional A-b for the other patches, which have not
>   been modified.
> 
> - Rebase to master, and retest.
> 
> See the Notes sections on the individual patches.
> 
> I wanted to get v2 out on the list before having to ask Intel folks to
> do an incremental review.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Michael Kinney <michael.d.kinney@intel.com>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> 
> Thanks,
> Laszlo
> 
> Laszlo Ersek (16):
>   MdeModulePkg/PiSmmCore: log SMM image start failure
>   UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
>   OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg
>   OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm
>   OvmfPkg: enable CPU hotplug support in PiSmmCpuDxeSmm
>   OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver
>   OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions
>   OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro
>   OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events
>   OvmfPkg/CpuHotplugSmm: collect CPUs with events
>   OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs
>   OvmfPkg/CpuHotplugSmm: introduce First SMI Handler for hot-added CPUs
>   OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug
>   OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg
>   OvmfPkg/CpuS3DataDxe: superficial cleanups
>   OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug
> 
>  MdeModulePkg/Core/PiSmmCore/Dispatcher.c                                                                                                              |   6 +
>  OvmfPkg/CpuHotplugSmm/ApicId.h                                                                                                                        |  23 ++
>  OvmfPkg/CpuHotplugSmm/CpuHotplug.c                                                                                                                    | 426 ++++++++++++++++++++
>  OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf                                                                                                               |  64 +++
>  OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm                                                                                                            | 154 +++++++
>  OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h                                                                                                        |  47 +++
>  OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm                                                                                                                 | 151 +++++++
>  OvmfPkg/CpuHotplugSmm/QemuCpuhp.c                                                                                                                     | 301 ++++++++++++++
>  OvmfPkg/CpuHotplugSmm/QemuCpuhp.h                                                                                                                     |  61 +++
>  OvmfPkg/CpuHotplugSmm/Smbase.c                                                                                                                        | 267 ++++++++++++
>  OvmfPkg/CpuHotplugSmm/Smbase.h                                                                                                                        |  46 +++
>  OvmfPkg/Include/IndustryStandard/Q35MchIch9.h                                                                                                         |   5 +-
>  OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h                                                                                                     |   3 +
>  OvmfPkg/OvmfPkgIa32.dsc                                                                                                                               |   7 +-
>  OvmfPkg/OvmfPkgIa32.fdf                                                                                                                               |   3 +-
>  OvmfPkg/OvmfPkgIa32X64.dsc                                                                                                                            |   7 +-
>  OvmfPkg/OvmfPkgIa32X64.fdf                                                                                                                            |   3 +-
>  OvmfPkg/OvmfPkgX64.dsc                                                                                                                                |   7 +-
>  OvmfPkg/OvmfPkgX64.fdf                                                                                                                                |   3 +-
>  UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c     |  45 ++-
>  UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf |  24 +-
>  UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c                                                                                                                     |  14 +-
>  {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c                                                                                                      |  99 +++--
>  {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf                                                                                                 |  30 +-
>  24 files changed, 1707 insertions(+), 89 deletions(-)
>  copy UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.c (61%)
>  copy UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf => OvmfPkg/Library/SmmCpuPlatformHookLibQemu/SmmCpuPlatformHookLibQemu.inf (43%)
>  copy {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3Data.c (77%)
>  copy {UefiCpuPkg => OvmfPkg}/CpuS3DataDxe/CpuS3DataDxe.inf (69%)
>  create mode 100644 OvmfPkg/CpuHotplugSmm/ApicId.h
>  create mode 100644 OvmfPkg/CpuHotplugSmm/CpuHotplug.c
>  create mode 100644 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
>  create mode 100644 OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm
>  create mode 100644 OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h
>  create mode 100644 OvmfPkg/CpuHotplugSmm/PostSmmPen.nasm
>  create mode 100644 OvmfPkg/CpuHotplugSmm/QemuCpuhp.c
>  create mode 100644 OvmfPkg/CpuHotplugSmm/QemuCpuhp.h
>  create mode 100644 OvmfPkg/CpuHotplugSmm/Smbase.c
>  create mode 100644 OvmfPkg/CpuHotplugSmm/Smbase.h
> 
> 
> base-commit: edfe16a6d9f8c6830d7ad93ee7616225fe4e9c13
> 

Merged as commit range 61d3b2d4279e..1158fc8e2c7b, via
<https://github.com/tianocore/edk2/pull/416/>.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-03-02 19:59 ` Laszlo Ersek
@ 2020-03-04 13:29   ` Philippe Mathieu-Daudé
  2020-03-04 18:09     ` Laszlo Ersek
  0 siblings, 1 reply; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-03-04 13:29 UTC (permalink / raw)
  To: devel, lersek
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney, Ray Ni,
	Boris Ostrovsky

On 3/2/20 8:59 PM, Laszlo Ersek wrote:
> On 02/26/20 23:11, Laszlo Ersek wrote:
>> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
>> Bugzilla:   https://bugzilla.tianocore.org/show_bug.cgi?id=1512
>> Repo:       https://github.com/lersek/edk2.git
>> Branch:     vcpu_hotplug_smm_bz_1512_v2
>>
>> V1 was posted at:
>>
>> * [edk2-devel] [PATCH 00/16]
>>    OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
>>
>>    https://edk2.groups.io/g/devel/message/54734
>>    http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com
>>
>> New in v2:
>>
>> - Document (in patch#11) and implement (in patch#12) the "combined"
>>    approach described here:
>>
>>    http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>>    https://edk2.groups.io/g/devel/message/54754
>>
>>    The idea is basically to make the SMM Monarch wait not just until the
>>    hot-added CPU hits the normal RAM Post-SMM Pen (which is safe wrt.
>>    ordering, but can be attacked by the OS), but *also* until the
>>    hot-added CPU is just about to execute RSM first (which is a bit less
>>    safe wrt. ordering, but cannot be attacked by the OS).
>>
>> - Pick up Ard's conditional A-b for the other patches, which have not
>>    been modified.
>>
>> - Rebase to master, and retest.
> 
> Thanks everyone for the feedback!
> 
> I plan to push this series soon after the hard feature freeze ends, and
> edk2-stable202002 is tagged. I have three questions / remarks regarding
> that:
> 
> - Phil, please tell me if you'd like me to hold the series for longer.
> (You seem to have reached the end of the series, and I'm unsure about
> the skipped patches -- maybe you want to skip them, maybe you need more
> time for them.)

I needed more time when this is too x86 specific, which is not my cup of 
tea. Next time!


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug
  2020-03-04 12:23     ` Laszlo Ersek
@ 2020-03-04 14:36       ` Dong, Eric
  0 siblings, 0 replies; 53+ messages in thread
From: Dong, Eric @ 2020-03-04 14:36 UTC (permalink / raw)
  To: Laszlo Ersek, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Igor Mammedov, Yao, Jiewen, Justen, Jordan L,
	Kinney, Michael D, Philippe Mathieu-Daudé, Ni, Ray,
	Boris Ostrovsky

Hi Laszlo,

Got it. Go ahead.

Thanks,
Eric

-----Original Message-----
From: Laszlo Ersek <lersek@redhat.com> 
Sent: Wednesday, March 4, 2020 8:23 PM
To: devel@edk2.groups.io; Dong, Eric <eric.dong@intel.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Igor Mammedov <imammedo@redhat.com>; Yao, Jiewen <jiewen.yao@intel.com>; Justen, Jordan L <jordan.l.justen@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>; Boris Ostrovsky <boris.ostrovsky@oracle.com>
Subject: Re: [edk2-devel] [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug

Hi Eric,

On 02/28/20 04:05, Dong, Eric wrote:
> Hi Laszlo,
>
> Thanks for your patch. The change make sense base on the comments in 
> the data structure header file.
>
> I also checked all the code related to this data structure. The inputs 
> for this data structure are CpuS3DataDxe and RegisterCpuFeaturesLib.
> Both these two drivers not support CPU hot plug feature, so the real 
> inputs for mAcpiCpuData.NumberOfCpus is the enabled CPU number in this 
> system. So before and after your code change, the CPU values are same.
> But the data structure comments said it can support CPU hot plug, so I 
> agree your code change.
>
> Reviewed-by: Eric Dong <eric.dong@intel.com>

while merging this patch, the edk2 CI system reported the following build warning (in the "Windows VS2019 PR" check):

https://github.com/tianocore/edk2/pull/416/checks?check_run_id=484688972
https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=4568&view=logs&j=898a5c7a-7a49-5be1-c417-92a6761a8039&t=7c50f5c2-8a2c-50f9-5007-e26f12377af8&l=64

> 2020-03-04T11:06:29.7838532Z ERROR - Compiler #2220 from d:\a\1\s\UefiCpuPkg\PiSmmCpuDxeSmm\CpuS3.c(624):   the following warning is treated as an error
> 2020-03-04T11:06:29.7839570Z WARNING - Compiler #4244 from d:\a\1\s\UefiCpuPkg\PiSmmCpuDxeSmm\CpuS3.c(624):   '=': conversion from 'UINTN' to 'volatile UINT32', possible loss of data
> 2020-03-04T11:06:29.7841177Z WARNING - Compiler #4244 from d:\a\1\s\UefiCpuPkg\PiSmmCpuDxeSmm\CpuS3.c(659):   '=': conversion from 'UINTN' to 'volatile UINT32', possible loss of data

I've suppressed that by squashing the following hunks into the patch:

> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c 
> b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> index 1e0840119724..29e9ba92b453 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
> @@ -621,7 +621,7 @@ InitializeCpuBeforeRebase (
>    } else {
>      ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);
>    }
> -  mNumberToFinish = mNumberOfCpus - 1;
> +  mNumberToFinish = (UINT32)(mNumberOfCpus - 1);
>    mExchangeInfo->ApFunction  = (VOID *) (UINTN) InitializeAp;
>
>    //
> @@ -656,7 +656,7 @@ InitializeCpuAfterRebase (
>    } else {
>      ASSERT (mNumberOfCpus == mAcpiCpuData.NumberOfCpus);
>    }
> -  mNumberToFinish = mNumberOfCpus - 1;
> +  mNumberToFinish = (UINT32)(mNumberOfCpus - 1);
>
>    //
>    // Signal that SMM base relocation is complete and to continue initialization for all APs.

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-03-04 13:29   ` Philippe Mathieu-Daudé
@ 2020-03-04 18:09     ` Laszlo Ersek
  0 siblings, 0 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-04 18:09 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, devel
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney, Ray Ni,
	Boris Ostrovsky

On 03/04/20 14:29, Philippe Mathieu-Daudé wrote:
> On 3/2/20 8:59 PM, Laszlo Ersek wrote:
>> On 02/26/20 23:11, Laszlo Ersek wrote:
>>> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
>>> Bugzilla:   https://bugzilla.tianocore.org/show_bug.cgi?id=1512
>>> Repo:       https://github.com/lersek/edk2.git
>>> Branch:     vcpu_hotplug_smm_bz_1512_v2
>>>
>>> V1 was posted at:
>>>
>>> * [edk2-devel] [PATCH 00/16]
>>>    OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
>>>
>>>    https://edk2.groups.io/g/devel/message/54734
>>>    http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com
>>>
>>> New in v2:
>>>
>>> - Document (in patch#11) and implement (in patch#12) the "combined"
>>>    approach described here:
>>>
>>>   
>>> http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>>>
>>>    https://edk2.groups.io/g/devel/message/54754
>>>
>>>    The idea is basically to make the SMM Monarch wait not just until the
>>>    hot-added CPU hits the normal RAM Post-SMM Pen (which is safe wrt.
>>>    ordering, but can be attacked by the OS), but *also* until the
>>>    hot-added CPU is just about to execute RSM first (which is a bit less
>>>    safe wrt. ordering, but cannot be attacked by the OS).
>>>
>>> - Pick up Ard's conditional A-b for the other patches, which have not
>>>    been modified.
>>>
>>> - Rebase to master, and retest.
>>
>> Thanks everyone for the feedback!
>>
>> I plan to push this series soon after the hard feature freeze ends, and
>> edk2-stable202002 is tagged. I have three questions / remarks regarding
>> that:
>>
>> - Phil, please tell me if you'd like me to hold the series for longer.
>> (You seem to have reached the end of the series, and I'm unsure about
>> the skipped patches -- maybe you want to skip them, maybe you need more
>> time for them.)
> 
> I needed more time when this is too x86 specific, which is not my cup of
> tea. Next time!
> 

Thanks for your reviews!

Apologies for not waiting any longer -- when I started queueing the
patches from this series, for the github pull req, I checked the mailing
list archive, to see whether you had followed up since your response at
<https://edk2.groups.io/g/devel/message/55237>. This was late in the
morning today (at ~11:00 or so, in CET), and I didn't see my above
question answered either way. I had two more series to merge, and I
wanted to handle it all with a single pullreq. I'm happy to give
reviewers more time; what I'd like to receive reasonably quickly is the
request for more time (especially if the review is not occurring
linearly over the series).

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
  2020-03-04 12:29 ` Laszlo Ersek
@ 2020-03-05  8:32   ` Laszlo Ersek
  0 siblings, 0 replies; 53+ messages in thread
From: Laszlo Ersek @ 2020-03-05  8:32 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Eric Dong, Hao A Wu, Igor Mammedov, Jian J Wang,
	Jiewen Yao, Jordan Justen, Michael Kinney,
	Philippe Mathieu-Daudé, Ray Ni, Boris Ostrovsky

On 03/04/20 13:29, Laszlo Ersek wrote:
> On 02/26/20 23:11, Laszlo Ersek wrote:
>> Supersedes: <20200223172537.28464-1-lersek@redhat.com>
>> Bugzilla:   https://bugzilla.tianocore.org/show_bug.cgi?id=1512
>> Repo:       https://github.com/lersek/edk2.git
>> Branch:     vcpu_hotplug_smm_bz_1512_v2
>>
>> V1 was posted at:
>>
>> * [edk2-devel] [PATCH 00/16]
>>   OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE
>>
>>   https://edk2.groups.io/g/devel/message/54734
>>   http://mid.mail-archive.com/20200223172537.28464-1-lersek@redhat.com
>>
>> New in v2:
>>
>> - Document (in patch#11) and implement (in patch#12) the "combined"
>>   approach described here:
>>
>>   http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redhat.com
>>   https://edk2.groups.io/g/devel/message/54754
>>
>>   The idea is basically to make the SMM Monarch wait not just until
>>   the hot-added CPU hits the normal RAM Post-SMM Pen (which is safe
>>   wrt. ordering, but can be attacked by the OS), but *also* until the
>>   hot-added CPU is just about to execute RSM first (which is a bit
>>   less safe wrt. ordering, but cannot be attacked by the OS).
>>
>> - Pick up Ard's conditional A-b for the other patches, which have not
>>   been modified.
>>
>> - Rebase to master, and retest.

> Merged as commit range 61d3b2d4279e..1158fc8e2c7b, via
> <https://github.com/tianocore/edk2/pull/416/>.

I've successfully tested this (now upstream) series with
- Windows Server 2012 R2 Standard, and
- Windows Server 2016 v1803
guests as well.

For that, an ACPI tweak is needed on the QEMU side (on top of Igor's PoC
patch). Namely, in the ASL quoted in the v1 blurb that's linked above,
Windows's ACPI parser does not like the "SMIR" OperationRegion to be
nested in a device, such as \_SB.SMI0.

("Does not like" means that Windows crashes during boot.)

Instead, Windows wants the OperationRegion directly under the \_SB
scope; like this:

> @@ -82,25 +82,10 @@
>              }
>          }
>
> -        Device (SMI0)
> +        OperationRegion (SMIR, SystemIO, 0xB2, One)
> +        Field (SMIR, ByteAcc, NoLock, WriteAsZeros)
>          {
> -            Name (_HID, "PNP0A06" /* Generic Container Device */)  // _HID: Hardware ID
> -            Name (_UID, "SMI resources")  // _UID: Unique ID
> -            Name (_STA, 0x0B)  // _STA: Status
> -            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
> -            {
> -                IO (Decode16,
> -                    0x00B2,             // Range Minimum
> -                    0x00B2,             // Range Maximum
> -                    0x01,               // Alignment
> -                    0x01,               // Length
> -                    )
> -            })
> -            OperationRegion (SMIR, SystemIO, 0xB2, One)
> -            Field (SMIR, ByteAcc, NoLock, WriteAsZeros)
> -            {
> -                SMIC,   8
> -            }
> +            SMIC,   8
>          }
>      }
>
> @@ -3037,7 +3022,7 @@
>              Method (CSCN, 0, Serialized)
>              {
>                  Acquire (\_SB.PCI0.PRES.CPLK, 0xFFFF)
> -                \_SB.SMI0.SMIC = 0x04
> +                \_SB.SMIC = 0x04
>                  Local0 = One
>                  While ((Local0 == One))
>                  {

The Linux guest is happy either way.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2020-03-05  8:32 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-02-26 22:11 [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Laszlo Ersek
2020-02-26 22:11 ` [PATCH v2 01/16] MdeModulePkg/PiSmmCore: log SMM image start failure Laszlo Ersek
2020-03-02 12:47   ` [edk2-devel] " Laszlo Ersek
2020-03-02 12:55     ` Liming Gao
2020-03-02 13:46   ` Philippe Mathieu-Daudé
2020-03-03  0:46   ` Dong, Eric
2020-02-26 22:11 ` [PATCH v2 02/16] UefiCpuPkg/PiSmmCpuDxeSmm: fix S3 Resume for CPU hotplug Laszlo Ersek
2020-02-28  3:05   ` [edk2-devel] " Dong, Eric
2020-02-28 10:50     ` Laszlo Ersek
2020-03-04 12:23     ` Laszlo Ersek
2020-03-04 14:36       ` Dong, Eric
2020-02-26 22:11 ` [PATCH v2 03/16] OvmfPkg: clone SmmCpuPlatformHookLib from UefiCpuPkg Laszlo Ersek
2020-03-02 13:27   ` Ard Biesheuvel
2020-03-02 13:49   ` Philippe Mathieu-Daudé
2020-02-26 22:11 ` [PATCH v2 04/16] OvmfPkg: enable SMM Monarch Election in PiSmmCpuDxeSmm Laszlo Ersek
2020-03-02 13:32   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 05/16] OvmfPkg: enable CPU hotplug support " Laszlo Ersek
2020-03-02 13:33   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 06/16] OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver Laszlo Ersek
2020-03-02 13:44   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 07/16] OvmfPkg/CpuHotplugSmm: add hotplug register block helper functions Laszlo Ersek
2020-03-02 13:24   ` Philippe Mathieu-Daudé
2020-03-02 13:45   ` [edk2-devel] " Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 08/16] OvmfPkg/CpuHotplugSmm: define the QEMU_CPUHP_CMD_GET_ARCH_ID macro Laszlo Ersek
2020-03-02 13:22   ` Philippe Mathieu-Daudé
2020-03-02 13:45   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events Laszlo Ersek
2020-03-02 13:49   ` Ard Biesheuvel
2020-03-02 20:34   ` Philippe Mathieu-Daudé
2020-03-03 10:31     ` Laszlo Ersek
2020-02-26 22:11 ` [PATCH v2 10/16] OvmfPkg/CpuHotplugSmm: collect " Laszlo Ersek
2020-03-02 13:58   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 11/16] OvmfPkg/CpuHotplugSmm: introduce Post-SMM Pen for hot-added CPUs Laszlo Ersek
2020-03-02 14:02   ` [edk2-devel] " Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler " Laszlo Ersek
2020-03-02 14:03   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 13/16] OvmfPkg/CpuHotplugSmm: complete root MMI handler for CPU hotplug Laszlo Ersek
2020-03-02 14:05   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 14/16] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg Laszlo Ersek
2020-03-02 13:44   ` Philippe Mathieu-Daudé
2020-03-02 14:06   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 15/16] OvmfPkg/CpuS3DataDxe: superficial cleanups Laszlo Ersek
2020-03-02 13:25   ` Philippe Mathieu-Daudé
2020-03-02 14:06   ` Ard Biesheuvel
2020-02-26 22:11 ` [PATCH v2 16/16] OvmfPkg/CpuS3DataDxe: enable S3 resume after CPU hotplug Laszlo Ersek
2020-03-02 14:16   ` Ard Biesheuvel
2020-03-02 15:46 ` [edk2-devel] [PATCH v2 00/16] OvmfPkg: support VCPU hotplug with -D SMM_REQUIRE Boris Ostrovsky
2020-03-02 19:22   ` Laszlo Ersek
2020-03-02 19:59 ` Laszlo Ersek
2020-03-04 13:29   ` Philippe Mathieu-Daudé
2020-03-04 18:09     ` Laszlo Ersek
2020-03-04 12:29 ` Laszlo Ersek
2020-03-05  8:32   ` Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox