ftwlite.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 971 行 · 第 1/3 页
C
971 行
EfiInitializeDriverLib (ImageHandle, SystemTable);
//
// Allocate Private data of this driver,
// INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
//
FtwLiteDevice = NULL;
FtwLiteDevice = EfiLibAllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);
if (FtwLiteDevice != NULL) {
Status = EFI_SUCCESS;
} else {
Status = EFI_OUT_OF_RESOURCES;
}
ASSERT_EFI_ERROR (Status);
EfiZeroMem (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->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE;
EfiSetMem (
FtwLiteDevice->FtwWorkSpace,
FtwLiteDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace;
FtwLiteDevice->FtwLastRecord = NULL;
//
// Get EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL protocol Boot Firmware Device,
// Using this protocol to access the working block and spare block
//
Status = EfiLibGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
ASSERT_EFI_ERROR (Status);
FtwLiteDevice->SpareAreaLength = 0;
FtwLiteDevice->WorkSpaceLength = 0;
for (;;) {
Status = GetNextGuidHob (&HobList, &gEfiFlashMapHobGuid, &Buffer, NULL);
if (EFI_ERROR (Status)) {
break;
}
FlashMapEntry = (EFI_FLASH_MAP_ENTRY_DATA *) Buffer;
//
// Get the FTW work space Flash Map SUB area
//
if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_STATE) && (FlashMapEntry->NumEntries == 1)) {
FtwLiteDevice->WorkSpaceAddress = FlashMapEntry->Entries[0].Base;
FtwLiteDevice->WorkSpaceLength = (UINTN) FlashMapEntry->Entries[0].Length;
}
//
// Get the FTW backup SUB area
//
if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_BACKUP) && (FlashMapEntry->NumEntries == 1)) {
FtwLiteDevice->SpareAreaAddress = FlashMapEntry->Entries[0].Base;
FtwLiteDevice->SpareAreaLength = (UINTN) FlashMapEntry->Entries[0].Length;
}
}
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 < (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->FvBlockMap[0];
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) {
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) {
FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;
//
// Get the Work space size and Base(Offset)
//
FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength;
FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->BlockLength * (LbaIndex - 1)));
break;
}
}
//
// end for
//
FvbMapEntry++;
}
//
// end while
//
}
}
if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&
(FtwLiteDevice->SpareAreaAddress < (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->FvBlockMap[0];
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) {
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) {
//
// Get the NumberOfSpareBlock and SizeOfSpareBlock
//
FtwLiteDevice->FtwSpareLba = LbaIndex - 1;
FtwLiteDevice->SizeOfSpareBlock = FvbMapEntry->BlockLength;
FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->SizeOfSpareBlock;
//
// Check the range of spare area to make sure that it's in FV range
//
ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks);
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) {
FtwLiteDevice->FtwWorkBlockLba = 0;
}
if ((FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||
(FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))
) {
DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));
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_FTW_LITE, "FtwLite: Workspace invalid, read from backup\n"));
//
// Read from spare block
//
Length = FtwLiteDevice->FtwWorkSpaceSize;
WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
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_FTW_LITE, "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)) {
return EFI_ABORTED;
}
} else {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Both are invalid, init workspace\n"));
//
// If both are invalid, then initialize work space.
//
EfiSetMem (
FtwLiteDevice->FtwWorkSpace,
FtwLiteDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);
//
// Write to work space on the working block
//
Length = FtwLiteDevice->FtwWorkSpaceSize;
Status = FtwLiteDevice->FtwFvBlock->Write (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase,
&Length,
FtwLiteDevice->FtwWorkSpace
);
if (EFI_ERROR (Status)) {
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)) {
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_FTW_LITE, "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_FTW_LITE, "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 += WRITE_TOTAL_SIZE;
}
if (!IsErasedFlashBuffer (
FTW_ERASE_POLARITY,
FtwLiteDevice->FtwWorkSpace + Offset,
FtwLiteDevice->FtwWorkSpaceSize - Offset
)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n"));
Status = FtwReclaimWorkSpace (FtwLiteDevice);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status));
return EFI_ABORTED;
}
}
return EFI_SUCCESS;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?