mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-27 23:54:02 +02:00
Update Variable driver to depend on full version FaultTolerantWrite protocol, and remove the lite version FaultTolerantWrite Dxe Driver. New full version FaultTolerantWriteDxe driver is added in MdeModulePkg.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7788 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
85e923a528
commit
88a5561c66
@ -1,73 +0,0 @@
|
||||
/** @file
|
||||
Fault tolerant write lite protocol defines only one interface to write
|
||||
the buffer to the fault tolerant storage.
|
||||
|
||||
Copyright (c) 2006 - 2008, Intel Corporation. <BR>
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __FW_FAULT_TOLERANT_WRITE_LITE_PROTOCOL_H__
|
||||
#define __FW_FAULT_TOLERANT_WRITE_LITE_PROTOCOL_H__
|
||||
|
||||
#define EFI_FTW_LITE_PROTOCOL_GUID \
|
||||
{ 0x3f557189, 0x8dae, 0x45ae, {0xa0, 0xb3, 0x2b, 0x99, 0xca, 0x7a, 0xa7, 0xa0 } }
|
||||
|
||||
//
|
||||
// Forward reference for pure ANSI compatability
|
||||
//
|
||||
typedef struct _EFI_FTW_LITE_PROTOCOL EFI_FTW_LITE_PROTOCOL;
|
||||
|
||||
//
|
||||
// Protocol API definitions
|
||||
//
|
||||
/**
|
||||
Starts a target block update. This records information about the write
|
||||
in fault tolerant storage will complete the write in a recoverable
|
||||
manner, ensuring at all times that either the original contents or
|
||||
the modified contents are available.
|
||||
|
||||
@param This The pointer to this protocol instance.
|
||||
@param FvbHandle The handle of FVB protocol that provides services
|
||||
for reading, writing, and erasing the target block.
|
||||
@param Lba The logical block address of the target block.
|
||||
@param Offset The offset within the target block to place the data.
|
||||
@param NumBytes The number of bytes to write to the target block.
|
||||
@param Buffer The data to write.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
@retval EFI_BAD_BUFFER_SIZE The input data can't fit within the FTW range.
|
||||
The write buffer is too large to be supported.
|
||||
@retval EFI_ACCESS_DENIED No writes have been allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
|
||||
@retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI * EFI_FTW_LITE_WRITE)(
|
||||
IN EFI_FTW_LITE_PROTOCOL *This,
|
||||
IN EFI_HANDLE FvbHandle,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN Offset,
|
||||
IN UINTN *NumBytes,
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
//
|
||||
// Protocol declaration
|
||||
//
|
||||
struct _EFI_FTW_LITE_PROTOCOL {
|
||||
EFI_FTW_LITE_WRITE Write;
|
||||
};
|
||||
|
||||
extern EFI_GUID gEfiFaultTolerantWriteLiteProtocolGuid;
|
||||
|
||||
#endif
|
@ -173,11 +173,6 @@
|
||||
## This protocol defines the generic memory test interfaces in Dxe phase.
|
||||
## Include/Protocol/GenericMemoryTest.h
|
||||
gEfiGenericMemTestProtocolGuid = { 0x309DE7F1, 0x7F5E, 0x4ACE, { 0xB4, 0x9C, 0x53, 0x1B, 0xE5, 0xAA, 0x95, 0xEF }}
|
||||
|
||||
## Fault tolerant write lite protocol defines only one interface to write
|
||||
# the buffer to the fault tolerant storage.
|
||||
## Include/Protocol/FaultTolerantWriteLite.h
|
||||
gEfiFaultTolerantWriteLiteProtocolGuid = { 0x3F557189, 0x8DAE, 0x45AE, { 0xA0, 0xB3, 0x2B, 0x99, 0xCA, 0x7A, 0xA7, 0xA0 }}
|
||||
|
||||
## This protocol provides the interfaces to Get/Set the current video mode for GOP/UGA screen
|
||||
## Include/Protocol/ConsoleControl.h
|
||||
|
@ -1,922 +0,0 @@
|
||||
/** @file
|
||||
|
||||
This is a simple fault tolerant write driver.
|
||||
|
||||
This boot service protocol only provides fault tolerant write capability for
|
||||
block devices. The protocol has internal non-volatile intermediate storage
|
||||
of the data and private information. It should be able to recover
|
||||
automatically from a critical fault, such as power failure.
|
||||
|
||||
The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
|
||||
This work space is a memory copy of the work space on the Working Block,
|
||||
the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
|
||||
|
||||
The work space stores each write record as EFI_FTW_LITE_RECORD structure.
|
||||
The spare block stores the write buffer before write to the target block.
|
||||
|
||||
The write record has three states to specify the different phase of write operation.
|
||||
1) WRITE_ALLOCATED is that the record is allocated in write space.
|
||||
The information of write operation is stored in write record structure.
|
||||
2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
|
||||
3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
|
||||
|
||||
This driver operates the data as the whole size of spare block.
|
||||
It first read the SpareAreaLength data from the target block into the spare memory buffer.
|
||||
Then copy the write buffer data into the spare memory buffer.
|
||||
Then write the spare memory buffer into the spare block.
|
||||
Final copy the data from the spare block to the target block.
|
||||
|
||||
To make this drive work well, the following conditions must be satisfied:
|
||||
1. The write NumBytes data must be fit within Spare area.
|
||||
Offset + NumBytes <= SpareAreaLength
|
||||
2. The whole flash range has the same block size.
|
||||
3. Working block is an area which contains working space in its last block and has the same size as spare block.
|
||||
4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
|
||||
5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
|
||||
6. Any write data area (SpareAreaLength Area) which the data will be written into must be
|
||||
in the single one Firmware Volume Block range which FVB protocol is produced on.
|
||||
7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
|
||||
The spare area must be enough large to store the write data before write them into the target range.
|
||||
If one of them is not satisfied, FtwLiteWrite may fail.
|
||||
Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
|
||||
|
||||
Copyright (c) 2006 - 2009, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "FtwLite.h"
|
||||
|
||||
/**
|
||||
Starts a target block update. This function will record data about write
|
||||
in fault tolerant storage and will complete the write in a recoverable
|
||||
manner, ensuring at all times that either the original contents or
|
||||
the modified contents are available.
|
||||
|
||||
@param This The pointer to this protocol instance.
|
||||
@param FvbHandle The handle of FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
@param Lba The logical block address of the target block.
|
||||
@param Offset The offset within the target block to place the data.
|
||||
@param NumBytes The number of bytes to write to the target block.
|
||||
@param Buffer The data to write.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
@retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
|
||||
Offset + *NumBytes > SpareAreaLength.
|
||||
@retval EFI_ACCESS_DENIED No writes have been allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
|
||||
@retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
FtwLiteWrite (
|
||||
IN EFI_FTW_LITE_PROTOCOL *This,
|
||||
IN EFI_HANDLE FvbHandle,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN Offset,
|
||||
IN OUT UINTN *NumBytes,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice;
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
|
||||
EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
|
||||
UINTN MyLength;
|
||||
UINTN MyOffset;
|
||||
UINTN MyBufferSize;
|
||||
UINT8 *MyBuffer;
|
||||
UINTN SpareBufferSize;
|
||||
UINT8 *SpareBuffer;
|
||||
UINTN Index;
|
||||
UINT8 *Ptr;
|
||||
EFI_DEV_PATH_PTR DevPtr;
|
||||
//
|
||||
// Refresh work space and get last record
|
||||
//
|
||||
FtwLiteDevice = FTW_LITE_CONTEXT_FROM_THIS (This);
|
||||
Status = WorkSpaceRefresh (FtwLiteDevice);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Record = FtwLiteDevice->FtwLastRecord;
|
||||
|
||||
//
|
||||
// Check the flags of last write record
|
||||
//
|
||||
if ((Record->WriteAllocated == FTW_VALID_STATE) || (Record->SpareCompleted == FTW_VALID_STATE)) {
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
//
|
||||
// IF former record has completed, THEN use next record
|
||||
//
|
||||
if (Record->WriteCompleted == FTW_VALID_STATE) {
|
||||
Record++;
|
||||
FtwLiteDevice->FtwLastRecord = Record;
|
||||
}
|
||||
|
||||
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
|
||||
|
||||
//
|
||||
// Check if the input data can fit within the target block
|
||||
//
|
||||
if ((Offset +*NumBytes) > FtwLiteDevice->SpareAreaLength) {
|
||||
*NumBytes = FtwLiteDevice->SpareAreaLength - Offset;
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
}
|
||||
//
|
||||
// Check if there is enough free space for allocate a record
|
||||
//
|
||||
if ((MyOffset + FTW_LITE_RECORD_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) {
|
||||
Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim work space - %r", Status));
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Get the FVB protocol by handle
|
||||
//
|
||||
Status = FtwGetFvbByHandle (FvbHandle, &Fvb);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
//
|
||||
// Allocate a write record in workspace.
|
||||
// Update Header->WriteAllocated as VALID
|
||||
//
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
|
||||
WRITE_ALLOCATED
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Allocate record - %r\n", Status));
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Record->WriteAllocated = FTW_VALID_STATE;
|
||||
|
||||
//
|
||||
// Prepare data of write record, filling DevPath with memory mapped address.
|
||||
//
|
||||
DevPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath;
|
||||
DevPtr.MemMap->Header.Type = HARDWARE_DEVICE_PATH;
|
||||
DevPtr.MemMap->Header.SubType = HW_MEMMAP_DP;
|
||||
SetDevicePathNodeLength (&DevPtr.MemMap->Header, sizeof (MEMMAP_DEVICE_PATH));
|
||||
|
||||
Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
DevPtr.MemMap->MemoryType = EfiMemoryMappedIO;
|
||||
DevPtr.MemMap->StartingAddress = FvbPhysicalAddress;
|
||||
DevPtr.MemMap->EndingAddress = FvbPhysicalAddress +*NumBytes;
|
||||
//
|
||||
// ignored!
|
||||
//
|
||||
Record->Lba = Lba;
|
||||
Record->Offset = Offset;
|
||||
Record->NumBytes = *NumBytes;
|
||||
|
||||
//
|
||||
// Write the record to the work space.
|
||||
//
|
||||
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
|
||||
MyLength = FTW_LITE_RECORD_SIZE;
|
||||
|
||||
Status = FtwLiteDevice->FtwFvBlock->Write (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
|
||||
&MyLength,
|
||||
(UINT8 *) Record
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
//
|
||||
// Record has been written to working block, then write data.
|
||||
//
|
||||
//
|
||||
// Allocate a memory buffer
|
||||
//
|
||||
MyBufferSize = FtwLiteDevice->SpareAreaLength;
|
||||
MyBuffer = AllocatePool (MyBufferSize);
|
||||
if (MyBuffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Starting at Lba, if the number of the rest blocks on Fvb is less
|
||||
// than NumberOfSpareBlock.
|
||||
//
|
||||
//
|
||||
// Read all original data from target block to memory buffer
|
||||
//
|
||||
if (IsInWorkingBlock (FtwLiteDevice, Fvb, Lba)) {
|
||||
//
|
||||
// If target block falls into working block, we must follow the process of
|
||||
// updating working block.
|
||||
//
|
||||
Ptr = MyBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
MyLength = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwFvBlock->Read (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkBlockLba + Index,
|
||||
0,
|
||||
&MyLength,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (MyBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += MyLength;
|
||||
}
|
||||
//
|
||||
// Update Offset by adding the offset from the start LBA of working block to
|
||||
// the target LBA. The target block can not span working block!
|
||||
//
|
||||
Offset = (((UINTN) (Lba - FtwLiteDevice->FtwWorkBlockLba)) * FtwLiteDevice->BlockSize + Offset);
|
||||
ASSERT ((Offset +*NumBytes) <= FtwLiteDevice->SpareAreaLength);
|
||||
|
||||
} else {
|
||||
|
||||
Ptr = MyBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
MyLength = FtwLiteDevice->BlockSize;
|
||||
Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (MyBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += MyLength;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Overwrite the updating range data with
|
||||
// the input buffer content
|
||||
//
|
||||
CopyMem (MyBuffer + Offset, Buffer, *NumBytes);
|
||||
|
||||
//
|
||||
// Try to keep the content of spare block
|
||||
// Save spare block into a spare backup memory buffer (Sparebuffer)
|
||||
//
|
||||
SpareBufferSize = FtwLiteDevice->SpareAreaLength;
|
||||
SpareBuffer = AllocatePool (SpareBufferSize);
|
||||
if (SpareBuffer == NULL) {
|
||||
FreePool (MyBuffer);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ptr = SpareBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
MyLength = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Read (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&MyLength,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (MyBuffer);
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += MyLength;
|
||||
}
|
||||
//
|
||||
// Write the memory buffer to spare block
|
||||
// Don't forget to erase Flash first.
|
||||
//
|
||||
Status = FtwEraseSpareBlock (FtwLiteDevice);
|
||||
Ptr = MyBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
MyLength = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Write (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&MyLength,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (MyBuffer);
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += MyLength;
|
||||
}
|
||||
//
|
||||
// Free MyBuffer
|
||||
//
|
||||
FreePool (MyBuffer);
|
||||
|
||||
//
|
||||
// Set the SpareComplete in the FTW record,
|
||||
//
|
||||
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
|
||||
SPARE_COMPLETED
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Record->SpareCompleted = FTW_VALID_STATE;
|
||||
|
||||
//
|
||||
// Since the content has already backuped in spare block, the write is
|
||||
// guaranteed to be completed with fault tolerant manner.
|
||||
//
|
||||
Status = FtwWriteRecord (FtwLiteDevice, Fvb);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Record++;
|
||||
FtwLiteDevice->FtwLastRecord = Record;
|
||||
|
||||
//
|
||||
// Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
|
||||
//
|
||||
Status = FtwEraseSpareBlock (FtwLiteDevice);
|
||||
Ptr = SpareBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
MyLength = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Write (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&MyLength,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += MyLength;
|
||||
}
|
||||
//
|
||||
// All success.
|
||||
//
|
||||
FreePool (SpareBuffer);
|
||||
|
||||
DEBUG (
|
||||
(EFI_D_ERROR,
|
||||
"FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
|
||||
Lba,
|
||||
Offset,
|
||||
*NumBytes)
|
||||
);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write a record with fault tolerant manner.
|
||||
Since the content has already backuped in spare block, the write is
|
||||
guaranteed to be completed with fault tolerant manner.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
@param Fvb The FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwWriteRecord (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
EFI_LBA WorkSpaceLbaOffset;
|
||||
UINTN Offset;
|
||||
|
||||
//
|
||||
// Spare Complete but Destination not complete,
|
||||
// Recover the targt block with the spare block.
|
||||
//
|
||||
Record = FtwLiteDevice->FtwLastRecord;
|
||||
|
||||
//
|
||||
// IF target block is working block, THEN Flush Spare Block To Working Block;
|
||||
// ELSE flush spare block to normal target block.ENDIF
|
||||
//
|
||||
if (IsInWorkingBlock (FtwLiteDevice, Fvb, Record->Lba)) {
|
||||
//
|
||||
// If target block is working block, Attention:
|
||||
// it's required to set SPARE_COMPLETED to spare block.
|
||||
//
|
||||
WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
|
||||
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + Offset,
|
||||
SPARE_COMPLETED
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
|
||||
} else {
|
||||
//
|
||||
// Update blocks other than working block
|
||||
//
|
||||
Status = FlushSpareBlockToTargetBlock (FtwLiteDevice, Fvb, Record->Lba);
|
||||
}
|
||||
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// Set WriteCompleted flag in record
|
||||
//
|
||||
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + Offset,
|
||||
WRITE_COMPLETED
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Record->WriteCompleted = FTW_VALID_STATE;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Restarts a previously interrupted write. The caller must provide the
|
||||
block protocol needed to complete the interrupted write.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
FvbHandle - The handle of FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ACCESS_DENIED No pending writes exist
|
||||
@retval EFI_NOT_FOUND FVB protocol not found by the handle
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwRestart (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
|
||||
EFI_DEV_PATH_PTR DevPathPtr;
|
||||
|
||||
//
|
||||
// Spare Completed but Destination not complete,
|
||||
// Recover the targt block with the spare block.
|
||||
//
|
||||
Record = FtwLiteDevice->FtwLastRecord;
|
||||
|
||||
//
|
||||
// Only support memory mapped FVB device path by now.
|
||||
//
|
||||
DevPathPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath;
|
||||
if (!((DevPathPtr.MemMap->Header.Type == HARDWARE_DEVICE_PATH) && (DevPathPtr.MemMap->Header.SubType == HW_MEMMAP_DP))
|
||||
) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: FVB Device Path is not memory mapped\n"));
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Status = GetFvbByAddress (DevPathPtr.MemMap->StartingAddress, &Fvb);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
//
|
||||
// Since the content has already backuped in spare block, the write is
|
||||
// guaranteed to be completed with fault tolerant manner.
|
||||
//
|
||||
Status = FtwWriteRecord (FtwLiteDevice, Fvb);
|
||||
DEBUG ((EFI_D_INFO, "FtwLite: Restart() - %r\n", Status));
|
||||
|
||||
Record++;
|
||||
FtwLiteDevice->FtwLastRecord = Record;
|
||||
|
||||
//
|
||||
// Erase Spare block
|
||||
// This is restart, no need to keep spareblock content.
|
||||
//
|
||||
FtwEraseSpareBlock (FtwLiteDevice);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Aborts all previous allocated writes.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
@retval EFI_NOT_FOUND No allocated writes exist.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwAbort (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Offset;
|
||||
|
||||
if (FtwLiteDevice->FtwLastRecord->WriteCompleted == FTW_VALID_STATE) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
//
|
||||
// Update the complete state of the header as VALID and abort.
|
||||
//
|
||||
Offset = (UINT8 *) FtwLiteDevice->FtwLastRecord - FtwLiteDevice->FtwWorkSpace;
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + Offset,
|
||||
WRITE_COMPLETED
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
FtwLiteDevice->FtwLastRecord->WriteCompleted = FTW_VALID_STATE;
|
||||
|
||||
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
|
||||
|
||||
//
|
||||
// Erase the spare block
|
||||
//
|
||||
Status = FtwEraseSpareBlock (FtwLiteDevice);
|
||||
|
||||
DEBUG ((EFI_D_INFO, "FtwLite: Abort() success \n"));
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This function is the entry point of the Fault Tolerant Write driver.
|
||||
|
||||
@param ImageHandle A handle for the image that is initializing this driver
|
||||
@param SystemTable A pointer to the EFI system table
|
||||
|
||||
@retval EFI_SUCCESS FTW has finished the initialization
|
||||
@retval EFI_ABORTED FTW initialization error
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitializeFtwLite (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
|
||||
UINTN Index;
|
||||
EFI_HANDLE *HandleBuffer;
|
||||
UINTN HandleCount;
|
||||
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice;
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
EFI_STATUS Status;
|
||||
UINTN Offset;
|
||||
UINTN Length;
|
||||
EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
|
||||
UINT32 LbaIndex;
|
||||
//
|
||||
// Allocate Private data of this driver, including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
|
||||
//
|
||||
FtwLiteDevice = NULL;
|
||||
FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
|
||||
ASSERT (FtwLiteDevice != NULL);
|
||||
|
||||
ZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE));
|
||||
FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE;
|
||||
|
||||
//
|
||||
// Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
|
||||
//
|
||||
FtwLiteDevice->FtwWorkSpace = (UINT8 *) (FtwLiteDevice + 1);
|
||||
FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace;
|
||||
FtwLiteDevice->FtwLastRecord = NULL;
|
||||
|
||||
FtwLiteDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
|
||||
FtwLiteDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
|
||||
|
||||
FtwLiteDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
|
||||
FtwLiteDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
|
||||
|
||||
ASSERT ((FtwLiteDevice->WorkSpaceLength != 0) && (FtwLiteDevice->SpareAreaLength != 0));
|
||||
|
||||
//
|
||||
// Locate FVB protocol
|
||||
//
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gEfiFirmwareVolumeBlockProtocolGuid,
|
||||
NULL,
|
||||
&HandleCount,
|
||||
&HandleBuffer
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
ASSERT (HandleCount > 0);
|
||||
|
||||
FtwLiteDevice->FtwFvBlock = NULL;
|
||||
FtwLiteDevice->FtwBackupFvb = NULL;
|
||||
FtwLiteDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
|
||||
FtwLiteDevice->FtwSpareLba = (EFI_LBA) (-1);
|
||||
for (Index = 0; Index < HandleCount; Index += 1) {
|
||||
Status = gBS->HandleProtocol (
|
||||
HandleBuffer[Index],
|
||||
&gEfiFirmwareVolumeBlockProtocolGuid,
|
||||
(VOID **) &Fvb
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);
|
||||
|
||||
if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) &&
|
||||
((FtwLiteDevice->WorkSpaceAddress + FtwLiteDevice->WorkSpaceLength) <= (BaseAddress + FwVolHeader->FvLength))
|
||||
) {
|
||||
FtwLiteDevice->FtwFvBlock = Fvb;
|
||||
//
|
||||
// To get the LBA of work space
|
||||
//
|
||||
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
|
||||
//
|
||||
// FV may have multiple types of BlockLength
|
||||
//
|
||||
FvbMapEntry = &FwVolHeader->BlockMap[0];
|
||||
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {
|
||||
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
|
||||
if ((FtwLiteDevice->WorkSpaceAddress >= (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
|
||||
&& (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex))) {
|
||||
FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;
|
||||
//
|
||||
// Get the Work space size and Base(Offset)
|
||||
//
|
||||
FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength;
|
||||
FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
// end for
|
||||
//
|
||||
if (LbaIndex <= FvbMapEntry->NumBlocks) {
|
||||
//
|
||||
// Work space range is found.
|
||||
//
|
||||
break;
|
||||
}
|
||||
FvbMapEntry++;
|
||||
}
|
||||
//
|
||||
// end while
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&
|
||||
((FtwLiteDevice->SpareAreaAddress + FtwLiteDevice->SpareAreaLength) <= (BaseAddress + FwVolHeader->FvLength))
|
||||
) {
|
||||
FtwLiteDevice->FtwBackupFvb = Fvb;
|
||||
//
|
||||
// To get the LBA of spare
|
||||
//
|
||||
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
|
||||
//
|
||||
// FV may have multiple types of BlockLength
|
||||
//
|
||||
FvbMapEntry = &FwVolHeader->BlockMap[0];
|
||||
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {
|
||||
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
|
||||
if ((FtwLiteDevice->SpareAreaAddress >= (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
|
||||
&& (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex))) {
|
||||
//
|
||||
// Get the NumberOfSpareBlock and BlockSize
|
||||
//
|
||||
FtwLiteDevice->FtwSpareLba = LbaIndex - 1;
|
||||
FtwLiteDevice->BlockSize = FvbMapEntry->Length;
|
||||
FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->BlockSize;
|
||||
//
|
||||
// Check the range of spare area to make sure that it's in FV range
|
||||
// To do delete
|
||||
//
|
||||
ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (LbaIndex <= FvbMapEntry->NumBlocks) {
|
||||
//
|
||||
// Spare FV range is found.
|
||||
//
|
||||
break;
|
||||
}
|
||||
FvbMapEntry++;
|
||||
}
|
||||
//
|
||||
// end while
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the start LBA of working block. Working block is an area which
|
||||
// contains working space in its last block and has the same size as spare
|
||||
// block, unless there are not enough blocks before the block that contains
|
||||
// working space.
|
||||
//
|
||||
FtwLiteDevice->FtwWorkBlockLba = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->NumberOfSpareBlock + 1;
|
||||
if ((INT64) (FtwLiteDevice->FtwWorkBlockLba) < 0) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: The spare block range is too large than the working block range!\n"));
|
||||
FreePool (FtwLiteDevice);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
if ((FtwLiteDevice->FtwFvBlock == NULL) ||
|
||||
(FtwLiteDevice->FtwBackupFvb == NULL) ||
|
||||
(FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||
|
||||
(FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))
|
||||
) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));
|
||||
FreePool (FtwLiteDevice);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Refresh workspace data from working block
|
||||
//
|
||||
Status = WorkSpaceRefresh (FtwLiteDevice);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// If the working block workspace is not valid, try the spare block
|
||||
//
|
||||
if (!IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Workspace invalid, read from backup\n"));
|
||||
//
|
||||
// Read from spare block
|
||||
//
|
||||
Length = FtwLiteDevice->FtwWorkSpaceSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Read (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase,
|
||||
&Length,
|
||||
FtwLiteDevice->FtwWorkSpace
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// If spare block is valid, then replace working block content.
|
||||
//
|
||||
if (IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
|
||||
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Restart working block in Init() - %r\n", Status));
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
FtwAbort (FtwLiteDevice);
|
||||
//
|
||||
// Refresh work space.
|
||||
//
|
||||
Status = WorkSpaceRefresh (FtwLiteDevice);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (FtwLiteDevice);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
} else {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Both are invalid, init workspace\n"));
|
||||
//
|
||||
// If both are invalid, then initialize work space.
|
||||
//
|
||||
SetMem (
|
||||
FtwLiteDevice->FtwWorkSpace,
|
||||
FtwLiteDevice->FtwWorkSpaceSize,
|
||||
FTW_ERASED_BYTE
|
||||
);
|
||||
InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);
|
||||
//
|
||||
// Initialize the work space
|
||||
//
|
||||
Status = FtwReclaimWorkSpace (FtwLiteDevice, FALSE);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (FtwLiteDevice);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Hook the protocol API
|
||||
//
|
||||
FtwLiteDevice->FtwLiteInstance.Write = FtwLiteWrite;
|
||||
|
||||
//
|
||||
// Install protocol interface
|
||||
//
|
||||
Status = gBS->InstallProtocolInterface (
|
||||
&FtwLiteDevice->Handle,
|
||||
&gEfiFaultTolerantWriteLiteProtocolGuid,
|
||||
EFI_NATIVE_INTERFACE,
|
||||
&FtwLiteDevice->FtwLiteInstance
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (FtwLiteDevice);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
//
|
||||
// If (!SpareCompleted) THEN Abort to rollback.
|
||||
//
|
||||
if ((FtwLiteDevice->FtwLastRecord->WriteAllocated == FTW_VALID_STATE) &&
|
||||
(FtwLiteDevice->FtwLastRecord->SpareCompleted != FTW_VALID_STATE)
|
||||
) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
|
||||
FtwAbort (FtwLiteDevice);
|
||||
}
|
||||
//
|
||||
// if (SpareCompleted) THEN Restart to fault tolerant write.
|
||||
//
|
||||
if ((FtwLiteDevice->FtwLastRecord->SpareCompleted == FTW_VALID_STATE) &&
|
||||
(FtwLiteDevice->FtwLastRecord->WriteCompleted != FTW_VALID_STATE)
|
||||
) {
|
||||
|
||||
Status = FtwRestart (FtwLiteDevice);
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
//
|
||||
// To check the workspace buffer behind last records is EMPTY or not.
|
||||
// If it's not EMPTY, FTW_LITE also need to call reclaim().
|
||||
//
|
||||
Record = FtwLiteDevice->FtwLastRecord;
|
||||
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
|
||||
if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
|
||||
Offset += FTW_LITE_RECORD_SIZE;
|
||||
}
|
||||
|
||||
if (!IsErasedFlashBuffer (
|
||||
FTW_ERASE_POLARITY,
|
||||
FtwLiteDevice->FtwWorkSpace + Offset,
|
||||
FtwLiteDevice->FtwWorkSpaceSize - Offset
|
||||
)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Workspace is dirty, call reclaim...\n"));
|
||||
Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Workspace reclaim - %r\n", Status));
|
||||
FreePool (FtwLiteDevice);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
@ -1,497 +0,0 @@
|
||||
/** @file
|
||||
|
||||
The internal header file includes the common header files, defines
|
||||
internal structure and functions used by FtwLite module.
|
||||
|
||||
Copyright (c) 2006 - 2008, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EFI_FAULT_TOLERANT_WRITE_LITE_H_
|
||||
#define _EFI_FAULT_TOLERANT_WRITE_LITE_H_
|
||||
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Guid/SystemNvDataGuid.h>
|
||||
#include <Protocol/FaultTolerantWriteLite.h>
|
||||
#include <Protocol/FirmwareVolumeBlock.h>
|
||||
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/UefiDriverEntryPoint.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
|
||||
//
|
||||
// Flash erase polarity is 1
|
||||
//
|
||||
#define FTW_ERASE_POLARITY 1
|
||||
|
||||
#define FTW_VALID_STATE 0
|
||||
#define FTW_INVALID_STATE 1
|
||||
|
||||
#define FTW_ERASED_BYTE ((UINT8) (255))
|
||||
#define FTW_POLARITY_REVERT ((UINT8) (255))
|
||||
|
||||
typedef struct {
|
||||
UINT8 WriteAllocated : 1;
|
||||
UINT8 SpareCompleted : 1;
|
||||
UINT8 WriteCompleted : 1;
|
||||
UINT8 Reserved : 5;
|
||||
#define WRITE_ALLOCATED 0x1
|
||||
#define SPARE_COMPLETED 0x2
|
||||
#define WRITE_COMPLETED 0x4
|
||||
|
||||
EFI_DEV_PATH DevPath;
|
||||
EFI_LBA Lba;
|
||||
UINTN Offset;
|
||||
UINTN NumBytes;
|
||||
//
|
||||
// UINTN SpareAreaOffset;
|
||||
//
|
||||
} EFI_FTW_LITE_RECORD;
|
||||
|
||||
#define FTW_LITE_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'T', 'W', 'L')
|
||||
|
||||
//
|
||||
// MACRO for FTW header and record
|
||||
//
|
||||
#define FTW_LITE_RECORD_SIZE (sizeof (EFI_FTW_LITE_RECORD))
|
||||
|
||||
//
|
||||
// EFI Fault tolerant protocol private data structure
|
||||
//
|
||||
typedef struct {
|
||||
UINTN Signature;
|
||||
EFI_HANDLE Handle;
|
||||
EFI_FTW_LITE_PROTOCOL FtwLiteInstance;
|
||||
EFI_PHYSICAL_ADDRESS WorkSpaceAddress; // Base address of working space range in flash.
|
||||
UINTN WorkSpaceLength; // Size of working space range in flash.
|
||||
EFI_PHYSICAL_ADDRESS SpareAreaAddress; // Base address of spare range in flash.
|
||||
UINTN SpareAreaLength; // Size of spare range in flash.
|
||||
UINTN NumberOfSpareBlock; // Number of the blocks in spare block.
|
||||
UINTN BlockSize; // Block size in bytes of the blocks in flash
|
||||
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader;// Pointer to Working Space Header in memory buffer
|
||||
EFI_FTW_LITE_RECORD *FtwLastRecord; // Pointer to last record in memory buffer
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwFvBlock; // FVB of working block
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwBackupFvb; // FVB of spare block
|
||||
EFI_LBA FtwSpareLba; // Start LBA of spare block
|
||||
EFI_LBA FtwWorkBlockLba; // Start LBA of working block that contains working space in its last block.
|
||||
EFI_LBA FtwWorkSpaceLba; // Start LBA of working space
|
||||
UINTN FtwWorkSpaceBase; // Offset into the FtwWorkSpaceLba block.
|
||||
UINTN FtwWorkSpaceSize; // Size of working space range that stores write record.
|
||||
UINT8 *FtwWorkSpace; // Point to Work Space in memory buffer
|
||||
//
|
||||
// Following a buffer of FtwWorkSpace[FTW_WORK_SPACE_SIZE],
|
||||
// Allocated with EFI_FTW_LITE_DEVICE.
|
||||
//
|
||||
} EFI_FTW_LITE_DEVICE;
|
||||
|
||||
#define FTW_LITE_CONTEXT_FROM_THIS(a) CR (a, EFI_FTW_LITE_DEVICE, FtwLiteInstance, FTW_LITE_DEVICE_SIGNATURE)
|
||||
|
||||
//
|
||||
// Driver entry point
|
||||
//
|
||||
/**
|
||||
This function is the entry point of the Fault Tolerant Write driver.
|
||||
|
||||
|
||||
@param ImageHandle A handle for the image that is initializing
|
||||
this driver
|
||||
@param SystemTable A pointer to the EFI system table
|
||||
|
||||
@retval EFI_SUCCESS FTW has finished the initialization
|
||||
@retval EFI_ABORTED FTW initialization error
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitializeFtwLite (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
);
|
||||
|
||||
//
|
||||
// Fault Tolerant Write Protocol API
|
||||
//
|
||||
/**
|
||||
Starts a target block update. This function will record data about write
|
||||
in fault tolerant storage and will complete the write in a recoverable
|
||||
manner, ensuring at all times that either the original contents or
|
||||
the modified contents are available.
|
||||
|
||||
|
||||
@param This Calling context
|
||||
@param FvbHandle The handle of FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
@param Lba The logical block address of the target block.
|
||||
@param Offset The offset within the target block to place the data.
|
||||
@param NumBytes The number of bytes to write to the target block.
|
||||
@param Buffer The data to write.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_BAD_BUFFER_SIZE The write would span a target block, which is not
|
||||
a valid action.
|
||||
@retval EFI_ACCESS_DENIED No writes have been allocated.
|
||||
@retval EFI_NOT_FOUND Cannot find FVB by handle.
|
||||
@retval EFI_OUT_OF_RESOURCES Cannot allocate memory.
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
FtwLiteWrite (
|
||||
IN EFI_FTW_LITE_PROTOCOL *This,
|
||||
IN EFI_HANDLE FvbHandle,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN Offset,
|
||||
IN OUT UINTN *NumBytes,
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
//
|
||||
// Internal functions
|
||||
//
|
||||
/**
|
||||
Restarts a previously interrupted write. The caller must provide the
|
||||
block protocol needed to complete the interrupted write.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
FvbHandle - The handle of FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ACCESS_DENIED No pending writes exist
|
||||
@retval EFI_NOT_FOUND FVB protocol not found by the handle
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwRestart (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
);
|
||||
|
||||
/**
|
||||
Aborts all previous allocated writes.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
@retval EFI_NOT_FOUND No allocated writes exist.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwAbort (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Write a record with fault tolerant mannaer.
|
||||
Since the content has already backuped in spare block, the write is
|
||||
guaranteed to be completed with fault tolerant manner.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
@param Fvb The FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwWriteRecord (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
|
||||
);
|
||||
|
||||
/**
|
||||
To erase the block with the spare block size.
|
||||
|
||||
|
||||
@param FtwLiteDevice Calling context
|
||||
@param FvBlock FVB Protocol interface
|
||||
@param Lba Lba of the firmware block
|
||||
|
||||
@retval EFI_SUCCESS Block LBA is Erased successfully
|
||||
@retval Others Error occurs
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwEraseBlock (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
EFI_LBA Lba
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Erase spare block.
|
||||
|
||||
|
||||
@param FtwLiteDevice Calling context
|
||||
|
||||
@retval EFI_SUCCESS The erase request was 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
|
||||
FtwEraseSpareBlock (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
);
|
||||
|
||||
/**
|
||||
Retrive the proper FVB protocol interface by HANDLE.
|
||||
|
||||
|
||||
@param FvBlockHandle The handle of FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
@param FvBlock The interface of FVB protocol
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwGetFvbByHandle (
|
||||
IN EFI_HANDLE FvBlockHandle,
|
||||
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Get firmware block by address.
|
||||
|
||||
|
||||
@param Address Address specified the block
|
||||
@param FvBlock The block caller wanted
|
||||
|
||||
@retval EFI_SUCCESS The protocol instance if found.
|
||||
@retval EFI_NOT_FOUND Block not found
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
GetFvbByAddress (
|
||||
IN EFI_PHYSICAL_ADDRESS Address,
|
||||
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Is it in working block?
|
||||
|
||||
|
||||
@param FtwLiteDevice Calling context
|
||||
@param FvBlock Fvb protocol instance
|
||||
@param Lba The block specified
|
||||
|
||||
@return A BOOLEAN value indicating in working block or not.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsInWorkingBlock (
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
EFI_LBA Lba
|
||||
);
|
||||
|
||||
/**
|
||||
Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
|
||||
Spare block is accessed by FTW backup FVB protocol interface. LBA is
|
||||
FtwLiteDevice->FtwSpareLba.
|
||||
Target block is accessed by FvBlock protocol interface. LBA is Lba.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
@param FvBlock FVB Protocol interface to access target block
|
||||
@param Lba Lba of the target block
|
||||
|
||||
@retval EFI_SUCCESS Spare block content is copied to target block
|
||||
@retval EFI_INVALID_PARAMETER Input parameter error
|
||||
@retval EFI_OUT_OF_RESOURCES Allocate memory error
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FlushSpareBlockToTargetBlock (
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
EFI_LBA Lba
|
||||
);
|
||||
|
||||
/**
|
||||
Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
|
||||
Spare block is accessed by FTW backup FVB protocol interface. LBA is
|
||||
FtwLiteDevice->FtwSpareLba.
|
||||
Working block is accessed by FTW working FVB protocol interface. LBA is
|
||||
FtwLiteDevice->FtwWorkBlockLba.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
|
||||
@retval EFI_SUCCESS Spare block content is copied to target block
|
||||
@retval EFI_OUT_OF_RESOURCES Allocate memory error
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
Notes:
|
||||
Since the working block header is important when FTW initializes, the
|
||||
state of the operation should be handled carefully. The Crc value is
|
||||
calculated without STATE element.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FlushSpareBlockToWorkingBlock (
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
);
|
||||
|
||||
/**
|
||||
Update a bit of state on a block device. The location of the bit is
|
||||
calculated by the (Lba, Offset, bit). Here bit is determined by the
|
||||
the name of a certain bit.
|
||||
|
||||
|
||||
@param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
|
||||
@param Lba Lba of a block
|
||||
@param Offset Offset on the Lba
|
||||
@param NewBit New value that will override the old value if it can be change
|
||||
|
||||
@retval EFI_SUCCESS A state bit has been updated successfully
|
||||
@retval Others Access block device error.
|
||||
Notes:
|
||||
Assume all bits of State are inside the same BYTE.
|
||||
@retval EFI_ABORTED Read block fail
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwUpdateFvState (
|
||||
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN Offset,
|
||||
IN UINT8 NewBit
|
||||
);
|
||||
|
||||
/**
|
||||
Get the last Write record pointer.
|
||||
The last record is the record whose 'complete' state hasn't been set.
|
||||
After all, this header may be a EMPTY header entry for next Allocate.
|
||||
|
||||
|
||||
@param FtwLiteDevice Private data of this driver
|
||||
@param FtwLastRecord Pointer to retrieve the last write record
|
||||
|
||||
@retval EFI_SUCCESS Get the last write record successfully
|
||||
@retval EFI_ABORTED The FTW work space is damaged
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwGetLastRecord (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
OUT EFI_FTW_LITE_RECORD **FtwLastRecord
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Check whether a flash buffer is erased.
|
||||
|
||||
|
||||
@param Polarity All 1 or all 0
|
||||
@param Buffer Buffer to check
|
||||
@param BufferSize Size of the buffer
|
||||
|
||||
@return A BOOLEAN value indicating erased or not.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsErasedFlashBuffer (
|
||||
IN BOOLEAN Polarity,
|
||||
IN UINT8 *Buffer,
|
||||
IN UINTN BufferSize
|
||||
);
|
||||
|
||||
/**
|
||||
Initialize a work space when there is no work space.
|
||||
|
||||
|
||||
@param WorkingHeader Pointer of working block header
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
InitWorkSpaceHeader (
|
||||
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
|
||||
);
|
||||
|
||||
/**
|
||||
Read from working block to refresh the work space in memory.
|
||||
|
||||
|
||||
@param FtwLiteDevice Point to private data of FTW driver
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
WorkSpaceRefresh (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
);
|
||||
|
||||
/**
|
||||
Check to see if it is a valid work space.
|
||||
|
||||
|
||||
@param WorkingHeader Pointer of working block header
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsValidWorkSpace (
|
||||
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
|
||||
);
|
||||
|
||||
/**
|
||||
Reclaim the work space on the working block.
|
||||
|
||||
|
||||
@param FtwLiteDevice Point to private data of FTW driver
|
||||
@param PreserveRecord Whether to preserve the working record is needed
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_OUT_OF_RESOURCES Allocate memory error
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwReclaimWorkSpace (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
IN BOOLEAN PreserveRecord
|
||||
);
|
||||
|
||||
#endif
|
@ -1,64 +0,0 @@
|
||||
#/** @file
|
||||
# This driver provides lite version of fault tolerant capability for writing operation on flash devices.
|
||||
# Its implementation depends on the full functionality FVB protocol that support read, write/erase flash access.
|
||||
#
|
||||
# Copyright (c) 2006 - 2009, Intel Corporation
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#**/
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = FtwLite
|
||||
FILE_GUID = 4C862FC6-0E54-4e36-8C8F-FF6F3167951F
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = InitializeFtwLite
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||
#
|
||||
|
||||
[Sources.common]
|
||||
FtwWorkSpace.c
|
||||
FtwMisc.c
|
||||
FtwLite.c
|
||||
FtwLite.h
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiBootServicesTableLib
|
||||
MemoryAllocationLib
|
||||
BaseMemoryLib
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
PcdLib
|
||||
DevicePathLib
|
||||
|
||||
[Guids]
|
||||
gEfiSystemNvDataFvGuid ## CONSUMED ## FV Signature of Working Space Header
|
||||
|
||||
[Protocols]
|
||||
gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMED
|
||||
gEfiFaultTolerantWriteLiteProtocolGuid ## PRODUCED
|
||||
|
||||
[Pcd.common]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
|
||||
|
||||
[Depex]
|
||||
gEfiFirmwareVolumeBlockProtocolGuid AND gEfiAlternateFvBlockGuid ## gEfiAlternateFvBlockGuid specifies FVB protocol with read, write/erase flash access.
|
||||
|
@ -1,505 +0,0 @@
|
||||
/** @file
|
||||
|
||||
Internal generic functions to operate flash block.
|
||||
|
||||
Copyright (c) 2006 - 2008, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "FtwLite.h"
|
||||
|
||||
/**
|
||||
|
||||
Check whether a flash buffer is erased.
|
||||
|
||||
|
||||
@param Polarity All 1 or all 0
|
||||
@param Buffer Buffer to check
|
||||
@param BufferSize Size of the buffer
|
||||
|
||||
@return A BOOLEAN value indicating erased or not.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsErasedFlashBuffer (
|
||||
IN BOOLEAN Polarity,
|
||||
IN UINT8 *Buffer,
|
||||
IN UINTN BufferSize
|
||||
)
|
||||
{
|
||||
UINT8 ErasedValue;
|
||||
UINT8 *Ptr;
|
||||
|
||||
if (Polarity) {
|
||||
ErasedValue = 0xFF;
|
||||
} else {
|
||||
ErasedValue = 0;
|
||||
}
|
||||
|
||||
Ptr = Buffer;
|
||||
while ((BufferSize--) != 0) {
|
||||
if (*Ptr++ != ErasedValue) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
To erase the block with the spare block size.
|
||||
|
||||
|
||||
@param FtwLiteDevice Calling context
|
||||
@param FvBlock FVB Protocol interface
|
||||
@param Lba Lba of the firmware block
|
||||
|
||||
@retval EFI_SUCCESS Block LBA is Erased successfully
|
||||
@retval Others Error occurs
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwEraseBlock (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
EFI_LBA Lba
|
||||
)
|
||||
{
|
||||
return FvBlock->EraseBlocks (
|
||||
FvBlock,
|
||||
Lba,
|
||||
FtwLiteDevice->NumberOfSpareBlock,
|
||||
EFI_LBA_LIST_TERMINATOR
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Erase spare block.
|
||||
|
||||
|
||||
@param FtwLiteDevice Calling context
|
||||
|
||||
@retval EFI_SUCCESS The erase request was 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
|
||||
FtwEraseSpareBlock (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
)
|
||||
{
|
||||
return FtwLiteDevice->FtwBackupFvb->EraseBlocks (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba,
|
||||
FtwLiteDevice->NumberOfSpareBlock,
|
||||
EFI_LBA_LIST_TERMINATOR
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrive the proper FVB protocol interface by HANDLE.
|
||||
|
||||
|
||||
@param FvBlockHandle The handle of FVB protocol that provides services for
|
||||
reading, writing, and erasing the target block.
|
||||
@param FvBlock The interface of FVB protocol
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwGetFvbByHandle (
|
||||
IN EFI_HANDLE FvBlockHandle,
|
||||
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
|
||||
)
|
||||
{
|
||||
//
|
||||
// To get the FVB protocol interface on the handle
|
||||
//
|
||||
return gBS->HandleProtocol (
|
||||
FvBlockHandle,
|
||||
&gEfiFirmwareVolumeBlockProtocolGuid,
|
||||
(VOID **) FvBlock
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Get firmware block by address.
|
||||
|
||||
|
||||
@param Address Address specified the block
|
||||
@param FvBlock The block caller wanted
|
||||
|
||||
@retval EFI_SUCCESS The protocol instance if found.
|
||||
@retval EFI_NOT_FOUND Block not found
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
GetFvbByAddress (
|
||||
IN EFI_PHYSICAL_ADDRESS Address,
|
||||
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE *HandleBuffer;
|
||||
UINTN HandleCount;
|
||||
UINTN Index;
|
||||
EFI_PHYSICAL_ADDRESS FvbBaseAddress;
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
|
||||
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
|
||||
|
||||
*FvBlock = NULL;
|
||||
//
|
||||
// Locate all handles of Fvb protocol
|
||||
//
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gEfiFirmwareVolumeBlockProtocolGuid,
|
||||
NULL,
|
||||
&HandleCount,
|
||||
&HandleBuffer
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
//
|
||||
// Search all FVB until find the right one
|
||||
//
|
||||
for (Index = 0; Index < HandleCount; Index += 1) {
|
||||
Status = gBS->HandleProtocol (
|
||||
HandleBuffer[Index],
|
||||
&gEfiFirmwareVolumeBlockProtocolGuid,
|
||||
(VOID **) &Fvb
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Status = EFI_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Compare the address and select the right one
|
||||
//
|
||||
Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
|
||||
if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {
|
||||
*FvBlock = Fvb;
|
||||
Status = EFI_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreePool (HandleBuffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Is it in working block?
|
||||
|
||||
|
||||
@param FtwLiteDevice Calling context
|
||||
@param FvBlock Fvb protocol instance
|
||||
@param Lba The block specified
|
||||
|
||||
@return A BOOLEAN value indicating in working block or not.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsInWorkingBlock (
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
EFI_LBA Lba
|
||||
)
|
||||
{
|
||||
//
|
||||
// If matching the following condition, the target block is in working block.
|
||||
// 1. Target block is on the FV of working block (Using the same FVB protocol instance).
|
||||
// 2. Lba falls into the range of working block.
|
||||
//
|
||||
return (BOOLEAN)
|
||||
(
|
||||
(FvBlock == FtwLiteDevice->FtwFvBlock) &&
|
||||
(Lba >= FtwLiteDevice->FtwWorkBlockLba) &&
|
||||
(Lba <= FtwLiteDevice->FtwWorkSpaceLba)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
|
||||
Spare block is accessed by FTW backup FVB protocol interface. LBA is
|
||||
FtwLiteDevice->FtwSpareLba.
|
||||
Target block is accessed by FvBlock protocol interface. LBA is Lba.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
@param FvBlock FVB Protocol interface to access target block
|
||||
@param Lba Lba of the target block
|
||||
|
||||
@retval EFI_SUCCESS Spare block content is copied to target block
|
||||
@retval EFI_INVALID_PARAMETER Input parameter error
|
||||
@retval EFI_OUT_OF_RESOURCES Allocate memory error
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FlushSpareBlockToTargetBlock (
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
EFI_LBA Lba
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Length;
|
||||
UINT8 *Buffer;
|
||||
UINTN Count;
|
||||
UINT8 *Ptr;
|
||||
UINTN Index;
|
||||
|
||||
if ((FtwLiteDevice == NULL) || (FvBlock == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Allocate a memory buffer
|
||||
//
|
||||
Length = FtwLiteDevice->SpareAreaLength;
|
||||
Buffer = AllocatePool (Length);
|
||||
if (Buffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Read all content of spare block to memory buffer
|
||||
//
|
||||
Ptr = Buffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Count = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Read (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&Count,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Ptr += Count;
|
||||
}
|
||||
//
|
||||
// Erase the target block
|
||||
//
|
||||
Status = FtwEraseBlock (FtwLiteDevice, FvBlock, Lba);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
//
|
||||
// Write memory buffer to block, using the FvbBlock protocol interface
|
||||
//
|
||||
Ptr = Buffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Count = FtwLiteDevice->BlockSize;
|
||||
Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: FVB Write block - %r\n", Status));
|
||||
FreePool (Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Ptr += Count;
|
||||
}
|
||||
|
||||
FreePool (Buffer);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
|
||||
Spare block is accessed by FTW backup FVB protocol interface. LBA is
|
||||
FtwLiteDevice->FtwSpareLba.
|
||||
Working block is accessed by FTW working FVB protocol interface. LBA is
|
||||
FtwLiteDevice->FtwWorkBlockLba.
|
||||
|
||||
|
||||
@param FtwLiteDevice The private data of FTW_LITE driver
|
||||
|
||||
@retval EFI_SUCCESS Spare block content is copied to target block
|
||||
@retval EFI_OUT_OF_RESOURCES Allocate memory error
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
Notes:
|
||||
Since the working block header is important when FTW initializes, the
|
||||
state of the operation should be handled carefully. The Crc value is
|
||||
calculated without STATE element.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FlushSpareBlockToWorkingBlock (
|
||||
EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Length;
|
||||
UINT8 *Buffer;
|
||||
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
|
||||
EFI_LBA WorkSpaceLbaOffset;
|
||||
UINTN Count;
|
||||
UINT8 *Ptr;
|
||||
UINTN Index;
|
||||
|
||||
//
|
||||
// Allocate a memory buffer
|
||||
//
|
||||
Length = FtwLiteDevice->SpareAreaLength;
|
||||
Buffer = AllocatePool (Length);
|
||||
if (Buffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// To guarantee that the WorkingBlockValid is set on spare block
|
||||
//
|
||||
// Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
|
||||
// WorkingBlockValid);
|
||||
// To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
|
||||
//
|
||||
WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
|
||||
FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
|
||||
WORKING_BLOCK_VALID
|
||||
);
|
||||
//
|
||||
// Read from spare block to memory buffer
|
||||
//
|
||||
Ptr = Buffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Count = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Read (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&Count,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Ptr += Count;
|
||||
}
|
||||
//
|
||||
// Clear the CRC and STATE, copy data from spare to working block.
|
||||
//
|
||||
WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwLiteDevice->BlockSize + FtwLiteDevice->FtwWorkSpaceBase);
|
||||
InitWorkSpaceHeader (WorkingBlockHeader);
|
||||
WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
|
||||
WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
|
||||
|
||||
//
|
||||
// target block is working block, then
|
||||
// Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
|
||||
// before erase the working block.
|
||||
//
|
||||
// Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
|
||||
// WorkingBlockInvalid);
|
||||
// To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
|
||||
//
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
|
||||
WORKING_BLOCK_INVALID
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
|
||||
|
||||
//
|
||||
// Erase the working block
|
||||
//
|
||||
Status = FtwEraseBlock (
|
||||
FtwLiteDevice,
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkBlockLba
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
//
|
||||
// Write memory buffer to working block, using the FvbBlock protocol interface
|
||||
//
|
||||
Ptr = Buffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Count = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwFvBlock->Write (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkBlockLba + Index,
|
||||
0,
|
||||
&Count,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: FVB Write block - %r\n", Status));
|
||||
FreePool (Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Ptr += Count;
|
||||
}
|
||||
//
|
||||
// Since the memory buffer will not be used, free memory Buffer.
|
||||
//
|
||||
FreePool (Buffer);
|
||||
|
||||
//
|
||||
// Update the VALID of the working block
|
||||
//
|
||||
// Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
|
||||
// WorkingBlockValid);
|
||||
// Hardcode offset sizeof(EFI_GUID)+sizeof(UINT32), to skip Signature and Crc
|
||||
//
|
||||
Status = FtwUpdateFvState (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
|
||||
WORKING_BLOCK_VALID
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
@ -1,504 +0,0 @@
|
||||
/** @file
|
||||
|
||||
Internal functions to operate Working Block Space.
|
||||
|
||||
Copyright (c) 2006 - 2008, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include "FtwLite.h"
|
||||
|
||||
/**
|
||||
Check to see if it is a valid work space.
|
||||
|
||||
|
||||
@param WorkingHeader Pointer of working block header
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsValidWorkSpace (
|
||||
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;
|
||||
|
||||
ASSERT (WorkingHeader != NULL);
|
||||
if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Work block header valid bit check error\n"));
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Check signature with gEfiSystemNvDataFvGuid
|
||||
//
|
||||
if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Work block header signature check error\n"));
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Check the CRC of header
|
||||
//
|
||||
CopyMem (
|
||||
&WorkingBlockHeader,
|
||||
WorkingHeader,
|
||||
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
|
||||
);
|
||||
|
||||
//
|
||||
// Filter out the Crc and State fields
|
||||
//
|
||||
SetMem (
|
||||
&WorkingBlockHeader.Crc,
|
||||
sizeof (UINT32),
|
||||
FTW_ERASED_BYTE
|
||||
);
|
||||
WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;
|
||||
WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;
|
||||
|
||||
//
|
||||
// Calculate the Crc of woking block header
|
||||
//
|
||||
Status = gBS->CalculateCrc32 (
|
||||
(UINT8 *) &WorkingBlockHeader,
|
||||
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
|
||||
&WorkingBlockHeader.Crc
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Work block header CRC check error\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize a work space when there is no work space.
|
||||
|
||||
|
||||
@param WorkingHeader Pointer of working block header
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
InitWorkSpaceHeader (
|
||||
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (WorkingHeader != NULL);
|
||||
|
||||
//
|
||||
// Here using gEfiSystemNvDataFvGuid as the signature.
|
||||
//
|
||||
CopyMem (
|
||||
&WorkingHeader->Signature,
|
||||
&gEfiSystemNvDataFvGuid,
|
||||
sizeof (EFI_GUID)
|
||||
);
|
||||
WorkingHeader->WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
|
||||
|
||||
//
|
||||
// Crc is calculated with all the fields except Crc and STATE
|
||||
//
|
||||
WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
|
||||
WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
|
||||
SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);
|
||||
|
||||
//
|
||||
// Calculate the CRC value
|
||||
//
|
||||
Status = gBS->CalculateCrc32 (
|
||||
(UINT8 *) WorkingHeader,
|
||||
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
|
||||
&WorkingHeader->Crc
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// Restore the WorkingBlockValid flag to VALID state
|
||||
//
|
||||
WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;
|
||||
WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Update a bit of state on a block device. The location of the bit is
|
||||
calculated by the (Lba, Offset, bit). Here bit is determined by the
|
||||
the name of a certain bit.
|
||||
|
||||
|
||||
@param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
|
||||
@param Lba Lba of a block
|
||||
@param Offset Offset on the Lba
|
||||
@param NewBit New value that will override the old value if it can be change
|
||||
|
||||
@retval EFI_SUCCESS A state bit has been updated successfully
|
||||
@retval Others Access block device error.
|
||||
Notes:
|
||||
Assume all bits of State are inside the same BYTE.
|
||||
@retval EFI_ABORTED Read block fail
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwUpdateFvState (
|
||||
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN Offset,
|
||||
IN UINT8 NewBit
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT8 State;
|
||||
UINTN Length;
|
||||
|
||||
//
|
||||
// Read state from device, assume State is only one byte.
|
||||
//
|
||||
Length = sizeof (UINT8);
|
||||
Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
State ^= FTW_POLARITY_REVERT;
|
||||
State = (UINT8) (State | NewBit);
|
||||
State ^= FTW_POLARITY_REVERT;
|
||||
|
||||
//
|
||||
// Write state back to device
|
||||
//
|
||||
Length = sizeof (UINT8);
|
||||
Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the last Write record pointer.
|
||||
The last record is the record whose 'complete' state hasn't been set.
|
||||
After all, this header may be a EMPTY header entry for next Allocate.
|
||||
|
||||
|
||||
@param FtwLiteDevice Private data of this driver
|
||||
@param FtwLastRecord Pointer to retrieve the last write record
|
||||
|
||||
@retval EFI_SUCCESS Get the last write record successfully
|
||||
@retval EFI_ABORTED The FTW work space is damaged
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwGetLastRecord (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
OUT EFI_FTW_LITE_RECORD **FtwLastRecord
|
||||
)
|
||||
{
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
|
||||
*FtwLastRecord = NULL;
|
||||
Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);
|
||||
while (Record->WriteCompleted == FTW_VALID_STATE) {
|
||||
//
|
||||
// If Offset exceed the FTW work space boudary, return error.
|
||||
//
|
||||
if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Record++;
|
||||
}
|
||||
//
|
||||
// Last write record is found
|
||||
//
|
||||
*FtwLastRecord = Record;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Read from working block to refresh the work space in memory.
|
||||
|
||||
|
||||
@param FtwLiteDevice Point to private data of FTW driver
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_ABORTED The function could not complete successfully.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
WorkSpaceRefresh (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Length;
|
||||
UINTN Offset;
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
|
||||
//
|
||||
// Initialize WorkSpace as FTW_ERASED_BYTE
|
||||
//
|
||||
SetMem (
|
||||
FtwLiteDevice->FtwWorkSpace,
|
||||
FtwLiteDevice->FtwWorkSpaceSize,
|
||||
FTW_ERASED_BYTE
|
||||
);
|
||||
|
||||
//
|
||||
// Read from working block
|
||||
//
|
||||
Length = FtwLiteDevice->FtwWorkSpaceSize;
|
||||
Status = FtwLiteDevice->FtwFvBlock->Read (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkSpaceLba,
|
||||
FtwLiteDevice->FtwWorkSpaceBase,
|
||||
&Length,
|
||||
FtwLiteDevice->FtwWorkSpace
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
//
|
||||
// Refresh the FtwLastRecord
|
||||
//
|
||||
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
|
||||
|
||||
Record = FtwLiteDevice->FtwLastRecord;
|
||||
Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;
|
||||
|
||||
//
|
||||
// If work space has error or Record is out of the workspace limit, THEN
|
||||
// call reclaim.
|
||||
//
|
||||
if (EFI_ERROR (Status) || (Offset + FTW_LITE_RECORD_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {
|
||||
//
|
||||
// reclaim work space in working block.
|
||||
//
|
||||
Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim workspace - %r\n", Status));
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Reclaim the work space on the working block.
|
||||
|
||||
|
||||
@param FtwLiteDevice Point to private data of FTW driver
|
||||
@param PreserveRecord Whether get the last record or not
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully
|
||||
@retval EFI_OUT_OF_RESOURCES Allocate memory error
|
||||
@retval EFI_ABORTED The function could not complete successfully
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FtwReclaimWorkSpace (
|
||||
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
|
||||
IN BOOLEAN PreserveRecord
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT8 *TempBuffer;
|
||||
UINTN TempBufferSize;
|
||||
UINT8 *Ptr;
|
||||
UINTN Length;
|
||||
UINTN Index;
|
||||
UINTN SpareBufferSize;
|
||||
UINT8 *SpareBuffer;
|
||||
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
|
||||
EFI_FTW_LITE_RECORD *Record;
|
||||
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: start to reclaim work space\n"));
|
||||
|
||||
//
|
||||
// Read all original data from working block to a memory buffer
|
||||
//
|
||||
TempBufferSize = FtwLiteDevice->SpareAreaLength;
|
||||
TempBuffer = AllocateZeroPool (TempBufferSize);
|
||||
if (TempBuffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ptr = TempBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Length = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwFvBlock->Read (
|
||||
FtwLiteDevice->FtwFvBlock,
|
||||
FtwLiteDevice->FtwWorkBlockLba + Index,
|
||||
0,
|
||||
&Length,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (TempBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += Length;
|
||||
}
|
||||
//
|
||||
// Clean up the workspace, remove all the completed records.
|
||||
//
|
||||
Ptr = TempBuffer +
|
||||
((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *
|
||||
FtwLiteDevice->BlockSize + FtwLiteDevice->FtwWorkSpaceBase;
|
||||
|
||||
//
|
||||
// Clear the content of buffer that will save the new work space data
|
||||
//
|
||||
SetMem (Ptr, FtwLiteDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);
|
||||
|
||||
//
|
||||
// Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
|
||||
//
|
||||
CopyMem (
|
||||
Ptr,
|
||||
FtwLiteDevice->FtwWorkSpaceHeader,
|
||||
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
|
||||
);
|
||||
if (PreserveRecord) {
|
||||
//
|
||||
// Get the last record
|
||||
//
|
||||
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
|
||||
Record = FtwLiteDevice->FtwLastRecord;
|
||||
if (!EFI_ERROR (Status) &&
|
||||
Record != NULL &&
|
||||
Record->WriteAllocated == FTW_VALID_STATE &&
|
||||
Record->WriteCompleted != FTW_VALID_STATE) {
|
||||
CopyMem (
|
||||
(UINT8 *) Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
|
||||
Record,
|
||||
FTW_LITE_RECORD_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CopyMem (
|
||||
FtwLiteDevice->FtwWorkSpace,
|
||||
Ptr,
|
||||
FtwLiteDevice->FtwWorkSpaceSize
|
||||
);
|
||||
|
||||
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
|
||||
|
||||
//
|
||||
// Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
|
||||
//
|
||||
WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;
|
||||
WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;
|
||||
WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
|
||||
|
||||
//
|
||||
// Try to keep the content of spare block
|
||||
// Save spare block into a spare backup memory buffer (Sparebuffer)
|
||||
//
|
||||
SpareBufferSize = FtwLiteDevice->SpareAreaLength;
|
||||
SpareBuffer = AllocatePool (SpareBufferSize);
|
||||
if (SpareBuffer == NULL) {
|
||||
FreePool (TempBuffer);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ptr = SpareBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Length = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Read (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&Length,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (TempBuffer);
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += Length;
|
||||
}
|
||||
//
|
||||
// Write the memory buffer to spare block
|
||||
//
|
||||
Status = FtwEraseSpareBlock (FtwLiteDevice);
|
||||
Ptr = TempBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Length = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Write (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&Length,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (TempBuffer);
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += Length;
|
||||
}
|
||||
//
|
||||
// Free TempBuffer
|
||||
//
|
||||
FreePool (TempBuffer);
|
||||
|
||||
//
|
||||
// Write the spare block to working block
|
||||
//
|
||||
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (SpareBuffer);
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
|
||||
//
|
||||
Status = FtwEraseSpareBlock (FtwLiteDevice);
|
||||
Ptr = SpareBuffer;
|
||||
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
|
||||
Length = FtwLiteDevice->BlockSize;
|
||||
Status = FtwLiteDevice->FtwBackupFvb->Write (
|
||||
FtwLiteDevice->FtwBackupFvb,
|
||||
FtwLiteDevice->FtwSpareLba + Index,
|
||||
0,
|
||||
&Length,
|
||||
Ptr
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (SpareBuffer);
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
Ptr += Length;
|
||||
}
|
||||
|
||||
FreePool (SpareBuffer);
|
||||
|
||||
DEBUG ((EFI_D_ERROR, "FtwLite: reclaim work space success\n"));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
@ -201,21 +201,21 @@ FtwVariableSpace (
|
||||
IN UINTN BufferSize
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE FvbHandle;
|
||||
EFI_FTW_LITE_PROTOCOL *FtwLiteProtocol;
|
||||
EFI_LBA VarLba;
|
||||
UINTN VarOffset;
|
||||
UINT8 *FtwBuffer;
|
||||
UINTN FtwBufferSize;
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE FvbHandle;
|
||||
EFI_LBA VarLba;
|
||||
UINTN VarOffset;
|
||||
UINT8 *FtwBuffer;
|
||||
UINTN FtwBufferSize;
|
||||
EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
|
||||
|
||||
//
|
||||
// Locate fault tolerant write protocol
|
||||
//
|
||||
Status = gBS->LocateProtocol (
|
||||
&gEfiFaultTolerantWriteLiteProtocolGuid,
|
||||
&gEfiFaultTolerantWriteProtocolGuid,
|
||||
NULL,
|
||||
(VOID **) &FtwLiteProtocol
|
||||
(VOID **) &FtwProtocol
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
@ -249,13 +249,14 @@ FtwVariableSpace (
|
||||
//
|
||||
// FTW write record
|
||||
//
|
||||
Status = FtwLiteProtocol->Write (
|
||||
FtwLiteProtocol,
|
||||
FvbHandle,
|
||||
Status = FtwProtocol->Write (
|
||||
FtwProtocol,
|
||||
VarLba, // LBA
|
||||
VarOffset, // Offset
|
||||
&FtwBufferSize, // NumBytes
|
||||
FtwBuffer
|
||||
FtwBufferSize, // NumBytes
|
||||
NULL, // PrivateData NULL
|
||||
FvbHandle, // Fvb Handle
|
||||
FtwBuffer // write buffer
|
||||
);
|
||||
|
||||
FreePool (FtwBuffer);
|
||||
|
@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Protocol/VariableWrite.h>
|
||||
#include <Protocol/FaultTolerantWriteLite.h>
|
||||
#include <Protocol/FaultTolerantWrite.h>
|
||||
#include <Protocol/FirmwareVolumeBlock.h>
|
||||
#include <Protocol/Variable.h>
|
||||
#include <Library/PcdLib.h>
|
||||
|
@ -55,9 +55,9 @@
|
||||
|
||||
[Protocols]
|
||||
gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gEfiFaultTolerantWriteLiteProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES
|
||||
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
|
||||
gEfiFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[Guids]
|
||||
gEfiVariableGuid ## PRODUCES ## Configuration Table Guid
|
||||
@ -75,7 +75,7 @@
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## SOMETIME_CONSUMES (statistic the information of variable.)
|
||||
|
||||
[Depex]
|
||||
gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteLiteProtocolGuid
|
||||
gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid
|
||||
|
||||
# [Event]
|
||||
# ##
|
||||
|
Loading…
x
Reference in New Issue
Block a user