]> git.proxmox.com Git - mirror_edk2.git/commitdiff
IntelFrameworkModulePkg: Add UpdateDriverDxe driver
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 1 Sep 2011 19:57:46 +0000 (19:57 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 1 Sep 2011 19:57:46 +0000 (19:57 +0000)
Signed-off-by: jljusten
Reviewed-by: rsun3
Reviewed-by: lgao4
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12257 6f19259b-4bc3-4df7-8a09-765794883524

IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni [new file with mode: 0644]

index 7eaac50eafa40af8f7735a34ae8f06ef6cfa7959..97d922895239e03ced93278eb6c6d59a49ead76e 100644 (file)
   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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c
new file mode 100644 (file)
index 0000000..56514c9
--- /dev/null
@@ -0,0 +1,1218 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c
new file mode 100644 (file)
index 0000000..17e728d
--- /dev/null
@@ -0,0 +1,1134 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c
new file mode 100644 (file)
index 0000000..177e799
--- /dev/null
@@ -0,0 +1,846 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h
new file mode 100644 (file)
index 0000000..9fd00b3
--- /dev/null
@@ -0,0 +1,218 @@
+/** @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf
new file mode 100644 (file)
index 0000000..5ec26e2
--- /dev/null
@@ -0,0 +1,69 @@
+## @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
diff --git a/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni
new file mode 100644 (file)
index 0000000..914a012
Binary files /dev/null and b/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni differ