/** @file | |
Functions in this file will mainly focus on looking through the capsule | |
for the image to be programmed, and the flash area that is going to be | |
programed. | |
Copyright (c) 2002 - 2018, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions | |
of the BSD License which accompanies this distribution. The | |
full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "UpdateDriver.h" | |
EFI_HII_HANDLE gHiiHandle; | |
/** | |
Update the whole FV, or certain files in the FV. | |
@param ConfigData Pointer to the config data on updating file. | |
@param ImageBuffer Image buffer to be updated. | |
@param ImageSize Image size. | |
@param FileType FFS file type. | |
@param FileAttributes FFS file attribute. | |
@retval EFI_NOT_FOUND The matched FVB protocol is not found. | |
@retval EFI_SUCCESS The image buffer is updated into FV. | |
**/ | |
EFI_STATUS | |
PerformUpdateOnFirmwareVolume ( | |
IN UPDATE_CONFIG_DATA *ConfigData, | |
IN UINT8 *ImageBuffer, | |
IN UINTN ImageSize, | |
IN EFI_FV_FILETYPE FileType, | |
IN EFI_FV_FILE_ATTRIBUTES FileAttributes | |
) | |
{ | |
EFI_STATUS Status; | |
BOOLEAN Found; | |
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; | |
UINTN Index; | |
UINTN NumOfHandles; | |
EFI_HANDLE *HandleBuffer; | |
EFI_PHYSICAL_ADDRESS BaseAddress; | |
EFI_FVB_ATTRIBUTES_2 Attributes; | |
// | |
// Locate all Fvb protocol | |
// | |
HandleBuffer = NULL; | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
&gEfiFirmwareVolumeBlockProtocolGuid, | |
NULL, | |
&NumOfHandles, | |
&HandleBuffer | |
); | |
if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) { | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
} | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Check the FVB protocol one by one | |
// | |
Found = FALSE; | |
FvbProtocol = NULL; | |
for (Index = 0; Index < NumOfHandles; Index++) { | |
Status = gBS->HandleProtocol ( | |
HandleBuffer[Index], | |
&gEfiFirmwareVolumeBlockProtocolGuid, | |
(VOID **) &FvbProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
// | |
// Ensure this FVB protocol supported Write operation. | |
// | |
Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes); | |
if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { | |
continue; | |
} | |
Status = FvbProtocol->GetPhysicalAddress ( | |
FvbProtocol, | |
&BaseAddress | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
if (BaseAddress == ConfigData->BaseAddress) { | |
Found = TRUE; | |
break; | |
} | |
} | |
if (!Found) { | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
HandleBuffer = NULL; | |
} | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Now we have got the corresponding FVB protocol. Use the FVB protocol | |
// to update the whole FV, or certain files in the FV. | |
// | |
if (ConfigData->UpdateType == UpdateWholeFV) { | |
if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { | |
Status = EFI_INVALID_PARAMETER; | |
} else { | |
Status = PerformUpdateOnWholeFv ( | |
HandleBuffer[Index], | |
FvbProtocol, | |
ConfigData, | |
ImageBuffer, | |
ImageSize | |
); | |
} | |
} else if (ConfigData->UpdateType == UpdateFvFile) { | |
Status = PerformUpdateOnFvFile ( | |
HandleBuffer[Index], | |
FvbProtocol, | |
ConfigData, | |
ImageBuffer, | |
ImageSize, | |
FileType, | |
FileAttributes | |
); | |
} | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
HandleBuffer = NULL; | |
} | |
return Status; | |
} | |
/** | |
Update the file directly into flash area. | |
@param ConfigData Pointer to the config data on updating file. | |
@param ImageBuffer Image buffer to be updated. | |
@param ImageSize Image size. | |
@retval EFI_SUCCESS The file is updated into flash area. | |
@retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found. | |
**/ | |
EFI_STATUS | |
PerformUpdateOnFlashArea ( | |
IN UPDATE_CONFIG_DATA *ConfigData, | |
IN UINT8 *ImageBuffer, | |
IN UINTN ImageSize | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN SizeLeft; | |
EFI_PHYSICAL_ADDRESS FlashAddress; | |
UINT8 *PtrImage; | |
BOOLEAN Found; | |
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; | |
UINTN Index; | |
UINTN NumOfHandles; | |
EFI_HANDLE *HandleBuffer; | |
EFI_PHYSICAL_ADDRESS BaseAddress; | |
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; | |
EFI_HANDLE FvbHandle; | |
UINTN SizeUpdated; | |
CHAR16 *TmpStr; | |
EFI_FVB_ATTRIBUTES_2 Attributes; | |
SizeLeft = ImageSize; | |
PtrImage = ImageBuffer; | |
FlashAddress = ConfigData->BaseAddress; | |
Status = EFI_SUCCESS; | |
HandleBuffer = NULL; | |
// | |
// Print on screen | |
// | |
TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FLASH_RANGE), NULL); | |
if (TmpStr != NULL) { | |
Print (TmpStr, FlashAddress, ((UINT64)SizeLeft + FlashAddress)); | |
FreePool (TmpStr); | |
} | |
// | |
// Locate all Fvb protocol | |
// | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
&gEfiFirmwareVolumeBlockProtocolGuid, | |
NULL, | |
&NumOfHandles, | |
&HandleBuffer | |
); | |
if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) { | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
} | |
return EFI_NOT_FOUND; | |
} | |
while (SizeLeft > 0) { | |
// | |
// First get the FVB protocols. If the flash area is a FV, or sub FV, | |
// we can directly locate all the FVB protocol. Otherwise we should use | |
// implementation specific method to get the alternate FVB protocol | |
// | |
Found = FALSE; | |
FvbProtocol = NULL; | |
// | |
// Check the FVB protocol one by one | |
// | |
for (Index = 0; Index < NumOfHandles; Index++) { | |
Status = gBS->HandleProtocol ( | |
HandleBuffer[Index], | |
&gEfiFirmwareVolumeBlockProtocolGuid, | |
(VOID **) &FvbProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
// | |
// Ensure this FVB protocol supported Write operation. | |
// | |
Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes); | |
if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { | |
continue; | |
} | |
Status = FvbProtocol->GetPhysicalAddress ( | |
FvbProtocol, | |
&BaseAddress | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; | |
// | |
// This sub area entry falls in the range of the FV | |
// | |
if ((FlashAddress >= BaseAddress) && (FlashAddress < (BaseAddress + FwVolHeader->FvLength))) { | |
Found = TRUE; | |
break; | |
} | |
} | |
if (!Found) { | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
HandleBuffer = NULL; | |
} | |
return EFI_NOT_FOUND; | |
} | |
FvbHandle = HandleBuffer[Index]; | |
SizeUpdated = 0; | |
// | |
// If the flash area is boot required, the update must be fault tolerant | |
// | |
if (ConfigData->FaultTolerant) { | |
// | |
// Finally we are here. We have got the corresponding FVB protocol. Now | |
// we need to convert the physical address to LBA and offset and call | |
// FTW write. Also check if the flash range is larger than the FV. | |
// | |
Status = FaultTolerantUpdateOnPartFv ( | |
PtrImage, | |
SizeLeft, | |
&SizeUpdated, | |
ConfigData, | |
FlashAddress, | |
FvbProtocol, | |
FvbHandle | |
); | |
} else { | |
// | |
// Finally we are here. We have got the corresponding FVB protocol. Now | |
// we need to convert the physical address to LBA and offset and call | |
// FVB write. Also check if the flash range is larger than the FV. | |
// | |
Status = NonFaultTolerantUpdateOnPartFv ( | |
PtrImage, | |
SizeLeft, | |
&SizeUpdated, | |
FlashAddress, | |
FvbProtocol, | |
FvbHandle | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// As part of the FV has been replaced, the FV driver shall re-parse | |
// the firmware volume. So re-install FVB protocol here | |
// | |
Status = gBS->ReinstallProtocolInterface ( | |
FvbHandle, | |
&gEfiFirmwareVolumeBlockProtocolGuid, | |
FvbProtocol, | |
FvbProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Check if we are done with the update | |
// | |
SizeLeft = SizeLeft - SizeUpdated; | |
FlashAddress = FlashAddress + SizeUpdated; | |
PtrImage = PtrImage + SizeUpdated; | |
} | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
HandleBuffer = NULL; | |
} | |
return Status; | |
} | |
/** | |
Find the updated file, and program it into the flash area based on the config data. | |
@param FwVolProtocol Pointer to FV protocol that contains the updated file. | |
@param ConfigData Pointer to the Config Data on updating file. | |
@retval EFI_INVALID_PARAMETER The update operation is not valid. | |
@retval EFI_NOT_FOUND The updated file is not found. | |
@retval EFI_SUCCESS The file is updated into the flash area. | |
**/ | |
EFI_STATUS | |
PerformUpdate ( | |
IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol, | |
IN UPDATE_CONFIG_DATA *ConfigData | |
) | |
{ | |
EFI_STATUS Status; | |
UINT8 *FileBuffer; | |
UINTN FileBufferSize; | |
EFI_FV_FILETYPE FileType; | |
EFI_FV_FILE_ATTRIBUTES Attrib; | |
EFI_SECTION_TYPE SectionType; | |
UINT32 AuthenticationStatus; | |
CHAR16 *TmpStr; | |
BOOLEAN StartToUpdate; | |
Status = EFI_SUCCESS; | |
FileBuffer = NULL; | |
FileBufferSize = 0; | |
Status = FwVolProtocol->ReadFile ( | |
FwVolProtocol, | |
&(ConfigData->FileGuid), | |
(VOID **) &FileBuffer, | |
&FileBufferSize, | |
&FileType, | |
&Attrib, | |
&AuthenticationStatus | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
StartToUpdate = FALSE; | |
// | |
// Check if the update image is the one we require | |
// and then perform the update | |
// | |
switch (ConfigData->UpdateType) { | |
case UpdateWholeFV: | |
// | |
// For UpdateWholeFv, the update file shall be a firmware volume | |
// image file. | |
// | |
if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { | |
DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n")); | |
Status = EFI_INVALID_PARAMETER; | |
} else { | |
if (FileBuffer != NULL) { | |
FreePool (FileBuffer); | |
} | |
SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; | |
FileBuffer = NULL; | |
FileBufferSize = 0; | |
Status = FwVolProtocol->ReadSection ( | |
FwVolProtocol, | |
&(ConfigData->FileGuid), | |
SectionType, | |
0, | |
(VOID **) &FileBuffer, | |
&FileBufferSize, | |
&AuthenticationStatus | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Execute the update. For UpdateWholeFv, the update | |
// will always execute on a whole FV | |
// | |
StartToUpdate = TRUE; | |
Status = PerformUpdateOnFirmwareVolume ( | |
ConfigData, | |
FileBuffer, | |
FileBufferSize, | |
FileType, | |
Attrib | |
); | |
} else { | |
DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n")); | |
} | |
} | |
break; | |
case UpdateFvRange: | |
// | |
// For UpdateFvRange, the update file shall be a raw file | |
// which does not contain any sections. The contents of the file | |
// will be directly programmed. | |
// | |
if (FileType != EFI_FV_FILETYPE_RAW) { | |
DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n")); | |
Status = EFI_INVALID_PARAMETER; | |
} else { | |
// | |
// For UpdateFvRange, the update may be performed on a sub area | |
// of a certain FV, or a flash area that is not FV, or part of FV. | |
// The update may also go across more than one FVs. | |
// | |
StartToUpdate = TRUE; | |
Status = PerformUpdateOnFlashArea ( | |
ConfigData, | |
FileBuffer, | |
FileBufferSize | |
); | |
} | |
break; | |
case UpdateFvFile: | |
// | |
// No check will be done the the file got. The contents of the file | |
// will be directly programmed. | |
// Though UpdateFvFile will only update a single file, but the update | |
// will always execute on a FV | |
// | |
StartToUpdate = TRUE; | |
Status = PerformUpdateOnFirmwareVolume ( | |
ConfigData, | |
FileBuffer, | |
FileBufferSize, | |
FileType, | |
Attrib | |
); | |
break; | |
default: | |
Status = EFI_INVALID_PARAMETER; | |
} | |
if (StartToUpdate) { | |
if (EFI_ERROR (Status)) { | |
TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_ABORTED), NULL); | |
} else { | |
TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_DONE), NULL); | |
} | |
if (TmpStr != NULL) { | |
Print (TmpStr); | |
FreePool (TmpStr); | |
} | |
} | |
if (FileBuffer != NULL) { | |
FreePool(FileBuffer); | |
FileBuffer = NULL; | |
} | |
return Status; | |
} | |
/** | |
Process the input firmware volume by using DXE service ProcessFirmwareVolume. | |
@param DataBuffer Point to the FV image to be processed. | |
@param BufferSize Size of the FV image buffer. | |
@param FwVolProtocol Point to the installed FV protocol for the input FV image. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_VOLUME_CORRUPTED FV image is corrupted. | |
@retval EFI_SUCCESS FV image is processed and FV protocol is installed. | |
**/ | |
EFI_STATUS | |
ProcessUpdateImage ( | |
UINT8 *DataBuffer, | |
UINTN BufferSize, | |
EFI_FIRMWARE_VOLUME2_PROTOCOL **FwVolProtocol | |
) | |
{ | |
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; | |
EFI_HANDLE FwVolHandle; | |
EFI_STATUS Status; | |
UINT8 *ProcessedDataBuffer; | |
UINT32 FvAlignment; | |
ProcessedDataBuffer = NULL; | |
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DataBuffer; | |
if (FwVolHeader->FvLength != BufferSize) { | |
return EFI_VOLUME_CORRUPTED; | |
} | |
FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16); | |
// | |
// FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value. | |
// | |
if (FvAlignment < 8) { | |
FvAlignment = 8; | |
} | |
// | |
// Check FvImage Align is required. | |
// | |
if (((UINTN) FwVolHeader % FvAlignment) == 0) { | |
ProcessedDataBuffer = DataBuffer; | |
} else { | |
// | |
// Allocate new aligned buffer to store DataBuffer. | |
// | |
ProcessedDataBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment); | |
if (ProcessedDataBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (ProcessedDataBuffer, DataBuffer, BufferSize); | |
} | |
// | |
// Process the firmware volume | |
// | |
gDS->ProcessFirmwareVolume ( | |
ProcessedDataBuffer, | |
BufferSize, | |
&FwVolHandle | |
); | |
// | |
// Get the FwVol protocol | |
// | |
Status = gBS->HandleProtocol ( | |
FwVolHandle, | |
&gEfiFirmwareVolume2ProtocolGuid, | |
(VOID **) FwVolProtocol | |
); | |
return Status; | |
} | |
/** | |
Find the image in the same FV and program it in a target Firmware Volume device. | |
After update image, it will reset system and no return. | |
@param ImageHandle A handle for the image that is initializing this driver | |
@param SystemTable A pointer to the EFI system table | |
@retval EFI_ABORTED System reset failed. | |
@retval EFI_NOT_FOUND The updated image is not found in the same FV. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
InitializeUpdateDriver ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol; | |
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol; | |
EFI_FIRMWARE_VOLUME2_PROTOCOL *DataFwVolProtocol; | |
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode; | |
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *AlignedDevPathNode; | |
EFI_DEVICE_PATH_PROTOCOL *FilePathNode; | |
EFI_SECTION_TYPE SectionType; | |
UINT8 *FileBuffer; | |
UINTN FileBufferSize; | |
EFI_FV_FILETYPE FileType; | |
EFI_FV_FILE_ATTRIBUTES Attrib; | |
UINT32 AuthenticationStatus; | |
UPDATE_CONFIG_DATA *ConfigData; | |
UPDATE_CONFIG_DATA *UpdateConfigData; | |
UINTN NumOfUpdates; | |
UINTN Index; | |
CHAR16 *TmpStr; | |
// | |
// Clear screen | |
// | |
if (gST->ConOut != NULL) { | |
gST->ConOut->ClearScreen (gST->ConOut); | |
gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT); | |
gST->ConOut->EnableCursor (gST->ConOut, FALSE); | |
} | |
gHiiHandle = HiiAddPackages ( | |
&gEfiCallerIdGuid, | |
NULL, | |
UpdateDriverDxeStrings, | |
NULL | |
); | |
ASSERT (gHiiHandle != NULL); | |
// | |
// In order to look for the update data file and programmed image file | |
// from the same volume which this driver is dispatched from, we need | |
// to get the device path of this driver image. It is done by first | |
// locate the LoadedImageProtocol and then get its device path | |
// | |
Status = gBS->OpenProtocol ( | |
ImageHandle, | |
&gEfiLoadedImageProtocolGuid, | |
(VOID **)&LoadedImageProtocol, | |
ImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Get the firmware volume protocol where this file resides | |
// | |
Status = gBS->HandleProtocol ( | |
LoadedImageProtocol->DeviceHandle, | |
&gEfiFirmwareVolume2ProtocolGuid, | |
(VOID **) &FwVolProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Shall do some extra check to see if it is really contained in the FV? | |
// Should be able to find the section of this driver in the the FV. | |
// | |
FilePathNode = LoadedImageProtocol->FilePath; | |
FwVolFilePathNode = NULL; | |
while (!IsDevicePathEnd (FilePathNode)) { | |
if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePathNode)!= NULL) { | |
FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePathNode; | |
break; | |
} | |
FilePathNode = NextDevicePathNode (FilePathNode); | |
} | |
if (FwVolFilePathNode != NULL) { | |
AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode), FwVolFilePathNode); | |
SectionType = EFI_SECTION_PE32; | |
FileBuffer = NULL; | |
FileBufferSize = 0; | |
Status = FwVolProtocol->ReadSection ( | |
FwVolProtocol, | |
&(AlignedDevPathNode->FvFileName), | |
SectionType, | |
0, | |
(VOID **) &FileBuffer, | |
&FileBufferSize, | |
&AuthenticationStatus | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (AlignedDevPathNode); | |
return Status; | |
} | |
if (FileBuffer != NULL) { | |
FreePool(FileBuffer); | |
FileBuffer = NULL; | |
} | |
// | |
// Check the NameGuid of the udpate driver so that it can be | |
// used as the CallerId in fault tolerant write protocol | |
// | |
if (!CompareGuid (&gEfiCallerIdGuid, &(AlignedDevPathNode->FvFileName))) { | |
FreePool (AlignedDevPathNode); | |
return EFI_NOT_FOUND; | |
} | |
FreePool (AlignedDevPathNode); | |
} else { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Now try to find the script file. The script file is usually | |
// a raw data file which does not contain any sections. | |
// | |
FileBuffer = NULL; | |
FileBufferSize = 0; | |
Status = FwVolProtocol->ReadFile ( | |
FwVolProtocol, | |
&gEfiConfigFileNameGuid, | |
(VOID **) &FileBuffer, | |
&FileBufferSize, | |
&FileType, | |
&Attrib, | |
&AuthenticationStatus | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (FileType != EFI_FV_FILETYPE_RAW) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Parse the configuration file. | |
// | |
ConfigData = NULL; | |
NumOfUpdates = 0; | |
Status = ParseUpdateDataFile ( | |
FileBuffer, | |
FileBufferSize, | |
&NumOfUpdates, | |
&ConfigData | |
); | |
if (FileBuffer != NULL) { | |
FreePool (FileBuffer); | |
FileBuffer = NULL; | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
ASSERT (ConfigData != NULL); | |
// | |
// Now find the update image. The update image should be put in a FV, and then | |
// encapsulated as a raw FFS file. This is to prevent the update image from | |
// being dispatched. So the raw data we get here should be an FV. We need to | |
// process this FV and read the files that is going to be updated. | |
// | |
FileBuffer = NULL; | |
FileBufferSize = 0; | |
Status = FwVolProtocol->ReadFile ( | |
FwVolProtocol, | |
&gEfiUpdateDataFileGuid, | |
(VOID **) &FileBuffer, | |
&FileBufferSize, | |
&FileType, | |
&Attrib, | |
&AuthenticationStatus | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (FileType != EFI_FV_FILETYPE_RAW) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// FileBuffer should be an FV. Process the FV | |
// | |
DataFwVolProtocol = NULL; | |
Status = ProcessUpdateImage ( | |
FileBuffer, | |
FileBufferSize, | |
&DataFwVolProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (FileBuffer); | |
return Status; | |
} | |
// | |
// Print on screen | |
// | |
TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_PROCESS_DATA), NULL); | |
if (TmpStr != NULL) { | |
Print (TmpStr); | |
FreePool(TmpStr); | |
} | |
// | |
// Execute the update | |
// | |
Index = 0; | |
UpdateConfigData = ConfigData; | |
while (Index < NumOfUpdates) { | |
Status = PerformUpdate ( | |
DataFwVolProtocol, | |
UpdateConfigData | |
); | |
// | |
// Shall updates be serialized so that if an update is not successfully completed, | |
// the remaining updates won't be performed. | |
// | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
Index++; | |
UpdateConfigData++; | |
} | |
if (EFI_ERROR (Status)) { | |
if (ConfigData != NULL) { | |
FreePool(ConfigData); | |
ConfigData = NULL; | |
} | |
return Status; | |
} | |
// | |
// Call system reset | |
// | |
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); | |
// | |
// Hopefully it won't be reached | |
// | |
return EFI_ABORTED; | |
} |