diff --git a/UefiPayloadPkg/Include/Library/SmmStoreLib.h b/UefiPayloadPkg/Include/Library/SmmStoreLib.h
new file mode 100644
index 0000000000..bf0b8a01b8
--- /dev/null
+++ b/UefiPayloadPkg/Include/Library/SmmStoreLib.h
@@ -0,0 +1,146 @@
+/** @file SmmStoreLib.h
+
+ Copyright (c) 2022, 9elements GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SMM_STORE_LIB_H_
+#define SMM_STORE_LIB_H_
+
+#include
+#include
+#include
+
+#define SMMSTORE_COMBUF_SIZE 16
+
+/**
+ Get the SmmStore block size
+
+ @param BlockSize The pointer to store the block size in.
+
+**/
+EFI_STATUS
+SmmStoreLibGetBlockSize (
+ OUT UINTN *BlockSize
+ );
+
+/**
+ Get the SmmStore number of blocks
+
+ @param NumBlocks The pointer to store the number of blocks in.
+
+**/
+EFI_STATUS
+SmmStoreLibGetNumBlocks (
+ OUT UINTN *NumBlocks
+ );
+
+/**
+ Get the SmmStore MMIO address
+
+ @param MmioAddress The pointer to store the address in.
+
+**/
+EFI_STATUS
+SmmStoreLibGetMmioAddress (
+ OUT EFI_PHYSICAL_ADDRESS *MmioAddress
+ );
+
+/**
+ Read from SmmStore
+
+ @param[in] Lba The starting logical block index to read from.
+ @param[in] Offset Offset into the block at which to begin reading.
+ @param[in] NumBytes On input, indicates the requested read size. On
+ output, indicates the actual number of bytes read.
+ @param[in] Buffer Pointer to the buffer to read into.
+
+**/
+EFI_STATUS
+SmmStoreLibRead (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Write to SmmStore
+
+ @param[in] Lba The starting logical block index to write to.
+ @param[in] Offset Offset into the block at which to begin writing.
+ @param[in] NumBytes On input, indicates the requested write size. On
+ output, indicates the actual number of bytes written.
+ @param[in] Buffer Pointer to the data to write.
+
+**/
+EFI_STATUS
+SmmStoreLibWrite (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Erase a block using the SmmStore
+
+ @param Lba The logical block index to erase.
+
+**/
+EFI_STATUS
+SmmStoreLibEraseBlock (
+ IN EFI_LBA Lba
+ );
+
+/**
+ Function to update a pointer on virtual address change. Matches the signature
+ and operation of EfiConvertPointer.
+
+**/
+typedef EFI_STATUS EFIAPI (*CONVERT_POINTER_CALLBACK) (
+ IN UINTN DebugDisposition,
+ IN OUT VOID **Address
+ );
+
+/**
+ Initializes SmmStore support
+
+ @retval EFI_WRITE_PROTECTED The SmmStore is not present.
+ @retval EFI_UNSUPPORTED The SmmStoreInfo HOB wasn't found.
+ @retval EFI_SUCCESS The SmmStore is supported.
+
+**/
+EFI_STATUS
+SmmStoreLibInitialize (
+ VOID
+ );
+
+/**
+ Fixup internal data so that EFI can be called in virtual mode.
+ Converts any pointers in lib to virtual mode. This function is meant to
+ be invoked on gEfiEventVirtualAddressChangeGuid event when the library is
+ used at run-time.
+
+ @param[in] ConvertPointer Function to switch virtual address space.
+
+**/
+VOID
+EFIAPI
+SmmStoreLibVirtualAddressChange (
+ IN CONVERT_POINTER_CALLBACK ConvertPointer
+ );
+
+/**
+ Deinitializes SmmStore support
+
+**/
+VOID
+EFIAPI
+SmmStoreLibDeinitialize (
+ VOID
+ );
+
+#endif /* SMM_STORE_LIB_H_ */
diff --git a/UefiPayloadPkg/Library/SmmStoreLib/SmmStore.c b/UefiPayloadPkg/Library/SmmStoreLib/SmmStore.c
new file mode 100644
index 0000000000..690bae0f1c
--- /dev/null
+++ b/UefiPayloadPkg/Library/SmmStoreLib/SmmStore.c
@@ -0,0 +1,447 @@
+/** @file SmmStore.c
+
+ Copyright (c) 2022, 9elements GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "SmmStore.h"
+
+/*
+ * A memory buffer to place arguments in.
+ */
+STATIC SMM_STORE_COM_BUF *mArgComBuf;
+STATIC EFI_PHYSICAL_ADDRESS mArgComBufPhys;
+
+/*
+ * Metadata provided by the first stage bootloader.
+ */
+STATIC SMMSTORE_INFO *mSmmStoreInfo;
+
+/**
+ Calls into SMM to use the SMMSTOREv2 implementation for persistent storage.
+
+ @param Cmd The command to write into the APM port. This allows to enter the
+ Smi special command handler.
+ @param SubCmd The subcommand to execute in the Smi handler.
+ @param Arg Optional argument to pass to the Smi handler. Typically a pointer
+ in 'flat' memory mode, which points to read only memory.
+
+ @retval EFI_NO_RESPONSE The SmmStore is not present or didn't response.
+ @retval EFI_UNSUPPORTED The request isn't supported.
+ @retval EFI_DEVICE_ERROR An error occurred while executing the request.
+ @retval EFI_SUCCESS The operation was executed successfully.
+**/
+STATIC
+EFI_STATUS
+CallSmm (
+ UINT8 Cmd,
+ UINT8 SubCmd,
+ UINTN Arg
+ )
+{
+ CONST UINTN Rax = ((SubCmd << 8) | Cmd);
+ CONST UINTN Rbx = Arg;
+ UINTN Result;
+
+ Result = TriggerSmi (Rax, Rbx, 5);
+ if (Result == Rax) {
+ return EFI_NO_RESPONSE;
+ } else if (Result == SMMSTORE_RET_SUCCESS) {
+ return EFI_SUCCESS;
+ } else if (Result == SMMSTORE_RET_UNSUPPORTED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Get the SmmStore block size
+
+ @param BlockSize The pointer to store the block size in.
+
+**/
+EFI_STATUS
+SmmStoreLibGetBlockSize (
+ OUT UINTN *BlockSize
+ )
+{
+ if (mSmmStoreInfo == NULL) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (BlockSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *BlockSize = mSmmStoreInfo->BlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the SmmStore number of blocks
+
+ @param NumBlocks The pointer to store the number of blocks in.
+
+**/
+EFI_STATUS
+SmmStoreLibGetNumBlocks (
+ OUT UINTN *NumBlocks
+ )
+{
+ if (mSmmStoreInfo == NULL) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (NumBlocks == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumBlocks = mSmmStoreInfo->NumBlocks;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the SmmStore MMIO address
+
+ @param MmioAddress The pointer to store the address in.
+
+**/
+EFI_STATUS
+SmmStoreLibGetMmioAddress (
+ OUT EFI_PHYSICAL_ADDRESS *MmioAddress
+ )
+{
+ if (mSmmStoreInfo == NULL) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (MmioAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *MmioAddress = mSmmStoreInfo->MmioAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read from SmmStore
+
+ @param[in] Lba The starting logical block index to read from.
+ @param[in] Offset Offset into the block at which to begin reading.
+ @param[in] NumBytes On input, indicates the requested read size. On
+ output, indicates the actual number of bytes read.
+ @param[in] Buffer Pointer to the buffer to read into.
+
+**/
+EFI_STATUS
+SmmStoreLibRead (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (mSmmStoreInfo == NULL) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (Lba >= mSmmStoreInfo->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((*NumBytes + Offset) > mSmmStoreInfo->BlockSize) ||
+ ((*NumBytes + Offset) > mSmmStoreInfo->ComBufferSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mArgComBuf->Read.BufSize = *NumBytes;
+ mArgComBuf->Read.BufOffset = Offset;
+ mArgComBuf->Read.BlockId = Lba;
+
+ Status = CallSmm (mSmmStoreInfo->ApmCmd, SMMSTORE_CMD_RAW_READ, mArgComBufPhys);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Buffer, (VOID *)(UINTN)(mSmmStoreInfo->ComBuffer + Offset), *NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write to SmmStore
+
+ @param[in] Lba The starting logical block index to write to.
+ @param[in] Offset Offset into the block at which to begin writing.
+ @param[in] NumBytes On input, indicates the requested write size. On
+ output, indicates the actual number of bytes written.
+ @param[in] Buffer Pointer to the data to write.
+
+**/
+EFI_STATUS
+SmmStoreLibWrite (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ if (mSmmStoreInfo == NULL) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (Lba >= mSmmStoreInfo->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((*NumBytes + Offset) > mSmmStoreInfo->BlockSize) ||
+ ((*NumBytes + Offset) > mSmmStoreInfo->ComBufferSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mArgComBuf->Write.BufSize = *NumBytes;
+ mArgComBuf->Write.BufOffset = Offset;
+ mArgComBuf->Write.BlockId = Lba;
+
+ CopyMem ((VOID *)(UINTN)(mSmmStoreInfo->ComBuffer + Offset), Buffer, *NumBytes);
+
+ return CallSmm (mSmmStoreInfo->ApmCmd, SMMSTORE_CMD_RAW_WRITE, mArgComBufPhys);
+}
+
+/**
+ Erase a SmmStore block
+
+ @param Lba The logical block index to erase.
+
+**/
+EFI_STATUS
+SmmStoreLibEraseBlock (
+ IN EFI_LBA Lba
+ )
+{
+ if (mSmmStoreInfo == NULL) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (Lba >= mSmmStoreInfo->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mArgComBuf->Clear.BlockId = Lba;
+
+ return CallSmm (mSmmStoreInfo->ApmCmd, SMMSTORE_CMD_RAW_CLEAR, mArgComBufPhys);
+}
+
+/**
+ Fixup internal data so that EFI can be called in virtual mode.
+ Converts any pointers in lib to virtual mode. This function is meant to
+ be invoked on gEfiEventVirtualAddressChangeGuid event when the library is
+ used at run-time.
+
+ @param[in] ConvertPointer Function to switch virtual address space.
+
+**/
+VOID
+EFIAPI
+SmmStoreLibVirtualAddressChange (
+ IN CONVERT_POINTER_CALLBACK ConvertPointer
+ )
+{
+ ConvertPointer (0x0, (VOID **)&mArgComBuf);
+ if (mSmmStoreInfo != NULL) {
+ ConvertPointer (0x0, (VOID **)&mSmmStoreInfo->ComBuffer);
+ ConvertPointer (0x0, (VOID **)&mSmmStoreInfo);
+ }
+
+ return;
+}
+
+/**
+ Initializes SmmStore support
+
+ @retval EFI_WRITE_PROTECTED The SmmStore is not present.
+ @retval EFI_OUT_OF_RESOURCES Run out of memory.
+ @retval EFI_SUCCESS The SmmStore is supported.
+
+**/
+EFI_STATUS
+SmmStoreLibInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *GuidHob;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+
+ //
+ // Find the SmmStore information guid hob
+ //
+ GuidHob = GetFirstGuidHob (&gEfiSmmStoreInfoHobGuid);
+ if (GuidHob == NULL) {
+ DEBUG ((DEBUG_WARN, "SmmStore not supported! Skipping driver init.\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Place SmmStore information hob in a runtime buffer
+ //
+ mSmmStoreInfo = AllocateRuntimePool (GET_GUID_HOB_DATA_SIZE (GuidHob));
+ if (mSmmStoreInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (mSmmStoreInfo, GET_GUID_HOB_DATA (GuidHob), GET_GUID_HOB_DATA_SIZE (GuidHob));
+
+ //
+ // Validate input
+ //
+ if ((mSmmStoreInfo->MmioAddress == 0) ||
+ (mSmmStoreInfo->ComBuffer == 0) ||
+ (mSmmStoreInfo->BlockSize == 0) ||
+ (mSmmStoreInfo->NumBlocks == 0))
+ {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid data in SmmStore Info hob\n", __func__));
+ FreePool (mSmmStoreInfo);
+ mSmmStoreInfo = NULL;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Allocate Communication Buffer for arguments to pass to SMM.
+ // The argument com buffer is only read by SMM, but never written.
+ // The FVB data send/retrieved will be placed in a separate bootloader
+ // pre-allocated memory region, the ComBuffer.
+ //
+ if (mSmmStoreInfo->ComBuffer < BASE_4GB) {
+ //
+ // Assume that SMM handler is running in 32-bit mode when ComBuffer is
+ // is placed below BASE_4GB.
+ //
+ mArgComBufPhys = BASE_4GB - 1;
+ } else {
+ mArgComBufPhys = BASE_8EB - 1;
+ }
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (sizeof (SMM_STORE_COM_BUF)),
+ &mArgComBufPhys
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (mSmmStoreInfo);
+ mSmmStoreInfo = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mArgComBuf = (VOID *)mArgComBufPhys;
+
+ //
+ // Finally mark the SMM communication buffer provided by CB or SBL as runtime memory
+ //
+ Status = gDS->GetMemorySpaceDescriptor (mSmmStoreInfo->ComBuffer, &GcdDescriptor);
+ if (EFI_ERROR (Status) || (GcdDescriptor.GcdMemoryType != EfiGcdMemoryTypeReserved)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: No memory space descriptor for com buffer found\n",
+ __func__
+ ));
+
+ //
+ // Add a new entry if not covered by existing mapping
+ //
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeReserved,
+ mSmmStoreInfo->ComBuffer,
+ mSmmStoreInfo->ComBufferSize,
+ EFI_MEMORY_WB | EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Mark as runtime service
+ //
+ Status = gDS->SetMemorySpaceAttributes (
+ mSmmStoreInfo->ComBuffer,
+ mSmmStoreInfo->ComBufferSize,
+ EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Mark the memory mapped store as MMIO memory
+ //
+ Status = gDS->GetMemorySpaceDescriptor (mSmmStoreInfo->MmioAddress, &GcdDescriptor);
+ if (EFI_ERROR (Status) || (GcdDescriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: No memory space descriptor for com buffer found\n",
+ __func__
+ ));
+
+ //
+ // Add a new entry if not covered by existing mapping
+ //
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ mSmmStoreInfo->MmioAddress,
+ mSmmStoreInfo->NumBlocks * mSmmStoreInfo->BlockSize,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Mark as runtime service
+ //
+ Status = gDS->SetMemorySpaceAttributes (
+ mSmmStoreInfo->MmioAddress,
+ mSmmStoreInfo->NumBlocks * mSmmStoreInfo->BlockSize,
+ EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Deinitializes SmmStore support by freeing allocated memory.
+
+**/
+VOID
+EFIAPI
+SmmStoreLibDeinitialize (
+ VOID
+ )
+{
+ if (mArgComBuf != NULL) {
+ gBS->FreePages (mArgComBufPhys, EFI_SIZE_TO_PAGES (sizeof (SMM_STORE_COM_BUF)));
+ mArgComBuf = NULL;
+ }
+
+ if (mSmmStoreInfo != NULL) {
+ FreePool (mSmmStoreInfo);
+ mSmmStoreInfo = NULL;
+ }
+}
diff --git a/UefiPayloadPkg/Library/SmmStoreLib/SmmStore.h b/UefiPayloadPkg/Library/SmmStoreLib/SmmStore.h
new file mode 100644
index 0000000000..d91b8e13c6
--- /dev/null
+++ b/UefiPayloadPkg/Library/SmmStoreLib/SmmStore.h
@@ -0,0 +1,82 @@
+/** @file SmmStore.h
+
+ Copyright (c) 2022, 9elements GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef COREBOOT_SMMSTORE_H_
+#define COREBOOT_SMMSTORE_H_
+
+#define SMMSTORE_RET_SUCCESS 0
+#define SMMSTORE_RET_FAILURE 1
+#define SMMSTORE_RET_UNSUPPORTED 2
+
+/* Version 2 only */
+#define SMMSTORE_CMD_INIT 4
+#define SMMSTORE_CMD_RAW_READ 5
+#define SMMSTORE_CMD_RAW_WRITE 6
+#define SMMSTORE_CMD_RAW_CLEAR 7
+
+/*
+ * This allows the payload to store raw data in the flash regions.
+ * This can be used by a FaultTolerantWrite implementation, that uses at least
+ * two regions in an A/B update scheme.
+ */
+
+#pragma pack(1)
+
+/*
+ * Reads a chunk of raw data with size BufSize from the block specified by
+ * block_id starting at BufOffset.
+ * The read data is placed in buf.
+ *
+ * block_id must be less than num_blocks
+ * BufOffset + BufSize must be less than block_size
+ */
+typedef struct {
+ UINT32 BufSize;
+ UINT32 BufOffset;
+ UINT32 BlockId;
+} SMM_STORE_PARAMS_WRITE;
+
+/*
+ * Writes a chunk of raw data with size BufSize to the block specified by
+ * block_id starting at BufOffset.
+ *
+ * block_id must be less than num_blocks
+ * BufOffset + BufSize must be less than block_size
+ */
+typedef struct {
+ UINT32 BufSize;
+ UINT32 BufOffset;
+ UINT32 BlockId;
+} SMM_STORE_PARAMS_READ;
+
+/*
+ * Erases the specified block.
+ *
+ * block_id must be less than num_blocks
+ */
+typedef struct {
+ UINT32 BlockId;
+} SMM_STORE_PARAMS_CLEAR;
+
+typedef union {
+ SMM_STORE_PARAMS_WRITE Write;
+ SMM_STORE_PARAMS_READ Read;
+ SMM_STORE_PARAMS_CLEAR Clear;
+} SMM_STORE_COM_BUF;
+
+#pragma pack(0)
+
+UINTN
+EFIAPI
+TriggerSmi (
+ IN UINTN Cmd,
+ IN UINTN Arg,
+ IN UINTN Retry
+ );
+
+#endif // COREBOOT_SMMSTORE_H_
diff --git a/UefiPayloadPkg/Library/SmmStoreLib/SmmStoreLib.inf b/UefiPayloadPkg/Library/SmmStoreLib/SmmStoreLib.inf
new file mode 100644
index 0000000000..8111100f46
--- /dev/null
+++ b/UefiPayloadPkg/Library/SmmStoreLib/SmmStoreLib.inf
@@ -0,0 +1,40 @@
+## @file
+# SmmStore library for coreboot
+#
+# Copyright (c) 2022 9elements GmbH.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmStoreLib
+ FILE_GUID = 40A2CBC6-CFB8-447b-A90E-298E88FD345E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmStoreLib
+
+[Sources]
+ SmmStore.c
+ SmmStore.h
+
+[Sources.X64]
+ X64/SmmStore.nasm
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DxeServicesTableLib
+ HobLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEfiSmmStoreInfoHobGuid ## CONSUMES
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
diff --git a/UefiPayloadPkg/Library/SmmStoreLib/X64/SmmStore.nasm b/UefiPayloadPkg/Library/SmmStoreLib/X64/SmmStore.nasm
new file mode 100644
index 0000000000..ee20c1fae8
--- /dev/null
+++ b/UefiPayloadPkg/Library/SmmStoreLib/X64/SmmStore.nasm
@@ -0,0 +1,48 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2022, 9elements GmbH. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;-------------------------------------------------------------------------------
+
+%include "Nasm.inc"
+
+DEFAULT REL
+SECTION .text
+
+;UINTN
+;EFIAPI
+;TriggerSmi (
+; UINTN Cmd,
+; UINTN Arg,
+; UINTN Retry
+; )
+
+global ASM_PFX(TriggerSmi)
+ASM_PFX(TriggerSmi):
+ push rbx
+ mov rax, rcx ; Smi handler expect Cmd in RAX
+ mov rbx, rdx ; Smi handler expect Argument in RBX
+@Trigger:
+ out 0b2h, al ; write to APM port to trigger SMI
+
+; There might be a delay between writing the Smi trigger register and
+; entering SMM, in which case the Smi handler will do nothing as only
+; synchronous Smis are handled. In addition when there's no Smi handler
+; or the SmmStore feature isn't compiled in, no register will be modified.
+
+; As there's no livesign from SMM, just wait a bit for the handler to fire,
+; and then try again.
+
+ cmp rax, rcx ; Check if rax was modified by SMM
+ jne @Return ; SMM modified rax, return now
+ push rcx ; save rcx to stack
+ mov rcx, 10000
+ rep pause ; add a small delay
+ pop rcx ; restore rcx
+ cmp r8, 0
+ je @Return
+ dec r8
+ jmp @Trigger
+@Return:
+ pop rbx
+ ret
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc
index 7cb5f83dd1..80e738dc66 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -341,6 +341,8 @@
AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
!endif
+ SmmStoreLib|UefiPayloadPkg/Library/SmmStoreLib/SmmStoreLib.inf
+
!if $(VARIABLE_SUPPORT) == "EMU"
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
!elseif $(VARIABLE_SUPPORT) == "SPI"