2022-10-24 16:41:43 +02:00
|
|
|
/** @file NorFlashDxe.c
|
|
|
|
|
|
|
|
Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
|
|
|
|
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <Library/BaseMemoryLib.h>
|
|
|
|
#include <Library/DxeServicesTableLib.h>
|
|
|
|
#include <Library/HobLib.h>
|
|
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include <Library/PcdLib.h>
|
|
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Library/UefiLib.h>
|
|
|
|
|
|
|
|
#include "VirtNorFlash.h"
|
|
|
|
|
|
|
|
STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Global variable declarations
|
|
|
|
//
|
|
|
|
NOR_FLASH_INSTANCE **mNorFlashInstances;
|
|
|
|
UINT32 mNorFlashDeviceCount;
|
|
|
|
UINTN mFlashNvStorageVariableBase;
|
|
|
|
EFI_EVENT mFvbVirtualAddrChangeEvent;
|
|
|
|
|
|
|
|
NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
|
|
|
|
NOR_FLASH_SIGNATURE, // Signature
|
|
|
|
NULL, // Handle ... NEED TO BE FILLED
|
|
|
|
|
|
|
|
0, // DeviceBaseAddress ... NEED TO BE FILLED
|
|
|
|
0, // RegionBaseAddress ... NEED TO BE FILLED
|
|
|
|
0, // Size ... NEED TO BE FILLED
|
|
|
|
0, // StartLba
|
2022-10-24 17:12:08 +02:00
|
|
|
0, // LastBlock
|
|
|
|
0, // BlockSize
|
2022-10-24 16:41:43 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
FvbGetAttributes, // GetAttributes
|
|
|
|
FvbSetAttributes, // SetAttributes
|
|
|
|
FvbGetPhysicalAddress, // GetPhysicalAddress
|
|
|
|
FvbGetBlockSize, // GetBlockSize
|
|
|
|
FvbRead, // Read
|
|
|
|
FvbWrite, // Write
|
|
|
|
FvbEraseBlocks, // EraseBlocks
|
|
|
|
NULL, // ParentHandle
|
|
|
|
}, // FvbProtoccol;
|
|
|
|
NULL, // ShadowBuffer
|
|
|
|
{
|
|
|
|
{
|
|
|
|
{
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
NorFlashCreateInstance (
|
|
|
|
IN UINTN NorFlashDeviceBase,
|
|
|
|
IN UINTN NorFlashRegionBase,
|
|
|
|
IN UINTN NorFlashSize,
|
|
|
|
IN UINT32 Index,
|
|
|
|
IN UINT32 BlockSize,
|
|
|
|
IN BOOLEAN SupportFvb,
|
|
|
|
OUT NOR_FLASH_INSTANCE **NorFlashInstance
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
NOR_FLASH_INSTANCE *Instance;
|
|
|
|
|
|
|
|
ASSERT (NorFlashInstance != NULL);
|
|
|
|
|
|
|
|
Instance = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INSTANCE), &mNorFlashInstanceTemplate);
|
|
|
|
if (Instance == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
Instance->DeviceBaseAddress = NorFlashDeviceBase;
|
|
|
|
Instance->RegionBaseAddress = NorFlashRegionBase;
|
|
|
|
Instance->Size = NorFlashSize;
|
2022-10-24 17:12:08 +02:00
|
|
|
Instance->BlockSize = BlockSize;
|
|
|
|
Instance->LastBlock = (NorFlashSize / BlockSize) - 1;
|
2022-10-24 16:41:43 +02:00
|
|
|
|
|
|
|
CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
|
|
|
|
Instance->DevicePath.Index = (UINT8)Index;
|
|
|
|
|
|
|
|
Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);
|
|
|
|
if (Instance->ShadowBuffer == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SupportFvb) {
|
|
|
|
NorFlashFvbInitialize (Instance);
|
|
|
|
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&Instance->Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
&Instance->DevicePath,
|
|
|
|
&gEfiFirmwareVolumeBlockProtocolGuid,
|
|
|
|
&Instance->FvbProtocol,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
FreePool (Instance);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&Instance->Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
&Instance->DevicePath,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
FreePool (Instance);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*NorFlashInstance = Instance;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function unlock and erase an entire NOR Flash block.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
NorFlashUnlockAndEraseSingleBlock (
|
|
|
|
IN NOR_FLASH_INSTANCE *Instance,
|
|
|
|
IN UINTN BlockAddress
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN Index;
|
|
|
|
EFI_TPL OriginalTPL;
|
|
|
|
|
|
|
|
if (!EfiAtRuntime ()) {
|
|
|
|
// Raise TPL to TPL_HIGH to stop anyone from interrupting us.
|
|
|
|
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
|
|
|
} else {
|
|
|
|
// This initialization is only to prevent the compiler to complain about the
|
|
|
|
// use of uninitialized variables
|
|
|
|
OriginalTPL = TPL_HIGH_LEVEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Index = 0;
|
|
|
|
// The block erase might fail a first time (SW bug ?). Retry it ...
|
|
|
|
do {
|
|
|
|
// Unlock the block if we have to
|
|
|
|
Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
|
|
|
|
Index++;
|
|
|
|
} while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
|
|
|
|
|
|
|
|
if (Index == NOR_FLASH_ERASE_RETRY) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!EfiAtRuntime ()) {
|
|
|
|
// Interruptions can resume.
|
|
|
|
gBS->RestoreTPL (OriginalTPL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
NorFlashWriteFullBlock (
|
|
|
|
IN NOR_FLASH_INSTANCE *Instance,
|
|
|
|
IN EFI_LBA Lba,
|
|
|
|
IN UINT32 *DataBuffer,
|
|
|
|
IN UINT32 BlockSizeInWords
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN WordAddress;
|
|
|
|
UINT32 WordIndex;
|
|
|
|
UINTN BufferIndex;
|
|
|
|
UINTN BlockAddress;
|
|
|
|
UINTN BuffersInBlock;
|
|
|
|
UINTN RemainingWords;
|
|
|
|
EFI_TPL OriginalTPL;
|
|
|
|
UINTN Cnt;
|
|
|
|
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
|
|
|
|
// Get the physical address of the block
|
|
|
|
BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);
|
|
|
|
|
|
|
|
// Start writing from the first address at the start of the block
|
|
|
|
WordAddress = BlockAddress;
|
|
|
|
|
|
|
|
if (!EfiAtRuntime ()) {
|
|
|
|
// Raise TPL to TPL_HIGH to stop anyone from interrupting us.
|
|
|
|
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
|
|
|
} else {
|
|
|
|
// This initialization is only to prevent the compiler to complain about the
|
|
|
|
// use of uninitialized variables
|
|
|
|
OriginalTPL = TPL_HIGH_LEVEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
// To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
|
|
|
|
|
|
|
|
// Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
|
|
|
|
if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
|
|
|
|
// First, break the entire block into buffer-sized chunks.
|
|
|
|
BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
|
|
|
|
|
|
|
|
// Then feed each buffer chunk to the NOR Flash
|
|
|
|
// If a buffer does not contain any data, don't write it.
|
|
|
|
for (BufferIndex = 0;
|
|
|
|
BufferIndex < BuffersInBlock;
|
|
|
|
BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// Check the buffer to see if it contains any data (not set all 1s).
|
|
|
|
for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
|
|
|
|
if (~DataBuffer[Cnt] != 0 ) {
|
|
|
|
// Some data found, write the buffer.
|
|
|
|
Status = NorFlashWriteBuffer (
|
|
|
|
Instance,
|
|
|
|
WordAddress,
|
|
|
|
P30_MAX_BUFFER_SIZE_IN_BYTES,
|
|
|
|
DataBuffer
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, finish off any remaining words that are less than the maximum size of the buffer
|
|
|
|
RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
|
|
|
|
|
|
|
|
if (RemainingWords != 0) {
|
|
|
|
Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// For now, use the single word programming algorithm
|
|
|
|
// It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
|
|
|
|
// i.e. which ends in the range 0x......01 - 0x......7F.
|
|
|
|
for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
|
|
|
|
Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EXIT:
|
2022-10-24 17:34:09 +02:00
|
|
|
// Put device back into Read Array mode
|
|
|
|
SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
|
|
|
|
|
2022-10-24 16:41:43 +02:00
|
|
|
if (!EfiAtRuntime ()) {
|
|
|
|
// Interruptions can resume.
|
|
|
|
gBS->RestoreTPL (OriginalTPL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
NorFlashInitialise (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 Index;
|
|
|
|
VIRT_NOR_FLASH_DESCRIPTION *NorFlashDevices;
|
|
|
|
BOOLEAN ContainVariableStorage;
|
|
|
|
|
|
|
|
Status = VirtNorFlashPlatformInitialization ();
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = VirtNorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash devices\n"));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
mNorFlashInstances = AllocateRuntimePool (sizeof (NOR_FLASH_INSTANCE *) * mNorFlashDeviceCount);
|
|
|
|
|
|
|
|
for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
|
|
|
|
// Check if this NOR Flash device contain the variable storage region
|
|
|
|
|
|
|
|
if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {
|
|
|
|
ContainVariableStorage =
|
|
|
|
(NorFlashDevices[Index].RegionBaseAddress <= PcdGet64 (PcdFlashNvStorageVariableBase64)) &&
|
|
|
|
(PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize) <=
|
|
|
|
NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
|
|
|
|
} else {
|
|
|
|
ContainVariableStorage =
|
|
|
|
(NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) &&
|
|
|
|
(PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <=
|
|
|
|
NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = NorFlashCreateInstance (
|
|
|
|
NorFlashDevices[Index].DeviceBaseAddress,
|
|
|
|
NorFlashDevices[Index].RegionBaseAddress,
|
|
|
|
NorFlashDevices[Index].Size,
|
|
|
|
Index,
|
|
|
|
NorFlashDevices[Index].BlockSize,
|
|
|
|
ContainVariableStorage,
|
|
|
|
&mNorFlashInstances[Index]
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n", Index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register for the virtual address change event
|
|
|
|
//
|
|
|
|
Status = gBS->CreateEventEx (
|
|
|
|
EVT_NOTIFY_SIGNAL,
|
|
|
|
TPL_NOTIFY,
|
|
|
|
NorFlashVirtualNotifyEvent,
|
|
|
|
NULL,
|
|
|
|
&gEfiEventVirtualAddressChangeGuid,
|
|
|
|
&mNorFlashVirtualAddrChangeEvent
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
NorFlashFvbInitialize (
|
|
|
|
IN NOR_FLASH_INSTANCE *Instance
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 FvbNumLba;
|
|
|
|
EFI_BOOT_MODE BootMode;
|
|
|
|
UINTN RuntimeMmioRegionSize;
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_BLKIO, "NorFlashFvbInitialize\n"));
|
|
|
|
ASSERT ((Instance != NULL));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME
|
|
|
|
//
|
|
|
|
|
|
|
|
// Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory;
|
|
|
|
// even if we only use the small block region at the top of the NOR Flash.
|
|
|
|
// The reason is when the NOR Flash memory is set into program mode, the command
|
|
|
|
// is written as the base of the flash region (ie: Instance->DeviceBaseAddress)
|
|
|
|
RuntimeMmioRegionSize = (Instance->RegionBaseAddress - Instance->DeviceBaseAddress) + Instance->Size;
|
|
|
|
|
|
|
|
Status = gDS->AddMemorySpace (
|
|
|
|
EfiGcdMemoryTypeMemoryMappedIo,
|
|
|
|
Instance->DeviceBaseAddress,
|
|
|
|
RuntimeMmioRegionSize,
|
OvmfPkg/VirtNorFlashDxe: use EFI_MEMORY_WC and drop AlignedCopyMem()
NOR flash emulation under KVM involves switching between two modes,
where array mode is backed by a read-only memslot, and programming mode
is fully emulated, i.e., the memory region is not backed by anything,
and the faulting accesses are forwarded to the VMM by the hypervisor,
which translates them into NOR flash programming commands.
Normally, we are limited to the use of device attributes when mapping
such regions, given that the programming mode has MMIO semantics.
However, when running under KVM, the chosen memory attributes only take
effect when in array mode, since no memory mapping exists otherwise.
This means we can tune the memory mapping so it behaves a bit more like
a ROM, by switching to EFI_MEMORY_WC attributes. This means we no longer
need a special CopyMem() implementation that avoids unaligned accesses
at all cost.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
2022-10-24 18:16:18 +02:00
|
|
|
EFI_MEMORY_WC | EFI_MEMORY_RUNTIME
|
2022-10-24 16:41:43 +02:00
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
Status = gDS->SetMemorySpaceAttributes (
|
|
|
|
Instance->DeviceBaseAddress,
|
|
|
|
RuntimeMmioRegionSize,
|
OvmfPkg/VirtNorFlashDxe: use EFI_MEMORY_WC and drop AlignedCopyMem()
NOR flash emulation under KVM involves switching between two modes,
where array mode is backed by a read-only memslot, and programming mode
is fully emulated, i.e., the memory region is not backed by anything,
and the faulting accesses are forwarded to the VMM by the hypervisor,
which translates them into NOR flash programming commands.
Normally, we are limited to the use of device attributes when mapping
such regions, given that the programming mode has MMIO semantics.
However, when running under KVM, the chosen memory attributes only take
effect when in array mode, since no memory mapping exists otherwise.
This means we can tune the memory mapping so it behaves a bit more like
a ROM, by switching to EFI_MEMORY_WC attributes. This means we no longer
need a special CopyMem() implementation that avoids unaligned accesses
at all cost.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
2022-10-24 18:16:18 +02:00
|
|
|
EFI_MEMORY_WC | EFI_MEMORY_RUNTIME
|
2022-10-24 16:41:43 +02:00
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
mFlashNvStorageVariableBase = (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) ?
|
|
|
|
PcdGet64 (PcdFlashNvStorageVariableBase64) : PcdGet32 (PcdFlashNvStorageVariableBase);
|
|
|
|
|
|
|
|
// Set the index of the first LBA for the FVB
|
2022-10-24 17:12:08 +02:00
|
|
|
Instance->StartLba = (mFlashNvStorageVariableBase - Instance->RegionBaseAddress) / Instance->BlockSize;
|
2022-10-24 16:41:43 +02:00
|
|
|
|
|
|
|
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
|
2022-10-24 17:12:08 +02:00
|
|
|
FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / Instance->BlockSize;
|
2022-10-24 16:41:43 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
}
|