/** @file
MM driver source for several Serial Flash devices
which are compliant with the Intel(R) Serial Flash Interface Compatibility Specification.
Copyright (c) 2017, Intel Corporation. All rights reserved.
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SpiFvbServiceCommon.h"
#include
#include
#include
/**
The function installs EFI_FIRMWARE_VOLUME_BLOCK protocol
for each FV in the system.
@param[in] FvbInstance The pointer to a FW volume instance structure,
which contains the information about one FV.
@retval VOID
**/
VOID
InstallFvbProtocol (
IN EFI_FVB_INSTANCE *FvbInstance
)
{
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
EFI_STATUS Status;
EFI_HANDLE FvbHandle;
ASSERT (FvbInstance != NULL);
if (FvbInstance == NULL) {
return;
}
CopyMem (&FvbInstance->FvbProtocol, &mFvbProtocolTemplate, sizeof (EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL));
FvHeader = &FvbInstance->FvHeader;
if (FvHeader == NULL) {
return;
}
//
// Set up the devicepath
//
DEBUG ((DEBUG_INFO, "FwBlockService.c: Setting up DevicePath for 0x%lx:\n", FvbInstance->FvBase));
if (FvHeader->ExtHeaderOffset == 0) {
//
// FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
//
FvbInstance->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
if (FvbInstance->DevicePath == NULL) {
DEBUG ((DEBUG_INFO, "SpiFvbServiceSmm.c: Memory allocation for MEMMAP_DEVICE_PATH failed\n"));
return;
}
((FV_MEMMAP_DEVICE_PATH *) FvbInstance->DevicePath)->MemMapDevPath.StartingAddress = FvbInstance->FvBase;
((FV_MEMMAP_DEVICE_PATH *) FvbInstance->DevicePath)->MemMapDevPath.EndingAddress = FvbInstance->FvBase + FvHeader->FvLength - 1;
} else {
FvbInstance->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
if (FvbInstance->DevicePath == NULL) {
DEBUG ((DEBUG_INFO, "SpiFvbServiceSmm.c: Memory allocation for FV_PIWG_DEVICE_PATH failed\n"));
return;
}
CopyGuid (
&((FV_PIWG_DEVICE_PATH *)FvbInstance->DevicePath)->FvDevPath.FvName,
(GUID *)(UINTN)(FvbInstance->FvBase + FvHeader->ExtHeaderOffset)
);
}
//
// LocateDevicePath fails so install a new interface and device path
//
FvbHandle = NULL;
Status = gMmst->MmInstallProtocolInterface (
&FvbHandle,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
EFI_NATIVE_INTERFACE,
&(FvbInstance->FvbProtocol)
);
ASSERT_EFI_ERROR (Status);
Status = gMmst->MmInstallProtocolInterface (
&FvbHandle,
&gEfiDevicePathProtocolGuid,
EFI_NATIVE_INTERFACE,
&(FvbInstance->DevicePath)
);
ASSERT_EFI_ERROR (Status);
}
/**
The function does the necessary initialization work for
Firmware Volume Block Driver.
**/
VOID
FvbInitialize (
VOID
)
{
EFI_FVB_INSTANCE *FvbInstance;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
EFI_PHYSICAL_ADDRESS BaseAddress;
EFI_STATUS Status;
UINTN BufferSize;
UINTN Idx;
UINT32 MaxLbaSize;
UINT32 BytesWritten;
UINTN BytesErased;
mPlatformFvBaseAddress[0].FvBase = PcdGet32(PcdFlashNvStorageVariableBase);
mPlatformFvBaseAddress[0].FvSize = PcdGet32(PcdFlashNvStorageVariableSize);
mPlatformFvBaseAddress[1].FvBase = PcdGet32(PcdFlashFvMicrocodeBase);
mPlatformFvBaseAddress[1].FvSize = PcdGet32(PcdFlashFvMicrocodeSize);
mPlatformDefaultBaseAddress[0].FvBase = PcdGet32(PcdFlashNvStorageVariableBase);
mPlatformDefaultBaseAddress[0].FvSize = PcdGet32(PcdFlashNvStorageVariableSize);
mPlatformDefaultBaseAddress[1].FvBase = PcdGet32(PcdFlashFvMicrocodeBase);
mPlatformDefaultBaseAddress[1].FvSize = PcdGet32(PcdFlashFvMicrocodeSize);
//
// We will only continue with FVB installation if the
// SPI is the active BIOS state
//
{
//
// Make sure all FVB are valid and/or fix if possible
//
for (Idx = 0;; Idx++) {
if (mPlatformFvBaseAddress[Idx].FvSize == 0 && mPlatformFvBaseAddress[Idx].FvBase == 0) {
break;
}
BaseAddress = mPlatformFvBaseAddress[Idx].FvBase;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
if (!IsFvHeaderValid (BaseAddress, FvHeader)) {
BytesWritten = 0;
BytesErased = 0;
DEBUG ((DEBUG_ERROR, "ERROR - The FV in 0x%x is invalid!\n", FvHeader));
Status = GetFvbInfo (BaseAddress, &FvHeader);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "ERROR - Can't recovery FV header at 0x%x. GetFvbInfo Status %r\n", BaseAddress, Status));
continue;
}
DEBUG ((DEBUG_INFO, "Rewriting FV header at 0x%X with static data\n", BaseAddress));
//
// Spi erase
//
BytesErased = (UINTN) FvHeader->BlockMap->Length;
Status = SpiFlashBlockErase( (UINTN) BaseAddress, &BytesErased);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "ERROR - SpiFlashBlockErase Error %r\n", Status));
continue;
}
if (BytesErased != FvHeader->BlockMap->Length) {
DEBUG ((DEBUG_WARN, "ERROR - BytesErased != FvHeader->BlockMap->Length\n"));
DEBUG ((DEBUG_INFO, " BytesErased = 0x%X\n Length = 0x%X\n", BytesErased, FvHeader->BlockMap->Length));
continue;
}
BytesWritten = FvHeader->HeaderLength;
Status = SpiFlashWrite ((UINTN)BaseAddress, &BytesWritten, (UINT8*)FvHeader);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "ERROR - SpiFlashWrite Error %r\n", Status));
continue;
}
if (BytesWritten != FvHeader->HeaderLength) {
DEBUG ((DEBUG_WARN, "ERROR - BytesWritten != HeaderLength\n"));
DEBUG ((DEBUG_INFO, " BytesWritten = 0x%X\n HeaderLength = 0x%X\n", BytesWritten, FvHeader->HeaderLength));
continue;
}
Status = SpiFlashLock ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "ERROR - SpiFlashLock Error %r\n", Status));
continue;
}
DEBUG ((DEBUG_INFO, "FV Header @ 0x%X restored with static data\n", BaseAddress));
//
// Clear cache for this range.
//
WriteBackInvalidateDataCacheRange ( (VOID *) (UINTN) BaseAddress, FvHeader->BlockMap->Length);
}
}
//
// Calculate the total size for all firmware volume block instances
//
BufferSize = 0;
for (Idx = 0; ; Idx++) {
if (mPlatformFvBaseAddress[Idx].FvSize == 0 && mPlatformFvBaseAddress[Idx].FvBase == 0) {
break;
}
BaseAddress = mPlatformFvBaseAddress[Idx].FvBase;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
if (!IsFvHeaderValid (BaseAddress, FvHeader)) {
DEBUG ((DEBUG_WARN, "ERROR - The FV in 0x%x is invalid!\n", FvHeader));
continue;
}
BufferSize += (FvHeader->HeaderLength +
sizeof (EFI_FVB_INSTANCE) -
sizeof (EFI_FIRMWARE_VOLUME_HEADER)
);
}
mFvbModuleGlobal.FvbInstance = (EFI_FVB_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
if (mFvbModuleGlobal.FvbInstance == NULL) {
ASSERT (FALSE);
return;
}
MaxLbaSize = 0;
FvbInstance = mFvbModuleGlobal.FvbInstance;
mFvbModuleGlobal.NumFv = 0;
for (Idx = 0; ; Idx++) {
if (mPlatformFvBaseAddress[Idx].FvSize == 0 && mPlatformFvBaseAddress[Idx].FvBase == 0) {
break;
}
BaseAddress = mPlatformFvBaseAddress[Idx].FvBase;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
if (!IsFvHeaderValid (BaseAddress, FvHeader)) {
DEBUG ((DEBUG_WARN, "ERROR - The FV in 0x%x is invalid!\n", FvHeader));
continue;
}
FvbInstance->Signature = FVB_INSTANCE_SIGNATURE;
CopyMem (&(FvbInstance->FvHeader), FvHeader, FvHeader->HeaderLength);
FvHeader = &(FvbInstance->FvHeader);
FvbInstance->FvBase = (UINTN)BaseAddress;
//
// Process the block map for each FV
//
FvbInstance->NumOfBlocks = 0;
for (PtrBlockMapEntry = FvHeader->BlockMap;
PtrBlockMapEntry->NumBlocks != 0;
PtrBlockMapEntry++) {
//
// Get the maximum size of a block.
//
if (MaxLbaSize < PtrBlockMapEntry->Length) {
MaxLbaSize = PtrBlockMapEntry->Length;
}
FvbInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
}
//
// Add a FVB Protocol Instance
//
InstallFvbProtocol (FvbInstance);
mFvbModuleGlobal.NumFv++;
//
// Move on to the next FvbInstance
//
FvbInstance = (EFI_FVB_INSTANCE *) ((UINTN)((UINT8 *)FvbInstance) +
FvHeader->HeaderLength +
(sizeof (EFI_FVB_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
}
}
}