diff --git a/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.c b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.c
new file mode 100644
index 0000000000..b19aec26dd
--- /dev/null
+++ b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.c
@@ -0,0 +1,329 @@
+/** @file BlSMMStoreDxe.c
+
+ Copyright (c) 2020, 9elements Agency GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "BlSMMStoreDxe.h"
+
+STATIC EFI_EVENT mSMMStoreVirtualAddrChangeEvent;
+
+//
+// Global variable declarations
+//
+SMMSTORE_INSTANCE *mSMMStoreInstance;
+
+SMMSTORE_INSTANCE mSMMStoreInstanceTemplate = {
+ SMMSTORE_SIGNATURE, // Signature
+ NULL, // Handle ... NEED TO BE FILLED
+ {
+ 0, // MediaId ... NEED TO BE FILLED
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicalPartition
+ FALSE, // ReadOnly
+ FALSE, // WriteCaching;
+ 0, // BlockSize ... NEED TO BE FILLED
+ 4, // IoAlign
+ 0, // LastBlock ... NEED TO BE FILLED
+ 0, // LowestAlignedLba
+ 1, // LogicalBlocksPerPhysicalBlock
+ }, //Media;
+
+ {
+ FvbGetAttributes, // GetAttributes
+ FvbSetAttributes, // SetAttributes
+ FvbGetPhysicalAddress, // GetPhysicalAddress
+ FvbGetBlockSize, // GetBlockSize
+ FvbRead, // Read
+ FvbWrite, // Write
+ FvbEraseBlocks, // EraseBlocks
+ NULL, //ParentHandle
+ }, // FvbProtoccol;
+ {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
+ (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
+ }
+ },
+ { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED
+ },
+ 0, // Index
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+ } // DevicePath
+};
+
+STATIC
+EFI_STATUS
+SMMStoreCreateInstance (
+ IN UINTN NumberofBlocks,
+ IN UINTN BlockSize,
+ OUT SMMSTORE_INSTANCE** SMMStoreInstance
+ )
+{
+ EFI_STATUS Status;
+ SMMSTORE_INSTANCE* Instance;
+
+ ASSERT(SMMStoreInstance != NULL);
+
+ Instance = AllocateRuntimeCopyPool (sizeof(SMMSTORE_INSTANCE),&mSMMStoreInstanceTemplate);
+ if (Instance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Instance->Media.MediaId = 0;
+ Instance->Media.BlockSize = BlockSize;
+ Instance->Media.LastBlock = NumberofBlocks - 1;
+
+ CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
+ Instance->DevicePath.Index = (UINT8)0;
+
+ Status = SMMStoreFvbInitialize (Instance);
+ if (EFI_ERROR(Status)) {
+ FreePool (Instance);
+ return Status;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Instance->Handle,
+ &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool (Instance);
+ return Status;
+ }
+
+ DEBUG((DEBUG_INFO, "%a: Created a new instance\n", __FUNCTION__));
+
+ *SMMStoreInstance = Instance;
+ return Status;
+}
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+BlSMMStoreVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ // Convert Fvb
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.EraseBlocks);
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.GetAttributes);
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.GetBlockSize);
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.GetPhysicalAddress);
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.Read);
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.SetAttributes);
+ EfiConvertPointer (0x0, (VOID**)&mSMMStoreInstance->FvbProtocol.Write);
+
+ SMMStoreVirtualNotifyEvent (Event, Context);
+
+ return;
+}
+
+EFI_STATUS
+EFIAPI
+BlSMMSTOREInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *ComBuf;
+ VOID *GuidHob;
+ SMMSTORE_INFO *SMMStoreInfoHob;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+
+ if (PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ DEBUG ((DEBUG_WARN, "Variable emulation is active! Skipping driver init.\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find the SMMSTORE information guid hob
+ //
+ GuidHob = GetFirstGuidHob (&gEfiSMMSTOREInfoHobGuid);
+ if (GuidHob == NULL) {
+ DEBUG ((DEBUG_WARN, "SMMSTORE not supported! Skipping driver init.\n"));
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Allocate Communication Buffer for arguments to pass to SMM
+ //
+ ComBuf = AllocateRuntimePool (SMMSTORE_COMBUF_SIZE);
+ if (!ComBuf) {
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Place SMMSTORE information hob in a runtime buffer
+ //
+ SMMStoreInfoHob = AllocateRuntimePool (GET_GUID_HOB_DATA_SIZE(GuidHob));
+ if (!SMMStoreInfoHob) {
+ FreePool(ComBuf);
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem(SMMStoreInfoHob, GET_GUID_HOB_DATA (GuidHob), GET_GUID_HOB_DATA_SIZE(GuidHob));
+
+ if (!SMMStoreInfoHob->MmioAddress ||
+ !SMMStoreInfoHob->ComBuffer ||
+ !SMMStoreInfoHob->BlockSize ||
+ !SMMStoreInfoHob->NumBlocks) {
+ DEBUG((DEBUG_ERROR, "%a: Invalid data in SMMStore Info hob\n", __FUNCTION__));
+ FreePool(ComBuf);
+ FreePool(SMMStoreInfoHob);
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Update PCDs for VariableRuntimeDxe
+ // Can't do it later as VariableRuntimeDxe has no Depex
+ //
+ PcdSet32S (PcdFlashNvStorageVariableBase,
+ PcdGet32 (PcdFlashNvStorageVariableBase) + SMMStoreInfoHob->MmioAddress);
+ PcdSet32S (PcdFlashNvStorageFtwWorkingBase,
+ PcdGet32 (PcdFlashNvStorageFtwWorkingBase) + SMMStoreInfoHob->MmioAddress);
+ PcdSet32S (PcdFlashNvStorageFtwSpareBase,
+ PcdGet32 (PcdFlashNvStorageFtwSpareBase) + SMMStoreInfoHob->MmioAddress);
+
+ Status = SMMStoreInitialize(ComBuf, SMMStoreInfoHob);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR,"%a: Failed to initialize SMMStore\n",
+ __FUNCTION__));
+ FreePool(ComBuf);
+ FreePool(SMMStoreInfoHob);
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return Status;
+ }
+
+ mSMMStoreInstance = AllocateRuntimePool (sizeof(SMMSTORE_INSTANCE*));
+ if (!mSMMStoreInstance) {
+ DEBUG((DEBUG_ERROR, "%a: Out of resources\n", __FUNCTION__));
+ FreePool(ComBuf);
+ FreePool(SMMStoreInfoHob);
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = SMMStoreCreateInstance (
+ SMMStoreInfoHob->NumBlocks,
+ SMMStoreInfoHob->BlockSize,
+ &mSMMStoreInstance
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "%a: Fail to create instance for SMMStore\n",
+ __FUNCTION__));
+ FreePool(ComBuf);
+ FreePool(SMMStoreInfoHob);
+ PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
+ return Status;
+ }
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ BlSMMStoreVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mSMMStoreVirtualAddrChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Finally mark the SMM communication buffer provided by CB or SBL as runtime memory
+ //
+ Status = gDS->GetMemorySpaceDescriptor (SMMStoreInfoHob->ComBuffer, &GcdDescriptor);
+ if (EFI_ERROR (Status) || GcdDescriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ DEBUG((DEBUG_INFO, "%a: No memory space descriptor for com buffer found\n",
+ __FUNCTION__));
+
+ //
+ // Add a new entry if not covered by existing mapping
+ //
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeReserved,
+ SMMStoreInfoHob->ComBuffer, SMMStoreInfoHob->ComBufferSize,
+ EFI_MEMORY_WB | EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Mark as runtime service
+ //
+ Status = gDS->SetMemorySpaceAttributes (
+ SMMStoreInfoHob->ComBuffer,
+ SMMStoreInfoHob->ComBufferSize,
+ EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Mark the memory mapped store as MMIO memory
+ //
+ Status = gDS->GetMemorySpaceDescriptor (SMMStoreInfoHob->MmioAddress, &GcdDescriptor);
+ if (EFI_ERROR (Status) || GcdDescriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
+ DEBUG((DEBUG_INFO, "%a: No memory space descriptor for com buffer found\n",
+ __FUNCTION__));
+
+ //
+ // Add a new entry if not covered by existing mapping
+ //
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ SMMStoreInfoHob->MmioAddress,
+ SMMStoreInfoHob->NumBlocks * SMMStoreInfoHob->BlockSize,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Mark as runtime service
+ //
+ Status = gDS->SetMemorySpaceAttributes (
+ SMMStoreInfoHob->MmioAddress,
+ SMMStoreInfoHob->NumBlocks * SMMStoreInfoHob->BlockSize,
+ EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.h b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.h
new file mode 100644
index 0000000000..87fcbc3894
--- /dev/null
+++ b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.h
@@ -0,0 +1,118 @@
+/** @file BlSMMStoreDxe.h
+
+ Copyright (c) 2020, 9elements Agency GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __COREBOOT_SMM_STORE_DXE_H__
+#define __COREBOOT_SMM_STORE_DXE_H__
+
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#define SMMSTORE_SIGNATURE SIGNATURE_32('S', 'M', 'M', 'S')
+#define INSTANCE_FROM_FVB_THIS(a) CR(a, SMMSTORE_INSTANCE, FvbProtocol, SMMSTORE_SIGNATURE)
+
+typedef struct _SMMSTORE_INSTANCE SMMSTORE_INSTANCE;
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ UINT8 Index;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} NOR_FLASH_DEVICE_PATH;
+#pragma pack ()
+
+struct _SMMSTORE_INSTANCE {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_MEDIA Media;
+
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
+
+ NOR_FLASH_DEVICE_PATH DevicePath;
+};
+
+//
+// BlSMMStoreFvbDxe.c
+//
+
+EFI_STATUS
+EFIAPI
+SMMStoreFvbInitialize (
+ IN SMMSTORE_INSTANCE* Instance
+ );
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+FvbSetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ );
+
+EFI_STATUS
+EFIAPI
+FvbRead(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+FvbWrite(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ );
+
+
+#endif /* __COREBOOT_SMM_STORE_DXE_H__ */
diff --git a/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.inf b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.inf
new file mode 100644
index 0000000000..823a191de6
--- /dev/null
+++ b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.inf
@@ -0,0 +1,62 @@
+#/** @file
+#
+# Component description file for SMMSTORE module
+#
+# Copyright (c) 2020, 9elements Agency GmbH
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiPayloadBlSMMStoreDxe
+ FILE_GUID = A0402FCA-6B25-4CEA-B7DD-C08F99714B29
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = BlSMMSTOREInitialise
+
+[Sources.common]
+ BlSMMStoreDxe.h
+ BlSMMStoreDxe.c
+ BlSMMStoreFvbDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ HobLib
+ SmmStoreLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeLib
+ DxeServicesTableLib
+
+[Guids]
+ gEfiSystemNvDataFvGuid
+ gEfiVariableGuid
+ gEfiAuthenticatedVariableGuid
+ gEfiEventVirtualAddressChangeGuid
+ gEdkiiNvVarStoreFormattedGuid ## PRODUCES ## PROTOCOL
+ gEfiSMMSTOREInfoHobGuid ## CONSUMES
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiFirmwareVolumeBlockProtocolGuid ## BY_START
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable
+
+[Depex]
+ BEFORE gVariableRuntimeDxeFileGuid
\ No newline at end of file
diff --git a/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreFvbDxe.c b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreFvbDxe.c
new file mode 100644
index 0000000000..3370edfeed
--- /dev/null
+++ b/UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreFvbDxe.c
@@ -0,0 +1,813 @@
+/*++ @file BlSMMStoreFvbDxe.c
+
+ Copyright (c) 2020, 9elements Agency GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ --*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "BlSMMStoreDxe.h"
+
+STATIC EFI_EVENT mFvbVirtualAddrChangeEvent;
+STATIC UINTN mFlashNvStorageVariableBase;
+
+///
+/// The Firmware Volume Block Protocol is the low-level interface
+/// to a firmware volume. File-level access to a firmware volume
+/// should not be done using the Firmware Volume Block Protocol.
+/// Normal access to a firmware volume must use the Firmware
+/// Volume Protocol. Typically, only the file system driver that
+/// produces the Firmware Volume Protocol will bind to the
+/// Firmware Volume Block Protocol.
+///
+
+/**
+ Initialises the FV Header and Variable Store Header
+ to support variable operations.
+
+ @param[in] Ptr - Location to initialise the headers
+
+**/
+EFI_STATUS
+InitializeFvAndVariableStoreHeaders (
+ IN SMMSTORE_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ VOID* Headers;
+ UINTN HeadersLength;
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);
+ Headers = AllocateZeroPool(HeadersLength);
+
+ // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous.
+ ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) + PcdGet32(PcdFlashNvStorageVariableSize) == PcdGet32(PcdFlashNvStorageFtwWorkingBase));
+ ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) == PcdGet32(PcdFlashNvStorageFtwSpareBase));
+
+ // Check if the size of the area is at least one block size
+ ASSERT((PcdGet32(PcdFlashNvStorageVariableSize) > 0) && (PcdGet32(PcdFlashNvStorageVariableSize) / Instance->Media.BlockSize > 0));
+ ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingSize) > 0) && (PcdGet32(PcdFlashNvStorageFtwWorkingSize) / Instance->Media.BlockSize > 0));
+ ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareSize) > 0) && (PcdGet32(PcdFlashNvStorageFtwSpareSize) / Instance->Media.BlockSize > 0));
+
+ // Ensure the Variable area Base Addresses are aligned on a block size boundaries
+ ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) % Instance->Media.BlockSize == 0);
+ ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) % Instance->Media.BlockSize == 0);
+ ASSERT(PcdGet32(PcdFlashNvStorageFtwSpareBase) % Instance->Media.BlockSize == 0);
+
+ //
+ // EFI_FIRMWARE_VOLUME_HEADER
+ //
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
+ CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+ FirmwareVolumeHeader->FvLength =
+ PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize);
+ FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
+ FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) (
+ EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
+ EFI_FVB2_READ_STATUS | // Reads are currently enabled
+ EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
+ EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
+ EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1')
+ EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
+ EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled
+ );
+ FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY);
+ FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
+ FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1;
+ FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize;
+ FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+ FirmwareVolumeHeader->BlockMap[1].Length = 0;
+ FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader,FirmwareVolumeHeader->HeaderLength);
+
+ //
+ // VARIABLE_STORE_HEADER
+ //
+ VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength);
+ CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid);
+ VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;
+ VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+ VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
+
+ // Install the combined super-header in the store
+ Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
+
+ FreePool (Headers);
+ return Status;
+}
+
+/**
+ Check the integrity of firmware volume header.
+
+ @param[in] FwVolHeader - A pointer to a firmware volume header
+
+ @retval EFI_SUCCESS - The firmware volume is consistent
+ @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
+
+**/
+EFI_STATUS
+ValidateFvHeader (
+ IN SMMSTORE_INSTANCE *Instance
+ )
+{
+ UINT16 Checksum;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VariableStoreLength;
+ UINTN FvLength;
+ EFI_STATUS TempStatus;
+ UINTN BufferSize;
+ UINTN BufferSizeReqested;
+
+ BufferSizeReqested = sizeof(EFI_FIRMWARE_VOLUME_HEADER);
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)AllocatePool(BufferSizeReqested);
+ if (!FwVolHeader) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ BufferSize = BufferSizeReqested;
+ TempStatus = SMMStoreRead (0, 0, &BufferSize, (UINT8 *)FwVolHeader);
+ if (EFI_ERROR (TempStatus) || BufferSizeReqested != BufferSize) {
+ FreePool (FwVolHeader);
+ return EFI_DEVICE_ERROR;
+ }
+
+ FvLength = PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize);
+
+ //
+ // Verify the header revision, header signature, length
+ // Length of FvBlock cannot be 2**64-1
+ // HeaderLength cannot be an odd number
+ //
+ if ( (FwVolHeader->Revision != EFI_FVH_REVISION)
+ || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
+ || (FwVolHeader->FvLength != FvLength)
+ )
+ {
+ DEBUG ((DEBUG_INFO, "%a: No Firmware Volume header present\n",
+ __FUNCTION__));
+ FreePool (FwVolHeader);
+ return EFI_NOT_FOUND;
+ }
+
+ // Check the Firmware Volume Guid
+ if( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) {
+ DEBUG ((DEBUG_INFO, "%a: Firmware Volume Guid non-compatible\n",
+ __FUNCTION__));
+ FreePool (FwVolHeader);
+ return EFI_NOT_FOUND;
+ }
+
+ BufferSizeReqested = FwVolHeader->HeaderLength;
+ FreePool (FwVolHeader);
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)AllocatePool(BufferSizeReqested);
+ if (!FwVolHeader) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ BufferSize = BufferSizeReqested;
+ TempStatus = SMMStoreRead (0, 0, &BufferSize, (UINT8 *)FwVolHeader);
+ if (EFI_ERROR (TempStatus) || BufferSizeReqested != BufferSize) {
+ FreePool (FwVolHeader);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Verify the header checksum
+ Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
+ if (Checksum != 0) {
+ DEBUG ((DEBUG_INFO, "%a: FV checksum is invalid (Checksum:0x%X)\n",
+ __FUNCTION__, Checksum));
+ FreePool (FwVolHeader);
+ return EFI_NOT_FOUND;
+ }
+
+ BufferSizeReqested = sizeof(VARIABLE_STORE_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER*)AllocatePool(BufferSizeReqested);
+ if (!VariableStoreHeader) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ BufferSize = BufferSizeReqested;
+ TempStatus = SMMStoreRead (0, FwVolHeader->HeaderLength, &BufferSize, (UINT8 *)VariableStoreHeader);
+ if (EFI_ERROR (TempStatus) || BufferSizeReqested != BufferSize) {
+ FreePool (VariableStoreHeader);
+ FreePool (FwVolHeader);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Check the Variable Store Guid
+ if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+ !CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)) {
+ DEBUG ((DEBUG_INFO, "%a: Variable Store Guid non-compatible\n",
+ __FUNCTION__));
+ FreePool (FwVolHeader);
+ FreePool (VariableStoreHeader);
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength;
+ if (VariableStoreHeader->Size != VariableStoreLength) {
+ DEBUG ((DEBUG_INFO, "%a: Variable Store Length does not match\n",
+ __FUNCTION__));
+ FreePool (FwVolHeader);
+ FreePool (VariableStoreHeader);
+ return EFI_NOT_FOUND;
+ }
+
+ FreePool (FwVolHeader);
+ FreePool (VariableStoreHeader);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
+ current settings are returned.
+ Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbGetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ SMMSTORE_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+
+ FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2) (
+
+ EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
+ EFI_FVB2_READ_STATUS | // Reads are currently enabled
+ EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
+ EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
+ EFI_FVB2_ERASE_POLARITY // After erasure all bits take this value (i.e. '1')
+
+ );
+
+ // Check if it is write protected
+ if (Instance->Media.ReadOnly != TRUE) {
+
+ FlashFvbAttributes = FlashFvbAttributes |
+ EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
+ EFI_FVB2_WRITE_ENABLED_CAP; // Writes may be enabled
+ }
+
+ *Attributes = FlashFvbAttributes;
+
+ DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The SetAttributes() function sets configurable firmware volume attributes
+ and returns the new settings of the firmware volume.
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to EFI_FVB_ATTRIBUTES_2
+ that contains the desired firmware volume settings.
+ On successful return, it contains the new settings of
+ the firmware volume.
+ Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with the capabilities
+ as declared in the firmware volume header.
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbSetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n",*Attributes));
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ ASSERT(Address != NULL);
+
+ *Address = mFlashNvStorageVariableBase;
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba Indicates the block for which to return the size.
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ SMMSTORE_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+
+ DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba, Instance->Media.BlockSize, Instance->Media.LastBlock));
+
+ if (Lba > Instance->Media.LastBlock) {
+ DEBUG ((DEBUG_ERROR, "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n", Lba, Instance->Media.LastBlock));
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ *BlockSize = (UINTN) Instance->Media.BlockSize;
+ *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1);
+
+ DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize, *NumberOfBlocks));
+
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index from which to read.
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN.
+ At entry, *NumBytes contains the total size of the buffer.
+ At exit, *NumBytes contains the total number of bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will be used
+ to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully, and contents are
+ in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
+ On output, NumBytes contains the total number of bytes
+ returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read.
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ UINTN BlockSize;
+ SMMSTORE_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+
+ DEBUG ((DEBUG_BLKIO, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
+
+ // Cache the block size to avoid de-referencing pointers all the time
+ BlockSize = Instance->Media.BlockSize;
+
+ DEBUG ((DEBUG_BLKIO, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
+
+ // The read must not span block boundaries.
+ // We need to check each variable individually because adding two large values together overflows.
+ if ((Offset >= BlockSize) ||
+ (*NumBytes > BlockSize) ||
+ ((Offset + *NumBytes) > BlockSize)) {
+ DEBUG ((DEBUG_ERROR, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // We must have some bytes to read
+ if (*NumBytes == 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ return SMMStoreRead (Lba, Offset, NumBytes, Buffer);
+}
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. Before calling the
+ Write() function, it is recommended for the caller to first call
+ the EraseBlocks() function to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes The pointer to a UINTN.
+ At entry, *NumBytes contains the total size of the buffer.
+ At exit, *NumBytes contains the total number of bytes actually written.
+
+ @param Buffer The pointer to a caller-allocated buffer that contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of bytes
+ actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written.
+
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ UINTN BlockSize;
+ SMMSTORE_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+
+ DEBUG ((DEBUG_BLKIO, "FvbWrite(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
+
+ // Cache the block size to avoid de-referencing pointers all the time
+ BlockSize = Instance->Media.BlockSize;
+
+ // The read must not span block boundaries.
+ // We need to check each variable individually because adding two large values together overflows.
+ if ((Offset >= BlockSize) ||
+ (*NumBytes > BlockSize) ||
+ ((Offset + *NumBytes) > BlockSize)) {
+ DEBUG ((DEBUG_ERROR, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // We must have some bytes to read
+ if (*NumBytes == 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ return SMMStoreWrite (Lba, Offset, NumBytes, Buffer);
+}
+
+/**
+ Erases and initialises a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks to erase.
+
+ The list is terminated with an EFI_LBA_LIST_TERMINATOR.
+ For example, the following indicates that two ranges of blocks
+ (5-7 and 10-11) are to be erased:
+ EraseBlocks (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
+
+ @retval EFI_SUCCESS The erase request successfully completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be written.
+ The firmware device may have been partially erased.
+
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable argument list do
+ not exist in the firmware volume.
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ EFI_LBA StartingLba; // Lba from which we start erasing
+ UINTN NumOfLba; // Number of Lba blocks to erase
+ SMMSTORE_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+
+ DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks()\n"));
+
+ Status = EFI_SUCCESS;
+
+ // Detect WriteDisabled state
+ if (Instance->Media.ReadOnly == TRUE) {
+ // Firmware volume is in WriteDisabled state
+ DEBUG ((DEBUG_ERROR, "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n"));
+ return EFI_ACCESS_DENIED;
+ }
+
+ // Before erasing, check the entire list of parameters to ensure all specified blocks are valid
+
+ VA_START (Args, This);
+ do {
+ // Get the Lba from which we start erasing
+ StartingLba = VA_ARG (Args, EFI_LBA);
+
+ // Have we reached the end of the list?
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ //Exit the while loop
+ break;
+ }
+
+ // How many Lba blocks are we requested to erase?
+ NumOfLba = VA_ARG (Args, UINTN);
+
+ // All blocks must be within range
+ DEBUG ((
+ DEBUG_BLKIO,
+ "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%Lu - 1 ) > LastBlock=%ld.\n",
+ StartingLba,
+ (UINT64)NumOfLba,
+ Instance->Media.LastBlock
+ ));
+ if ((NumOfLba == 0) || ((StartingLba + NumOfLba - 1) > Instance->Media.LastBlock)) {
+ VA_END (Args);
+ DEBUG ((DEBUG_ERROR, "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+ } while (TRUE);
+ VA_END (Args);
+
+ //
+ // To get here, all must be ok, so start erasing
+ //
+ VA_START (Args, This);
+ do {
+ // Get the Lba from which we start erasing
+ StartingLba = VA_ARG (Args, EFI_LBA);
+
+ // Have we reached the end of the list?
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ // Exit the while loop
+ break;
+ }
+
+ // How many Lba blocks are we requested to erase?
+ NumOfLba = VA_ARG (Args, UINTN);
+
+ // Go through each one and erase it
+ while (NumOfLba > 0) {
+ // Erase it
+ DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld\n", StartingLba));
+ Status = SMMStoreEraseBlock (StartingLba);
+ if (EFI_ERROR(Status)) {
+ VA_END (Args);
+ Status = EFI_DEVICE_ERROR;
+ goto EXIT;
+ }
+
+ // Move to the next Lba
+ StartingLba++;
+ NumOfLba--;
+ }
+ } while (TRUE);
+ VA_END (Args);
+
+EXIT:
+ return Status;
+}
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+FvbVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);
+ return;
+}
+
+EFI_STATUS
+EFIAPI
+SMMStoreFvbInitialize (
+ IN SMMSTORE_INSTANCE* Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FvbNumLba;
+ EFI_BOOT_MODE BootMode;
+
+ DEBUG((DEBUG_BLKIO,"NorFlashFvbInitialize\n"));
+ ASSERT((Instance != NULL));
+
+ mFlashNvStorageVariableBase = PcdGet32 (PcdFlashNvStorageVariableBase);
+
+ BootMode = GetBootModeHob ();
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ // Determine if there is a valid header at the beginning of the NorFlash
+ Status = ValidateFvHeader (Instance);
+ }
+
+ // Install the Default FVB header if required
+ if (EFI_ERROR(Status)) {
+ // There is no valid header, so time to install one.
+ DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__));
+ DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n",
+ __FUNCTION__));
+
+ // Erase all the NorFlash that is reserved for variable storage
+ FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize;
+
+ Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // Install all appropriate headers
+ Status = InitializeFvAndVariableStoreHeaders (Instance);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ DEBUG((DEBUG_INFO, "%a: FVB header is valid\n", __FUNCTION__));
+ }
+
+ //
+ // The driver implementing the variable read service can now be dispatched;
+ // the varstore headers are in place.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &gImageHandle,
+ &gEdkiiNvVarStoreFormattedGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FvbVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mFvbVirtualAddrChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/UefiPayloadPkg/Include/Coreboot.h b/UefiPayloadPkg/Include/Coreboot.h
index 8a6c300cde..340465177c 100644
--- a/UefiPayloadPkg/Include/Coreboot.h
+++ b/UefiPayloadPkg/Include/Coreboot.h
@@ -236,6 +236,19 @@ struct cb_cbmem_tab {
UINT64 cbmem_tab;
};
+#define CB_TAG_SMMSTOREV2 0x0039
+struct cb_smmstorev2 {
+ UINT32 tag;
+ UINT32 size;
+ UINT32 num_blocks; /* Number of writeable blocks in SMM */
+ UINT32 block_size; /* Size of a block in byte. Default: 64 KiB */
+ UINT32 mmap_addr; /* MMIO address of the store for read only access */
+ UINT32 com_buffer; /* Physical address of the communication buffer */
+ UINT32 com_buffer_size; /* Size of the communication buffer in byte */
+ UINT8 apm_cmd; /* The command byte to write to the APM I/O port */
+ UINT8 unused[3]; /* Set to zero */
+};
+
/* Helpful macros */
#define MEM_RANGE_COUNT(_rec) \
diff --git a/UefiPayloadPkg/Include/Guid/SMMSTOREInfoGuid.h b/UefiPayloadPkg/Include/Guid/SMMSTOREInfoGuid.h
new file mode 100644
index 0000000000..552f86115b
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/SMMSTOREInfoGuid.h
@@ -0,0 +1,27 @@
+/** @file
+ This file defines the hob structure for system tables like ACPI, SMBIOS tables.
+
+ Copyright (c) 2020, 9elements Agency GmbH
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMMSTORE_GUID_H__
+#define __SMMSTORE_GUID_H__
+
+///
+/// System Table Information GUID
+///
+extern EFI_GUID gEfiSMMSTOREInfoHobGuid;
+
+typedef struct {
+ UINT64 ComBuffer;
+ UINT32 ComBufferSize;
+ UINT32 NumBlocks;
+ UINT32 BlockSize;
+ UINT64 MmioAddress;
+ UINT8 ApmCmd;
+ UINT8 Reserved0[3];
+} SMMSTORE_INFO;
+
+#endif
diff --git a/UefiPayloadPkg/Include/Library/BlParseLib.h b/UefiPayloadPkg/Include/Library/BlParseLib.h
index 20a526d15c..f9439e30a7 100644
--- a/UefiPayloadPkg/Include/Library/BlParseLib.h
+++ b/UefiPayloadPkg/Include/Library/BlParseLib.h
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#ifndef __BOOTLOADER_PARSE_LIB__
#define __BOOTLOADER_PARSE_LIB__
@@ -117,4 +118,19 @@ ParseGfxDeviceInfo (
OUT EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *GfxDeviceInfo
);
+/**
+ Find the video frame buffer device information
+
+ @param SMMSTOREInfo Pointer to the SMMSTORE_INFO structure
+
+ @retval RETURN_SUCCESS Successfully find the SMM store buffer information.
+ @retval RETURN_NOT_FOUND Failed to find the SMM store buffer information .
+
+**/
+RETURN_STATUS
+EFIAPI
+ParseSMMSTOREInfo (
+ OUT SMMSTORE_INFO *SMMSTOREInfo
+ );
+
#endif
diff --git a/UefiPayloadPkg/Include/Library/SMMStoreLib.h b/UefiPayloadPkg/Include/Library/SMMStoreLib.h
new file mode 100644
index 0000000000..be7b9a54a1
--- /dev/null
+++ b/UefiPayloadPkg/Include/Library/SMMStoreLib.h
@@ -0,0 +1,98 @@
+/** @file SMMStoreLib.h
+
+ Copyright (c) 2020, 9elements Agency 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
+
+/**
+ 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
+SMMStoreRead (
+ 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
+SMMStoreWrite (
+ 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
+SMMStoreEraseBlock (
+ IN EFI_LBA Lba
+ );
+
+
+/**
+ Notify the SMMStore Library about a VirtualNotify
+
+**/
+
+VOID
+EFIAPI
+SMMStoreVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Initializes SMMStore support
+
+ @param[in] Ptr A runtime buffer where arguments are stored
+ for SMM communication
+ @param[in] SmmStoreInfoHob A runtime buffer with a copy of the
+ SmmStore Info Hob
+
+ @retval EFI_WRITE_PROTECTED The SMMSTORE is not present.
+ @retval EFI_SUCCESS The SMMSTORE is supported.
+
+**/
+EFI_STATUS
+SMMStoreInitialize (
+ IN VOID *Ptr,
+ IN SMMSTORE_INFO *SmmStoreInfoHob
+ );
+
+#endif /* __SMM_STORE_LIB_H__ */
diff --git a/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c b/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
index 4e23cff50e..2b449f05eb 100644
--- a/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
+++ b/UefiPayloadPkg/Library/CbParseLib/CbParseLib.c
@@ -558,3 +558,45 @@ ParseGfxDeviceInfo (
return RETURN_NOT_FOUND;
}
+/**
+ Find the SMM store information
+
+ @param SMMSTOREInfo Pointer to the SMMSTORE_INFO structure
+
+ @retval RETURN_SUCCESS Successfully find the SMM store buffer information.
+ @retval RETURN_NOT_FOUND Failed to find the SMM store buffer information .
+
+**/
+RETURN_STATUS
+EFIAPI
+ParseSMMSTOREInfo (
+ OUT SMMSTORE_INFO *SMMSTOREInfo
+ )
+{
+ struct cb_smmstorev2 *CbSSRec;
+
+ if (SMMSTOREInfo == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CbSSRec = FindCbTag (CB_TAG_SMMSTOREV2);
+ if (CbSSRec == NULL) {
+ return RETURN_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "Found SMM Store information\n"));
+ DEBUG ((DEBUG_INFO, "block size: 0x%x\n", CbSSRec->block_size));
+ DEBUG ((DEBUG_INFO, "number of blocks: 0x%x\n", CbSSRec->num_blocks));
+ DEBUG ((DEBUG_INFO, "communication buffer: 0x%x\n", CbSSRec->com_buffer));
+ DEBUG ((DEBUG_INFO, "communication buffer size: 0x%x\n", CbSSRec->com_buffer_size));
+ DEBUG ((DEBUG_INFO, "MMIO address of store: 0x%x\n", CbSSRec->mmap_addr));
+
+ SMMSTOREInfo->ComBuffer = CbSSRec->com_buffer;
+ SMMSTOREInfo->ComBufferSize = CbSSRec->com_buffer_size;
+ SMMSTOREInfo->BlockSize = CbSSRec->block_size;
+ SMMSTOREInfo->NumBlocks = CbSSRec->num_blocks;
+ SMMSTOREInfo->MmioAddress = CbSSRec->mmap_addr;
+ SMMSTOREInfo->ApmCmd = CbSSRec->apm_cmd;
+
+ return RETURN_SUCCESS;
+}
diff --git a/UefiPayloadPkg/Library/CbSMMStoreLib/CbSMMStoreLib.inf b/UefiPayloadPkg/Library/CbSMMStoreLib/CbSMMStoreLib.inf
new file mode 100644
index 0000000000..c93d959f94
--- /dev/null
+++ b/UefiPayloadPkg/Library/CbSMMStoreLib/CbSMMStoreLib.inf
@@ -0,0 +1,28 @@
+## @file
+# SMMStore library for coreboot
+#
+# Copyright (c) 2020 9elements Agency GmbH.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CbSmmStoreLib
+ FILE_GUID = 40A2CBC6-CFB8-447b-A90E-298E88FD345E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmStoreLib
+
+[Sources]
+ CorebootSMMStore.c
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
diff --git a/UefiPayloadPkg/Library/CbSMMStoreLib/CorebootSMMStore.c b/UefiPayloadPkg/Library/CbSMMStoreLib/CorebootSMMStore.c
new file mode 100644
index 0000000000..7673123adb
--- /dev/null
+++ b/UefiPayloadPkg/Library/CbSMMStoreLib/CorebootSMMStore.c
@@ -0,0 +1,305 @@
+/** @file CorebootSMMStoreDxe.c
+
+ Copyright (c) 2020, 9elements Agency GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * calls into SMM to use the SMMSTORE implementation for persistent storage.
+ * The given cmd and subcmd is in eax and the argument in ebx.
+ * On successful invocation the result is in eax.
+ */
+static UINT32 call_smm(UINT8 cmd, UINT8 subcmd, UINT32 arg) {
+ CONST UINT32 eax = ((subcmd << 8) | cmd);
+ CONST UINT32 ebx = arg;
+ UINT32 res;
+ UINTN i;
+
+ /* Retry a few times to make sure it works */
+ for (i = 0; i < 5; i++) {
+ __asm__ __volatile__ (
+ "\toutb %b0, $0xb2\n"
+ : "=a" (res)
+ : "a" (eax), "b" (ebx)
+ : "memory");
+ if (res == eax) {
+ /**
+ There might ba 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.
+ **/
+ for (UINTN j = 0; j < 0x10000; j++) {
+ CpuPause();
+ }
+ } else {
+ break;
+ }
+ }
+
+ return res;
+}
+
+#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
+ */
+struct smmstore_params_raw_write {
+ UINT32 bufsize;
+ UINT32 bufoffset;
+ UINT32 block_id;
+};
+
+/*
+ * 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
+ */
+struct smmstore_params_raw_read {
+ UINT32 bufsize;
+ UINT32 bufoffset;
+ UINT32 block_id;
+};
+
+/*
+ * Erases the specified block.
+ *
+ * @block_id must be less than num_blocks
+ */
+struct smmstore_params_raw_clear {
+ UINT32 block_id;
+};
+
+typedef struct smmstore_comm_buffer {
+ union {
+ struct smmstore_params_raw_write raw_write;
+ struct smmstore_params_raw_read raw_read;
+ struct smmstore_params_raw_clear raw_clear;
+ };
+} SMMSTORE_COMBUF;
+#pragma pack(0)
+
+/*
+ * A memory buffer to place arguments in.
+ */
+STATIC SMMSTORE_COMBUF *mArgComBuf;
+STATIC UINT32 mArgComBufPhys;
+
+/*
+ * Metadata provided by the first stage bootloader.
+ */
+STATIC SMMSTORE_INFO *mSmmStoreInfo;
+
+/**
+ 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
+SMMStoreRead (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ UINT32 Result;
+
+ if (!mSmmStoreInfo) {
+ 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->raw_read.bufsize = *NumBytes;
+ mArgComBuf->raw_read.bufoffset = Offset;
+ mArgComBuf->raw_read.block_id = Lba;
+
+ Result = call_smm(mSmmStoreInfo->ApmCmd, SMMSTORE_CMD_RAW_READ, mArgComBufPhys);
+ if (Result == SMMSTORE_RET_FAILURE) {
+ return EFI_DEVICE_ERROR;
+ } else if (Result == SMMSTORE_RET_UNSUPPORTED) {
+ return EFI_UNSUPPORTED;
+ } else if (Result != SMMSTORE_RET_SUCCESS) {
+ return EFI_NO_RESPONSE;
+ }
+
+ 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
+SMMStoreWrite (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ UINTN Result;
+
+ if (!mSmmStoreInfo) {
+ 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->raw_write.bufsize = *NumBytes;
+ mArgComBuf->raw_write.bufoffset = Offset;
+ mArgComBuf->raw_write.block_id = Lba;
+
+ CopyMem ((VOID *)(UINTN)(mSmmStoreInfo->ComBuffer + Offset), Buffer, *NumBytes);
+
+ Result = call_smm(mSmmStoreInfo->ApmCmd, SMMSTORE_CMD_RAW_WRITE, mArgComBufPhys);
+ if (Result == SMMSTORE_RET_FAILURE) {
+ return EFI_DEVICE_ERROR;
+ } else if (Result == SMMSTORE_RET_UNSUPPORTED) {
+ return EFI_UNSUPPORTED;
+ } else if (Result != SMMSTORE_RET_SUCCESS) {
+ return EFI_NO_RESPONSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Erase a SMMStore block
+
+ @param Lba The logical block index to erase.
+
+**/
+EFI_STATUS
+SMMStoreEraseBlock (
+ IN EFI_LBA Lba
+ )
+{
+ UINTN Result;
+
+ if (!mSmmStoreInfo) {
+ return EFI_NO_MEDIA;
+ }
+ if (Lba >= mSmmStoreInfo->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mArgComBuf->raw_clear.block_id = Lba;
+
+ Result = call_smm(mSmmStoreInfo->ApmCmd, SMMSTORE_CMD_RAW_CLEAR, mArgComBufPhys);
+ if (Result == SMMSTORE_RET_FAILURE) {
+ return EFI_DEVICE_ERROR;
+ } else if (Result == SMMSTORE_RET_UNSUPPORTED) {
+ return EFI_UNSUPPORTED;
+ } else if (Result != SMMSTORE_RET_SUCCESS) {
+ return EFI_NO_RESPONSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+SMMStoreVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID**)&mArgComBuf);
+ if (mSmmStoreInfo) {
+ EfiConvertPointer (0x0, (VOID**)&mSmmStoreInfo->ComBuffer);
+ EfiConvertPointer (0x0, (VOID**)&mSmmStoreInfo);
+ }
+
+ return;
+}
+
+/**
+ Initializes SMMStore support
+
+ @param[in] Ptr A runtime buffer where arguments are stored
+ for SMM communication
+ @param[in] SmmStoreInfoHob A runtime buffer with a copy of the
+ SmmStore Info Hob
+
+ @retval EFI_WRITE_PROTECTED The SMMSTORE is not present.
+ @retval EFI_SUCCESS The SMMSTORE is supported.
+
+**/
+EFI_STATUS
+SMMStoreInitialize (
+ IN VOID *Ptr,
+ IN SMMSTORE_INFO *SmmStoreInfoHob
+ )
+{
+ ASSERT (Ptr != NULL);
+ ASSERT (SmmStoreInfoHob != NULL);
+
+ mArgComBuf = Ptr;
+ mArgComBufPhys = (UINT32)(UINTN)mArgComBuf;
+
+ mSmmStoreInfo = SmmStoreInfoHob;
+
+ return EFI_SUCCESS;
+}
diff --git a/UefiPayloadPkg/Library/SblParseLib/SblParseLib.c b/UefiPayloadPkg/Library/SblParseLib/SblParseLib.c
index 7214fd87d2..87e7605a2b 100644
--- a/UefiPayloadPkg/Library/SblParseLib/SblParseLib.c
+++ b/UefiPayloadPkg/Library/SblParseLib/SblParseLib.c
@@ -221,3 +221,20 @@ ParseGfxDeviceInfo (
return RETURN_SUCCESS;
}
+/**
+ Find the video frame buffer device information
+
+ @param SMMSTOREInfo Pointer to the SMMSTORE_INFO structure
+
+ @retval RETURN_SUCCESS Successfully find the SMM store buffer information.
+ @retval RETURN_NOT_FOUND Failed to find the SMM store buffer information .
+
+**/
+RETURN_STATUS
+EFIAPI
+ParseSMMSTOREInfo (
+ OUT SMMSTORE_INFO *SMMSTOREInfo
+ )
+{
+ return RETURN_NOT_FOUND;
+}
diff --git a/UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStore.c b/UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStore.c
new file mode 100644
index 0000000000..f5a3bad763
--- /dev/null
+++ b/UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStore.c
@@ -0,0 +1,102 @@
+/** @file SblSMMStore.c
+
+ Copyright (c) 2020, 9elements Agency GmbH
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include
+
+#include
+#include
+#include
+#include
+
+/**
+ 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
+SMMStoreRead (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ 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
+SMMStoreWrite (
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Erase a SMMStore block
+
+ @param Lba The logical block index to erase.
+
+**/
+EFI_STATUS
+SMMStoreEraseBlock (
+ IN EFI_LBA Lba
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+VOID
+EFIAPI
+SMMStoreVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ return;
+}
+
+/**
+ Initializes SMMStore support
+
+ @param[in] Ptr A runtime buffer where arguments are stored
+ for SMM communication
+ @param[in] SmmStoreInfoHob A runtime buffer with a copy of the
+ SmmStore Info Hob
+
+ @retval EFI_WRITE_PROTECTED The SMMSTORE is not present.
+ @retval EFI_SUCCESS The SMMSTORE is supported.
+
+**/
+EFI_STATUS
+SMMStoreInitialize (
+ IN VOID *Ptr,
+ IN SMMSTORE_INFO *SmmStoreInfoHob
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStoreLib.inf b/UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStoreLib.inf
new file mode 100644
index 0000000000..cf6246ed19
--- /dev/null
+++ b/UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStoreLib.inf
@@ -0,0 +1,28 @@
+## @file
+# SMMStore library for Slimbootloader
+#
+# Copyright (c) 2020 9elements Agency GmbH.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SblSmmStoreLib
+ FILE_GUID = 2CA0BC03-A619-4B88-A0C5-06A1992750C3
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmStoreLib
+
+[Sources]
+ SblSMMStore.c
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
index ae16f25c7c..d230e6485b 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
@@ -389,6 +389,8 @@ BuildHobFromBl (
SYSTEM_TABLE_INFO *NewSysTableInfo;
ACPI_BOARD_INFO AcpiBoardInfo;
ACPI_BOARD_INFO *NewAcpiBoardInfo;
+ SMMSTORE_INFO SMMSTOREInfo;
+ SMMSTORE_INFO *NewSMMSTOREInfo;
EFI_PEI_GRAPHICS_INFO_HOB GfxInfo;
EFI_PEI_GRAPHICS_INFO_HOB *NewGfxInfo;
EFI_PEI_GRAPHICS_DEVICE_INFO_HOB GfxDeviceInfo;
@@ -435,6 +437,16 @@ BuildHobFromBl (
DEBUG ((DEBUG_INFO, "Created graphics device info hob\n"));
}
+ //
+ // Create guid hob for SMMSTORE
+ //
+ Status = ParseSMMSTOREInfo (&SMMSTOREInfo);
+ if (!EFI_ERROR (Status)) {
+ NewSMMSTOREInfo = BuildGuidHob (&gEfiSMMSTOREInfoHobGuid, sizeof (SMMSTOREInfo));
+ ASSERT (NewSMMSTOREInfo != NULL);
+ CopyMem (NewSMMSTOREInfo, &SMMSTOREInfo, sizeof (SMMSTOREInfo));
+ DEBUG ((DEBUG_INFO, "Created SMMSTORE info hob\n"));
+ }
//
// Create guid hob for system tables like acpi table and smbios table
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h
index 331724c687..54d8e9e960 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#define LEGACY_8259_MASK_REGISTER_MASTER 0x21
#define LEGACY_8259_MASK_REGISTER_SLAVE 0xA1
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
index 8d42925fcd..88c661b09f 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
@@ -56,6 +56,7 @@
PeCoffLib
PlatformSupportLib
UefiCpuLib
+ PcdLib
[Guids]
gEfiMemoryTypeInformationGuid
@@ -66,6 +67,7 @@
gUefiAcpiBoardInfoGuid
gUniversalPayloadSmbiosTableGuid
gUniversalPayloadAcpiTableGuid
+ gEfiSMMSTOREInfoHobGuid
[FeaturePcd.IA32]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
@@ -92,4 +94,3 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES
-
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayloadPkg.dec
index 8f0a7e3f95..18f7607ec7 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -36,6 +36,14 @@
gUefiAcpiBoardInfoGuid = {0xad3d31b, 0xb3d8, 0x4506, {0xae, 0x71, 0x2e, 0xf1, 0x10, 0x6, 0xd9, 0xf}}
gUefiSerialPortInfoGuid = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }
gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }
+ gEfiSMMSTOREInfoHobGuid = { 0xf585ca19, 0x881b, 0x44fb, { 0x3f, 0x3d, 0x81, 0x89, 0x7c, 0x57, 0xbb, 0x01 } }
+
+[Guids.common]
+ #
+ # Following Guid must match FILE_GUID in
+ # MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+ #
+ gVariableRuntimeDxeFileGuid = { 0xcbd2e4d5, 0x7068, 0x4ff5, { 0xb4, 0x62, 0x98, 0x22, 0xb4, 0xad, 0x8d, 0x60 } }
[Ppis]
gEfiPayLoadHobBasePpiGuid = { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6, 0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} }
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc
index b04dcf263f..a7be9b934e 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -247,6 +247,11 @@
VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+!if $(BOOTLOADER) == "COREBOOT"
+ SmmStoreLib|UefiPayloadPkg/Library/CbSMMStoreLib/CbSMMStoreLib.inf
+!else
+ SmmStoreLib|UefiPayloadPkg/Library/SblSMMStoreLib/SblSMMStoreLib.inf
+!endif
[LibraryClasses.common.SEC]
HobLib|UefiPayloadPkg/Library/PayloadEntryHobLib/HobLib.inf
@@ -304,14 +309,11 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom|FALSE
[PcdsFixedAtBuild]
- gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x10000
+ # UEFI spec: Minimal value is 0x8000!
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8800
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize|0x8000
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000
- #
- # Make VariableRuntimeDxe work at emulated non-volatile variable mode.
- #
- gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
-
gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress|0x0
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE
gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|TRUE
@@ -385,10 +387,11 @@
!endif
gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved|0
- gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0
gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|2
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE
## This PCD defines the video horizontal resolution.
# This PCD could be set to 0 then video resolution could be at highest resolution.
@@ -466,6 +469,7 @@
!endif
PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
!if $(EMU_VARIABLE_ENABLE) == TRUE
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
!endif
#
@@ -567,6 +571,11 @@
RngLib|UefiPayloadPkg/Library/BaseRngLib/BaseRngLib.inf
}
+ #
+ # SMMSTORE
+ #
+ UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.inf
+
#------------------------------
# Build the shell
#------------------------------
diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayloadPkg.fdf
index 75a19839e5..0d0ec5c738 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.fdf
+++ b/UefiPayloadPkg/UefiPayloadPkg.fdf
@@ -115,6 +115,7 @@ INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
!if $(EMU_VARIABLE_ENABLE) == TRUE
+INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
!endif
@@ -128,6 +129,7 @@ INF UefiPayloadPkg/BlSupportDxe/BlSupportDxe.inf
INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
INF MdeModulePkg/Logo/LogoDxe.inf
+INF UefiPayloadPkg/BlSMMStoreDxe/BlSMMStoreDxe.inf
FILE FREEFORM = PCD(gEfiMdeModulePkgTokenSpaceGuid.PcdLogoFile) {
SECTION RAW = MdeModulePkg/Logo/Logo.bmp
@@ -226,6 +228,19 @@ INF ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf
INF ShellPkg/Application/Shell/Shell.inf
!endif
+# Constraints:
+# PcdFlashNvStorageVariableSize <= FtwMaxBlockSize
+# GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))
+DEFINE BLOCK_SIZE = 0x10000
+
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase = 0
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize = $(BLOCK_SIZE)
+
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase = gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(BLOCK_SIZE)
+
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase = gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(BLOCK_SIZE)
################################################################################
#