IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf\r
IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf\r
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf\r
+ IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf\r
\r
[Components.IA32,Components.X64]\r
IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf\r
--- /dev/null
+/** @file\r
+ Functions in this file will program the image into flash area.\r
+\r
+ Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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
--- /dev/null
+/** @file\r
+ Source file for the component update driver. It parse the update\r
+ configuration file and pass the information to the update driver\r
+ so that the driver can perform updates accordingly.\r
+\r
+ Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UpdateDriver.h"\r
+\r
+/**\r
+ Copy one line data from buffer data to the line buffer.\r
+\r
+ @param Buffer Buffer data.\r
+ @param BufferSize Buffer Size.\r
+ @param LineBuffer Line buffer to store the found line data.\r
+ @param LineSize On input, size of the input line buffer.\r
+ On output, size of the actual line buffer.\r
+\r
+ @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough.\r
+ @retval EFI_SUCCESS Copy line data into the line buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+ProfileGetLine (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT UINT8 *LineBuffer,\r
+ IN OUT UINTN *LineSize\r
+ )\r
+{\r
+ UINTN Length;\r
+ UINT8 *PtrBuf;\r
+ UINTN PtrEnd;\r
+\r
+ PtrBuf = Buffer;\r
+ PtrEnd = (UINTN)Buffer + BufferSize;\r
+\r
+ //\r
+ // 0x0D indicates a line break. Otherwise there is no line break\r
+ //\r
+ while ((UINTN)PtrBuf < PtrEnd) {\r
+ if (*PtrBuf == 0x0D) {\r
+ break;\r
+ }\r
+ PtrBuf++;\r
+ }\r
+\r
+ if ((UINTN)PtrBuf >= (PtrEnd - 1)) {\r
+ //\r
+ // The buffer ends without any line break\r
+ // or it is the last character of the buffer\r
+ //\r
+ Length = BufferSize;\r
+ } else if (*(PtrBuf + 1) == 0x0A) {\r
+ //\r
+ // Further check if a 0x0A follows. If yes, count 0xA\r
+ //\r
+ Length = (UINTN) PtrBuf - (UINTN) Buffer + 2;\r
+ } else {\r
+ Length = (UINTN) PtrBuf - (UINTN) Buffer + 1;\r
+ }\r
+\r
+ if (Length > (*LineSize)) {\r
+ *LineSize = Length;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ SetMem (LineBuffer, *LineSize, 0x0);\r
+ *LineSize = Length;\r
+ CopyMem (LineBuffer, Buffer, Length);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.\r
+\r
+ @param Buffer On input, buffer data to be trimed.\r
+ On output, the trimmed buffer.\r
+ @param BufferSize On input, size of original buffer data.\r
+ On output, size of the trimmed buffer.\r
+\r
+**/\r
+VOID\r
+ProfileTrim (\r
+ IN OUT UINT8 *Buffer,\r
+ IN OUT UINTN *BufferSize\r
+ )\r
+{\r
+ UINTN Length;\r
+ UINT8 *PtrBuf;\r
+ UINT8 *PtrEnd;\r
+\r
+ if (*BufferSize == 0) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Trim the tail first, include CR, LF, TAB, and SPACE.\r
+ //\r
+ Length = *BufferSize;\r
+ PtrBuf = (UINT8 *) ((UINTN) Buffer + Length - 1);\r
+ while (PtrBuf >= Buffer) {\r
+ if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )\r
+ && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {\r
+ break;\r
+ }\r
+ PtrBuf --;\r
+ }\r
+\r
+ //\r
+ // all spaces, a blank line, return directly;\r
+ //\r
+ if (PtrBuf < Buffer) {\r
+ *BufferSize = 0;\r
+ return;\r
+ }\r
+\r
+ Length = (UINTN)PtrBuf - (UINTN)Buffer + 1;\r
+ PtrEnd = PtrBuf;\r
+ PtrBuf = Buffer;\r
+\r
+ //\r
+ // Now skip the heading CR, LF, TAB and SPACE\r
+ //\r
+ while (PtrBuf <= PtrEnd) {\r
+ if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )\r
+ && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {\r
+ break;\r
+ }\r
+ PtrBuf++;\r
+ }\r
+\r
+ //\r
+ // If no heading CR, LF, TAB or SPACE, directly return\r
+ //\r
+ if (PtrBuf == Buffer) {\r
+ *BufferSize = Length;\r
+ return;\r
+ }\r
+\r
+ *BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1;\r
+\r
+ //\r
+ // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.\r
+ // Now move out all these characters.\r
+ //\r
+ while (PtrBuf <= PtrEnd) {\r
+ *Buffer = *PtrBuf;\r
+ Buffer++;\r
+ PtrBuf++;\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Insert new comment item into comment head.\r
+\r
+ @param Buffer Comment buffer to be added.\r
+ @param BufferSize Size of comment buffer.\r
+ @param CommentHead Comment Item head entry.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS New comment item is inserted.\r
+\r
+**/\r
+EFI_STATUS\r
+ProfileGetComments (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT COMMENT_LINE **CommentHead\r
+ )\r
+{\r
+ COMMENT_LINE *CommentItem;\r
+\r
+ CommentItem = NULL;\r
+ CommentItem = AllocatePool (sizeof (COMMENT_LINE));\r
+ if (CommentItem == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CommentItem->ptrNext = *CommentHead;\r
+ *CommentHead = CommentItem;\r
+\r
+ //\r
+ // Add a trailing '\0'\r
+ //\r
+ CommentItem->ptrComment = AllocatePool (BufferSize + 1);\r
+ if (CommentItem->ptrComment == NULL) {\r
+ FreePool (CommentItem);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CopyMem (CommentItem->ptrComment, Buffer, BufferSize);\r
+ *(CommentItem->ptrComment + BufferSize) = '\0';\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Add new section item into Section head.\r
+\r
+ @param Buffer Section item data buffer.\r
+ @param BufferSize Size of section item.\r
+ @param SectionHead Section item head entry.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS Section item is NULL or Section item is added.\r
+\r
+**/\r
+EFI_STATUS\r
+ProfileGetSection (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT SECTION_ITEM **SectionHead\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SECTION_ITEM *SectionItem;\r
+ UINTN Length;\r
+ UINT8 *PtrBuf;\r
+\r
+ Status = EFI_SUCCESS;\r
+ //\r
+ // The first character of Buffer is '[', now we want for ']'\r
+ //\r
+ PtrBuf = (UINT8 *)((UINTN)Buffer + BufferSize - 1);\r
+ while (PtrBuf > Buffer) {\r
+ if (*PtrBuf == ']') {\r
+ break;\r
+ }\r
+ PtrBuf --;\r
+ }\r
+ if (PtrBuf <= Buffer) {\r
+ //\r
+ // Not found. Omit this line\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // excluding the heading '[' and tailing ']'\r
+ //\r
+ Length = PtrBuf - Buffer - 1;\r
+ ProfileTrim (\r
+ Buffer + 1,\r
+ &Length\r
+ );\r
+\r
+ //\r
+ // omit this line if the section name is null\r
+ //\r
+ if (Length == 0) {\r
+ return Status;\r
+ }\r
+\r
+ SectionItem = AllocatePool (sizeof (SECTION_ITEM));\r
+ if (SectionItem == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ SectionItem->ptrSection = NULL;\r
+ SectionItem->SecNameLen = Length;\r
+ SectionItem->ptrEntry = NULL;\r
+ SectionItem->ptrValue = NULL;\r
+ SectionItem->ptrNext = *SectionHead;\r
+ *SectionHead = SectionItem;\r
+\r
+ //\r
+ // Add a trailing '\0'\r
+ //\r
+ SectionItem->ptrSection = AllocatePool (Length + 1);\r
+ if (SectionItem->ptrSection == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // excluding the heading '['\r
+ //\r
+ CopyMem (SectionItem->ptrSection, Buffer + 1, Length);\r
+ *(SectionItem->ptrSection + Length) = '\0';\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Add new section entry and entry value into Section head.\r
+\r
+ @param Buffer Section entry data buffer.\r
+ @param BufferSize Size of section entry.\r
+ @param SectionHead Section item head entry.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS Section entry is NULL or Section entry is added.\r
+\r
+**/\r
+EFI_STATUS\r
+ProfileGetEntry (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT SECTION_ITEM **SectionHead\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SECTION_ITEM *SectionItem;\r
+ SECTION_ITEM *PtrSection;\r
+ UINTN Length;\r
+ UINT8 *PtrBuf;\r
+ UINT8 *PtrEnd;\r
+\r
+ Status = EFI_SUCCESS;\r
+ PtrBuf = Buffer;\r
+ PtrEnd = (UINT8 *) ((UINTN)Buffer + BufferSize - 1);\r
+\r
+ //\r
+ // First search for '='\r
+ //\r
+ while (PtrBuf <= PtrEnd) {\r
+ if (*PtrBuf == '=') {\r
+ break;\r
+ }\r
+ PtrBuf++;\r
+ }\r
+ if (PtrBuf > PtrEnd) {\r
+ //\r
+ // Not found. Omit this line\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // excluding the tailing '='\r
+ //\r
+ Length = PtrBuf - Buffer;\r
+ ProfileTrim (\r
+ Buffer,\r
+ &Length\r
+ );\r
+\r
+ //\r
+ // Omit this line if the entry name is null\r
+ //\r
+ if (Length == 0) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Omit this line if no section header has been found before\r
+ //\r
+ if (*SectionHead == NULL) {\r
+ return Status;\r
+ }\r
+ PtrSection = *SectionHead;\r
+\r
+ SectionItem = AllocatePool (sizeof (SECTION_ITEM));\r
+ if (SectionItem == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ SectionItem->ptrSection = NULL;\r
+ SectionItem->ptrEntry = NULL;\r
+ SectionItem->ptrValue = NULL;\r
+ SectionItem->SecNameLen = PtrSection->SecNameLen;\r
+ SectionItem->ptrNext = *SectionHead;\r
+ *SectionHead = SectionItem;\r
+\r
+ //\r
+ // SectionName, add a trailing '\0'\r
+ //\r
+ SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1);\r
+ if (SectionItem->ptrSection == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1);\r
+\r
+ //\r
+ // EntryName, add a trailing '\0'\r
+ //\r
+ SectionItem->ptrEntry = AllocatePool (Length + 1);\r
+ if (SectionItem->ptrEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CopyMem (SectionItem->ptrEntry, Buffer, Length);\r
+ *(SectionItem->ptrEntry + Length) = '\0';\r
+\r
+ //\r
+ // Next search for '#'\r
+ //\r
+ PtrBuf = PtrBuf + 1;\r
+ Buffer = PtrBuf;\r
+ while (PtrBuf <= PtrEnd) {\r
+ if (*PtrBuf == '#') {\r
+ break;\r
+ }\r
+ PtrBuf++;\r
+ }\r
+ Length = PtrBuf - Buffer;\r
+ ProfileTrim (\r
+ Buffer,\r
+ &Length\r
+ );\r
+\r
+ if (Length > 0) {\r
+ //\r
+ // EntryValue, add a trailing '\0'\r
+ //\r
+ SectionItem->ptrValue = AllocatePool (Length + 1);\r
+ if (SectionItem->ptrValue == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CopyMem (SectionItem->ptrValue, Buffer, Length);\r
+ *(SectionItem->ptrValue + Length) = '\0';\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free all comment entry and section entry.\r
+\r
+ @param Section Section entry list.\r
+ @param Comment Comment entry list.\r
+\r
+**/\r
+VOID\r
+FreeAllList (\r
+ IN SECTION_ITEM *Section,\r
+ IN COMMENT_LINE *Comment\r
+ )\r
+{\r
+ SECTION_ITEM *PtrSection;\r
+ COMMENT_LINE *PtrComment;\r
+\r
+ while (Section != NULL) {\r
+ PtrSection = Section;\r
+ Section = Section->ptrNext;\r
+ if (PtrSection->ptrEntry != NULL) {\r
+ FreePool (PtrSection->ptrEntry);\r
+ }\r
+ if (PtrSection->ptrSection != NULL) {\r
+ FreePool (PtrSection->ptrSection);\r
+ }\r
+ if (PtrSection->ptrValue != NULL) {\r
+ FreePool (PtrSection->ptrValue);\r
+ }\r
+ FreePool (PtrSection);\r
+ }\r
+\r
+ while (Comment != NULL) {\r
+ PtrComment = Comment;\r
+ Comment = Comment->ptrNext;\r
+ if (PtrComment->ptrComment != NULL) {\r
+ FreePool (PtrComment->ptrComment);\r
+ }\r
+ FreePool (PtrComment);\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Get section entry value.\r
+\r
+ @param Section Section entry list.\r
+ @param SectionName Section name.\r
+ @param EntryName Section entry name.\r
+ @param EntryValue Point to the got entry value.\r
+\r
+ @retval EFI_NOT_FOUND Section is not found.\r
+ @retval EFI_SUCCESS Section entry value is got.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateGetProfileString (\r
+ IN SECTION_ITEM *Section,\r
+ IN UINT8 *SectionName,\r
+ IN UINT8 *EntryName,\r
+ OUT UINT8 **EntryValue\r
+ )\r
+{\r
+ *EntryValue = NULL;\r
+\r
+ while (Section != NULL) {\r
+ if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) {\r
+ if (Section->ptrEntry != NULL) {\r
+ if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ Section = Section->ptrNext;\r
+ }\r
+\r
+ if (Section == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *EntryValue = (UINT8 *) Section->ptrValue;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert the dec or hex ascii string to value.\r
+\r
+ @param Str ascii string to be converted.\r
+\r
+ @return the converted value.\r
+\r
+**/\r
+UINTN\r
+UpdateAtoi (\r
+ IN UINT8 *Str\r
+ )\r
+{\r
+ UINTN Number;\r
+\r
+ Number = 0;\r
+\r
+ //\r
+ // Skip preceeding while spaces\r
+ //\r
+ while (*Str != '\0') {\r
+ if (*Str != 0x20) {\r
+ break;\r
+ }\r
+ Str++;\r
+ }\r
+\r
+ if (*Str == '\0') {\r
+ return Number;\r
+ }\r
+\r
+ //\r
+ // Find whether the string is prefixed by 0x.\r
+ // That is, it should be xtoi or atoi.\r
+ //\r
+ if (*Str == '0') {\r
+ if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) {\r
+ return AsciiStrHexToUintn ((CONST CHAR8 *) Str);\r
+ }\r
+ }\r
+\r
+ while (*Str != '\0') {\r
+ if ((*Str >= '0') && (*Str <= '9')) {\r
+ Number = Number * 10 + *Str - '0';\r
+ } else {\r
+ break;\r
+ }\r
+ Str++;\r
+ }\r
+\r
+ return Number;\r
+}\r
+\r
+/**\r
+ Converts a decimal value to a Null-terminated ascii string.\r
+\r
+ @param Buffer Pointer to the output buffer for the produced Null-terminated\r
+ ASCII string.\r
+ @param Value The 64-bit sgned value to convert to a string.\r
+\r
+ @return The number of ASCII characters in Buffer not including the Null-terminator.\r
+\r
+**/\r
+UINTN\r
+UpdateValueToString (\r
+ IN OUT UINT8 *Buffer,\r
+ IN INT64 Value\r
+ )\r
+{\r
+ UINT8 TempBuffer[30];\r
+ UINT8 *TempStr;\r
+ UINT8 *BufferPtr;\r
+ UINTN Count;\r
+ UINT32 Remainder;\r
+\r
+ TempStr = TempBuffer;\r
+ BufferPtr = Buffer;\r
+ Count = 0;\r
+\r
+ if (Value < 0) {\r
+ *BufferPtr = '-';\r
+ BufferPtr++;\r
+ Value = -Value;\r
+ Count++;\r
+ }\r
+\r
+ do {\r
+ Value = (INT64) DivU64x32Remainder ((UINT64)Value, 10, &Remainder);\r
+ //\r
+ // The first item of TempStr is not occupied. It's kind of flag\r
+ //\r
+ TempStr++;\r
+ Count++;\r
+ *TempStr = (UINT8) ((UINT8)Remainder + '0');\r
+ } while (Value != 0);\r
+\r
+ //\r
+ // Reverse temp string into Buffer.\r
+ //\r
+ while (TempStr != TempBuffer) {\r
+ *BufferPtr = *TempStr;\r
+ BufferPtr++;\r
+ TempStr --;\r
+ }\r
+\r
+ *BufferPtr = 0;\r
+\r
+ return Count;\r
+}\r
+\r
+/**\r
+ Convert the input value to a ascii string, \r
+ and concatenates this string to the input string.\r
+\r
+ @param Str Pointer to a Null-terminated ASCII string.\r
+ @param Number The unsgned value to convert to a string.\r
+\r
+**/\r
+VOID\r
+UpdateStrCatNumber (\r
+ IN OUT UINT8 *Str,\r
+ IN UINTN Number\r
+ )\r
+{\r
+ UINTN Count;\r
+\r
+ while (*Str != '\0') {\r
+ Str++;\r
+ }\r
+\r
+ Count = UpdateValueToString (Str, (INT64)Number);\r
+\r
+ *(Str + Count) = '\0';\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Convert the input ascii string into GUID value.\r
+\r
+ @param Str Ascii GUID string to be converted.\r
+ @param Guid Pointer to the converted GUID value.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_NOT_FOUND The input ascii string is not a valid GUID format string.\r
+ @retval EFI_SUCCESS GUID value is got.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateStringToGuid (\r
+ IN UINT8 *Str,\r
+ IN OUT EFI_GUID *Guid\r
+ )\r
+{\r
+ UINT8 *PtrBuffer;\r
+ UINT8 *PtrPosition;\r
+ UINT8 *Buffer;\r
+ UINTN Data;\r
+ UINTN StrLen;\r
+ UINTN Index;\r
+ UINT8 Digits[3];\r
+\r
+ StrLen = AsciiStrLen ((CONST CHAR8 *) Str);\r
+ Buffer = AllocatePool (StrLen + 1);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AsciiStrCpy ((CHAR8 *)Buffer, (CHAR8 *)Str);\r
+\r
+ //\r
+ // Data1\r
+ //\r
+ PtrBuffer = Buffer;\r
+ PtrPosition = PtrBuffer;\r
+ while (*PtrBuffer != '\0') {\r
+ if (*PtrBuffer == '-') {\r
+ break;\r
+ }\r
+ PtrBuffer++;\r
+ }\r
+ if (*PtrBuffer == '\0') {\r
+ FreePool (Buffer);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *PtrBuffer = '\0';\r
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);\r
+ Guid->Data1 = (UINT32)Data;\r
+\r
+ //\r
+ // Data2\r
+ //\r
+ PtrBuffer++;\r
+ PtrPosition = PtrBuffer;\r
+ while (*PtrBuffer != '\0') {\r
+ if (*PtrBuffer == '-') {\r
+ break;\r
+ }\r
+ PtrBuffer++;\r
+ }\r
+ if (*PtrBuffer == '\0') {\r
+ FreePool (Buffer);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ *PtrBuffer = '\0';\r
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);\r
+ Guid->Data2 = (UINT16)Data;\r
+\r
+ //\r
+ // Data3\r
+ //\r
+ PtrBuffer++;\r
+ PtrPosition = PtrBuffer;\r
+ while (*PtrBuffer != '\0') {\r
+ if (*PtrBuffer == '-') {\r
+ break;\r
+ }\r
+ PtrBuffer++;\r
+ }\r
+ if (*PtrBuffer == '\0') {\r
+ FreePool (Buffer);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ *PtrBuffer = '\0';\r
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);\r
+ Guid->Data3 = (UINT16)Data;\r
+\r
+ //\r
+ // Data4[0..1]\r
+ //\r
+ for ( Index = 0 ; Index < 2 ; Index++) {\r
+ PtrBuffer++;\r
+ if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {\r
+ FreePool (Buffer);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ Digits[0] = *PtrBuffer;\r
+ PtrBuffer++;\r
+ Digits[1] = *PtrBuffer;\r
+ Digits[2] = '\0';\r
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);\r
+ Guid->Data4[Index] = (UINT8)Data;\r
+ }\r
+\r
+ //\r
+ // skip the '-'\r
+ //\r
+ PtrBuffer++;\r
+ if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Data4[2..7]\r
+ //\r
+ for ( ; Index < 8; Index++) {\r
+ PtrBuffer++;\r
+ if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {\r
+ FreePool (Buffer);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ Digits[0] = *PtrBuffer;\r
+ PtrBuffer++;\r
+ Digits[1] = *PtrBuffer;\r
+ Digits[2] = '\0';\r
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);\r
+ Guid->Data4[Index] = (UINT8)Data;\r
+ }\r
+\r
+ FreePool (Buffer);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Pre process config data buffer into Section entry list and Comment entry list.\r
+ \r
+ @param DataBuffer Config raw file buffer.\r
+ @param BufferSize Size of raw buffer.\r
+ @param SectionHead Pointer to the section entry list.\r
+ @param CommentHead Pointer to the comment entry list.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS Config data buffer is preprocessed.\r
+\r
+**/\r
+EFI_STATUS\r
+PreProcessDataFile (\r
+ IN UINT8 *DataBuffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT SECTION_ITEM **SectionHead,\r
+ IN OUT COMMENT_LINE **CommentHead\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *Source;\r
+ CHAR8 *CurrentPtr;\r
+ CHAR8 *BufferEnd;\r
+ CHAR8 *PtrLine;\r
+ UINTN LineLength;\r
+ UINTN SourceLength;\r
+ UINTN MaxLineLength;\r
+\r
+ *SectionHead = NULL;\r
+ *CommentHead = NULL;\r
+ BufferEnd = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize);\r
+ CurrentPtr = (CHAR8 *) DataBuffer;\r
+ MaxLineLength = MAX_LINE_LENGTH;\r
+ Status = EFI_SUCCESS;\r
+\r
+ PtrLine = AllocatePool (MaxLineLength);\r
+ if (PtrLine == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ while (CurrentPtr < BufferEnd) {\r
+ Source = CurrentPtr;\r
+ SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr;\r
+ LineLength = MaxLineLength;\r
+ //\r
+ // With the assumption that line length is less than 512\r
+ // characters. Otherwise BUFFER_TOO_SMALL will be returned.\r
+ //\r
+ Status = ProfileGetLine (\r
+ (UINT8 *) Source,\r
+ SourceLength,\r
+ (UINT8 *) PtrLine,\r
+ &LineLength\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // If buffer too small, re-allocate the buffer according\r
+ // to the returned LineLength and try again.\r
+ //\r
+ FreePool (PtrLine);\r
+ PtrLine = NULL;\r
+ PtrLine = AllocatePool (LineLength);\r
+ if (PtrLine == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+ SourceLength = LineLength;\r
+ Status = ProfileGetLine (\r
+ (UINT8 *) Source,\r
+ SourceLength,\r
+ (UINT8 *) PtrLine,\r
+ &LineLength\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ MaxLineLength = LineLength;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ CurrentPtr = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength);\r
+\r
+ //\r
+ // Line got. Trim the line before processing it.\r
+ //\r
+ ProfileTrim (\r
+ (UINT8 *) PtrLine,\r
+ &LineLength\r
+ );\r
+\r
+ //\r
+ // Blank line\r
+ //\r
+ if (LineLength == 0) {\r
+ continue;\r
+ }\r
+\r
+ if (PtrLine[0] == '#') {\r
+ Status = ProfileGetComments (\r
+ (UINT8 *) PtrLine,\r
+ LineLength,\r
+ CommentHead\r
+ );\r
+ } else if (PtrLine[0] == '[') {\r
+ Status = ProfileGetSection (\r
+ (UINT8 *) PtrLine,\r
+ LineLength,\r
+ SectionHead\r
+ );\r
+ } else {\r
+ Status = ProfileGetEntry (\r
+ (UINT8 *) PtrLine,\r
+ LineLength,\r
+ SectionHead\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free buffer\r
+ //\r
+ FreePool (PtrLine);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Parse Config data file to get the updated data array.\r
+\r
+ @param DataBuffer Config raw file buffer.\r
+ @param BufferSize Size of raw buffer.\r
+ @param NumOfUpdates Pointer to the number of update data.\r
+ @param UpdateArray Pointer to the config of update data.\r
+\r
+ @retval EFI_NOT_FOUND No config data is found.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS Parse the config file successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseUpdateDataFile (\r
+ IN UINT8 *DataBuffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT UINTN *NumOfUpdates,\r
+ IN OUT UPDATE_CONFIG_DATA **UpdateArray\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *Value;\r
+ CHAR8 *SectionName;\r
+ CHAR8 Entry[MAX_LINE_LENGTH];\r
+ SECTION_ITEM *SectionHead;\r
+ COMMENT_LINE *CommentHead;\r
+ UINTN Num;\r
+ UINTN Index;\r
+ EFI_GUID FileGuid;\r
+\r
+ SectionHead = NULL;\r
+ CommentHead = NULL;\r
+\r
+ //\r
+ // First process the data buffer and get all sections and entries\r
+ //\r
+ Status = PreProcessDataFile (\r
+ DataBuffer,\r
+ BufferSize,\r
+ &SectionHead,\r
+ &CommentHead\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Now get NumOfUpdate\r
+ //\r
+ Value = NULL;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) "Head",\r
+ (UINT8 *) "NumOfUpdate",\r
+ (UINT8 **) &Value\r
+ );\r
+ if (Value == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ Num = UpdateAtoi((UINT8 *) Value);\r
+ if (Num <= 0) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *NumOfUpdates = Num;\r
+ *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num));\r
+ if (*UpdateArray == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for ( Index = 0 ; Index < *NumOfUpdates ; Index++) {\r
+ //\r
+ // Get the section name of each update\r
+ //\r
+ AsciiStrCpy (Entry, "Update");\r
+ UpdateStrCatNumber ((UINT8 *) Entry, Index);\r
+ Value = NULL;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) "Head",\r
+ (UINT8 *) Entry,\r
+ (UINT8 **) &Value\r
+ );\r
+ if (Value == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // The section name of this update has been found.\r
+ // Now looks for all the config data of this update\r
+ //\r
+ SectionName = Value;\r
+\r
+ //\r
+ // UpdateType\r
+ //\r
+ Value = NULL;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) SectionName,\r
+ (UINT8 *) "UpdateType",\r
+ (UINT8 **) &Value\r
+ );\r
+ if (Value == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Num = UpdateAtoi((UINT8 *) Value);\r
+ if (( Num >= (UINTN) UpdateOperationMaximum)) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return Status;\r
+ }\r
+ (*UpdateArray)[Index].Index = Index;\r
+ (*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num;\r
+\r
+ //\r
+ // FvBaseAddress\r
+ //\r
+ Value = NULL;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) SectionName,\r
+ (UINT8 *) "FvBaseAddress",\r
+ (UINT8 **) &Value\r
+ );\r
+ if (Value == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value);\r
+ (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num;\r
+\r
+ //\r
+ // FileBuid\r
+ //\r
+ Value = NULL;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) SectionName,\r
+ (UINT8 *) "FileGuid",\r
+ (UINT8 **) &Value\r
+ );\r
+ if (Value == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid);\r
+ if (EFI_ERROR (Status)) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return Status;\r
+ }\r
+ CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID));\r
+\r
+ //\r
+ // FaultTolerant\r
+ // Default value is FALSE\r
+ //\r
+ Value = NULL;\r
+ (*UpdateArray)[Index].FaultTolerant = FALSE;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) SectionName,\r
+ (UINT8 *) "FaultTolerant",\r
+ (UINT8 **) &Value\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return Status;\r
+ } else if (Value != NULL) {\r
+ if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) {\r
+ (*UpdateArray)[Index].FaultTolerant = TRUE;\r
+ } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) {\r
+ (*UpdateArray)[Index].FaultTolerant = FALSE;\r
+ }\r
+ }\r
+\r
+ if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) {\r
+ //\r
+ // Length\r
+ //\r
+ Value = NULL;\r
+ Status = UpdateGetProfileString (\r
+ SectionHead,\r
+ (UINT8 *) SectionName,\r
+ (UINT8 *) "Length",\r
+ (UINT8 **) &Value\r
+ );\r
+ if (Value == NULL) {\r
+ FreeAllList (SectionHead, CommentHead);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value);\r
+ (*UpdateArray)[Index].Length = (UINTN) Num;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Now all configuration data got. Free those temporary buffers\r
+ //\r
+ FreeAllList (SectionHead, CommentHead);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Functions in this file will mainly focus on looking through the capsule\r
+ for the image to be programmed, and the flash area that is going to be\r
+ programed.\r
+\r
+ Copyright (c) 2002 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UpdateDriver.h"\r
+\r
+EFI_GUID UpdateDataGuid = EFI_UPDATE_DATA_FILE_GUID;\r
+EFI_HII_HANDLE gHiiHandle;\r
+\r
+/**\r
+ Update the whole FV, or certain files in the FV.\r
+ \r
+ @param ConfigData Pointer to the config data on updating file.\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_NOT_FOUND The matched FVB protocol is not found.\r
+ @retval EFI_SUCCESS The image buffer is updated into FV.\r
+\r
+**/\r
+EFI_STATUS\r
+PerformUpdateOnFirmwareVolume (\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
+ BOOLEAN Found;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;\r
+ UINTN Index;\r
+ UINTN NumOfHandles;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+ EFI_FVB_ATTRIBUTES_2 Attributes;\r
+\r
+ //\r
+ // Locate all Fvb protocol\r
+ //\r
+ HandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ NULL,\r
+ &NumOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) {\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ }\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Check the FVB protocol one by one\r
+ //\r
+ Found = FALSE;\r
+ FvbProtocol = NULL;\r
+ for (Index = 0; Index < NumOfHandles; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID **) &FvbProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Ensure this FVB protocol supported Write operation.\r
+ //\r
+ Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes);\r
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
+ continue; \r
+ }\r
+\r
+ Status = FvbProtocol->GetPhysicalAddress (\r
+ FvbProtocol,\r
+ &BaseAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ if (BaseAddress == ConfigData->BaseAddress) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!Found) {\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ HandleBuffer = NULL;\r
+ }\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Now we have got the corresponding FVB protocol. Use the FVB protocol\r
+ // to update the whole FV, or certain files in the FV.\r
+ //\r
+ if (ConfigData->UpdateType == UpdateWholeFV) {\r
+ if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ Status = PerformUpdateOnWholeFv (\r
+ HandleBuffer[Index],\r
+ FvbProtocol,\r
+ ConfigData,\r
+ ImageBuffer,\r
+ ImageSize\r
+ );\r
+ }\r
+ } else if (ConfigData->UpdateType == UpdateFvFile) {\r
+ Status = PerformUpdateOnFvFile (\r
+ HandleBuffer[Index],\r
+ FvbProtocol,\r
+ ConfigData,\r
+ ImageBuffer,\r
+ ImageSize,\r
+ FileType,\r
+ FileAttributes\r
+ );\r
+ }\r
+\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ HandleBuffer = NULL;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Update the file directly into flash area.\r
+\r
+ @param ConfigData Pointer to the config data on updating file.\r
+ @param ImageBuffer Image buffer to be updated.\r
+ @param ImageSize Image size.\r
+\r
+ @retval EFI_SUCCESS The file is updated into flash area.\r
+ @retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found.\r
+\r
+**/\r
+EFI_STATUS\r
+PerformUpdateOnFlashArea (\r
+ IN UPDATE_CONFIG_DATA *ConfigData,\r
+ IN UINT8 *ImageBuffer,\r
+ IN UINTN ImageSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN SizeLeft;\r
+ EFI_PHYSICAL_ADDRESS FlashAddress;\r
+ UINT8 *PtrImage;\r
+ BOOLEAN Found;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;\r
+ UINTN Index;\r
+ UINTN NumOfHandles;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+ EFI_HANDLE FvbHandle;\r
+ UINTN SizeUpdated;\r
+ CHAR16 *TmpStr;\r
+ EFI_FVB_ATTRIBUTES_2 Attributes;\r
+\r
+ SizeLeft = ImageSize;\r
+ PtrImage = ImageBuffer;\r
+ FlashAddress = ConfigData->BaseAddress;\r
+ Status = EFI_SUCCESS;\r
+ HandleBuffer = NULL;\r
+\r
+ //\r
+ // Print on screen\r
+ //\r
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FLASH_RANGE), NULL);\r
+ if (TmpStr != NULL) {\r
+ Print (TmpStr, FlashAddress, ((UINT64)SizeLeft + FlashAddress));\r
+ FreePool (TmpStr);\r
+ }\r
+ \r
+ //\r
+ // Locate all Fvb protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ NULL,\r
+ &NumOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) {\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ }\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ while (SizeLeft > 0) {\r
+ //\r
+ // First get the FVB protocols. If the flash area is a FV, or sub FV,\r
+ // we can directly locate all the FVB protocol. Otherwise we should use\r
+ // implementation specific method to get the alternate FVB protocol\r
+ //\r
+ Found = FALSE;\r
+ FvbProtocol = NULL;\r
+\r
+ //\r
+ // Check the FVB protocol one by one\r
+ //\r
+ for (Index = 0; Index < NumOfHandles; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID **) &FvbProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Ensure this FVB protocol supported Write operation.\r
+ //\r
+ Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes);\r
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
+ continue; \r
+ }\r
+\r
+ Status = FvbProtocol->GetPhysicalAddress (\r
+ FvbProtocol,\r
+ &BaseAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
+\r
+ //\r
+ // This sub area entry falls in the range of the FV\r
+ //\r
+ if ((FlashAddress >= BaseAddress) && (FlashAddress < (BaseAddress + FwVolHeader->FvLength))) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!Found) {\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ HandleBuffer = NULL;\r
+ }\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ FvbHandle = HandleBuffer[Index];\r
+ SizeUpdated = 0;\r
+\r
+ //\r
+ // If the flash area is boot required, the update must be fault tolerant\r
+ //\r
+ if (ConfigData->FaultTolerant) {\r
+ //\r
+ // Finally we are here. We have got the corresponding FVB protocol. Now\r
+ // we need to convert the physical address to LBA and offset and call\r
+ // FTW write. Also check if the flash range is larger than the FV.\r
+ //\r
+ Status = FaultTolerantUpdateOnPartFv (\r
+ PtrImage,\r
+ SizeLeft,\r
+ &SizeUpdated,\r
+ ConfigData,\r
+ FlashAddress,\r
+ FvbProtocol,\r
+ FvbHandle\r
+ );\r
+ } else {\r
+ //\r
+ // Finally we are here. We have got the corresponding FVB protocol. Now\r
+ // we need to convert the physical address to LBA and offset and call\r
+ // FVB write. Also check if the flash range is larger than the FV.\r
+ //\r
+ Status = NonFaultTolerantUpdateOnPartFv (\r
+ PtrImage,\r
+ SizeLeft,\r
+ &SizeUpdated,\r
+ FlashAddress,\r
+ FvbProtocol,\r
+ FvbHandle\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // As part of the FV has been replaced, the FV driver shall re-parse\r
+ // the firmware volume. So re-install FVB protocol here\r
+ //\r
+ Status = gBS->ReinstallProtocolInterface (\r
+ FvbHandle,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ FvbProtocol,\r
+ FvbProtocol\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Check if we are done with the update\r
+ //\r
+ SizeLeft = SizeLeft - SizeUpdated;\r
+ FlashAddress = FlashAddress + SizeUpdated;\r
+ PtrImage = PtrImage + SizeUpdated;\r
+ }\r
+\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ HandleBuffer = NULL;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Find the updated file, and program it into the flash area based on the config data.\r
+\r
+ @param FwVolProtocol Pointer to FV protocol that contains the updated file.\r
+ @param ConfigData Pointer to the Config Data on updating file.\r
+\r
+ @retval EFI_INVALID_PARAMETER The update operation is not valid.\r
+ @retval EFI_NOT_FOUND The updated file is not found.\r
+ @retval EFI_SUCCESS The file is updated into the flash area.\r
+\r
+**/\r
+EFI_STATUS\r
+PerformUpdate (\r
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol,\r
+ IN UPDATE_CONFIG_DATA *ConfigData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *FileBuffer;\r
+ UINTN FileBufferSize;\r
+ EFI_FV_FILETYPE FileType;\r
+ EFI_FV_FILE_ATTRIBUTES Attrib;\r
+ EFI_SECTION_TYPE SectionType;\r
+ UINT32 AuthenticationStatus;\r
+ CHAR16 *TmpStr;\r
+ BOOLEAN StartToUpdate;\r
+\r
+ Status = EFI_SUCCESS;\r
+ FileBuffer = NULL;\r
+ FileBufferSize = 0;\r
+ Status = FwVolProtocol->ReadFile (\r
+ FwVolProtocol,\r
+ &(ConfigData->FileGuid),\r
+ (VOID **) &FileBuffer,\r
+ &FileBufferSize,\r
+ &FileType,\r
+ &Attrib,\r
+ &AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StartToUpdate = FALSE;\r
+\r
+ //\r
+ // Check if the update image is the one we require\r
+ // and then perform the update\r
+ //\r
+ switch (ConfigData->UpdateType) {\r
+\r
+ case UpdateWholeFV:\r
+\r
+ //\r
+ // For UpdateWholeFv, the update file shall be a firmware volume\r
+ // image file.\r
+ //\r
+ if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n"));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ if (FileBuffer != NULL) {\r
+ FreePool (FileBuffer);\r
+ }\r
+ SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
+ FileBuffer = NULL;\r
+ FileBufferSize = 0;\r
+ Status = FwVolProtocol->ReadSection (\r
+ FwVolProtocol,\r
+ &(ConfigData->FileGuid),\r
+ SectionType,\r
+ 0,\r
+ (VOID **) &FileBuffer,\r
+ &FileBufferSize,\r
+ &AuthenticationStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Execute the update. For UpdateWholeFv, the update\r
+ // will always execute on a whole FV\r
+ //\r
+ StartToUpdate = TRUE;\r
+ Status = PerformUpdateOnFirmwareVolume (\r
+ ConfigData,\r
+ FileBuffer,\r
+ FileBufferSize,\r
+ FileType,\r
+ Attrib\r
+ );\r
+\r
+ } else {\r
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n"));\r
+ }\r
+ }\r
+ break;\r
+\r
+ case UpdateFvRange:\r
+\r
+ //\r
+ // For UpdateFvRange, the update file shall be a raw file\r
+ // which does not contain any sections. The contents of the file\r
+ // will be directly programmed.\r
+ //\r
+ if (FileType != EFI_FV_FILETYPE_RAW) {\r
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n"));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ //\r
+ // For UpdateFvRange, the update may be performed on a sub area\r
+ // of a certain FV, or a flash area that is not FV, or part of FV.\r
+ // The update may also go across more than one FVs.\r
+ //\r
+ StartToUpdate = TRUE;\r
+ Status = PerformUpdateOnFlashArea (\r
+ ConfigData,\r
+ FileBuffer,\r
+ FileBufferSize\r
+ );\r
+ }\r
+ break;\r
+\r
+ case UpdateFvFile:\r
+\r
+ //\r
+ // No check will be done the the file got. The contents of the file\r
+ // will be directly programmed.\r
+ // Though UpdateFvFile will only update a single file, but the update\r
+ // will always execute on a FV\r
+ //\r
+ StartToUpdate = TRUE;\r
+ Status = PerformUpdateOnFirmwareVolume (\r
+ ConfigData,\r
+ FileBuffer,\r
+ FileBufferSize,\r
+ FileType,\r
+ Attrib\r
+ );\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (StartToUpdate) {\r
+ if (EFI_ERROR (Status)) {\r
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_ABORTED), NULL);\r
+ } else {\r
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_DONE), NULL);\r
+ }\r
+ if (TmpStr != NULL) {\r
+ Print (TmpStr);\r
+ FreePool (TmpStr);\r
+ }\r
+ }\r
+\r
+ if (FileBuffer != NULL) {\r
+ FreePool(FileBuffer);\r
+ FileBuffer = NULL;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Process the input firmware volume by using DXE service ProcessFirmwareVolume.\r
+\r
+ @param DataBuffer Point to the FV image to be processed.\r
+ @param BufferSize Size of the FV image buffer.\r
+ @param FwVolProtocol Point to the installed FV protocol for the input FV image.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_VOLUME_CORRUPTED FV image is corrupted.\r
+ @retval EFI_SUCCESS FV image is processed and FV protocol is installed.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessUpdateImage (\r
+ UINT8 *DataBuffer,\r
+ UINTN BufferSize,\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL **FwVolProtocol\r
+ )\r
+{\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+ EFI_HANDLE FwVolHandle;\r
+ EFI_STATUS Status;\r
+ UINT8 *ProcessedDataBuffer;\r
+ UINT32 FvAlignment;\r
+\r
+ ProcessedDataBuffer = NULL;\r
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DataBuffer;\r
+ if (FwVolHeader->FvLength != BufferSize) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);\r
+ //\r
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.\r
+ // \r
+ if (FvAlignment < 8) {\r
+ FvAlignment = 8;\r
+ }\r
+ //\r
+ // Check FvImage Align is required.\r
+ //\r
+ if (((UINTN) FwVolHeader % FvAlignment) == 0) {\r
+ ProcessedDataBuffer = DataBuffer;\r
+ } else {\r
+ //\r
+ // Allocate new aligned buffer to store DataBuffer.\r
+ //\r
+ ProcessedDataBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);\r
+ if (ProcessedDataBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CopyMem (ProcessedDataBuffer, DataBuffer, BufferSize);\r
+ }\r
+ //\r
+ // Process the firmware volume\r
+ //\r
+ gDS->ProcessFirmwareVolume (\r
+ ProcessedDataBuffer,\r
+ BufferSize,\r
+ &FwVolHandle\r
+ );\r
+\r
+ //\r
+ // Get the FwVol protocol\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ FwVolHandle,\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ (VOID **) FwVolProtocol\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Find the image in the same FV and program it in a target Firmware Volume device.\r
+ After update image, it will reset system and no return.\r
+ \r
+ @param ImageHandle A handle for the image that is initializing this driver\r
+ @param SystemTable A pointer to the EFI system table\r
+\r
+ @retval EFI_ABORTED System reset failed.\r
+ @retval EFI_NOT_FOUND The updated image is not found in the same FV.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeUpdateDriver (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *DataFwVolProtocol;\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode; \r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *AlignedDevPathNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *FilePathNode;\r
+ EFI_SECTION_TYPE SectionType;\r
+ UINT8 *FileBuffer;\r
+ UINTN FileBufferSize;\r
+ EFI_FV_FILETYPE FileType;\r
+ EFI_FV_FILE_ATTRIBUTES Attrib;\r
+ UINT32 AuthenticationStatus;\r
+ UPDATE_CONFIG_DATA *ConfigData;\r
+ UPDATE_CONFIG_DATA *UpdateConfigData;\r
+ UINTN NumOfUpdates;\r
+ UINTN Index;\r
+ CHAR16 *TmpStr;\r
+\r
+ //\r
+ // Clear screen\r
+ //\r
+ if (gST->ConOut != NULL) {\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT);\r
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+ }\r
+\r
+ gHiiHandle = HiiAddPackages (\r
+ &gEfiCallerIdGuid,\r
+ NULL,\r
+ UpdateDriverDxeStrings,\r
+ NULL\r
+ );\r
+ ASSERT (gHiiHandle != NULL);\r
+\r
+ //\r
+ // In order to look for the update data file and programmed image file\r
+ // from the same volume which this driver is dispatched from, we need\r
+ // to get the device path of this driver image. It is done by first\r
+ // locate the LoadedImageProtocol and then get its device path\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&LoadedImageProtocol,\r
+ ImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the firmware volume protocol where this file resides\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ LoadedImageProtocol->DeviceHandle,\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ (VOID **) &FwVolProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Shall do some extra check to see if it is really contained in the FV?\r
+ // Should be able to find the section of this driver in the the FV.\r
+ //\r
+ FilePathNode = LoadedImageProtocol->FilePath;\r
+ FwVolFilePathNode = NULL;\r
+ while (!IsDevicePathEnd (FilePathNode)) {\r
+ if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePathNode)!= NULL) {\r
+ FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePathNode;\r
+ break;\r
+ }\r
+ FilePathNode = NextDevicePathNode (FilePathNode);\r
+ }\r
+\r
+ if (FwVolFilePathNode != NULL) {\r
+ AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode), FwVolFilePathNode);\r
+\r
+ SectionType = EFI_SECTION_PE32;\r
+ FileBuffer = NULL;\r
+ FileBufferSize = 0;\r
+ Status = FwVolProtocol->ReadSection (\r
+ FwVolProtocol,\r
+ &(AlignedDevPathNode->FvFileName),\r
+ SectionType,\r
+ 0,\r
+ (VOID **) &FileBuffer,\r
+ &FileBufferSize,\r
+ &AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (AlignedDevPathNode);\r
+ return Status;\r
+ }\r
+\r
+ if (FileBuffer != NULL) {\r
+ FreePool(FileBuffer);\r
+ FileBuffer = NULL;\r
+ }\r
+\r
+ //\r
+ // Check the NameGuid of the udpate driver so that it can be\r
+ // used as the CallerId in fault tolerant write protocol\r
+ //\r
+ if (!CompareGuid (&gEfiCallerIdGuid, &(AlignedDevPathNode->FvFileName))) {\r
+ FreePool (AlignedDevPathNode);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ FreePool (AlignedDevPathNode);\r
+ } else {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Now try to find the script file. The script file is usually\r
+ // a raw data file which does not contain any sections.\r
+ //\r
+ FileBuffer = NULL;\r
+ FileBufferSize = 0;\r
+ Status = FwVolProtocol->ReadFile (\r
+ FwVolProtocol,\r
+ &gEfiConfigFileNameGuid,\r
+ (VOID **) &FileBuffer,\r
+ &FileBufferSize,\r
+ &FileType,\r
+ &Attrib,\r
+ &AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (FileType != EFI_FV_FILETYPE_RAW) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Parse the configuration file.\r
+ //\r
+ ConfigData = NULL;\r
+ NumOfUpdates = 0;\r
+ Status = ParseUpdateDataFile (\r
+ FileBuffer,\r
+ FileBufferSize,\r
+ &NumOfUpdates,\r
+ &ConfigData\r
+ );\r
+ if (FileBuffer != NULL) {\r
+ FreePool (FileBuffer);\r
+ FileBuffer = NULL;\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Now find the update image. The update image should be put in a FV, and then\r
+ // encapsulated as a raw FFS file. This is to prevent the update image from\r
+ // being dispatched. So the raw data we get here should be an FV. We need to\r
+ // process this FV and read the files that is going to be updated.\r
+ //\r
+ FileBuffer = NULL;\r
+ FileBufferSize = 0;\r
+ Status = FwVolProtocol->ReadFile (\r
+ FwVolProtocol,\r
+ &UpdateDataGuid,\r
+ (VOID **) &FileBuffer,\r
+ &FileBufferSize,\r
+ &FileType,\r
+ &Attrib,\r
+ &AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (FileType != EFI_FV_FILETYPE_RAW) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // FileBuffer should be an FV. Process the FV\r
+ //\r
+ DataFwVolProtocol = NULL;\r
+ Status = ProcessUpdateImage (\r
+ FileBuffer,\r
+ FileBufferSize,\r
+ &DataFwVolProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (FileBuffer);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Print on screen\r
+ //\r
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_PROCESS_DATA), NULL);\r
+ if (TmpStr != NULL) {\r
+ Print (TmpStr);\r
+ FreePool(TmpStr);\r
+ }\r
+\r
+ //\r
+ // Execute the update\r
+ //\r
+ Index = 0;\r
+ UpdateConfigData = ConfigData;\r
+ while (Index < NumOfUpdates) {\r
+ Status = PerformUpdate (\r
+ DataFwVolProtocol,\r
+ UpdateConfigData\r
+ );\r
+ //\r
+ // Shall updates be serialized so that if an update is not successfully completed, \r
+ // the remaining updates won't be performed.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ Index++;\r
+ UpdateConfigData++;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (ConfigData != NULL) {\r
+ FreePool(ConfigData);\r
+ ConfigData = NULL;\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Call system reset\r
+ //\r
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+\r
+ //\r
+ // Hopefully it won't be reached\r
+ //\r
+ return EFI_ABORTED;\r
+}\r
--- /dev/null
+/** @file\r
+ Common defines and definitions for a component update driver.\r
+\r
+ Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_UPDATE_DRIVER_H_\r
+#define _EFI_UPDATE_DRIVER_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/LoadedImage.h>\r
+#include <Guid/Capsule.h>\r
+#include <Protocol/FaultTolerantWrite.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+//\r
+// {283FA2EE-532C-484d-9383-9F93B36F0B7E}\r
+//\r
+#define EFI_UPDATE_DATA_FILE_GUID \\r
+ { 0x283fa2ee, 0x532c, 0x484d, { 0x93, 0x83, 0x9f, 0x93, 0xb3, 0x6f, 0xb, 0x7e } }\r
+\r
+extern EFI_HII_HANDLE gHiiHandle;\r
+\r
+typedef enum {\r
+ UpdateWholeFV = 0, // 0, update whole FV\r
+ UpdateFvFile, // 1, update a set of FV files asynchronously\r
+ UpdateFvRange, // 2, update part of FV or flash\r
+ UpdateOperationMaximum // 3\r
+} UPDATE_OPERATION_TYPE;\r
+\r
+typedef struct {\r
+ UINTN Index;\r
+ UPDATE_OPERATION_TYPE UpdateType;\r
+ EFI_DEVICE_PATH_PROTOCOL DevicePath;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+ EFI_GUID FileGuid;\r
+ UINTN Length;\r
+ BOOLEAN FaultTolerant;\r
+} UPDATE_CONFIG_DATA;\r
+\r
+typedef struct _SECTION_ITEM SECTION_ITEM;\r
+struct _SECTION_ITEM {\r
+ CHAR8 *ptrSection;\r
+ UINTN SecNameLen;\r
+ CHAR8 *ptrEntry;\r
+ CHAR8 *ptrValue;\r
+ SECTION_ITEM *ptrNext;\r
+};\r
+\r
+typedef struct _COMMENT_LINE COMMENT_LINE;\r
+struct _COMMENT_LINE {\r
+ CHAR8 *ptrComment;\r
+ COMMENT_LINE *ptrNext;\r
+};\r
+\r
+typedef struct {\r
+ EFI_GUID FileGuid;\r
+} UPDATE_PRIVATE_DATA;\r
+\r
+#define MAX_LINE_LENGTH 512\r
+#define EFI_D_UPDATE EFI_D_ERROR\r
+\r
+#define MIN_ALIGNMENT_SIZE 4\r
+#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0)\r
+\r
+/**\r
+ Parse Config data file to get the updated data array.\r
+\r
+ @param DataBuffer Config raw file buffer.\r
+ @param BufferSize Size of raw buffer.\r
+ @param NumOfUpdates Pointer to the number of update data.\r
+ @param UpdateArray Pointer to the config of update data.\r
+\r
+ @retval EFI_NOT_FOUND No config data is found.\r
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
+ @retval EFI_SUCCESS Parse the config file successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseUpdateDataFile (\r
+ IN UINT8 *DataBuffer,\r
+ IN UINTN BufferSize,\r
+ IN OUT UINTN *NumOfUpdates,\r
+ IN OUT UPDATE_CONFIG_DATA **UpdateArray\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
+/**\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
+/**\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
+/**\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
+#endif\r
--- /dev/null
+## @file\r
+# This driver is intended to be put in a capsule (FV). If all goes well, \r
+# then it should be dispatched from the capsule FV, then find the image \r
+# in the same FV and program it in a target Firmware Volume device.\r
+#\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are\r
+# licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = UpdateDriverDxe\r
+ FILE_GUID = 0E84FC69-29CC-4C6D-92AC-6D476921850F\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializeUpdateDriver\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ UpdateDriver.h\r
+ UpdateStrings.uni\r
+ UpdateDispatcher.c\r
+ ParseUpdateProfile.c\r
+ FlashUpdate.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ PrintLib\r
+ HiiLib\r
+ DxeServicesTableLib\r
+ MemoryAllocationLib\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ UefiRuntimeServicesTableLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ DevicePathLib\r
+\r
+[Guids]\r
+ gEfiConfigFileNameGuid ## CONSUMES FileName to store ConfigFile\r
+\r
+[Protocols]\r
+ gEfiFaultTolerantWriteProtocolGuid ## CONSUMES\r
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES\r
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES\r
+ gEfiLoadedImageProtocolGuid ## CONSUMES\r
+\r
+[Depex]\r
+ gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid\r
+\r