summaryrefslogtreecommitdiff
path: root/IntelFrameworkModulePkg
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-01 19:57:46 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-01 19:57:46 +0000
commitb2824a8e1362b89285663e1ab9b88e9fbb4bc572 (patch)
treeed98e189cc42a8fed60b5d30559e62ba9242401c /IntelFrameworkModulePkg
parentc2df8e13f68ab18f96874cadc0a3dfada67a7e7c (diff)
downloadedk2-platforms-b2824a8e1362b89285663e1ab9b88e9fbb4bc572.tar.xz
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
Diffstat (limited to 'IntelFrameworkModulePkg')
-rw-r--r--IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc1
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c1218
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c1134
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c846
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h218
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf69
-rw-r--r--IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.unibin0 -> 2344 bytes
7 files changed, 3486 insertions, 0 deletions
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.<BR>
+
+ 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.<BR>
+
+ 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.<BR>
+
+ 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.<BR>
+
+ 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 <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Guid/Capsule.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/FirmwareVolume2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DevicePathLib.h>
+
+//
+// {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.<BR>
+#
+# 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
--- /dev/null
+++ b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni
Binary files differ