+++ /dev/null
-/** @file\r
- Functions in this file will program the image into flash area.\r
-\r
- Copyright (c) 2002 - 2018, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "UpdateDriver.h"\r
-\r
-/**\r
- Write a block size data into flash.\r
-\r
- @param FvbProtocol Pointer to FVB protocol.\r
- @param Lba Logic block index to be updated.\r
- @param BlockSize Block size\r
- @param Buffer Buffer data to be written.\r
-\r
- @retval EFI_SUCCESS Write data successfully.\r
- @retval other errors Write data failed.\r
-\r
-**/\r
-EFI_STATUS\r
-UpdateOneBlock (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN EFI_LBA Lba,\r
- IN UINTN BlockSize,\r
- IN UINT8 *Buffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Size;\r
-\r
- //\r
- // First erase the block\r
- //\r
- Status = FvbProtocol->EraseBlocks (\r
- FvbProtocol,\r
- Lba, // Lba\r
- 1, // NumOfBlocks\r
- EFI_LBA_LIST_TERMINATOR\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Write the block\r
- //\r
- Size = BlockSize;\r
- Status = FvbProtocol->Write (\r
- FvbProtocol,\r
- Lba, // Lba\r
- 0, // Offset\r
- &Size, // Size\r
- Buffer // Buffer\r
- );\r
- if ((EFI_ERROR (Status)) || (Size != BlockSize)) {\r
- return Status;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Write buffer data in a flash block.\r
-\r
- @param FvbProtocol Pointer to FVB protocol.\r
- @param Lba Logic block index to be updated.\r
- @param Offset The offset within the block.\r
- @param Length Size of buffer to be updated.\r
- @param BlockSize Block size.\r
- @param Buffer Buffer data to be updated.\r
-\r
- @retval EFI_SUCCESS Write data successfully.\r
- @retval other errors Write data failed.\r
-\r
-**/\r
-EFI_STATUS\r
-UpdateBufferInOneBlock (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN EFI_LBA Lba,\r
- IN UINTN Offset,\r
- IN UINTN Length,\r
- IN UINTN BlockSize,\r
- IN UINT8 *Buffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Size;\r
- UINT8 *ReservedBuffer;\r
-\r
- //\r
- // If we are going to update a whole block\r
- //\r
- if ((Offset == 0) && (Length == BlockSize)) {\r
- Status = UpdateOneBlock (\r
- FvbProtocol,\r
- Lba,\r
- BlockSize,\r
- Buffer\r
- );\r
- return Status;\r
- }\r
-\r
- //\r
- // If it is not a full block update, we need to coalesce data in\r
- // the block that is not going to be updated and new data together.\r
- //\r
-\r
- //\r
- // Allocate a reserved buffer to make up the final buffer for update\r
- //\r
- ReservedBuffer = NULL;\r
- ReservedBuffer = AllocatePool (BlockSize);\r
- if (ReservedBuffer == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // First get the original content of the block\r
- //\r
- Size = BlockSize;\r
- Status = FvbProtocol->Read (\r
- FvbProtocol,\r
- Lba,\r
- 0,\r
- &Size,\r
- ReservedBuffer\r
- );\r
- if ((EFI_ERROR (Status)) || (Size != BlockSize)) {\r
- FreePool (ReservedBuffer);\r
- return Status;\r
- }\r
-\r
- //\r
- // Overwrite the reserved buffer with new content\r
- //\r
- CopyMem (ReservedBuffer + Offset, Buffer, Length);\r
-\r
- Status = UpdateOneBlock (\r
- FvbProtocol,\r
- Lba,\r
- BlockSize,\r
- ReservedBuffer\r
- );\r
-\r
- FreePool (ReservedBuffer);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Get the last write log, and check the status of last write.\r
- If not complete, restart will be taken.\r
-\r
- @param FvbHandle Handle of FVB protocol.\r
- @param FtwProtocol FTW protocol instance.\r
- @param ConfigData Config data on updating driver.\r
- @param PrivateDataSize bytes from the private data\r
- stored for this write.\r
- @param PrivateData A pointer to a buffer. The function will copy.\r
- @param Lba The logical block address of the last write.\r
- @param Offset The offset within the block of the last write.\r
- @param Length The length of the last write.\r
- @param Pending A Boolean value with TRUE indicating\r
- that the write was completed.\r
-\r
- @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
- @retval EFI_ABORTED The FTW work space is damaged.\r
- @retval EFI_NOT_FOUND The last write is not done by this driver.\r
- @retval EFI_SUCCESS Last write log is got.\r
-\r
-**/\r
-EFI_STATUS\r
-RetrieveLastWrite (\r
- IN EFI_HANDLE FvbHandle,\r
- IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol,\r
- IN UPDATE_CONFIG_DATA *ConfigData,\r
- IN UINTN PrivateDataSize,\r
- IN OUT UPDATE_PRIVATE_DATA *PrivateData,\r
- IN OUT EFI_LBA *Lba,\r
- IN OUT UINTN *Offset,\r
- IN OUT UINTN *Length,\r
- IN OUT BOOLEAN *Pending\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_GUID CallerId;\r
- UINTN PrivateBufferSize;\r
- BOOLEAN Complete;\r
- VOID *PrivateDataBuffer;\r
-\r
- //\r
- // Get the last write\r
- //\r
- *Pending = FALSE;\r
- PrivateBufferSize = PrivateDataSize;\r
- PrivateDataBuffer = NULL;\r
- Status = FtwProtocol->GetLastWrite (\r
- FtwProtocol,\r
- &CallerId,\r
- Lba,\r
- Offset,\r
- Length,\r
- &PrivateBufferSize,\r
- PrivateData,\r
- &Complete\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // If there is no incompleted record, return success.\r
- //\r
- if ((Status == EFI_NOT_FOUND) && Complete) {\r
- return EFI_SUCCESS;\r
- } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
- //\r
- // If buffer too small, reallocate buffer and call getlastwrite again\r
- //\r
- PrivateDataBuffer = AllocatePool (PrivateBufferSize);\r
-\r
- if (PrivateDataBuffer == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Status = FtwProtocol->GetLastWrite (\r
- FtwProtocol,\r
- &CallerId,\r
- Lba,\r
- Offset,\r
- Length,\r
- &PrivateBufferSize,\r
- PrivateDataBuffer,\r
- &Complete\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool ( PrivateDataBuffer);\r
- return EFI_ABORTED;\r
- } else {\r
- CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize);\r
- FreePool (PrivateDataBuffer);\r
- PrivateDataBuffer = NULL;\r
- }\r
- } else {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- *Pending = TRUE;\r
-\r
- //\r
- // If the caller is not the update driver, then return.\r
- // The update driver cannot continue to perform the update\r
- //\r
- if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Check the private data and see if it is the one I need.\r
- //\r
- if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // If the caller is the update driver and complete is not true, then restart().\r
- //\r
- if (!Complete) {\r
- //\r
- // Re-start the update\r
- //\r
- Status = FtwProtocol->Restart (\r
- FtwProtocol,\r
- FvbHandle\r
- );\r
- //\r
- // If restart() error, then abort().\r
- //\r
- if (EFI_ERROR (Status)) {\r
- FtwProtocol->Abort (FtwProtocol);\r
- //\r
- // Now set Pending as FALSE as this record has been cleared\r
- //\r
- *Pending = FALSE;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Update the whole FV image in fault tolerant write method.\r
-\r
- @param FvbHandle Handle of FVB protocol for the updated flash range.\r
- @param FvbProtocol FVB protocol.\r
- @param BlockMap Block array to specify flash area.\r
- @param ConfigData Config data on updating driver.\r
- @param ImageBuffer Image buffer to be updated.\r
- @param ImageSize Image size.\r
-\r
- @retval EFI_SUCCESS FV image is writed into flash.\r
- @retval EFI_INVALID_PARAMETER Config data is not valid.\r
- @retval EFI_NOT_FOUND FTW protocol doesn't exist.\r
- @retval EFI_OUT_OF_RESOURCES No enough backup space.\r
- @retval EFI_ABORTED Error happen when update FV.\r
-\r
-**/\r
-EFI_STATUS\r
-FaultTolerantUpdateOnWholeFv (\r
- IN EFI_HANDLE FvbHandle,\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,\r
- IN UPDATE_CONFIG_DATA *ConfigData,\r
- IN UINT8 *ImageBuffer,\r
- IN UINTN ImageSize\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;\r
- UINTN MaxBlockSize;\r
- UINTN FtwMaxBlockSize;\r
- BOOLEAN Pending;\r
- UPDATE_PRIVATE_DATA PrivateData;\r
- EFI_LBA PendingLba;\r
- EFI_LBA Lba;\r
- UINTN PendingOffset;\r
- UINTN Offset;\r
- UINTN PendingLength;\r
- UINTN Length;\r
- EFI_FV_BLOCK_MAP_ENTRY *PtrMap;\r
- UINTN NumOfBlocks;\r
- UINTN Index;\r
- UINT8 *UpdateBuffer;\r
-\r
- if ((ConfigData->UpdateType != UpdateWholeFV)\r
- || (!ConfigData->FaultTolerant)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Get the FTW protocol\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiFaultTolerantWriteProtocolGuid,\r
- NULL,\r
- (VOID **) &FtwProtocol\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Get the maximum block size of the FV, and number of blocks\r
- // NumOfBlocks will be the NumOfUdpates.\r
- //\r
- MaxBlockSize = 0;\r
- NumOfBlocks = 0;\r
- PtrMap = BlockMap;\r
- while (TRUE) {\r
- if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
- break;\r
- }\r
- if (MaxBlockSize < PtrMap->Length) {\r
- MaxBlockSize = PtrMap->Length;\r
- }\r
- NumOfBlocks = NumOfBlocks + PtrMap->NumBlocks;\r
- PtrMap++;\r
- }\r
-\r
- FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);\r
- //\r
- // Not enough backup space. return directly\r
- //\r
- if (FtwMaxBlockSize < MaxBlockSize) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- PendingLba = 0;\r
- PendingOffset = 0;\r
- PendingLength = 0;\r
- Pending = FALSE;\r
-\r
- //\r
- // Fault Tolerant Write can only support actual fault tolerance if the write\r
- // is a reclaim operation, which means the data buffer (new and old) are\r
- // acutally both stored in flash. But for component update write, the data\r
- // are now in memory. So we cannot actually recover the data after power\r
- // failure.\r
- //\r
- Status = RetrieveLastWrite (\r
- FvbHandle,\r
- FtwProtocol,\r
- ConfigData,\r
- sizeof (UPDATE_PRIVATE_DATA),\r
- &PrivateData,\r
- &PendingLba,\r
- &PendingOffset,\r
- &PendingLength,\r
- &Pending\r
- );\r
-\r
- if (Pending && (Status == EFI_NOT_FOUND)) {\r
- //\r
- // Cannot continue with the write operation\r
- //\r
- return EFI_ABORTED;\r
- }\r
-\r
- if (EFI_ERROR(Status)) {\r
- return EFI_ABORTED;\r
- }\r
-\r
- //\r
- // Currently we start from the pending write if there is any. But as we\r
- // are going to update a whole FV, we can just abort last write and start\r
- // from the very begining.\r
- //\r
- if (!Pending) {\r
- //\r
- // Now allocte the update private data in FTW. If there is pending\r
- // write, it has already been allocated and no need to allocate here.\r
- //\r
- Status = FtwProtocol->Allocate (\r
- FtwProtocol,\r
- &gEfiCallerIdGuid,\r
- sizeof (UPDATE_PRIVATE_DATA),\r
- NumOfBlocks\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- //\r
- // Perform the update now. If there are pending writes, we need to\r
- // start from the pending write instead of the very beginning.\r
- //\r
- PtrMap = BlockMap;\r
- Lba = 0;\r
- Offset = 0;\r
- UpdateBuffer = ImageBuffer;\r
- CopyMem (\r
- (VOID *) &PrivateData.FileGuid,\r
- (VOID *) &ConfigData->FileGuid,\r
- sizeof (EFI_GUID)\r
- );\r
-\r
- while (TRUE) {\r
- if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
- break;\r
- }\r
- Length = (UINTN)PtrMap->Length;\r
- for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
-\r
- //\r
- // Add an extra check here to see if the pending record is correct\r
- //\r
- if (Pending && (Lba == PendingLba)) {\r
- if ((PendingOffset != Offset) || (PendingLength != Length)) {\r
- //\r
- // Error.\r
- //\r
- Status = EFI_ABORTED;\r
- break;\r
- }\r
- }\r
-\r
- if ((!Pending) || (Lba >= PendingLba)) {\r
- Status = FtwProtocol->Write (\r
- FtwProtocol,\r
- Lba, // Lba\r
- Offset, // Offset\r
- Length, // Size\r
- &PrivateData, // Private Data\r
- FvbHandle, // FVB handle\r
- UpdateBuffer // Buffer\r
- );\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- Lba++;\r
- UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + Length);\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- PtrMap++;\r
- }\r
-\r
- return Status;\r
-\r
-}\r
-\r
-/**\r
- Directly update the whole FV image without fault tolerant write method.\r
-\r
- @param FvbHandle Handle of FVB protocol for the updated flash range.\r
- @param FvbProtocol FVB protocol.\r
- @param BlockMap Block array to specify flash area.\r
- @param ConfigData Config data on updating driver.\r
- @param ImageBuffer Image buffer to be updated.\r
- @param ImageSize Image size.\r
-\r
- @retval EFI_SUCCESS FV image is writed into flash.\r
- @retval EFI_INVALID_PARAMETER Config data is not valid.\r
- @retval EFI_ABORTED Error happen when update FV.\r
-\r
-**/\r
-EFI_STATUS\r
-NonFaultTolerantUpdateOnWholeFv (\r
- IN EFI_HANDLE FvbHandle,\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,\r
- IN UPDATE_CONFIG_DATA *ConfigData,\r
- IN UINT8 *ImageBuffer,\r
- IN UINTN ImageSize\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FV_BLOCK_MAP_ENTRY *PtrMap;\r
- UINTN Index;\r
- EFI_LBA UpdateLba;\r
- UINT8 *UpdateBuffer;\r
- UINTN UpdateSize;\r
-\r
- if ((ConfigData->UpdateType != UpdateWholeFV )\r
- || (ConfigData->FaultTolerant)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
- PtrMap = BlockMap;\r
- UpdateLba = 0;\r
- UpdateBuffer = ImageBuffer;\r
-\r
- //\r
- // Perform the update now\r
- //\r
- while (TRUE) {\r
- if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
- break;\r
- }\r
- UpdateSize = (UINTN)PtrMap->Length;\r
- for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
- Status = UpdateOneBlock (\r
- FvbProtocol,\r
- UpdateLba,\r
- UpdateSize,\r
- UpdateBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
-\r
- UpdateLba++;\r
- UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize);\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- PtrMap++;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Update the whole FV image, and reinsall FVB protocol for the updated FV image.\r
-\r
- @param FvbHandle Handle of FVB protocol for the updated flash range.\r
- @param FvbProtocol FVB protocol.\r
- @param ConfigData Config data on updating driver.\r
- @param ImageBuffer Image buffer to be updated.\r
- @param ImageSize Image size.\r
-\r
- @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV.\r
- Or Image size is not same to the size of whole FV.\r
- @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated.\r
- @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled.\r
-\r
-**/\r
-EFI_STATUS\r
-PerformUpdateOnWholeFv (\r
- IN EFI_HANDLE FvbHandle,\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN UPDATE_CONFIG_DATA *ConfigData,\r
- IN UINT8 *ImageBuffer,\r
- IN UINTN ImageSize\r
-)\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
- CHAR16 *TmpStr;\r
-\r
- if (ConfigData->UpdateType != UpdateWholeFV) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Get the header of the firmware volume\r
- //\r
- FwVolHeader = NULL;\r
- FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength);\r
- if (FwVolHeader == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- CopyMem (\r
- FwVolHeader,\r
- (VOID *) ((UINTN) (ConfigData->BaseAddress)),\r
- ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength\r
- );\r
-\r
- //\r
- // Check if ImageSize is the same as the size of the whole FV\r
- //\r
- if ((UINT64)ImageSize != FwVolHeader->FvLength) {\r
- FreePool (FwVolHeader);\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Print on screen\r
- //\r
- TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL);\r
- if (TmpStr != NULL) {\r
- Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress));\r
- FreePool (TmpStr);\r
- }\r
-\r
- DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n",\r
- ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)));\r
-\r
- //\r
- // Get the block map of the firmware volume\r
- //\r
- BlockMap = &(FwVolHeader->BlockMap[0]);\r
-\r
- //\r
- // It is about the same if we are going to fault tolerantly update\r
- // a certain FV in our current design. But we divide non-fault tolerant\r
- // and fault tolerant udpate here for better maintenance as fault\r
- // tolerance may change and may be done more wisely if we have space.\r
- //\r
- if (ConfigData->FaultTolerant) {\r
- Status = FaultTolerantUpdateOnWholeFv (\r
- FvbHandle,\r
- FvbProtocol,\r
- BlockMap,\r
- ConfigData,\r
- ImageBuffer,\r
- ImageSize\r
- );\r
- } else {\r
- Status = NonFaultTolerantUpdateOnWholeFv (\r
- FvbHandle,\r
- FvbProtocol,\r
- BlockMap,\r
- ConfigData,\r
- ImageBuffer,\r
- ImageSize\r
- );\r
- }\r
-\r
- FreePool (FwVolHeader);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // As the whole FV has been replaced, the FV driver shall re-parse the\r
- // firmware volume. So re-install FVB protocol here\r
- //\r
- Status = gBS->ReinstallProtocolInterface (\r
- FvbHandle,\r
- &gEfiFirmwareVolumeBlockProtocolGuid,\r
- FvbProtocol,\r
- FvbProtocol\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Update certain file in the FV.\r
-\r
- @param FvbHandle Handle of FVB protocol for the updated flash range.\r
- @param FvbProtocol FVB protocol.\r
- @param ConfigData Config data on updating driver.\r
- @param ImageBuffer Image buffer to be updated.\r
- @param ImageSize Image size.\r
- @param FileType FFS file type.\r
- @param FileAttributes FFS file attribute\r
-\r
- @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile.\r
- Or Image size is not same to the size of whole FV.\r
- @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated.\r
- @retval EFI_SUCCESS The FFS file is added into FV.\r
-\r
-**/\r
-EFI_STATUS\r
-PerformUpdateOnFvFile (\r
- IN EFI_HANDLE FvbHandle,\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN UPDATE_CONFIG_DATA *ConfigData,\r
- IN UINT8 *ImageBuffer,\r
- IN UINTN ImageSize,\r
- IN EFI_FV_FILETYPE FileType,\r
- IN EFI_FV_FILE_ATTRIBUTES FileAttributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol;\r
- EFI_FV_WRITE_FILE_DATA FileData;\r
- CHAR16 *TmpStr;\r
-\r
- if (ConfigData->UpdateType != UpdateFvFile) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Print on screen\r
- //\r
- TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL);\r
- if (TmpStr != NULL) {\r
- Print (TmpStr, &(ConfigData->FileGuid));\r
- FreePool (TmpStr);\r
- }\r
-\r
- DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n",\r
- &(ConfigData->FileGuid)));\r
-\r
- //\r
- // Get Firmware volume protocol on this FVB protocol\r
- //\r
- Status = gBS->HandleProtocol (\r
- FvbHandle,\r
- &gEfiFirmwareVolume2ProtocolGuid,\r
- (VOID **) &FwVolProtocol\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // If it is a PEIM, we need first to rebase it before committing\r
- // the write to target\r
- //\r
- if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM )\r
- || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- FileData.NameGuid = &(ConfigData->FileGuid);\r
- FileData.Type = FileType;\r
- FileData.FileAttributes = FileAttributes;\r
- FileData.Buffer = ImageBuffer;\r
- FileData.BufferSize = (UINT32) ImageSize;\r
-\r
- Status = FwVolProtocol->WriteFile (\r
- FwVolProtocol,\r
- 1, // NumberOfFiles\r
- (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant,\r
- &FileData\r
- );\r
- return Status;\r
-}\r
-\r
-/**\r
- Update the buffer into flash area in fault tolerant write method.\r
-\r
- @param ImageBuffer Image buffer to be updated.\r
- @param SizeLeft Size of the image buffer.\r
- @param UpdatedSize Size of the updated buffer.\r
- @param ConfigData Config data on updating driver.\r
- @param FlashAddress Flash address to be updated as start address.\r
- @param FvbProtocol FVB protocol.\r
- @param FvbHandle Handle of FVB protocol for the updated flash range.\r
-\r
- @retval EFI_SUCCESS Buffer data is updated into flash.\r
- @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.\r
- @retval EFI_NOT_FOUND FTW protocol doesn't exist.\r
- @retval EFI_OUT_OF_RESOURCES No enough backup space.\r
- @retval EFI_ABORTED Error happen when update flash area.\r
-\r
-**/\r
-EFI_STATUS\r
-FaultTolerantUpdateOnPartFv (\r
- IN UINT8 *ImageBuffer,\r
- IN UINTN SizeLeft,\r
- IN OUT UINTN *UpdatedSize,\r
- IN UPDATE_CONFIG_DATA *ConfigData,\r
- IN EFI_PHYSICAL_ADDRESS FlashAddress,\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN EFI_HANDLE FvbHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp;\r
- EFI_PHYSICAL_ADDRESS BaseAddress;\r
- EFI_PHYSICAL_ADDRESS FvBase;\r
- EFI_PHYSICAL_ADDRESS NextBlock;\r
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
- EFI_FV_BLOCK_MAP_ENTRY *PtrMap;\r
- UINTN NumOfUpdates;\r
- UINTN TotalSize;\r
- EFI_PHYSICAL_ADDRESS StartAddress;\r
- EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;\r
- UINTN MaxBlockSize;\r
- UINTN FtwMaxBlockSize;\r
- BOOLEAN Pending;\r
- UPDATE_PRIVATE_DATA PrivateData;\r
- EFI_LBA PendingLba;\r
- EFI_LBA Lba;\r
- UINTN BlockSize;\r
- UINTN PendingOffset;\r
- UINTN Offset;\r
- UINTN PendingLength;\r
- UINTN Length;\r
- UINTN Index;\r
- UINT8 *Image;\r
-\r
- //\r
- // Get the block map to update the block one by one\r
- //\r
- Status = FvbProtocol->GetPhysicalAddress (\r
- FvbProtocol,\r
- &FvBase\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;\r
- if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (\r
- FwVolHeaderTmp->HeaderLength,\r
- FwVolHeaderTmp\r
- );\r
- if (FwVolHeader == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // For fault tolerant write, we have to know how many blocks we need to\r
- // update. So we will calculate number of updates and max block size first\r
- //\r
- NumOfUpdates = 0;\r
- MaxBlockSize = 0;\r
- TotalSize = SizeLeft;\r
- StartAddress = FlashAddress;\r
- BaseAddress = FvBase;\r
- BlockMap = &(FwVolHeader->BlockMap[0]);\r
- PtrMap = BlockMap;\r
-\r
- while (TotalSize > 0) {\r
- if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
- break;\r
- }\r
-\r
- BlockSize = PtrMap->Length;\r
- for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
- NextBlock = BaseAddress + BlockSize;\r
- //\r
- // Check if this block need to be updated\r
- //\r
- if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {\r
- //\r
- // Get the maximum block size\r
- //\r
- if (MaxBlockSize < BlockSize) {\r
- MaxBlockSize = BlockSize;\r
- }\r
-\r
- //\r
- // This block shall be udpated. So increment number of updates\r
- //\r
- NumOfUpdates++;\r
- Offset = (UINTN) (StartAddress - BaseAddress);\r
- Length = TotalSize;\r
- if ((Length + Offset ) > BlockSize) {\r
- Length = BlockSize - Offset;\r
- }\r
-\r
- StartAddress = StartAddress + Length;\r
- TotalSize = TotalSize - Length;\r
- if (TotalSize <= 0) {\r
- break;\r
- }\r
- }\r
- BaseAddress = NextBlock;\r
- }\r
- PtrMap++;\r
- }\r
-\r
- //\r
- // Get the FTW protocol\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiFaultTolerantWriteProtocolGuid,\r
- NULL,\r
- (VOID **) &FtwProtocol\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (FwVolHeader);\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);\r
-\r
- //\r
- // Not enough backup space. return directly\r
- //\r
- if (FtwMaxBlockSize < MaxBlockSize) {\r
- FreePool (FwVolHeader);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- PendingLba = 0;\r
- PendingOffset = 0;\r
- PendingLength = 0;\r
- Pending = FALSE;\r
-\r
- //\r
- // Fault Tolerant Write can only support actual fault tolerance if the write\r
- // is a reclaim operation, which means the data buffer (new and old) are\r
- // acutally both stored in flash. But for component update write, the data\r
- // are now in memory. So we cannot actually recover the data after power\r
- // failure.\r
- //\r
- Status = RetrieveLastWrite (\r
- FvbHandle,\r
- FtwProtocol,\r
- ConfigData,\r
- sizeof (UPDATE_PRIVATE_DATA),\r
- &PrivateData,\r
- &PendingLba,\r
- &PendingOffset,\r
- &PendingLength,\r
- &Pending\r
- );\r
- if (Pending && (Status == EFI_NOT_FOUND)) {\r
- //\r
- // I'm not the owner of the pending fault tolerant write record\r
- // Cannot continue with the write operation\r
- //\r
- FreePool (FwVolHeader);\r
- return EFI_ABORTED;\r
- }\r
-\r
- if (EFI_ERROR(Status)) {\r
- FreePool (FwVolHeader);\r
- return EFI_ABORTED;\r
- }\r
-\r
- //\r
- // Currently we start from the pending write if there is any. But if the\r
- // caller is exactly the same, and the new data is already a in memory, (it\r
- // cannot be stored in flash in last write,) we can just abort last write\r
- // and start from the very begining.\r
- //\r
- if (!Pending) {\r
- //\r
- // Now allocte the update private data in FTW. If there is pending\r
- // write, it has already been allocated and no need to allocate here.\r
- //\r
- Status = FtwProtocol->Allocate (\r
- FtwProtocol,\r
- &gEfiCallerIdGuid,\r
- sizeof (UPDATE_PRIVATE_DATA),\r
- NumOfUpdates\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (FwVolHeader);\r
- return Status;\r
- }\r
- }\r
-\r
- //\r
- // Perform the update now. If there are pending writes, we need to\r
- // start from the pending write instead of the very beginning.\r
- //\r
- TotalSize = SizeLeft;\r
- Lba = 0;\r
- StartAddress = FlashAddress;\r
- BaseAddress = FvBase;\r
- PtrMap = BlockMap;\r
- Image = ImageBuffer;\r
- CopyMem (\r
- (VOID *) &PrivateData.FileGuid,\r
- (VOID *) &ConfigData->FileGuid,\r
- sizeof (EFI_GUID)\r
- );\r
-\r
- while (TotalSize > 0) {\r
- if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
- break;\r
- }\r
-\r
- BlockSize = (UINTN)PtrMap->Length;\r
- for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
- NextBlock = BaseAddress + BlockSize;\r
- if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {\r
- //\r
- // So we need to update this block\r
- //\r
- Offset = (UINTN) (StartAddress - BaseAddress);\r
- Length = TotalSize;\r
- if ((Length + Offset ) > BlockSize) {\r
- Length = BlockSize - Offset;\r
- }\r
-\r
- //\r
- // Add an extra check here to see if the pending record is correct\r
- //\r
- if (Pending && (Lba == PendingLba)) {\r
- if ((PendingOffset != Offset) || (PendingLength != Length)) {\r
- //\r
- // Error.\r
- //\r
- Status = EFI_ABORTED;\r
- break;\r
- }\r
- }\r
-\r
- if ((!Pending) || (Lba >= PendingLba)) {\r
- DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length));\r
- Status = FtwProtocol->Write (\r
- FtwProtocol,\r
- Lba, // Lba\r
- Offset, // Offset\r
- Length, // Size\r
- &PrivateData, // Private Data\r
- FvbHandle, // FVB handle\r
- Image // Buffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Now increment StartAddress, ImageBuffer and decrease the\r
- // left size to prepare for the next block update.\r
- //\r
- StartAddress = StartAddress + Length;\r
- Image = Image + Length;\r
- TotalSize = TotalSize - Length;\r
- if (TotalSize <= 0) {\r
- break;\r
- }\r
- }\r
- BaseAddress = NextBlock;\r
- Lba++;\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- PtrMap++;\r
- }\r
-\r
- FreePool (FwVolHeader);\r
-\r
- *UpdatedSize = SizeLeft - TotalSize;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Directly update the buffer into flash area without fault tolerant write method.\r
-\r
- @param ImageBuffer Image buffer to be updated.\r
- @param SizeLeft Size of the image buffer.\r
- @param UpdatedSize Size of the updated buffer.\r
- @param FlashAddress Flash address to be updated as start address.\r
- @param FvbProtocol FVB protocol.\r
- @param FvbHandle Handle of FVB protocol for the updated flash range.\r
-\r
- @retval EFI_SUCCESS Buffer data is updated into flash.\r
- @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.\r
- @retval EFI_OUT_OF_RESOURCES No enough backup space.\r
-\r
-**/\r
-EFI_STATUS\r
-NonFaultTolerantUpdateOnPartFv (\r
- IN UINT8 *ImageBuffer,\r
- IN UINTN SizeLeft,\r
- IN OUT UINTN *UpdatedSize,\r
- IN EFI_PHYSICAL_ADDRESS FlashAddress,\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
- IN EFI_HANDLE FvbHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp;\r
- EFI_PHYSICAL_ADDRESS BaseAddress;\r
- EFI_PHYSICAL_ADDRESS NextBlock;\r
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
- UINTN Index;\r
- UINTN TotalSize;\r
- UINTN BlockSize;\r
- EFI_LBA Lba;\r
- UINTN Offset;\r
- UINTN Length;\r
- UINT8 *Image;\r
-\r
- //\r
- // Get the block map to update the block one by one\r
- //\r
- Status = FvbProtocol->GetPhysicalAddress (\r
- FvbProtocol,\r
- &BaseAddress\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
- if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (\r
- FwVolHeaderTmp->HeaderLength,\r
- FwVolHeaderTmp\r
- );\r
- if (FwVolHeader == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Image = ImageBuffer;\r
- TotalSize = SizeLeft;\r
- BlockMap = &(FwVolHeader->BlockMap[0]);\r
- Lba = 0;\r
-\r
- while (TotalSize > 0) {\r
- if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) {\r
- break;\r
- }\r
-\r
- BlockSize = BlockMap->Length;\r
- for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) {\r
- NextBlock = BaseAddress + BlockSize;\r
- if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) {\r
- //\r
- // So we need to update this block\r
- //\r
- Offset = (UINTN) FlashAddress - (UINTN) BaseAddress;\r
- Length = TotalSize;\r
- if ((Length + Offset ) > BlockSize) {\r
- Length = BlockSize - Offset;\r
- }\r
-\r
- DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length));\r
- //\r
- // Update the block\r
- //\r
- Status = UpdateBufferInOneBlock (\r
- FvbProtocol,\r
- Lba,\r
- Offset,\r
- Length,\r
- BlockSize,\r
- Image\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (FwVolHeader);\r
- return Status;\r
- }\r
-\r
- //\r
- // Now increment FlashAddress, ImageBuffer and decrease the\r
- // left size to prepare for the next block update.\r
- //\r
- FlashAddress = FlashAddress + Length;\r
- Image = Image + Length;\r
- TotalSize = TotalSize - Length;\r
- if (TotalSize <= 0) {\r
- break;\r
- }\r
- }\r
- BaseAddress = NextBlock;\r
- Lba++;\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- BlockMap++;\r
- }\r
-\r
- FreePool (FwVolHeader);\r
-\r
- *UpdatedSize = SizeLeft - TotalSize;\r
-\r
- return EFI_SUCCESS;\r
-}\r