summaryrefslogtreecommitdiffstats
path: root/UefiPayloadPkg/SmmControlRuntimeDxe
diff options
context:
space:
mode:
authorGuo Dong <guo.dong@intel.com>2021-09-22 14:22:42 -0700
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2021-10-25 17:28:21 +0000
commite7e8ea27d4d8790e76c26fa150e85b3277a72fd5 (patch)
tree4330de4bc255f9a2eed37864fd624dbf80800325 /UefiPayloadPkg/SmmControlRuntimeDxe
parent87a34ca0cf6892e8c6784eb7e381b392d1176bb5 (diff)
downloadedk2-e7e8ea27d4d8790e76c26fa150e85b3277a72fd5.tar.gz
edk2-e7e8ea27d4d8790e76c26fa150e85b3277a72fd5.tar.bz2
edk2-e7e8ea27d4d8790e76c26fa150e85b3277a72fd5.zip
UefiPayloadPkg: Add a common SMM control Runtime DXE module
This module consumes SMM Registers HOB (SMI_GBL_EN and SMI_APM_EN) to install SMM control 2 protocol gEfiSmmControl2ProtocolGuid. The protocol activate() would set SMI_GBL_EN and SMI_APM_EN and trigger SMI by writing to IO port 0xB3 and 0xB2. Signed-off-by: Guo Dong <guo.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Maurice Ma <maurice.ma@intel.com> Cc: Benjamin You <benjamin.you@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Benjamin You <benjamin.you@intel.com>
Diffstat (limited to 'UefiPayloadPkg/SmmControlRuntimeDxe')
-rw-r--r--UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c256
-rw-r--r--UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf50
2 files changed, 306 insertions, 0 deletions
diff --git a/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
new file mode 100644
index 0000000000..6dd91e2601
--- /dev/null
+++ b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
@@ -0,0 +1,256 @@
+/** @file
+ This module produces the SMM Control2 Protocol
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/SmmControl2.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Guid/SmmRegisterInfoGuid.h>
+
+#define SMM_DATA_PORT 0xB3
+#define SMM_CONTROL_PORT 0xB2
+
+typedef struct {
+ UINT8 GblBitOffset;
+ UINT8 ApmBitOffset;
+ UINT32 Address;
+} SMM_CONTROL2_REG;
+
+SMM_CONTROL2_REG mSmiCtrlReg;
+
+/**
+ Invokes SMI activation from either the preboot or runtime environment.
+
+ This function generates an SMI.
+
+ @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
+ @param[in,out] CommandPort The value written to the command port.
+ @param[in,out] DataPort The value written to the data port.
+ @param[in] Periodic Optional mechanism to engender a periodic stream.
+ @param[in] ActivationInterval Optional parameter to repeat at this period one
+ time or, if the Periodic Boolean is set, periodically.
+
+ @retval EFI_SUCCESS The SMI has been engendered.
+ @retval EFI_DEVICE_ERROR The timing is unsupported.
+ @retval EFI_INVALID_PARAMETER The activation period is unsupported.
+ @retval EFI_INVALID_PARAMETER The last periodic activation has not been cleared.
+ @retval EFI_NOT_STARTED The MM base service has not been initialized.
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN OUT UINT8 *CommandPort OPTIONAL,
+ IN OUT UINT8 *DataPort OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
+ )
+{
+ UINT32 SmiEn;
+ UINT32 SmiEnableBits;
+
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiEn = IoRead32 (mSmiCtrlReg.Address);
+ SmiEnableBits = (1 << mSmiCtrlReg.GblBitOffset) | (1 << mSmiCtrlReg.ApmBitOffset);
+ if ((SmiEn & SmiEnableBits) != SmiEnableBits) {
+ //
+ // Set the "global SMI enable" bit and APM bit
+ //
+ IoWrite32 (mSmiCtrlReg.Address, SmiEn | SmiEnableBits);
+ }
+
+ IoWrite8 (SMM_DATA_PORT, DataPort == NULL ? 0 : *DataPort);
+ IoWrite8 (SMM_CONTROL_PORT, CommandPort == NULL ? 0 : *CommandPort);
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears an SMI.
+
+ @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear ()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN BOOLEAN Periodic
+ )
+{
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Temporarily do nothing here
+ //
+ return EFI_SUCCESS;
+}
+
+///
+/// SMM COntrol2 Protocol instance
+///
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
+ Activate,
+ Deactivate,
+ 0
+};
+
+/**
+ Get specified SMI register based on given register ID
+
+ @param[in] SmmRegister SMI related register array from bootloader
+ @param[in] Id The register ID to get.
+
+ @retval NULL The register is not found or the format is not expected.
+ @return smi register
+
+**/
+PLD_GENERIC_REGISTER *
+GetSmmCtrlRegById (
+ IN PLD_SMM_REGISTERS *SmmRegister,
+ IN UINT32 Id
+ )
+{
+ UINT32 Index;
+ PLD_GENERIC_REGISTER *PldReg;
+
+ PldReg = NULL;
+ for (Index = 0; Index < SmmRegister->Count; Index++) {
+ if (SmmRegister->Registers[Index].Id == Id) {
+ PldReg = &SmmRegister->Registers[Index];
+ break;
+ }
+ }
+
+ if (PldReg == NULL) {
+ DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id));
+ return NULL;
+ }
+
+ //
+ // Checking the register if it is expected.
+ //
+ if ((PldReg->Address.AccessSize != EFI_ACPI_3_0_DWORD) ||
+ (PldReg->Address.Address == 0) ||
+ (PldReg->Address.RegisterBitWidth != 1) ||
+ (PldReg->Address.AddressSpaceId != EFI_ACPI_3_0_SYSTEM_IO) ||
+ (PldReg->Value != 1)) {
+ DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n"));
+ DEBUG ((DEBUG_INFO, "AddressSpaceId= 0x%x\n", PldReg->Address.AddressSpaceId));
+ DEBUG ((DEBUG_INFO, "RegBitWidth = 0x%x\n", PldReg->Address.RegisterBitWidth));
+ DEBUG ((DEBUG_INFO, "RegBitOffset = 0x%x\n", PldReg->Address.RegisterBitOffset));
+ DEBUG ((DEBUG_INFO, "AccessSize = 0x%x\n", PldReg->Address.AccessSize));
+ DEBUG ((DEBUG_INFO, "Address = 0x%lx\n",PldReg->Address.Address ));
+ return NULL;
+ }
+ return PldReg;
+}
+
+
+/**
+ Fixup data pointers so that the services can be called in virtual mode.
+
+ @param[in] Event The event registered.
+ @param[in] Context Event context.
+
+**/
+VOID
+EFIAPI
+SmmControlVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Trigger));
+ EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Clear));
+}
+
+
+/**
+ This function installs EFI_SMM_CONTROL2_PROTOCOL.
+
+ @param ImageHandle Handle for the image of this driver
+ @param SystemTable Pointer to the EFI System Table
+
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+ @return The status returned from InstallProtocolInterface().
+
+**/
+EFI_STATUS
+EFIAPI
+SmmControlEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PLD_SMM_REGISTERS *SmmRegister;
+ PLD_GENERIC_REGISTER *SmiGblEnReg;
+ PLD_GENERIC_REGISTER *SmiApmEnReg;
+ EFI_EVENT Event;
+
+ GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
+ if (GuidHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SmmRegister = (PLD_SMM_REGISTERS *) (GET_GUID_HOB_DATA(GuidHob));
+ SmiGblEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_GBL_EN);
+ if (SmiGblEnReg == NULL) {
+ DEBUG ((DEBUG_ERROR, "SMI global enable reg not found.\n"));
+ return EFI_NOT_FOUND;
+ }
+ mSmiCtrlReg.Address = (UINT32)SmiGblEnReg->Address.Address;
+ mSmiCtrlReg.GblBitOffset = SmiGblEnReg->Address.RegisterBitOffset;
+
+ SmiApmEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_EN);
+ if (SmiApmEnReg == NULL) {
+ DEBUG ((DEBUG_ERROR, "SMI APM enable reg not found.\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (SmiApmEnReg->Address.Address != mSmiCtrlReg.Address) {
+ DEBUG ((DEBUG_ERROR, "SMI APM EN and SMI GBL EN are expected to have same register base\n"));
+ DEBUG ((DEBUG_ERROR, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg->Address.Address, mSmiCtrlReg.Address));
+ return EFI_UNSUPPORTED;
+ }
+ mSmiCtrlReg.ApmBitOffset = SmiApmEnReg->Address.RegisterBitOffset;
+
+ //
+ // Install our protocol interfaces on the device's handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiSmmControl2ProtocolGuid,
+ &mSmmControl2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SmmControlVirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ return Status;
+}
diff --git a/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf
new file mode 100644
index 0000000000..f0c2a4586b
--- /dev/null
+++ b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf
@@ -0,0 +1,50 @@
+## @file
+# SMM Control runtime DXE Module
+#
+# Provides the ability to generate a software SMI.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmControlRuntimeDxe
+ FILE_GUID = C3099578-F815-4a96-84A3-FC593760181D
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmmControlEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmControlRuntimeDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+ UefiRuntimeLib
+ PcdLib
+ IoLib
+ HobLib
+
+[Guids]
+ gSmmRegisterInfoGuid
+ gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+ gEfiSmmControl2ProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE