From e7e8ea27d4d8790e76c26fa150e85b3277a72fd5 Mon Sep 17 00:00:00 2001 From: Guo Dong Date: Wed, 22 Sep 2021 14:22:42 -0700 Subject: [PATCH] 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 Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You --- .../Include/Guid/SmmRegisterInfoGuid.h | 48 ++++ .../SmmControlRuntimeDxe.c | 256 ++++++++++++++++++ .../SmmControlRuntimeDxe.inf | 50 ++++ UefiPayloadPkg/UefiPayloadPkg.dec | 2 + 4 files changed, 356 insertions(+) create mode 100644 UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h create mode 100644 UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c create mode 100644 UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf diff --git a/UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h b/UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h new file mode 100644 index 0000000000..8a1d3d7486 --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h @@ -0,0 +1,48 @@ +/** @file + This file defines the SMM info hob structure. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PAYLOAD_SMM_REGISTER_INFO_GUID_H_ +#define PAYLOAD_SMM_REGISTER_INFO_GUID_H_ + +#include + +/// +/// SMM Information GUID +/// +extern EFI_GUID gSmmRegisterInfoGuid; + +/// +/// Reuse ACPI definition +/// AddressSpaceId(0xC0-0xFF) is defined by OEM for MSR and other spaces +/// +typedef EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PLD_GENERIC_ADDRESS; + +#define REGISTER_ID_SMI_GBL_EN 1 +#define REGISTER_ID_SMI_GBL_EN_LOCK 2 +#define REGISTER_ID_SMI_EOS 3 +#define REGISTER_ID_SMI_APM_EN 4 +#define REGISTER_ID_SMI_APM_STS 5 + +#pragma pack(1) +typedef struct { + UINT64 Id; + UINT64 Value; + PLD_GENERIC_ADDRESS Address; +} PLD_GENERIC_REGISTER; + +typedef struct { + UINT16 Revision; + UINT16 Reserved; + UINT32 Count; + PLD_GENERIC_REGISTER Registers[0]; +} PLD_SMM_REGISTERS; + + +#pragma pack() + +#endif 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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 diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayloadPkg.dec index e5e8db8863..4f93d3e671 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -37,6 +37,8 @@ gUefiSerialPortInfoGuid = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } } gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } } + gSmmRegisterInfoGuid = { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9, 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } } + [Ppis] gEfiPayLoadHobBasePpiGuid = { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6, 0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} }