/** @file SmmStoreFvbRuntime.c
Copyright (c) 2022, 9elements GmbH
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include "SmmStoreFvbRuntime.h"
STATIC EFI_EVENT mSmmStoreVirtualAddrChangeEvent;
//
// Global variable declarations
//
SMMSTORE_INSTANCE *mSmmStoreInstance;
SMMSTORE_INSTANCE mSmmStoreInstanceTemplate = {
SMMSTORE_SIGNATURE, // Signature
NULL, // Handle ... NEED TO BE FILLED
{
FvbGetAttributes, // GetAttributes
FvbSetAttributes, // SetAttributes
FvbGetPhysicalAddress, // GetPhysicalAddress
FvbGetBlockSize, // GetBlockSize
FvbRead, // Read
FvbWrite, // Write
FvbEraseBlocks, // EraseBlocks
NULL, // ParentHandle
}, // FvbProtoccol
0, // BlockSize ... NEED TO BE FILLED
0, // LastBlock ... NEED TO BE FILLED
0, // MmioAddress ... NEED TO BE FILLED
{
{
{
HARDWARE_DEVICE_PATH,
HW_MEMMAP_DP,
{
(UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
(UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
}
},
EfiMemoryMappedIO,
(EFI_PHYSICAL_ADDRESS)0, // NEED TO BE FILLED
(EFI_PHYSICAL_ADDRESS)0, // NEED TO BE FILLED
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
END_DEVICE_PATH_LENGTH,
0
}
}
} // DevicePath
};
/**
Initialize the SmmStore instance.
@param[in] FvBase The physical MMIO base address of the FV containing
the variable store.
@param[in] NumberofBlocks Number of blocks within the FV.
@param[in] BlockSize The size in bytes of one block within the FV.
@param[in, out] Instance The SmmStore instace to initialize
**/
STATIC
EFI_STATUS
SmmStoreInitInstance (
IN EFI_PHYSICAL_ADDRESS FvBase,
IN UINTN NumberofBlocks,
IN UINTN BlockSize,
IN OUT SMMSTORE_INSTANCE *Instance
)
{
EFI_STATUS Status;
FV_MEMMAP_DEVICE_PATH *FvDevicePath;
ASSERT (Instance != NULL);
Instance->BlockSize = BlockSize;
Instance->LastBlock = NumberofBlocks - 1;
Instance->MmioAddress = FvBase;
FvDevicePath = &Instance->DevicePath;
FvDevicePath->MemMapDevPath.StartingAddress = FvBase;
FvDevicePath->MemMapDevPath.EndingAddress = FvBase + BlockSize * NumberofBlocks - 1;
Status = FvbInitialize (Instance);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->InstallMultipleProtocolInterfaces (
&Instance->Handle,
&gEfiDevicePathProtocolGuid,
&Instance->DevicePath,
&gEfiFirmwareVolumeBlockProtocolGuid,
&Instance->FvbProtocol,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_INFO, "%a: Created a new instance\n", __FUNCTION__));
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
**/
STATIC
VOID
EFIAPI
SmmStoreVirtualNotifyEvent (
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);
EfiConvertPointer (0x0, (VOID **)&mSmmStoreInstance->MmioAddress);
EfiConvertPointer (0x0, (VOID **)&mSmmStoreInstance);
return;
}
/**
The user Entry Point for module SmmStoreFvbRuntimeDxe. The user code starts with this function.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
SmmStoreInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS MmioAddress;
UINTN BlockSize;
UINTN BlockCount;
UINT32 NvStorageBase;
UINT32 NvStorageSize;
UINT32 NvVariableSize;
UINT32 FtwWorkingSize;
UINT32 FtwSpareSize;
Status = SmmStoreLibInitialize ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to initialize SmmStoreLib\n", __FUNCTION__));
return Status;
}
Status = SmmStoreLibGetMmioAddress (&MmioAddress);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to get SmmStore MMIO address\n", __FUNCTION__));
SmmStoreLibDeinitialize ();
return Status;
}
Status = SmmStoreLibGetNumBlocks (&BlockCount);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to get SmmStore No. blocks\n", __FUNCTION__));
SmmStoreLibDeinitialize ();
return Status;
}
Status = SmmStoreLibGetBlockSize (&BlockSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to get SmmStore block size\n", __FUNCTION__));
SmmStoreLibDeinitialize ();
return Status;
}
NvStorageSize = BlockCount * BlockSize;
NvStorageBase = MmioAddress;
FtwSpareSize = (BlockCount / 2) * BlockSize;
FtwWorkingSize = BlockSize;
NvVariableSize = NvStorageSize - FtwSpareSize - FtwWorkingSize;
DEBUG ((DEBUG_INFO, "NvStorageBase:0x%x, NvStorageSize:0x%x\n", NvStorageBase, NvStorageSize));
if (NvVariableSize >= 0x80000000) {
SmmStoreLibDeinitialize ();
return EFI_INVALID_PARAMETER;
}
Status = PcdSet32S (PcdFlashNvStorageVariableSize, NvVariableSize);
ASSERT_EFI_ERROR (Status);
Status = PcdSet32S (PcdFlashNvStorageVariableBase, NvStorageBase);
ASSERT_EFI_ERROR (Status);
Status = PcdSet64S (PcdFlashNvStorageVariableBase64, NvStorageBase);
ASSERT_EFI_ERROR (Status);
Status = PcdSet32S (PcdFlashNvStorageFtwWorkingSize, FtwWorkingSize);
ASSERT_EFI_ERROR (Status);
Status = PcdSet32S (PcdFlashNvStorageFtwWorkingBase, NvStorageBase + NvVariableSize);
ASSERT_EFI_ERROR (Status);
Status = PcdSet64S (PcdFlashNvStorageFtwWorkingBase64, NvStorageBase + NvVariableSize);
ASSERT_EFI_ERROR (Status);
Status = PcdSet32S (PcdFlashNvStorageFtwSpareSize, FtwSpareSize);
ASSERT_EFI_ERROR (Status);
Status = PcdSet32S (PcdFlashNvStorageFtwSpareBase, NvStorageBase + NvVariableSize + FtwWorkingSize);
ASSERT_EFI_ERROR (Status);
Status = PcdSet64S (PcdFlashNvStorageFtwSpareBase64, NvStorageBase + NvVariableSize + FtwWorkingSize);
ASSERT_EFI_ERROR (Status);
mSmmStoreInstance = AllocateRuntimeCopyPool (sizeof (SMMSTORE_INSTANCE), &mSmmStoreInstanceTemplate);
if (mSmmStoreInstance == NULL) {
SmmStoreLibDeinitialize ();
DEBUG ((DEBUG_ERROR, "%a: Out of resources\n", __FUNCTION__));
return EFI_OUT_OF_RESOURCES;
}
Status = SmmStoreInitInstance (
MmioAddress,
BlockCount,
BlockSize,
mSmmStoreInstance
);
if (EFI_ERROR (Status)) {
DEBUG (
(
DEBUG_ERROR,
"%a: Fail to create instance for SmmStore\n",
__FUNCTION__
)
);
FreePool (mSmmStoreInstance);
SmmStoreLibDeinitialize ();
return Status;
}
//
// Register for the virtual address change event
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
SmmStoreVirtualNotifyEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mSmmStoreVirtualAddrChangeEvent
);
ASSERT_EFI_ERROR (Status);
return Status;
}