summaryrefslogtreecommitdiffstats
path: root/OvmfPkg
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg')
-rw-r--r--OvmfPkg/CpuHotplugSmm/CpuHotplug.c191
-rw-r--r--OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf48
-rw-r--r--OvmfPkg/Include/IndustryStandard/Q35MchIch9.h5
-rw-r--r--OvmfPkg/OvmfPkgIa32.dsc1
-rw-r--r--OvmfPkg/OvmfPkgIa32.fdf1
-rw-r--r--OvmfPkg/OvmfPkgIa32X64.dsc1
-rw-r--r--OvmfPkg/OvmfPkgIa32X64.fdf1
-rw-r--r--OvmfPkg/OvmfPkgX64.dsc1
-rw-r--r--OvmfPkg/OvmfPkgX64.fdf1
9 files changed, 248 insertions, 2 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
diff --git a/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h b/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
index cb705fee92..73db4b59a1 100644
--- a/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
+++ b/OvmfPkg/Include/IndustryStandard/Q35MchIch9.h
@@ -109,8 +109,9 @@
//
// 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
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 25e704be10..7a8a49af95 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -880,6 +880,7 @@
#
# Privileged drivers (DXE_SMM_DRIVER modules)
#
+ OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
<LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index 2e12807282..d58214eb80 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -322,6 +322,7 @@ 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
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 6def3f0c20..67c1635e33 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -893,6 +893,7 @@
#
# Privileged drivers (DXE_SMM_DRIVER modules)
#
+ OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
<LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index d67d336876..c21c3b92d8 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -329,6 +329,7 @@ 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
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 2c1902f9f2..45014190a6 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -891,6 +891,7 @@
#
# Privileged drivers (DXE_SMM_DRIVER modules)
#
+ OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf
UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf {
<LibraryClasses>
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index d67d336876..c21c3b92d8 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -329,6 +329,7 @@ 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