From b2824a8e1362b89285663e1ab9b88e9fbb4bc572 Mon Sep 17 00:00:00 2001 From: jljusten Date: Thu, 1 Sep 2011 19:57:46 +0000 Subject: IntelFrameworkModulePkg: Add UpdateDriverDxe driver Signed-off-by: jljusten Reviewed-by: rsun3 Reviewed-by: lgao4 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12257 6f19259b-4bc3-4df7-8a09-765794883524 --- .../IntelFrameworkModulePkg.dsc | 1 + .../FirmwareVolume/UpdateDriverDxe/FlashUpdate.c | 1218 ++++++++++++++++++++ .../UpdateDriverDxe/ParseUpdateProfile.c | 1134 ++++++++++++++++++ .../UpdateDriverDxe/UpdateDispatcher.c | 846 ++++++++++++++ .../FirmwareVolume/UpdateDriverDxe/UpdateDriver.h | 218 ++++ .../UpdateDriverDxe/UpdateDriverDxe.inf | 69 ++ .../UpdateDriverDxe/UpdateStrings.uni | Bin 0 -> 2344 bytes 7 files changed, 3486 insertions(+) create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf create mode 100644 IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni (limited to 'IntelFrameworkModulePkg') diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc index 7eaac50eaf..97d9228952 100644 --- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc +++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc @@ -163,6 +163,7 @@ IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf + IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf [Components.IA32,Components.X64] IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c new file mode 100644 index 0000000000..56514c9855 --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c @@ -0,0 +1,1218 @@ +/** @file + Functions in this file will program the image into flash area. + + Copyright (c) 2002 - 2010, 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 "UpdateDriver.h" + +/** + Write a block size data into flash. + + @param FvbProtocol Pointer to FVB protocol. + @param Lba Logic block index to be updated. + @param BlockSize Block size + @param Buffer Buffer data to be written. + + @retval EFI_SUCCESS Write data successfully. + @retval other errors Write data failed. + +**/ +EFI_STATUS +UpdateOneBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_LBA Lba, + IN UINTN BlockSize, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN Size; + + // + // First erase the block + // + Status = FvbProtocol->EraseBlocks ( + FvbProtocol, + Lba, // Lba + 1, // NumOfBlocks + EFI_LBA_LIST_TERMINATOR + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Write the block + // + Size = BlockSize; + Status = FvbProtocol->Write ( + FvbProtocol, + Lba, // Lba + 0, // Offset + &Size, // Size + Buffer // Buffer + ); + if ((EFI_ERROR (Status)) || (Size != BlockSize)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Write buffer data in a flash block. + + @param FvbProtocol Pointer to FVB protocol. + @param Lba Logic block index to be updated. + @param Offset The offset within the block. + @param Length Size of buffer to be updated. + @param BlockSize Block size. + @param Buffer Buffer data to be updated. + + @retval EFI_SUCCESS Write data successfully. + @retval other errors Write data failed. + +**/ +EFI_STATUS +UpdateBufferInOneBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINTN Length, + IN UINTN BlockSize, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN Size; + UINT8 *ReservedBuffer; + + // + // If we are going to update a whole block + // + if ((Offset == 0) && (Length == BlockSize)) { + Status = UpdateOneBlock ( + FvbProtocol, + Lba, + BlockSize, + Buffer + ); + return Status; + } + + // + // If it is not a full block update, we need to coalesce data in + // the block that is not going to be updated and new data together. + // + + // + // Allocate a reserved buffer to make up the final buffer for update + // + ReservedBuffer = NULL; + ReservedBuffer = AllocatePool (BlockSize); + if (ReservedBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // First get the original content of the block + // + Size = BlockSize; + Status = FvbProtocol->Read ( + FvbProtocol, + Lba, + 0, + &Size, + ReservedBuffer + ); + if ((EFI_ERROR (Status)) || (Size != BlockSize)) { + FreePool (ReservedBuffer); + return Status; + } + + // + // Overwrite the reserved buffer with new content + // + CopyMem (ReservedBuffer + Offset, Buffer, Length); + + Status = UpdateOneBlock ( + FvbProtocol, + Lba, + BlockSize, + ReservedBuffer + ); + + FreePool (ReservedBuffer); + + return Status; +} + +/** + Get the last write log, and check the status of last write. + If not complete, restart will be taken. + + @param FvbHandle Handle of FVB protocol. + @param FtwProtocol FTW protocol instance. + @param ConfigData Config data on updating driver. + @param PrivateDataSize bytes from the private data + stored for this write. + @param PrivateData A pointer to a buffer. The function will copy. + @param Lba The logical block address of the last write. + @param Offset The offset within the block of the last write. + @param Length The length of the last write. + @param Pending A Boolean value with TRUE indicating + that the write was completed. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_ABORTED The FTW work space is damaged. + @retval EFI_NOT_FOUND The last write is not done by this driver. + @retval EFI_SUCCESS Last write log is got. + +**/ +EFI_STATUS +RetrieveLastWrite ( + IN EFI_HANDLE FvbHandle, + IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINTN PrivateDataSize, + IN OUT UPDATE_PRIVATE_DATA *PrivateData, + IN OUT EFI_LBA *Lba, + IN OUT UINTN *Offset, + IN OUT UINTN *Length, + IN OUT BOOLEAN *Pending + ) +{ + EFI_STATUS Status; + EFI_GUID CallerId; + UINTN PrivateBufferSize; + BOOLEAN Complete; + VOID *PrivateDataBuffer; + + // + // Get the last write + // + *Pending = FALSE; + PrivateBufferSize = PrivateDataSize; + PrivateDataBuffer = NULL; + Status = FtwProtocol->GetLastWrite ( + FtwProtocol, + &CallerId, + Lba, + Offset, + Length, + &PrivateBufferSize, + PrivateData, + &Complete + ); + if (EFI_ERROR (Status)) { + // + // If there is no incompleted record, return success. + // + if ((Status == EFI_NOT_FOUND) && Complete) { + return EFI_SUCCESS; + } else if (Status == EFI_BUFFER_TOO_SMALL) { + // + // If buffer too small, reallocate buffer and call getlastwrite again + // + PrivateDataBuffer = AllocatePool (PrivateBufferSize); + + if (PrivateDataBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = FtwProtocol->GetLastWrite ( + FtwProtocol, + &CallerId, + Lba, + Offset, + Length, + &PrivateBufferSize, + PrivateDataBuffer, + &Complete + ); + if (EFI_ERROR (Status)) { + FreePool ( PrivateDataBuffer); + return EFI_ABORTED; + } else { + CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize); + FreePool (PrivateDataBuffer); + PrivateDataBuffer = NULL; + } + } else { + return EFI_ABORTED; + } + } + + *Pending = TRUE; + + // + // If the caller is not the update driver, then return. + // The update driver cannot continue to perform the update + // + if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) { + return EFI_NOT_FOUND; + } + + // + // Check the private data and see if it is the one I need. + // + if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) { + return EFI_NOT_FOUND; + } + + // + // If the caller is the update driver and complete is not true, then restart(). + // + if (!Complete) { + // + // Re-start the update + // + Status = FtwProtocol->Restart ( + FtwProtocol, + FvbHandle + ); + // + // If restart() error, then abort(). + // + if (EFI_ERROR (Status)) { + FtwProtocol->Abort (FtwProtocol); + // + // Now set Pending as FALSE as this record has been cleared + // + *Pending = FALSE; + return EFI_SUCCESS; + } + + } + + return Status; +} + +/** + Update the whole FV image in fault tolerant write method. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param BlockMap Block array to specify flash area. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_SUCCESS FV image is writed into flash. + @retval EFI_INVALID_PARAMETER Config data is not valid. + @retval EFI_NOT_FOUND FTW protocol doesn't exist. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + @retval EFI_ABORTED Error happen when update FV. + +**/ +EFI_STATUS +FaultTolerantUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ) +{ + EFI_STATUS Status; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + UINTN MaxBlockSize; + UINTN FtwMaxBlockSize; + BOOLEAN Pending; + UPDATE_PRIVATE_DATA PrivateData; + EFI_LBA PendingLba; + EFI_LBA Lba; + UINTN PendingOffset; + UINTN Offset; + UINTN PendingLength; + UINTN Length; + EFI_FV_BLOCK_MAP_ENTRY *PtrMap; + UINTN NumOfBlocks; + UINTN Index; + UINT8 *UpdateBuffer; + + if ((ConfigData->UpdateType != UpdateWholeFV) + || (!ConfigData->FaultTolerant)) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the FTW protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteProtocolGuid, + NULL, + (VOID **) &FtwProtocol + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get the maximum block size of the FV, and number of blocks + // NumOfBlocks will be the NumOfUdpates. + // + MaxBlockSize = 0; + NumOfBlocks = 0; + PtrMap = BlockMap; + while (TRUE) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + if (MaxBlockSize < PtrMap->Length) { + MaxBlockSize = PtrMap->Length; + } + NumOfBlocks = NumOfBlocks + PtrMap->NumBlocks; + PtrMap++; + } + + FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize); + // + // Not enough backup space. return directly + // + if (FtwMaxBlockSize < MaxBlockSize) { + return EFI_OUT_OF_RESOURCES; + } + + PendingLba = 0; + PendingOffset = 0; + PendingLength = 0; + Pending = FALSE; + + // + // Fault Tolerant Write can only support actual fault tolerance if the write + // is a reclaim operation, which means the data buffer (new and old) are + // acutally both stored in flash. But for component update write, the data + // are now in memory. So we cannot actually recover the data after power + // failure. + // + Status = RetrieveLastWrite ( + FvbHandle, + FtwProtocol, + ConfigData, + sizeof (UPDATE_PRIVATE_DATA), + &PrivateData, + &PendingLba, + &PendingOffset, + &PendingLength, + &Pending + ); + + if (Pending && (Status == EFI_NOT_FOUND)) { + // + // Cannot continue with the write operation + // + return EFI_ABORTED; + } + + if (EFI_ERROR(Status)) { + return EFI_ABORTED; + } + + // + // Currently we start from the pending write if there is any. But as we + // are going to update a whole FV, we can just abort last write and start + // from the very begining. + // + if (!Pending) { + // + // Now allocte the update private data in FTW. If there is pending + // write, it has already been allocated and no need to allocate here. + // + Status = FtwProtocol->Allocate ( + FtwProtocol, + &gEfiCallerIdGuid, + sizeof (UPDATE_PRIVATE_DATA), + NumOfBlocks + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Perform the update now. If there are pending writes, we need to + // start from the pending write instead of the very beginning. + // + PtrMap = BlockMap; + Lba = 0; + Offset = 0; + UpdateBuffer = ImageBuffer; + CopyMem ( + (VOID *) &PrivateData.FileGuid, + (VOID *) &ConfigData->FileGuid, + sizeof (EFI_GUID) + ); + + while (TRUE) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + Length = (UINTN)PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + + // + // Add an extra check here to see if the pending record is correct + // + if (Pending && (Lba == PendingLba)) { + if ((PendingOffset != Offset) || (PendingLength != Length)) { + // + // Error. + // + Status = EFI_ABORTED; + break; + } + } + + if ((!Pending) || (Lba >= PendingLba)) { + Status = FtwProtocol->Write ( + FtwProtocol, + Lba, // Lba + Offset, // Offset + Length, // Size + &PrivateData, // Private Data + FvbHandle, // FVB handle + UpdateBuffer // Buffer + ); + } + + if (EFI_ERROR (Status)) { + break; + } + Lba++; + UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + Length); + } + + if (EFI_ERROR (Status)) { + break; + } + PtrMap++; + } + + return Status; + +} + +/** + Directly update the whole FV image without fault tolerant write method. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param BlockMap Block array to specify flash area. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_SUCCESS FV image is writed into flash. + @retval EFI_INVALID_PARAMETER Config data is not valid. + @retval EFI_ABORTED Error happen when update FV. + +**/ +EFI_STATUS +NonFaultTolerantUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ) +{ + EFI_STATUS Status; + EFI_FV_BLOCK_MAP_ENTRY *PtrMap; + UINTN Index; + EFI_LBA UpdateLba; + UINT8 *UpdateBuffer; + UINTN UpdateSize; + + if ((ConfigData->UpdateType != UpdateWholeFV ) + || (ConfigData->FaultTolerant)) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + PtrMap = BlockMap; + UpdateLba = 0; + UpdateBuffer = ImageBuffer; + + // + // Perform the update now + // + while (TRUE) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + UpdateSize = (UINTN)PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + Status = UpdateOneBlock ( + FvbProtocol, + UpdateLba, + UpdateSize, + UpdateBuffer + ); + if (EFI_ERROR (Status)) { + break; + } + + UpdateLba++; + UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize); + } + + if (EFI_ERROR (Status)) { + break; + } + PtrMap++; + } + + return Status; +} + +/** + Update the whole FV image, and reinsall FVB protocol for the updated FV image. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV. + Or Image size is not same to the size of whole FV. + @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated. + @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled. + +**/ +EFI_STATUS +PerformUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize +) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + CHAR16 *TmpStr; + + if (ConfigData->UpdateType != UpdateWholeFV) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the header of the firmware volume + // + FwVolHeader = NULL; + FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength); + if (FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem ( + FwVolHeader, + (VOID *) ((UINTN) (ConfigData->BaseAddress)), + ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength + ); + + // + // Check if ImageSize is the same as the size of the whole FV + // + if ((UINT64)ImageSize != FwVolHeader->FvLength) { + FreePool (FwVolHeader); + return EFI_INVALID_PARAMETER; + } + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL); + if (TmpStr != NULL) { + Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)); + FreePool (TmpStr); + } + + DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n", + ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress))); + + // + // Get the block map of the firmware volume + // + BlockMap = &(FwVolHeader->BlockMap[0]); + + // + // It is about the same if we are going to fault tolerantly update + // a certain FV in our current design. But we divide non-fault tolerant + // and fault tolerant udpate here for better maintenance as fault + // tolerance may change and may be done more wisely if we have space. + // + if (ConfigData->FaultTolerant) { + Status = FaultTolerantUpdateOnWholeFv ( + FvbHandle, + FvbProtocol, + BlockMap, + ConfigData, + ImageBuffer, + ImageSize + ); + } else { + Status = NonFaultTolerantUpdateOnWholeFv ( + FvbHandle, + FvbProtocol, + BlockMap, + ConfigData, + ImageBuffer, + ImageSize + ); + } + + FreePool (FwVolHeader); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // As the whole FV has been replaced, the FV driver shall re-parse the + // firmware volume. So re-install FVB protocol here + // + Status = gBS->ReinstallProtocolInterface ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + FvbProtocol, + FvbProtocol + ); + + return Status; +} + +/** + Update certain file in the FV. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + @param FileType FFS file type. + @param FileAttributes FFS file attribute + + @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile. + Or Image size is not same to the size of whole FV. + @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated. + @retval EFI_SUCCESS The FFS file is added into FV. + +**/ +EFI_STATUS +PerformUpdateOnFvFile ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize, + IN EFI_FV_FILETYPE FileType, + IN EFI_FV_FILE_ATTRIBUTES FileAttributes + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol; + EFI_FV_WRITE_FILE_DATA FileData; + CHAR16 *TmpStr; + + if (ConfigData->UpdateType != UpdateFvFile) { + return EFI_INVALID_PARAMETER; + } + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL); + if (TmpStr != NULL) { + Print (TmpStr, &(ConfigData->FileGuid)); + FreePool (TmpStr); + } + + DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n", + &(ConfigData->FileGuid))); + + // + // Get Firmware volume protocol on this FVB protocol + // + Status = gBS->HandleProtocol ( + FvbHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) &FwVolProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If it is a PEIM, we need first to rebase it before committing + // the write to target + // + if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM ) + || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { + return EFI_UNSUPPORTED; + } + + FileData.NameGuid = &(ConfigData->FileGuid); + FileData.Type = FileType; + FileData.FileAttributes = FileAttributes; + FileData.Buffer = ImageBuffer; + FileData.BufferSize = (UINT32) ImageSize; + + Status = FwVolProtocol->WriteFile ( + FwVolProtocol, + 1, // NumberOfFiles + (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant, + &FileData + ); + return Status; +} + +/** + Update the buffer into flash area in fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param ConfigData Config data on updating driver. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_NOT_FOUND FTW protocol doesn't exist. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + @retval EFI_ABORTED Error happen when update flash area. + +**/ +EFI_STATUS +FaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN UPDATE_CONFIG_DATA *ConfigData, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_PHYSICAL_ADDRESS FvBase; + EFI_PHYSICAL_ADDRESS NextBlock; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_FV_BLOCK_MAP_ENTRY *PtrMap; + UINTN NumOfUpdates; + UINTN TotalSize; + EFI_PHYSICAL_ADDRESS StartAddress; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + UINTN MaxBlockSize; + UINTN FtwMaxBlockSize; + BOOLEAN Pending; + UPDATE_PRIVATE_DATA PrivateData; + EFI_LBA PendingLba; + EFI_LBA Lba; + UINTN BlockSize; + UINTN PendingOffset; + UINTN Offset; + UINTN PendingLength; + UINTN Length; + UINTN Index; + UINT8 *Image; + + // + // Get the block map to update the block one by one + // + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &FvBase + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; + if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) { + return EFI_INVALID_PARAMETER; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool ( + FwVolHeaderTmp->HeaderLength, + FwVolHeaderTmp + ); + if (FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // For fault tolerant write, we have to know how many blocks we need to + // update. So we will calculate number of updates and max block size first + // + NumOfUpdates = 0; + MaxBlockSize = 0; + TotalSize = SizeLeft; + StartAddress = FlashAddress; + BaseAddress = FvBase; + BlockMap = &(FwVolHeader->BlockMap[0]); + PtrMap = BlockMap; + + while (TotalSize > 0) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + + BlockSize = PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + NextBlock = BaseAddress + BlockSize; + // + // Check if this block need to be updated + // + if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) { + // + // Get the maximum block size + // + if (MaxBlockSize < BlockSize) { + MaxBlockSize = BlockSize; + } + + // + // This block shall be udpated. So increment number of updates + // + NumOfUpdates++; + Offset = (UINTN) (StartAddress - BaseAddress); + Length = TotalSize; + if ((Length + Offset ) > BlockSize) { + Length = BlockSize - Offset; + } + + StartAddress = StartAddress + Length; + TotalSize = TotalSize - Length; + if (TotalSize <= 0) { + break; + } + } + BaseAddress = NextBlock; + } + PtrMap++; + } + + // + // Get the FTW protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteProtocolGuid, + NULL, + (VOID **) &FtwProtocol + ); + if (EFI_ERROR (Status)) { + FreePool (FwVolHeader); + return EFI_NOT_FOUND; + } + + FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize); + + // + // Not enough backup space. return directly + // + if (FtwMaxBlockSize < MaxBlockSize) { + FreePool (FwVolHeader); + return EFI_OUT_OF_RESOURCES; + } + + PendingLba = 0; + PendingOffset = 0; + PendingLength = 0; + Pending = FALSE; + + // + // Fault Tolerant Write can only support actual fault tolerance if the write + // is a reclaim operation, which means the data buffer (new and old) are + // acutally both stored in flash. But for component update write, the data + // are now in memory. So we cannot actually recover the data after power + // failure. + // + Status = RetrieveLastWrite ( + FvbHandle, + FtwProtocol, + ConfigData, + sizeof (UPDATE_PRIVATE_DATA), + &PrivateData, + &PendingLba, + &PendingOffset, + &PendingLength, + &Pending + ); + if (Pending && (Status == EFI_NOT_FOUND)) { + // + // I'm not the owner of the pending fault tolerant write record + // Cannot continue with the write operation + // + FreePool (FwVolHeader); + return EFI_ABORTED; + } + + if (EFI_ERROR(Status)) { + FreePool (FwVolHeader); + return EFI_ABORTED; + } + + // + // Currently we start from the pending write if there is any. But if the + // caller is exactly the same, and the new data is already a in memory, (it + // cannot be stored in flash in last write,) we can just abort last write + // and start from the very begining. + // + if (!Pending) { + // + // Now allocte the update private data in FTW. If there is pending + // write, it has already been allocated and no need to allocate here. + // + Status = FtwProtocol->Allocate ( + FtwProtocol, + &gEfiCallerIdGuid, + sizeof (UPDATE_PRIVATE_DATA), + NumOfUpdates + ); + if (EFI_ERROR (Status)) { + FreePool (FwVolHeader); + return Status; + } + } + + // + // Perform the update now. If there are pending writes, we need to + // start from the pending write instead of the very beginning. + // + TotalSize = SizeLeft; + Lba = 0; + StartAddress = FlashAddress; + BaseAddress = FvBase; + PtrMap = BlockMap; + Image = ImageBuffer; + CopyMem ( + (VOID *) &PrivateData.FileGuid, + (VOID *) &ConfigData->FileGuid, + sizeof (EFI_GUID) + ); + + while (TotalSize > 0) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + + BlockSize = (UINTN)PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + NextBlock = BaseAddress + BlockSize; + if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) { + // + // So we need to update this block + // + Offset = (UINTN) (StartAddress - BaseAddress); + Length = TotalSize; + if ((Length + Offset ) > BlockSize) { + Length = BlockSize - Offset; + } + + // + // Add an extra check here to see if the pending record is correct + // + if (Pending && (Lba == PendingLba)) { + if ((PendingOffset != Offset) || (PendingLength != Length)) { + // + // Error. + // + Status = EFI_ABORTED; + break; + } + } + + if ((!Pending) || (Lba >= PendingLba)) { + DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length)); + Status = FtwProtocol->Write ( + FtwProtocol, + Lba, // Lba + Offset, // Offset + Length, // Size + &PrivateData, // Private Data + FvbHandle, // FVB handle + Image // Buffer + ); + if (EFI_ERROR (Status)) { + break; + } + } + + // + // Now increment StartAddress, ImageBuffer and decrease the + // left size to prepare for the next block update. + // + StartAddress = StartAddress + Length; + Image = Image + Length; + TotalSize = TotalSize - Length; + if (TotalSize <= 0) { + break; + } + } + BaseAddress = NextBlock; + Lba++; + } + + if (EFI_ERROR (Status)) { + break; + } + PtrMap++; + } + + FreePool (FwVolHeader); + + *UpdatedSize = SizeLeft - TotalSize; + + return EFI_SUCCESS; +} + +/** + Directly update the buffer into flash area without fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + +**/ +EFI_STATUS +NonFaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_PHYSICAL_ADDRESS NextBlock; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + UINTN Index; + UINTN TotalSize; + UINTN BlockSize; + EFI_LBA Lba; + UINTN Offset; + UINTN Length; + UINT8 *Image; + + // + // Get the block map to update the block one by one + // + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &BaseAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; + if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) { + return EFI_INVALID_PARAMETER; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool ( + FwVolHeaderTmp->HeaderLength, + FwVolHeaderTmp + ); + if (FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Image = ImageBuffer; + TotalSize = SizeLeft; + BlockMap = &(FwVolHeader->BlockMap[0]); + Lba = 0; + + while (TotalSize > 0) { + if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) { + break; + } + + BlockSize = BlockMap->Length; + for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) { + NextBlock = BaseAddress + BlockSize; + if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) { + // + // So we need to update this block + // + Offset = (UINTN) FlashAddress - (UINTN) BaseAddress; + Length = TotalSize; + if ((Length + Offset ) > BlockSize) { + Length = BlockSize - Offset; + } + + DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length)); + // + // Update the block + // + Status = UpdateBufferInOneBlock ( + FvbProtocol, + Lba, + Offset, + Length, + BlockSize, + Image + ); + if (EFI_ERROR (Status)) { + FreePool (FwVolHeader); + return Status; + } + + // + // Now increment FlashAddress, ImageBuffer and decrease the + // left size to prepare for the next block update. + // + FlashAddress = FlashAddress + Length; + Image = Image + Length; + TotalSize = TotalSize - Length; + if (TotalSize <= 0) { + break; + } + } + BaseAddress = NextBlock; + Lba++; + } + + if (EFI_ERROR (Status)) { + break; + } + BlockMap++; + } + + FreePool (FwVolHeader); + + *UpdatedSize = SizeLeft - TotalSize; + + return EFI_SUCCESS; +} diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c new file mode 100644 index 0000000000..17e728db30 --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c @@ -0,0 +1,1134 @@ +/** @file + Source file for the component update driver. It parse the update + configuration file and pass the information to the update driver + so that the driver can perform updates accordingly. + + Copyright (c) 2002 - 2010, 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 "UpdateDriver.h" + +/** + Copy one line data from buffer data to the line buffer. + + @param Buffer Buffer data. + @param BufferSize Buffer Size. + @param LineBuffer Line buffer to store the found line data. + @param LineSize On input, size of the input line buffer. + On output, size of the actual line buffer. + + @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough. + @retval EFI_SUCCESS Copy line data into the line buffer. + +**/ +EFI_STATUS +ProfileGetLine ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT UINT8 *LineBuffer, + IN OUT UINTN *LineSize + ) +{ + UINTN Length; + UINT8 *PtrBuf; + UINTN PtrEnd; + + PtrBuf = Buffer; + PtrEnd = (UINTN)Buffer + BufferSize; + + // + // 0x0D indicates a line break. Otherwise there is no line break + // + while ((UINTN)PtrBuf < PtrEnd) { + if (*PtrBuf == 0x0D) { + break; + } + PtrBuf++; + } + + if ((UINTN)PtrBuf >= (PtrEnd - 1)) { + // + // The buffer ends without any line break + // or it is the last character of the buffer + // + Length = BufferSize; + } else if (*(PtrBuf + 1) == 0x0A) { + // + // Further check if a 0x0A follows. If yes, count 0xA + // + Length = (UINTN) PtrBuf - (UINTN) Buffer + 2; + } else { + Length = (UINTN) PtrBuf - (UINTN) Buffer + 1; + } + + if (Length > (*LineSize)) { + *LineSize = Length; + return EFI_BUFFER_TOO_SMALL; + } + + SetMem (LineBuffer, *LineSize, 0x0); + *LineSize = Length; + CopyMem (LineBuffer, Buffer, Length); + + return EFI_SUCCESS; +} + +/** + Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail. + + @param Buffer On input, buffer data to be trimed. + On output, the trimmed buffer. + @param BufferSize On input, size of original buffer data. + On output, size of the trimmed buffer. + +**/ +VOID +ProfileTrim ( + IN OUT UINT8 *Buffer, + IN OUT UINTN *BufferSize + ) +{ + UINTN Length; + UINT8 *PtrBuf; + UINT8 *PtrEnd; + + if (*BufferSize == 0) { + return; + } + + // + // Trim the tail first, include CR, LF, TAB, and SPACE. + // + Length = *BufferSize; + PtrBuf = (UINT8 *) ((UINTN) Buffer + Length - 1); + while (PtrBuf >= Buffer) { + if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A ) + && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) { + break; + } + PtrBuf --; + } + + // + // all spaces, a blank line, return directly; + // + if (PtrBuf < Buffer) { + *BufferSize = 0; + return; + } + + Length = (UINTN)PtrBuf - (UINTN)Buffer + 1; + PtrEnd = PtrBuf; + PtrBuf = Buffer; + + // + // Now skip the heading CR, LF, TAB and SPACE + // + while (PtrBuf <= PtrEnd) { + if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A ) + && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) { + break; + } + PtrBuf++; + } + + // + // If no heading CR, LF, TAB or SPACE, directly return + // + if (PtrBuf == Buffer) { + *BufferSize = Length; + return; + } + + *BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1; + + // + // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE. + // Now move out all these characters. + // + while (PtrBuf <= PtrEnd) { + *Buffer = *PtrBuf; + Buffer++; + PtrBuf++; + } + + return; +} + +/** + Insert new comment item into comment head. + + @param Buffer Comment buffer to be added. + @param BufferSize Size of comment buffer. + @param CommentHead Comment Item head entry. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS New comment item is inserted. + +**/ +EFI_STATUS +ProfileGetComments ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT COMMENT_LINE **CommentHead + ) +{ + COMMENT_LINE *CommentItem; + + CommentItem = NULL; + CommentItem = AllocatePool (sizeof (COMMENT_LINE)); + if (CommentItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CommentItem->ptrNext = *CommentHead; + *CommentHead = CommentItem; + + // + // Add a trailing '\0' + // + CommentItem->ptrComment = AllocatePool (BufferSize + 1); + if (CommentItem->ptrComment == NULL) { + FreePool (CommentItem); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (CommentItem->ptrComment, Buffer, BufferSize); + *(CommentItem->ptrComment + BufferSize) = '\0'; + + return EFI_SUCCESS; +} + +/** + Add new section item into Section head. + + @param Buffer Section item data buffer. + @param BufferSize Size of section item. + @param SectionHead Section item head entry. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Section item is NULL or Section item is added. + +**/ +EFI_STATUS +ProfileGetSection ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT SECTION_ITEM **SectionHead + ) +{ + EFI_STATUS Status; + SECTION_ITEM *SectionItem; + UINTN Length; + UINT8 *PtrBuf; + + Status = EFI_SUCCESS; + // + // The first character of Buffer is '[', now we want for ']' + // + PtrBuf = (UINT8 *)((UINTN)Buffer + BufferSize - 1); + while (PtrBuf > Buffer) { + if (*PtrBuf == ']') { + break; + } + PtrBuf --; + } + if (PtrBuf <= Buffer) { + // + // Not found. Omit this line + // + return Status; + } + + // + // excluding the heading '[' and tailing ']' + // + Length = PtrBuf - Buffer - 1; + ProfileTrim ( + Buffer + 1, + &Length + ); + + // + // omit this line if the section name is null + // + if (Length == 0) { + return Status; + } + + SectionItem = AllocatePool (sizeof (SECTION_ITEM)); + if (SectionItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SectionItem->ptrSection = NULL; + SectionItem->SecNameLen = Length; + SectionItem->ptrEntry = NULL; + SectionItem->ptrValue = NULL; + SectionItem->ptrNext = *SectionHead; + *SectionHead = SectionItem; + + // + // Add a trailing '\0' + // + SectionItem->ptrSection = AllocatePool (Length + 1); + if (SectionItem->ptrSection == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // excluding the heading '[' + // + CopyMem (SectionItem->ptrSection, Buffer + 1, Length); + *(SectionItem->ptrSection + Length) = '\0'; + + return EFI_SUCCESS; +} + +/** + Add new section entry and entry value into Section head. + + @param Buffer Section entry data buffer. + @param BufferSize Size of section entry. + @param SectionHead Section item head entry. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Section entry is NULL or Section entry is added. + +**/ +EFI_STATUS +ProfileGetEntry ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT SECTION_ITEM **SectionHead + ) +{ + EFI_STATUS Status; + SECTION_ITEM *SectionItem; + SECTION_ITEM *PtrSection; + UINTN Length; + UINT8 *PtrBuf; + UINT8 *PtrEnd; + + Status = EFI_SUCCESS; + PtrBuf = Buffer; + PtrEnd = (UINT8 *) ((UINTN)Buffer + BufferSize - 1); + + // + // First search for '=' + // + while (PtrBuf <= PtrEnd) { + if (*PtrBuf == '=') { + break; + } + PtrBuf++; + } + if (PtrBuf > PtrEnd) { + // + // Not found. Omit this line + // + return Status; + } + + // + // excluding the tailing '=' + // + Length = PtrBuf - Buffer; + ProfileTrim ( + Buffer, + &Length + ); + + // + // Omit this line if the entry name is null + // + if (Length == 0) { + return Status; + } + + // + // Omit this line if no section header has been found before + // + if (*SectionHead == NULL) { + return Status; + } + PtrSection = *SectionHead; + + SectionItem = AllocatePool (sizeof (SECTION_ITEM)); + if (SectionItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SectionItem->ptrSection = NULL; + SectionItem->ptrEntry = NULL; + SectionItem->ptrValue = NULL; + SectionItem->SecNameLen = PtrSection->SecNameLen; + SectionItem->ptrNext = *SectionHead; + *SectionHead = SectionItem; + + // + // SectionName, add a trailing '\0' + // + SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1); + if (SectionItem->ptrSection == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1); + + // + // EntryName, add a trailing '\0' + // + SectionItem->ptrEntry = AllocatePool (Length + 1); + if (SectionItem->ptrEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (SectionItem->ptrEntry, Buffer, Length); + *(SectionItem->ptrEntry + Length) = '\0'; + + // + // Next search for '#' + // + PtrBuf = PtrBuf + 1; + Buffer = PtrBuf; + while (PtrBuf <= PtrEnd) { + if (*PtrBuf == '#') { + break; + } + PtrBuf++; + } + Length = PtrBuf - Buffer; + ProfileTrim ( + Buffer, + &Length + ); + + if (Length > 0) { + // + // EntryValue, add a trailing '\0' + // + SectionItem->ptrValue = AllocatePool (Length + 1); + if (SectionItem->ptrValue == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (SectionItem->ptrValue, Buffer, Length); + *(SectionItem->ptrValue + Length) = '\0'; + } + + return EFI_SUCCESS; +} + +/** + Free all comment entry and section entry. + + @param Section Section entry list. + @param Comment Comment entry list. + +**/ +VOID +FreeAllList ( + IN SECTION_ITEM *Section, + IN COMMENT_LINE *Comment + ) +{ + SECTION_ITEM *PtrSection; + COMMENT_LINE *PtrComment; + + while (Section != NULL) { + PtrSection = Section; + Section = Section->ptrNext; + if (PtrSection->ptrEntry != NULL) { + FreePool (PtrSection->ptrEntry); + } + if (PtrSection->ptrSection != NULL) { + FreePool (PtrSection->ptrSection); + } + if (PtrSection->ptrValue != NULL) { + FreePool (PtrSection->ptrValue); + } + FreePool (PtrSection); + } + + while (Comment != NULL) { + PtrComment = Comment; + Comment = Comment->ptrNext; + if (PtrComment->ptrComment != NULL) { + FreePool (PtrComment->ptrComment); + } + FreePool (PtrComment); + } + + return; +} + +/** + Get section entry value. + + @param Section Section entry list. + @param SectionName Section name. + @param EntryName Section entry name. + @param EntryValue Point to the got entry value. + + @retval EFI_NOT_FOUND Section is not found. + @retval EFI_SUCCESS Section entry value is got. + +**/ +EFI_STATUS +UpdateGetProfileString ( + IN SECTION_ITEM *Section, + IN UINT8 *SectionName, + IN UINT8 *EntryName, + OUT UINT8 **EntryValue + ) +{ + *EntryValue = NULL; + + while (Section != NULL) { + if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) { + if (Section->ptrEntry != NULL) { + if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) { + break; + } + } + } + Section = Section->ptrNext; + } + + if (Section == NULL) { + return EFI_NOT_FOUND; + } + + *EntryValue = (UINT8 *) Section->ptrValue; + + return EFI_SUCCESS; +} + +/** + Convert the dec or hex ascii string to value. + + @param Str ascii string to be converted. + + @return the converted value. + +**/ +UINTN +UpdateAtoi ( + IN UINT8 *Str + ) +{ + UINTN Number; + + Number = 0; + + // + // Skip preceeding while spaces + // + while (*Str != '\0') { + if (*Str != 0x20) { + break; + } + Str++; + } + + if (*Str == '\0') { + return Number; + } + + // + // Find whether the string is prefixed by 0x. + // That is, it should be xtoi or atoi. + // + if (*Str == '0') { + if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) { + return AsciiStrHexToUintn ((CONST CHAR8 *) Str); + } + } + + while (*Str != '\0') { + if ((*Str >= '0') && (*Str <= '9')) { + Number = Number * 10 + *Str - '0'; + } else { + break; + } + Str++; + } + + return Number; +} + +/** + Converts a decimal value to a Null-terminated ascii string. + + @param Buffer Pointer to the output buffer for the produced Null-terminated + ASCII string. + @param Value The 64-bit sgned value to convert to a string. + + @return The number of ASCII characters in Buffer not including the Null-terminator. + +**/ +UINTN +UpdateValueToString ( + IN OUT UINT8 *Buffer, + IN INT64 Value + ) +{ + UINT8 TempBuffer[30]; + UINT8 *TempStr; + UINT8 *BufferPtr; + UINTN Count; + UINT32 Remainder; + + TempStr = TempBuffer; + BufferPtr = Buffer; + Count = 0; + + if (Value < 0) { + *BufferPtr = '-'; + BufferPtr++; + Value = -Value; + Count++; + } + + do { + Value = (INT64) DivU64x32Remainder ((UINT64)Value, 10, &Remainder); + // + // The first item of TempStr is not occupied. It's kind of flag + // + TempStr++; + Count++; + *TempStr = (UINT8) ((UINT8)Remainder + '0'); + } while (Value != 0); + + // + // Reverse temp string into Buffer. + // + while (TempStr != TempBuffer) { + *BufferPtr = *TempStr; + BufferPtr++; + TempStr --; + } + + *BufferPtr = 0; + + return Count; +} + +/** + Convert the input value to a ascii string, + and concatenates this string to the input string. + + @param Str Pointer to a Null-terminated ASCII string. + @param Number The unsgned value to convert to a string. + +**/ +VOID +UpdateStrCatNumber ( + IN OUT UINT8 *Str, + IN UINTN Number + ) +{ + UINTN Count; + + while (*Str != '\0') { + Str++; + } + + Count = UpdateValueToString (Str, (INT64)Number); + + *(Str + Count) = '\0'; + + return; +} + +/** + Convert the input ascii string into GUID value. + + @param Str Ascii GUID string to be converted. + @param Guid Pointer to the converted GUID value. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_NOT_FOUND The input ascii string is not a valid GUID format string. + @retval EFI_SUCCESS GUID value is got. + +**/ +EFI_STATUS +UpdateStringToGuid ( + IN UINT8 *Str, + IN OUT EFI_GUID *Guid + ) +{ + UINT8 *PtrBuffer; + UINT8 *PtrPosition; + UINT8 *Buffer; + UINTN Data; + UINTN StrLen; + UINTN Index; + UINT8 Digits[3]; + + StrLen = AsciiStrLen ((CONST CHAR8 *) Str); + Buffer = AllocatePool (StrLen + 1); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + AsciiStrCpy ((CHAR8 *)Buffer, (CHAR8 *)Str); + + // + // Data1 + // + PtrBuffer = Buffer; + PtrPosition = PtrBuffer; + while (*PtrBuffer != '\0') { + if (*PtrBuffer == '-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == '\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + + *PtrBuffer = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); + Guid->Data1 = (UINT32)Data; + + // + // Data2 + // + PtrBuffer++; + PtrPosition = PtrBuffer; + while (*PtrBuffer != '\0') { + if (*PtrBuffer == '-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == '\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + *PtrBuffer = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); + Guid->Data2 = (UINT16)Data; + + // + // Data3 + // + PtrBuffer++; + PtrPosition = PtrBuffer; + while (*PtrBuffer != '\0') { + if (*PtrBuffer == '-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == '\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + *PtrBuffer = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); + Guid->Data3 = (UINT16)Data; + + // + // Data4[0..1] + // + for ( Index = 0 ; Index < 2 ; Index++) { + PtrBuffer++; + if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + Digits[0] = *PtrBuffer; + PtrBuffer++; + Digits[1] = *PtrBuffer; + Digits[2] = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits); + Guid->Data4[Index] = (UINT8)Data; + } + + // + // skip the '-' + // + PtrBuffer++; + if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) { + return EFI_NOT_FOUND; + } + + // + // Data4[2..7] + // + for ( ; Index < 8; Index++) { + PtrBuffer++; + if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + Digits[0] = *PtrBuffer; + PtrBuffer++; + Digits[1] = *PtrBuffer; + Digits[2] = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits); + Guid->Data4[Index] = (UINT8)Data; + } + + FreePool (Buffer); + + return EFI_SUCCESS; +} + +/** + Pre process config data buffer into Section entry list and Comment entry list. + + @param DataBuffer Config raw file buffer. + @param BufferSize Size of raw buffer. + @param SectionHead Pointer to the section entry list. + @param CommentHead Pointer to the comment entry list. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Config data buffer is preprocessed. + +**/ +EFI_STATUS +PreProcessDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT SECTION_ITEM **SectionHead, + IN OUT COMMENT_LINE **CommentHead + ) +{ + EFI_STATUS Status; + CHAR8 *Source; + CHAR8 *CurrentPtr; + CHAR8 *BufferEnd; + CHAR8 *PtrLine; + UINTN LineLength; + UINTN SourceLength; + UINTN MaxLineLength; + + *SectionHead = NULL; + *CommentHead = NULL; + BufferEnd = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize); + CurrentPtr = (CHAR8 *) DataBuffer; + MaxLineLength = MAX_LINE_LENGTH; + Status = EFI_SUCCESS; + + PtrLine = AllocatePool (MaxLineLength); + if (PtrLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + while (CurrentPtr < BufferEnd) { + Source = CurrentPtr; + SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr; + LineLength = MaxLineLength; + // + // With the assumption that line length is less than 512 + // characters. Otherwise BUFFER_TOO_SMALL will be returned. + // + Status = ProfileGetLine ( + (UINT8 *) Source, + SourceLength, + (UINT8 *) PtrLine, + &LineLength + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // If buffer too small, re-allocate the buffer according + // to the returned LineLength and try again. + // + FreePool (PtrLine); + PtrLine = NULL; + PtrLine = AllocatePool (LineLength); + if (PtrLine == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + SourceLength = LineLength; + Status = ProfileGetLine ( + (UINT8 *) Source, + SourceLength, + (UINT8 *) PtrLine, + &LineLength + ); + if (EFI_ERROR (Status)) { + break; + } + MaxLineLength = LineLength; + } else { + break; + } + } + CurrentPtr = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength); + + // + // Line got. Trim the line before processing it. + // + ProfileTrim ( + (UINT8 *) PtrLine, + &LineLength + ); + + // + // Blank line + // + if (LineLength == 0) { + continue; + } + + if (PtrLine[0] == '#') { + Status = ProfileGetComments ( + (UINT8 *) PtrLine, + LineLength, + CommentHead + ); + } else if (PtrLine[0] == '[') { + Status = ProfileGetSection ( + (UINT8 *) PtrLine, + LineLength, + SectionHead + ); + } else { + Status = ProfileGetEntry ( + (UINT8 *) PtrLine, + LineLength, + SectionHead + ); + } + + if (EFI_ERROR (Status)) { + break; + } + } + + // + // Free buffer + // + FreePool (PtrLine); + + return Status; +} + +/** + Parse Config data file to get the updated data array. + + @param DataBuffer Config raw file buffer. + @param BufferSize Size of raw buffer. + @param NumOfUpdates Pointer to the number of update data. + @param UpdateArray Pointer to the config of update data. + + @retval EFI_NOT_FOUND No config data is found. + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Parse the config file successfully. + +**/ +EFI_STATUS +ParseUpdateDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT UINTN *NumOfUpdates, + IN OUT UPDATE_CONFIG_DATA **UpdateArray + ) +{ + EFI_STATUS Status; + CHAR8 *Value; + CHAR8 *SectionName; + CHAR8 Entry[MAX_LINE_LENGTH]; + SECTION_ITEM *SectionHead; + COMMENT_LINE *CommentHead; + UINTN Num; + UINTN Index; + EFI_GUID FileGuid; + + SectionHead = NULL; + CommentHead = NULL; + + // + // First process the data buffer and get all sections and entries + // + Status = PreProcessDataFile ( + DataBuffer, + BufferSize, + &SectionHead, + &CommentHead + ); + if (EFI_ERROR (Status)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } + + // + // Now get NumOfUpdate + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) "Head", + (UINT8 *) "NumOfUpdate", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + Num = UpdateAtoi((UINT8 *) Value); + if (Num <= 0) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + *NumOfUpdates = Num; + *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num)); + if (*UpdateArray == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_OUT_OF_RESOURCES; + } + + for ( Index = 0 ; Index < *NumOfUpdates ; Index++) { + // + // Get the section name of each update + // + AsciiStrCpy (Entry, "Update"); + UpdateStrCatNumber ((UINT8 *) Entry, Index); + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) "Head", + (UINT8 *) Entry, + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + // + // The section name of this update has been found. + // Now looks for all the config data of this update + // + SectionName = Value; + + // + // UpdateType + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "UpdateType", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Num = UpdateAtoi((UINT8 *) Value); + if (( Num >= (UINTN) UpdateOperationMaximum)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } + (*UpdateArray)[Index].Index = Index; + (*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num; + + // + // FvBaseAddress + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "FvBaseAddress", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); + (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num; + + // + // FileBuid + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "FileGuid", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid); + if (EFI_ERROR (Status)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } + CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID)); + + // + // FaultTolerant + // Default value is FALSE + // + Value = NULL; + (*UpdateArray)[Index].FaultTolerant = FALSE; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "FaultTolerant", + (UINT8 **) &Value + ); + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } else if (Value != NULL) { + if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) { + (*UpdateArray)[Index].FaultTolerant = TRUE; + } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) { + (*UpdateArray)[Index].FaultTolerant = FALSE; + } + } + + if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) { + // + // Length + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "Length", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); + (*UpdateArray)[Index].Length = (UINTN) Num; + } + } + + // + // Now all configuration data got. Free those temporary buffers + // + FreeAllList (SectionHead, CommentHead); + + return EFI_SUCCESS; +} + diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c new file mode 100644 index 0000000000..177e79908e --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c @@ -0,0 +1,846 @@ +/** @file + Functions in this file will mainly focus on looking through the capsule + for the image to be programmed, and the flash area that is going to be + programed. + + Copyright (c) 2002 - 2011, 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 "UpdateDriver.h" + +EFI_GUID UpdateDataGuid = EFI_UPDATE_DATA_FILE_GUID; +EFI_HII_HANDLE gHiiHandle; + +/** + Update the whole FV, or certain files in the FV. + + @param ConfigData Pointer to the config data on updating file. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + @param FileType FFS file type. + @param FileAttributes FFS file attribute. + + @retval EFI_NOT_FOUND The matched FVB protocol is not found. + @retval EFI_SUCCESS The image buffer is updated into FV. + +**/ +EFI_STATUS +PerformUpdateOnFirmwareVolume ( + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize, + IN EFI_FV_FILETYPE FileType, + IN EFI_FV_FILE_ATTRIBUTES FileAttributes + ) +{ + EFI_STATUS Status; + BOOLEAN Found; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + UINTN Index; + UINTN NumOfHandles; + EFI_HANDLE *HandleBuffer; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_FVB_ATTRIBUTES_2 Attributes; + + // + // Locate all Fvb protocol + // + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &NumOfHandles, + &HandleBuffer + ); + if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + return EFI_NOT_FOUND; + } + + // + // Check the FVB protocol one by one + // + Found = FALSE; + FvbProtocol = NULL; + for (Index = 0; Index < NumOfHandles; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &FvbProtocol + ); + if (EFI_ERROR (Status)) { + break; + } + + // + // Ensure this FVB protocol supported Write operation. + // + Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes); + if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { + continue; + } + + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &BaseAddress + ); + if (EFI_ERROR (Status)) { + break; + } + if (BaseAddress == ConfigData->BaseAddress) { + Found = TRUE; + break; + } + } + + if (!Found) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + return EFI_NOT_FOUND; + } + + // + // Now we have got the corresponding FVB protocol. Use the FVB protocol + // to update the whole FV, or certain files in the FV. + // + if (ConfigData->UpdateType == UpdateWholeFV) { + if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = PerformUpdateOnWholeFv ( + HandleBuffer[Index], + FvbProtocol, + ConfigData, + ImageBuffer, + ImageSize + ); + } + } else if (ConfigData->UpdateType == UpdateFvFile) { + Status = PerformUpdateOnFvFile ( + HandleBuffer[Index], + FvbProtocol, + ConfigData, + ImageBuffer, + ImageSize, + FileType, + FileAttributes + ); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + + return Status; +} + +/** + Update the file directly into flash area. + + @param ConfigData Pointer to the config data on updating file. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_SUCCESS The file is updated into flash area. + @retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found. + +**/ +EFI_STATUS +PerformUpdateOnFlashArea ( + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ) +{ + EFI_STATUS Status; + UINTN SizeLeft; + EFI_PHYSICAL_ADDRESS FlashAddress; + UINT8 *PtrImage; + BOOLEAN Found; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + UINTN Index; + UINTN NumOfHandles; + EFI_HANDLE *HandleBuffer; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_HANDLE FvbHandle; + UINTN SizeUpdated; + CHAR16 *TmpStr; + EFI_FVB_ATTRIBUTES_2 Attributes; + + SizeLeft = ImageSize; + PtrImage = ImageBuffer; + FlashAddress = ConfigData->BaseAddress; + Status = EFI_SUCCESS; + HandleBuffer = NULL; + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FLASH_RANGE), NULL); + if (TmpStr != NULL) { + Print (TmpStr, FlashAddress, ((UINT64)SizeLeft + FlashAddress)); + FreePool (TmpStr); + } + + // + // Locate all Fvb protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &NumOfHandles, + &HandleBuffer + ); + if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + return EFI_NOT_FOUND; + } + + while (SizeLeft > 0) { + // + // First get the FVB protocols. If the flash area is a FV, or sub FV, + // we can directly locate all the FVB protocol. Otherwise we should use + // implementation specific method to get the alternate FVB protocol + // + Found = FALSE; + FvbProtocol = NULL; + + // + // Check the FVB protocol one by one + // + for (Index = 0; Index < NumOfHandles; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &FvbProtocol + ); + if (EFI_ERROR (Status)) { + break; + } + + // + // Ensure this FVB protocol supported Write operation. + // + Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes); + if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { + continue; + } + + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &BaseAddress + ); + if (EFI_ERROR (Status)) { + break; + } + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; + + // + // This sub area entry falls in the range of the FV + // + if ((FlashAddress >= BaseAddress) && (FlashAddress < (BaseAddress + FwVolHeader->FvLength))) { + Found = TRUE; + break; + } + } + + if (!Found) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + return EFI_NOT_FOUND; + } + + FvbHandle = HandleBuffer[Index]; + SizeUpdated = 0; + + // + // If the flash area is boot required, the update must be fault tolerant + // + if (ConfigData->FaultTolerant) { + // + // Finally we are here. We have got the corresponding FVB protocol. Now + // we need to convert the physical address to LBA and offset and call + // FTW write. Also check if the flash range is larger than the FV. + // + Status = FaultTolerantUpdateOnPartFv ( + PtrImage, + SizeLeft, + &SizeUpdated, + ConfigData, + FlashAddress, + FvbProtocol, + FvbHandle + ); + } else { + // + // Finally we are here. We have got the corresponding FVB protocol. Now + // we need to convert the physical address to LBA and offset and call + // FVB write. Also check if the flash range is larger than the FV. + // + Status = NonFaultTolerantUpdateOnPartFv ( + PtrImage, + SizeLeft, + &SizeUpdated, + FlashAddress, + FvbProtocol, + FvbHandle + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // As part of the FV has been replaced, the FV driver shall re-parse + // the firmware volume. So re-install FVB protocol here + // + Status = gBS->ReinstallProtocolInterface ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + FvbProtocol, + FvbProtocol + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check if we are done with the update + // + SizeLeft = SizeLeft - SizeUpdated; + FlashAddress = FlashAddress + SizeUpdated; + PtrImage = PtrImage + SizeUpdated; + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + + return Status; +} + +/** + Find the updated file, and program it into the flash area based on the config data. + + @param FwVolProtocol Pointer to FV protocol that contains the updated file. + @param ConfigData Pointer to the Config Data on updating file. + + @retval EFI_INVALID_PARAMETER The update operation is not valid. + @retval EFI_NOT_FOUND The updated file is not found. + @retval EFI_SUCCESS The file is updated into the flash area. + +**/ +EFI_STATUS +PerformUpdate ( + IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol, + IN UPDATE_CONFIG_DATA *ConfigData + ) +{ + EFI_STATUS Status; + UINT8 *FileBuffer; + UINTN FileBufferSize; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES Attrib; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + CHAR16 *TmpStr; + BOOLEAN StartToUpdate; + + Status = EFI_SUCCESS; + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadFile ( + FwVolProtocol, + &(ConfigData->FileGuid), + (VOID **) &FileBuffer, + &FileBufferSize, + &FileType, + &Attrib, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + return Status; + } + + StartToUpdate = FALSE; + + // + // Check if the update image is the one we require + // and then perform the update + // + switch (ConfigData->UpdateType) { + + case UpdateWholeFV: + + // + // For UpdateWholeFv, the update file shall be a firmware volume + // image file. + // + if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n")); + Status = EFI_INVALID_PARAMETER; + } else { + if (FileBuffer != NULL) { + FreePool (FileBuffer); + } + SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadSection ( + FwVolProtocol, + &(ConfigData->FileGuid), + SectionType, + 0, + (VOID **) &FileBuffer, + &FileBufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + // + // Execute the update. For UpdateWholeFv, the update + // will always execute on a whole FV + // + StartToUpdate = TRUE; + Status = PerformUpdateOnFirmwareVolume ( + ConfigData, + FileBuffer, + FileBufferSize, + FileType, + Attrib + ); + + } else { + DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n")); + } + } + break; + + case UpdateFvRange: + + // + // For UpdateFvRange, the update file shall be a raw file + // which does not contain any sections. The contents of the file + // will be directly programmed. + // + if (FileType != EFI_FV_FILETYPE_RAW) { + DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n")); + Status = EFI_INVALID_PARAMETER; + } else { + // + // For UpdateFvRange, the update may be performed on a sub area + // of a certain FV, or a flash area that is not FV, or part of FV. + // The update may also go across more than one FVs. + // + StartToUpdate = TRUE; + Status = PerformUpdateOnFlashArea ( + ConfigData, + FileBuffer, + FileBufferSize + ); + } + break; + + case UpdateFvFile: + + // + // No check will be done the the file got. The contents of the file + // will be directly programmed. + // Though UpdateFvFile will only update a single file, but the update + // will always execute on a FV + // + StartToUpdate = TRUE; + Status = PerformUpdateOnFirmwareVolume ( + ConfigData, + FileBuffer, + FileBufferSize, + FileType, + Attrib + ); + break; + + default: + Status = EFI_INVALID_PARAMETER; + } + + if (StartToUpdate) { + if (EFI_ERROR (Status)) { + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_ABORTED), NULL); + } else { + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_DONE), NULL); + } + if (TmpStr != NULL) { + Print (TmpStr); + FreePool (TmpStr); + } + } + + if (FileBuffer != NULL) { + FreePool(FileBuffer); + FileBuffer = NULL; + } + + return Status; +} + +/** + Process the input firmware volume by using DXE service ProcessFirmwareVolume. + + @param DataBuffer Point to the FV image to be processed. + @param BufferSize Size of the FV image buffer. + @param FwVolProtocol Point to the installed FV protocol for the input FV image. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_VOLUME_CORRUPTED FV image is corrupted. + @retval EFI_SUCCESS FV image is processed and FV protocol is installed. + +**/ +EFI_STATUS +ProcessUpdateImage ( + UINT8 *DataBuffer, + UINTN BufferSize, + EFI_FIRMWARE_VOLUME2_PROTOCOL **FwVolProtocol + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_HANDLE FwVolHandle; + EFI_STATUS Status; + UINT8 *ProcessedDataBuffer; + UINT32 FvAlignment; + + ProcessedDataBuffer = NULL; + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DataBuffer; + if (FwVolHeader->FvLength != BufferSize) { + return EFI_VOLUME_CORRUPTED; + } + + FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16); + // + // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value. + // + if (FvAlignment < 8) { + FvAlignment = 8; + } + // + // Check FvImage Align is required. + // + if (((UINTN) FwVolHeader % FvAlignment) == 0) { + ProcessedDataBuffer = DataBuffer; + } else { + // + // Allocate new aligned buffer to store DataBuffer. + // + ProcessedDataBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment); + if (ProcessedDataBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (ProcessedDataBuffer, DataBuffer, BufferSize); + } + // + // Process the firmware volume + // + gDS->ProcessFirmwareVolume ( + ProcessedDataBuffer, + BufferSize, + &FwVolHandle + ); + + // + // Get the FwVol protocol + // + Status = gBS->HandleProtocol ( + FwVolHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) FwVolProtocol + ); + + return Status; +} + +/** + Find the image in the same FV and program it in a target Firmware Volume device. + After update image, it will reset system and no return. + + @param ImageHandle A handle for the image that is initializing this driver + @param SystemTable A pointer to the EFI system table + + @retval EFI_ABORTED System reset failed. + @retval EFI_NOT_FOUND The updated image is not found in the same FV. + +**/ +EFI_STATUS +EFIAPI +InitializeUpdateDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol; + EFI_FIRMWARE_VOLUME2_PROTOCOL *DataFwVolProtocol; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *AlignedDevPathNode; + EFI_DEVICE_PATH_PROTOCOL *FilePathNode; + EFI_SECTION_TYPE SectionType; + UINT8 *FileBuffer; + UINTN FileBufferSize; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES Attrib; + UINT32 AuthenticationStatus; + UPDATE_CONFIG_DATA *ConfigData; + UPDATE_CONFIG_DATA *UpdateConfigData; + UINTN NumOfUpdates; + UINTN Index; + CHAR16 *TmpStr; + + // + // Clear screen + // + if (gST->ConOut != NULL) { + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT); + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + } + + gHiiHandle = HiiAddPackages ( + &gEfiCallerIdGuid, + NULL, + UpdateDriverDxeStrings, + NULL + ); + ASSERT (gHiiHandle != NULL); + + // + // In order to look for the update data file and programmed image file + // from the same volume which this driver is dispatched from, we need + // to get the device path of this driver image. It is done by first + // locate the LoadedImageProtocol and then get its device path + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImageProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the firmware volume protocol where this file resides + // + Status = gBS->HandleProtocol ( + LoadedImageProtocol->DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) &FwVolProtocol + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Shall do some extra check to see if it is really contained in the FV? + // Should be able to find the section of this driver in the the FV. + // + FilePathNode = LoadedImageProtocol->FilePath; + FwVolFilePathNode = NULL; + while (!IsDevicePathEnd (FilePathNode)) { + if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePathNode)!= NULL) { + FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePathNode; + break; + } + FilePathNode = NextDevicePathNode (FilePathNode); + } + + if (FwVolFilePathNode != NULL) { + AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode), FwVolFilePathNode); + + SectionType = EFI_SECTION_PE32; + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadSection ( + FwVolProtocol, + &(AlignedDevPathNode->FvFileName), + SectionType, + 0, + (VOID **) &FileBuffer, + &FileBufferSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + FreePool (AlignedDevPathNode); + return Status; + } + + if (FileBuffer != NULL) { + FreePool(FileBuffer); + FileBuffer = NULL; + } + + // + // Check the NameGuid of the udpate driver so that it can be + // used as the CallerId in fault tolerant write protocol + // + if (!CompareGuid (&gEfiCallerIdGuid, &(AlignedDevPathNode->FvFileName))) { + FreePool (AlignedDevPathNode); + return EFI_NOT_FOUND; + } + FreePool (AlignedDevPathNode); + } else { + return EFI_NOT_FOUND; + } + + // + // Now try to find the script file. The script file is usually + // a raw data file which does not contain any sections. + // + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadFile ( + FwVolProtocol, + &gEfiConfigFileNameGuid, + (VOID **) &FileBuffer, + &FileBufferSize, + &FileType, + &Attrib, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (FileType != EFI_FV_FILETYPE_RAW) { + return EFI_NOT_FOUND; + } + + // + // Parse the configuration file. + // + ConfigData = NULL; + NumOfUpdates = 0; + Status = ParseUpdateDataFile ( + FileBuffer, + FileBufferSize, + &NumOfUpdates, + &ConfigData + ); + if (FileBuffer != NULL) { + FreePool (FileBuffer); + FileBuffer = NULL; + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now find the update image. The update image should be put in a FV, and then + // encapsulated as a raw FFS file. This is to prevent the update image from + // being dispatched. So the raw data we get here should be an FV. We need to + // process this FV and read the files that is going to be updated. + // + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadFile ( + FwVolProtocol, + &UpdateDataGuid, + (VOID **) &FileBuffer, + &FileBufferSize, + &FileType, + &Attrib, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (FileType != EFI_FV_FILETYPE_RAW) { + return EFI_NOT_FOUND; + } + + // + // FileBuffer should be an FV. Process the FV + // + DataFwVolProtocol = NULL; + Status = ProcessUpdateImage ( + FileBuffer, + FileBufferSize, + &DataFwVolProtocol + ); + if (EFI_ERROR (Status)) { + FreePool (FileBuffer); + return Status; + } + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_PROCESS_DATA), NULL); + if (TmpStr != NULL) { + Print (TmpStr); + FreePool(TmpStr); + } + + // + // Execute the update + // + Index = 0; + UpdateConfigData = ConfigData; + while (Index < NumOfUpdates) { + Status = PerformUpdate ( + DataFwVolProtocol, + UpdateConfigData + ); + // + // Shall updates be serialized so that if an update is not successfully completed, + // the remaining updates won't be performed. + // + if (EFI_ERROR (Status)) { + break; + } + + Index++; + UpdateConfigData++; + } + + if (EFI_ERROR (Status)) { + if (ConfigData != NULL) { + FreePool(ConfigData); + ConfigData = NULL; + } + return Status; + } + + // + // Call system reset + // + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + + // + // Hopefully it won't be reached + // + return EFI_ABORTED; +} diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h new file mode 100644 index 0000000000..9fd00b3b2d --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h @@ -0,0 +1,218 @@ +/** @file + Common defines and definitions for a component update driver. + + Copyright (c) 2002 - 2010, 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_UPDATE_DRIVER_H_ +#define _EFI_UPDATE_DRIVER_H_ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// {283FA2EE-532C-484d-9383-9F93B36F0B7E} +// +#define EFI_UPDATE_DATA_FILE_GUID \ + { 0x283fa2ee, 0x532c, 0x484d, { 0x93, 0x83, 0x9f, 0x93, 0xb3, 0x6f, 0xb, 0x7e } } + +extern EFI_HII_HANDLE gHiiHandle; + +typedef enum { + UpdateWholeFV = 0, // 0, update whole FV + UpdateFvFile, // 1, update a set of FV files asynchronously + UpdateFvRange, // 2, update part of FV or flash + UpdateOperationMaximum // 3 +} UPDATE_OPERATION_TYPE; + +typedef struct { + UINTN Index; + UPDATE_OPERATION_TYPE UpdateType; + EFI_DEVICE_PATH_PROTOCOL DevicePath; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_GUID FileGuid; + UINTN Length; + BOOLEAN FaultTolerant; +} UPDATE_CONFIG_DATA; + +typedef struct _SECTION_ITEM SECTION_ITEM; +struct _SECTION_ITEM { + CHAR8 *ptrSection; + UINTN SecNameLen; + CHAR8 *ptrEntry; + CHAR8 *ptrValue; + SECTION_ITEM *ptrNext; +}; + +typedef struct _COMMENT_LINE COMMENT_LINE; +struct _COMMENT_LINE { + CHAR8 *ptrComment; + COMMENT_LINE *ptrNext; +}; + +typedef struct { + EFI_GUID FileGuid; +} UPDATE_PRIVATE_DATA; + +#define MAX_LINE_LENGTH 512 +#define EFI_D_UPDATE EFI_D_ERROR + +#define MIN_ALIGNMENT_SIZE 4 +#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0) + +/** + Parse Config data file to get the updated data array. + + @param DataBuffer Config raw file buffer. + @param BufferSize Size of raw buffer. + @param NumOfUpdates Pointer to the number of update data. + @param UpdateArray Pointer to the config of update data. + + @retval EFI_NOT_FOUND No config data is found. + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Parse the config file successfully. + +**/ +EFI_STATUS +ParseUpdateDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT UINTN *NumOfUpdates, + IN OUT UPDATE_CONFIG_DATA **UpdateArray + ); + +/** + Update the whole FV image, and reinsall FVB protocol for the updated FV image. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV. + Or Image size is not same to the size of whole FV. + @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated. + @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled. + +**/ +EFI_STATUS +PerformUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ); + +/** + Update certain file in the FV. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + @param FileType FFS file type. + @param FileAttributes FFS file attribute + + @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile. + Or Image size is not same to the size of whole FV. + @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated. + @retval EFI_SUCCESS The FFS file is added into FV. + +**/ +EFI_STATUS +PerformUpdateOnFvFile ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize, + IN EFI_FV_FILETYPE FileType, + IN EFI_FV_FILE_ATTRIBUTES FileAttributes + ); + +/** + Update the buffer into flash area in fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param ConfigData Config data on updating driver. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_NOT_FOUND FTW protocol doesn't exist. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + @retval EFI_ABORTED Error happen when update flash area. + +**/ +EFI_STATUS +FaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN UPDATE_CONFIG_DATA *ConfigData, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ); + +/** + Directly update the buffer into flash area without fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + +**/ +EFI_STATUS +NonFaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ); + +#endif diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf new file mode 100644 index 0000000000..5ec26e249e --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf @@ -0,0 +1,69 @@ +## @file +# This driver is intended to be put in a capsule (FV). If all goes well, +# then it should be dispatched from the capsule FV, then find the image +# in the same FV and program it in a target Firmware Volume device. +# +# Copyright (c) 2006 - 2010, 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 = UpdateDriverDxe + FILE_GUID = 0E84FC69-29CC-4C6D-92AC-6D476921850F + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeUpdateDriver + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + UpdateDriver.h + UpdateStrings.uni + UpdateDispatcher.c + ParseUpdateProfile.c + FlashUpdate.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + BaseLib + PrintLib + HiiLib + DxeServicesTableLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + DevicePathLib + +[Guids] + gEfiConfigFileNameGuid ## CONSUMES FileName to store ConfigFile + +[Protocols] + gEfiFaultTolerantWriteProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + +[Depex] + gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid + diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni new file mode 100644 index 0000000000..914a012825 Binary files /dev/null and b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni differ -- cgit v1.2.3