mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-28 08:04:07 +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
|
|
@ -174,11 +174,6 @@
|
|||||||
## Include/Protocol/GenericMemoryTest.h
|
## Include/Protocol/GenericMemoryTest.h
|
||||||
gEfiGenericMemTestProtocolGuid = { 0x309DE7F1, 0x7F5E, 0x4ACE, { 0xB4, 0x9C, 0x53, 0x1B, 0xE5, 0xAA, 0x95, 0xEF }}
|
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
|
## This protocol provides the interfaces to Get/Set the current video mode for GOP/UGA screen
|
||||||
## Include/Protocol/ConsoleControl.h
|
## Include/Protocol/ConsoleControl.h
|
||||||
gEfiConsoleControlProtocolGuid = { 0xF42F7782, 0x012E, 0x4C12, { 0x99, 0x56, 0x49, 0xF9, 0x43, 0x04, 0xF7, 0x21 }}
|
gEfiConsoleControlProtocolGuid = { 0xF42F7782, 0x012E, 0x4C12, { 0x99, 0x56, 0x49, 0xF9, 0x43, 0x04, 0xF7, 0x21 }}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -203,19 +203,19 @@ FtwVariableSpace (
|
|||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
EFI_HANDLE FvbHandle;
|
EFI_HANDLE FvbHandle;
|
||||||
EFI_FTW_LITE_PROTOCOL *FtwLiteProtocol;
|
|
||||||
EFI_LBA VarLba;
|
EFI_LBA VarLba;
|
||||||
UINTN VarOffset;
|
UINTN VarOffset;
|
||||||
UINT8 *FtwBuffer;
|
UINT8 *FtwBuffer;
|
||||||
UINTN FtwBufferSize;
|
UINTN FtwBufferSize;
|
||||||
|
EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Locate fault tolerant write protocol
|
// Locate fault tolerant write protocol
|
||||||
//
|
//
|
||||||
Status = gBS->LocateProtocol (
|
Status = gBS->LocateProtocol (
|
||||||
&gEfiFaultTolerantWriteLiteProtocolGuid,
|
&gEfiFaultTolerantWriteProtocolGuid,
|
||||||
NULL,
|
NULL,
|
||||||
(VOID **) &FtwLiteProtocol
|
(VOID **) &FtwProtocol
|
||||||
);
|
);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return EFI_NOT_FOUND;
|
return EFI_NOT_FOUND;
|
||||||
@ -249,13 +249,14 @@ FtwVariableSpace (
|
|||||||
//
|
//
|
||||||
// FTW write record
|
// FTW write record
|
||||||
//
|
//
|
||||||
Status = FtwLiteProtocol->Write (
|
Status = FtwProtocol->Write (
|
||||||
FtwLiteProtocol,
|
FtwProtocol,
|
||||||
FvbHandle,
|
|
||||||
VarLba, // LBA
|
VarLba, // LBA
|
||||||
VarOffset, // Offset
|
VarOffset, // Offset
|
||||||
&FtwBufferSize, // NumBytes
|
FtwBufferSize, // NumBytes
|
||||||
FtwBuffer
|
NULL, // PrivateData NULL
|
||||||
|
FvbHandle, // Fvb Handle
|
||||||
|
FtwBuffer // write buffer
|
||||||
);
|
);
|
||||||
|
|
||||||
FreePool (FtwBuffer);
|
FreePool (FtwBuffer);
|
||||||
|
@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
|
|
||||||
#include <PiDxe.h>
|
#include <PiDxe.h>
|
||||||
#include <Protocol/VariableWrite.h>
|
#include <Protocol/VariableWrite.h>
|
||||||
#include <Protocol/FaultTolerantWriteLite.h>
|
#include <Protocol/FaultTolerantWrite.h>
|
||||||
#include <Protocol/FirmwareVolumeBlock.h>
|
#include <Protocol/FirmwareVolumeBlock.h>
|
||||||
#include <Protocol/Variable.h>
|
#include <Protocol/Variable.h>
|
||||||
#include <Library/PcdLib.h>
|
#include <Library/PcdLib.h>
|
||||||
|
@ -55,9 +55,9 @@
|
|||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
|
gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
|
||||||
gEfiFaultTolerantWriteLiteProtocolGuid ## SOMETIMES_CONSUMES
|
|
||||||
gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES
|
gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES
|
||||||
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
|
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
|
||||||
|
gEfiFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
|
||||||
|
|
||||||
[Guids]
|
[Guids]
|
||||||
gEfiVariableGuid ## PRODUCES ## Configuration Table Guid
|
gEfiVariableGuid ## PRODUCES ## Configuration Table Guid
|
||||||
@ -75,7 +75,7 @@
|
|||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## SOMETIME_CONSUMES (statistic the information of variable.)
|
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## SOMETIME_CONSUMES (statistic the information of variable.)
|
||||||
|
|
||||||
[Depex]
|
[Depex]
|
||||||
gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteLiteProtocolGuid
|
gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid
|
||||||
|
|
||||||
# [Event]
|
# [Event]
|
||||||
# ##
|
# ##
|
||||||
|
Loading…
x
Reference in New Issue
Block a user