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) ################################################################################ #