summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/CpuHotplugSmm
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2020-02-26 23:11:46 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-03-04 12:22:07 +0000
commit17efae27acaf00856ef648d85e4656bce5cc6bcd (patch)
tree8a7b6254c3b59fb291cd8f58b8e9e89e8ab78f68 /OvmfPkg/CpuHotplugSmm
parent49df3fcee13a7e84ac88422126e38d55bc34c6c7 (diff)
downloadedk2-17efae27acaf00856ef648d85e4656bce5cc6bcd.tar.gz
edk2-17efae27acaf00856ef648d85e4656bce5cc6bcd.tar.bz2
edk2-17efae27acaf00856ef648d85e4656bce5cc6bcd.zip
OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver
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> Message-Id: <20200226221156.29589-7-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.c191
-rw-r--r--OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf48
2 files changed, 239 insertions, 0 deletions
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
new file mode 100644
index 0000000000..fd09403eab
--- /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;
+}
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
new file mode 100644
index 0000000000..fa70858a8d
--- /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