]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/CpuHotplugSmm: collect CPUs with events
authorLaszlo Ersek <lersek@redhat.com>
Wed, 26 Feb 2020 22:11:50 +0000 (23:11 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 4 Mar 2020 12:22:07 +0000 (12:22 +0000)
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>
Message-Id: <20200226221156.29589-11-lersek@redhat.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
OvmfPkg/CpuHotplugSmm/CpuHotplug.c
OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf

index 5df8c689c63aac0ed4d4b3810d790c113bde5722..42e023cb85c0bff46009978b550fb428b5c2b7ac 100644 (file)
@@ -6,15 +6,19 @@
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
+#include <CpuHotPlugData.h>                  // CPU_HOT_PLUG_DATA\r
 #include <IndustryStandard/Q35MchIch9.h>     // ICH9_APM_CNT\r
 #include <IndustryStandard/QemuCpuHotplug.h> // QEMU_CPUHP_CMD_GET_PENDING\r
 #include <Library/BaseLib.h>                 // CpuDeadLoop()\r
 #include <Library/DebugLib.h>                // ASSERT()\r
 #include <Library/MmServicesTableLib.h>      // gMmst\r
 #include <Library/PcdLib.h>                  // PcdGetBool()\r
+#include <Library/SafeIntLib.h>              // SafeUintnSub()\r
 #include <Protocol/MmCpuIo.h>                // EFI_MM_CPU_IO_PROTOCOL\r
+#include <Protocol/SmmCpuService.h>          // EFI_SMM_CPU_SERVICE_PROTOCOL\r
 #include <Uefi/UefiBaseType.h>               // EFI_STATUS\r
 \r
+#include "ApicId.h"                          // APIC_ID\r
 #include "QemuCpuhp.h"                       // QemuCpuhpWriteCpuSelector()\r
 \r
 //\r
 //\r
 STATIC EFI_MM_CPU_IO_PROTOCOL *mMmCpuIo;\r
 //\r
+// The following protocol is used to report the addition or removal of a CPU to\r
+// the SMM CPU driver (PiSmmCpuDxeSmm).\r
+//\r
+STATIC EFI_SMM_CPU_SERVICE_PROTOCOL *mMmCpuService;\r
+//\r
+// This structure is a communication side-channel between the\r
+// EFI_SMM_CPU_SERVICE_PROTOCOL consumer (i.e., this driver) and provider\r
+// (i.e., PiSmmCpuDxeSmm).\r
+//\r
+STATIC CPU_HOT_PLUG_DATA *mCpuHotPlugData;\r
+//\r
+// SMRAM arrays for fetching the APIC IDs of processors with pending events (of\r
+// known event types), for the time of just one MMI.\r
+//\r
+// The lifetimes of these arrays match that of this driver only because we\r
+// don't want to allocate SMRAM at OS runtime, and potentially fail (or\r
+// fragment the SMRAM map).\r
+//\r
+// These arrays provide room for ("possible CPU count" minus one) APIC IDs\r
+// each, as we don't expect every possible CPU to appear, or disappear, in a\r
+// single MMI. The numbers of used (populated) elements in the arrays are\r
+// determined on every MMI separately.\r
+//\r
+STATIC APIC_ID *mPluggedApicIds;\r
+STATIC APIC_ID *mToUnplugApicIds;\r
+//\r
 // Represents the registration of the CPU Hotplug MMI handler.\r
 //\r
 STATIC EFI_HANDLE mDispatchHandle;\r
@@ -84,6 +114,8 @@ CpuHotplugMmi (
 {\r
   EFI_STATUS Status;\r
   UINT8      ApmControl;\r
+  UINT32     PluggedCount;\r
+  UINT32     ToUnplugCount;\r
 \r
   //\r
   // Assert that we are entering this function due to our root MMI handler\r
@@ -118,6 +150,27 @@ CpuHotplugMmi (
     return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
   }\r
 \r
+  //\r
+  // Collect the CPUs with pending events.\r
+  //\r
+  Status = QemuCpuhpCollectApicIds (\r
+             mMmCpuIo,\r
+             mCpuHotPlugData->ArrayLength,     // PossibleCpuCount\r
+             mCpuHotPlugData->ArrayLength - 1, // ApicIdCount\r
+             mPluggedApicIds,\r
+             &PluggedCount,\r
+             mToUnplugApicIds,\r
+             &ToUnplugCount\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Fatal;\r
+  }\r
+  if (ToUnplugCount > 0) {\r
+    DEBUG ((DEBUG_ERROR, "%a: hot-unplug is not supported yet\n",\r
+      __FUNCTION__));\r
+    goto Fatal;\r
+  }\r
+\r
   //\r
   // We've handled this MMI.\r
   //\r
@@ -144,6 +197,7 @@ CpuHotplugEntry (
   )\r
 {\r
   EFI_STATUS Status;\r
+  UINTN      Size;\r
 \r
   //\r
   // This module should only be included when SMM support is required.\r
@@ -170,6 +224,51 @@ CpuHotplugEntry (
     DEBUG ((DEBUG_ERROR, "%a: locate MmCpuIo: %r\n", __FUNCTION__, Status));\r
     goto Fatal;\r
   }\r
+  Status = gMmst->MmLocateProtocol (&gEfiSmmCpuServiceProtocolGuid,\r
+                    NULL /* Registration */, (VOID **)&mMmCpuService);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: locate MmCpuService: %r\n", __FUNCTION__,\r
+      Status));\r
+    goto Fatal;\r
+  }\r
+\r
+  //\r
+  // Our DEPEX on EFI_SMM_CPU_SERVICE_PROTOCOL guarantees that PiSmmCpuDxeSmm\r
+  // has pointed PcdCpuHotPlugDataAddress to CPU_HOT_PLUG_DATA in SMRAM.\r
+  //\r
+  mCpuHotPlugData = (VOID *)(UINTN)PcdGet64 (PcdCpuHotPlugDataAddress);\r
+  if (mCpuHotPlugData == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
+    DEBUG ((DEBUG_ERROR, "%a: CPU_HOT_PLUG_DATA: %r\n", __FUNCTION__, Status));\r
+    goto Fatal;\r
+  }\r
+  //\r
+  // If the possible CPU count is 1, there's nothing for this driver to do.\r
+  //\r
+  if (mCpuHotPlugData->ArrayLength == 1) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Allocate the data structures that depend on the possible CPU count.\r
+  //\r
+  if (RETURN_ERROR (SafeUintnSub (mCpuHotPlugData->ArrayLength, 1, &Size)) ||\r
+      RETURN_ERROR (SafeUintnMult (sizeof (APIC_ID), Size, &Size))) {\r
+    Status = EFI_ABORTED;\r
+    DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_PLUG_DATA\n", __FUNCTION__));\r
+    goto Fatal;\r
+  }\r
+  Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,\r
+                    (VOID **)&mPluggedApicIds);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));\r
+    goto Fatal;\r
+  }\r
+  Status = gMmst->MmAllocatePool (EfiRuntimeServicesData, Size,\r
+                    (VOID **)&mToUnplugApicIds);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: MmAllocatePool(): %r\n", __FUNCTION__, Status));\r
+    goto ReleasePluggedApicIds;\r
+  }\r
 \r
   //\r
   // Sanity-check the CPU hotplug interface.\r
@@ -200,7 +299,7 @@ CpuHotplugEntry (
     Status = EFI_NOT_FOUND;\r
     DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",\r
       __FUNCTION__, Status));\r
-    goto Fatal;\r
+    goto ReleaseToUnplugApicIds;\r
   }\r
 \r
   //\r
@@ -214,11 +313,19 @@ CpuHotplugEntry (
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "%a: MmiHandlerRegister(): %r\n", __FUNCTION__,\r
       Status));\r
-    goto Fatal;\r
+    goto ReleaseToUnplugApicIds;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
+ReleaseToUnplugApicIds:\r
+  gMmst->MmFreePool (mToUnplugApicIds);\r
+  mToUnplugApicIds = NULL;\r
+\r
+ReleasePluggedApicIds:\r
+  gMmst->MmFreePool (mPluggedApicIds);\r
+  mPluggedApicIds = NULL;\r
+\r
 Fatal:\r
   ASSERT (FALSE);\r
   CpuDeadLoop ();\r
index ab690a9e5e205cb4d601391381239ade5b9bca27..31c1ee1c9f6dbce5e2b149c8ee9623bf6ea4a5cf 100644 (file)
 [Packages]\r
   MdePkg/MdePkg.dec\r
   OvmfPkg/OvmfPkg.dec\r
+  UefiCpuPkg/UefiCpuPkg.dec\r
 \r
 [LibraryClasses]\r
   BaseLib\r
   DebugLib\r
   MmServicesTableLib\r
   PcdLib\r
+  SafeIntLib\r
   UefiDriverEntryPoint\r
 \r
 [Protocols]\r
   gEfiMmCpuIoProtocolGuid                                           ## CONSUMES\r
+  gEfiSmmCpuServiceProtocolGuid                                     ## CONSUMES\r
 \r
 [Pcd]\r
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress                ## CONSUMES\r
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase             ## CONSUMES\r
 \r
 [FeaturePcd]\r
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire                     ## CONSUMES\r
 \r
 [Depex]\r
-  gEfiMmCpuIoProtocolGuid\r
+  gEfiMmCpuIoProtocolGuid AND\r
+  gEfiSmmCpuServiceProtocolGuid\r