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} }