diff options
author | Laszlo Ersek <lersek@redhat.com> | 2020-02-26 23:11:50 +0100 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2020-03-04 12:22:07 +0000 |
commit | 17cb8ddba39b58e008a58aa6d502856d61f82dc9 (patch) | |
tree | 653845332283c9ab7e4dbe12553fecc6bc35442e /OvmfPkg/CpuHotplugSmm | |
parent | 763840c9abc8d48567498edf00e2f31a0220184f (diff) | |
download | edk2-17cb8ddba39b58e008a58aa6d502856d61f82dc9.tar.gz edk2-17cb8ddba39b58e008a58aa6d502856d61f82dc9.tar.bz2 edk2-17cb8ddba39b58e008a58aa6d502856d61f82dc9.zip |
OvmfPkg/CpuHotplugSmm: collect CPUs with events
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>
Diffstat (limited to 'OvmfPkg/CpuHotplugSmm')
-rw-r--r-- | OvmfPkg/CpuHotplugSmm/CpuHotplug.c | 111 | ||||
-rw-r--r-- | OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf | 7 |
2 files changed, 115 insertions, 3 deletions
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c index 5df8c689c6..42e023cb85 100644 --- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c @@ -6,15 +6,19 @@ 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()
//
@@ -22,6 +26,32 @@ //
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;
@@ -84,6 +114,8 @@ CpuHotplugMmi ( {
EFI_STATUS Status;
UINT8 ApmControl;
+ UINT32 PluggedCount;
+ UINT32 ToUnplugCount;
//
// Assert that we are entering this function due to our root MMI handler
@@ -119,6 +151,27 @@ 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;
+ }
+
+ //
// We've handled this MMI.
//
return EFI_SUCCESS;
@@ -144,6 +197,7 @@ CpuHotplugEntry ( )
{
EFI_STATUS Status;
+ UINTN Size;
//
// This module should only be included when SMM support is required.
@@ -170,6 +224,51 @@ CpuHotplugEntry ( 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.
@@ -200,7 +299,7 @@ CpuHotplugEntry ( Status = EFI_NOT_FOUND;
DEBUG ((DEBUG_ERROR, "%a: modern CPU hotplug interface: %r\n",
__FUNCTION__, Status));
- goto Fatal;
+ goto ReleaseToUnplugApicIds;
}
//
@@ -214,11 +313,19 @@ CpuHotplugEntry ( 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 ();
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf index ab690a9e5e..31c1ee1c9f 100644 --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf @@ -30,22 +30,27 @@ [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
|