2 Functions in this file will mainly focus on looking through the capsule
3 for the image to be programmed, and the flash area that is going to be
6 Copyright (c) 2002 - 2018, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "UpdateDriver.h"
14 EFI_HII_HANDLE gHiiHandle
;
17 Update the whole FV, or certain files in the FV.
19 @param ConfigData Pointer to the config data on updating file.
20 @param ImageBuffer Image buffer to be updated.
21 @param ImageSize Image size.
22 @param FileType FFS file type.
23 @param FileAttributes FFS file attribute.
25 @retval EFI_NOT_FOUND The matched FVB protocol is not found.
26 @retval EFI_SUCCESS The image buffer is updated into FV.
30 PerformUpdateOnFirmwareVolume (
31 IN UPDATE_CONFIG_DATA
*ConfigData
,
32 IN UINT8
*ImageBuffer
,
34 IN EFI_FV_FILETYPE FileType
,
35 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
40 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
43 EFI_HANDLE
*HandleBuffer
;
44 EFI_PHYSICAL_ADDRESS BaseAddress
;
45 EFI_FVB_ATTRIBUTES_2 Attributes
;
48 // Locate all Fvb protocol
51 Status
= gBS
->LocateHandleBuffer (
53 &gEfiFirmwareVolumeBlockProtocolGuid
,
58 if ((EFI_ERROR (Status
)) || (NumOfHandles
== 0) || (HandleBuffer
== NULL
)) {
59 if (HandleBuffer
!= NULL
) {
60 FreePool (HandleBuffer
);
66 // Check the FVB protocol one by one
70 for (Index
= 0; Index
< NumOfHandles
; Index
++) {
71 Status
= gBS
->HandleProtocol (
73 &gEfiFirmwareVolumeBlockProtocolGuid
,
74 (VOID
**) &FvbProtocol
76 if (EFI_ERROR (Status
)) {
81 // Ensure this FVB protocol supported Write operation.
83 Status
= FvbProtocol
->GetAttributes (FvbProtocol
, &Attributes
);
84 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
88 Status
= FvbProtocol
->GetPhysicalAddress (
92 if (EFI_ERROR (Status
)) {
95 if (BaseAddress
== ConfigData
->BaseAddress
) {
102 if (HandleBuffer
!= NULL
) {
103 FreePool (HandleBuffer
);
106 return EFI_NOT_FOUND
;
110 // Now we have got the corresponding FVB protocol. Use the FVB protocol
111 // to update the whole FV, or certain files in the FV.
113 if (ConfigData
->UpdateType
== UpdateWholeFV
) {
114 if (FileType
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
115 Status
= EFI_INVALID_PARAMETER
;
117 Status
= PerformUpdateOnWholeFv (
125 } else if (ConfigData
->UpdateType
== UpdateFvFile
) {
126 Status
= PerformUpdateOnFvFile (
137 if (HandleBuffer
!= NULL
) {
138 FreePool (HandleBuffer
);
146 Update the file directly into flash area.
148 @param ConfigData Pointer to the config data on updating file.
149 @param ImageBuffer Image buffer to be updated.
150 @param ImageSize Image size.
152 @retval EFI_SUCCESS The file is updated into flash area.
153 @retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found.
157 PerformUpdateOnFlashArea (
158 IN UPDATE_CONFIG_DATA
*ConfigData
,
159 IN UINT8
*ImageBuffer
,
165 EFI_PHYSICAL_ADDRESS FlashAddress
;
168 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
171 EFI_HANDLE
*HandleBuffer
;
172 EFI_PHYSICAL_ADDRESS BaseAddress
;
173 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
174 EFI_HANDLE FvbHandle
;
177 EFI_FVB_ATTRIBUTES_2 Attributes
;
179 SizeLeft
= ImageSize
;
180 PtrImage
= ImageBuffer
;
181 FlashAddress
= ConfigData
->BaseAddress
;
182 Status
= EFI_SUCCESS
;
188 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_FLASH_RANGE
), NULL
);
189 if (TmpStr
!= NULL
) {
190 Print (TmpStr
, FlashAddress
, ((UINT64
)SizeLeft
+ FlashAddress
));
195 // Locate all Fvb protocol
197 Status
= gBS
->LocateHandleBuffer (
199 &gEfiFirmwareVolumeBlockProtocolGuid
,
204 if ((EFI_ERROR (Status
)) || (NumOfHandles
== 0) || (HandleBuffer
== NULL
)) {
205 if (HandleBuffer
!= NULL
) {
206 FreePool (HandleBuffer
);
208 return EFI_NOT_FOUND
;
211 while (SizeLeft
> 0) {
213 // First get the FVB protocols. If the flash area is a FV, or sub FV,
214 // we can directly locate all the FVB protocol. Otherwise we should use
215 // implementation specific method to get the alternate FVB protocol
221 // Check the FVB protocol one by one
223 for (Index
= 0; Index
< NumOfHandles
; Index
++) {
224 Status
= gBS
->HandleProtocol (
226 &gEfiFirmwareVolumeBlockProtocolGuid
,
227 (VOID
**) &FvbProtocol
229 if (EFI_ERROR (Status
)) {
234 // Ensure this FVB protocol supported Write operation.
236 Status
= FvbProtocol
->GetAttributes (FvbProtocol
, &Attributes
);
237 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
241 Status
= FvbProtocol
->GetPhysicalAddress (
245 if (EFI_ERROR (Status
)) {
248 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)BaseAddress
;
251 // This sub area entry falls in the range of the FV
253 if ((FlashAddress
>= BaseAddress
) && (FlashAddress
< (BaseAddress
+ FwVolHeader
->FvLength
))) {
260 if (HandleBuffer
!= NULL
) {
261 FreePool (HandleBuffer
);
264 return EFI_NOT_FOUND
;
267 FvbHandle
= HandleBuffer
[Index
];
271 // If the flash area is boot required, the update must be fault tolerant
273 if (ConfigData
->FaultTolerant
) {
275 // Finally we are here. We have got the corresponding FVB protocol. Now
276 // we need to convert the physical address to LBA and offset and call
277 // FTW write. Also check if the flash range is larger than the FV.
279 Status
= FaultTolerantUpdateOnPartFv (
290 // Finally we are here. We have got the corresponding FVB protocol. Now
291 // we need to convert the physical address to LBA and offset and call
292 // FVB write. Also check if the flash range is larger than the FV.
294 Status
= NonFaultTolerantUpdateOnPartFv (
304 if (EFI_ERROR (Status
)) {
309 // As part of the FV has been replaced, the FV driver shall re-parse
310 // the firmware volume. So re-install FVB protocol here
312 Status
= gBS
->ReinstallProtocolInterface (
314 &gEfiFirmwareVolumeBlockProtocolGuid
,
319 if (EFI_ERROR (Status
)) {
324 // Check if we are done with the update
326 SizeLeft
= SizeLeft
- SizeUpdated
;
327 FlashAddress
= FlashAddress
+ SizeUpdated
;
328 PtrImage
= PtrImage
+ SizeUpdated
;
331 if (HandleBuffer
!= NULL
) {
332 FreePool (HandleBuffer
);
340 Find the updated file, and program it into the flash area based on the config data.
342 @param FwVolProtocol Pointer to FV protocol that contains the updated file.
343 @param ConfigData Pointer to the Config Data on updating file.
345 @retval EFI_INVALID_PARAMETER The update operation is not valid.
346 @retval EFI_NOT_FOUND The updated file is not found.
347 @retval EFI_SUCCESS The file is updated into the flash area.
352 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVolProtocol
,
353 IN UPDATE_CONFIG_DATA
*ConfigData
358 UINTN FileBufferSize
;
359 EFI_FV_FILETYPE FileType
;
360 EFI_FV_FILE_ATTRIBUTES Attrib
;
361 EFI_SECTION_TYPE SectionType
;
362 UINT32 AuthenticationStatus
;
364 BOOLEAN StartToUpdate
;
366 Status
= EFI_SUCCESS
;
369 Status
= FwVolProtocol
->ReadFile (
371 &(ConfigData
->FileGuid
),
372 (VOID
**) &FileBuffer
,
376 &AuthenticationStatus
378 if (EFI_ERROR (Status
)) {
382 StartToUpdate
= FALSE
;
385 // Check if the update image is the one we require
386 // and then perform the update
388 switch (ConfigData
->UpdateType
) {
393 // For UpdateWholeFv, the update file shall be a firmware volume
396 if (FileType
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
397 DEBUG ((EFI_D_UPDATE
, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n"));
398 Status
= EFI_INVALID_PARAMETER
;
400 if (FileBuffer
!= NULL
) {
401 FreePool (FileBuffer
);
403 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
406 Status
= FwVolProtocol
->ReadSection (
408 &(ConfigData
->FileGuid
),
411 (VOID
**) &FileBuffer
,
413 &AuthenticationStatus
415 if (!EFI_ERROR (Status
)) {
417 // Execute the update. For UpdateWholeFv, the update
418 // will always execute on a whole FV
420 StartToUpdate
= TRUE
;
421 Status
= PerformUpdateOnFirmwareVolume (
430 DEBUG ((EFI_D_UPDATE
, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n"));
438 // For UpdateFvRange, the update file shall be a raw file
439 // which does not contain any sections. The contents of the file
440 // will be directly programmed.
442 if (FileType
!= EFI_FV_FILETYPE_RAW
) {
443 DEBUG ((EFI_D_UPDATE
, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n"));
444 Status
= EFI_INVALID_PARAMETER
;
447 // For UpdateFvRange, the update may be performed on a sub area
448 // of a certain FV, or a flash area that is not FV, or part of FV.
449 // The update may also go across more than one FVs.
451 StartToUpdate
= TRUE
;
452 Status
= PerformUpdateOnFlashArea (
463 // No check will be done the the file got. The contents of the file
464 // will be directly programmed.
465 // Though UpdateFvFile will only update a single file, but the update
466 // will always execute on a FV
468 StartToUpdate
= TRUE
;
469 Status
= PerformUpdateOnFirmwareVolume (
479 Status
= EFI_INVALID_PARAMETER
;
483 if (EFI_ERROR (Status
)) {
484 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_DRIVER_ABORTED
), NULL
);
486 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_DRIVER_DONE
), NULL
);
488 if (TmpStr
!= NULL
) {
494 if (FileBuffer
!= NULL
) {
495 FreePool(FileBuffer
);
503 Process the input firmware volume by using DXE service ProcessFirmwareVolume.
505 @param DataBuffer Point to the FV image to be processed.
506 @param BufferSize Size of the FV image buffer.
507 @param FwVolProtocol Point to the installed FV protocol for the input FV image.
509 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
510 @retval EFI_VOLUME_CORRUPTED FV image is corrupted.
511 @retval EFI_SUCCESS FV image is processed and FV protocol is installed.
518 EFI_FIRMWARE_VOLUME2_PROTOCOL
**FwVolProtocol
521 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
522 EFI_HANDLE FwVolHandle
;
524 UINT8
*ProcessedDataBuffer
;
527 ProcessedDataBuffer
= NULL
;
528 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) DataBuffer
;
529 if (FwVolHeader
->FvLength
!= BufferSize
) {
530 return EFI_VOLUME_CORRUPTED
;
533 FvAlignment
= 1 << ((FwVolHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16);
535 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
537 if (FvAlignment
< 8) {
541 // Check FvImage Align is required.
543 if (((UINTN
) FwVolHeader
% FvAlignment
) == 0) {
544 ProcessedDataBuffer
= DataBuffer
;
547 // Allocate new aligned buffer to store DataBuffer.
549 ProcessedDataBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), (UINTN
) FvAlignment
);
550 if (ProcessedDataBuffer
== NULL
) {
551 return EFI_OUT_OF_RESOURCES
;
553 CopyMem (ProcessedDataBuffer
, DataBuffer
, BufferSize
);
556 // Process the firmware volume
558 gDS
->ProcessFirmwareVolume (
565 // Get the FwVol protocol
567 Status
= gBS
->HandleProtocol (
569 &gEfiFirmwareVolume2ProtocolGuid
,
570 (VOID
**) FwVolProtocol
577 Find the image in the same FV and program it in a target Firmware Volume device.
578 After update image, it will reset system and no return.
580 @param ImageHandle A handle for the image that is initializing this driver
581 @param SystemTable A pointer to the EFI system table
583 @retval EFI_ABORTED System reset failed.
584 @retval EFI_NOT_FOUND The updated image is not found in the same FV.
589 InitializeUpdateDriver (
590 IN EFI_HANDLE ImageHandle
,
591 IN EFI_SYSTEM_TABLE
*SystemTable
595 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImageProtocol
;
596 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVolProtocol
;
597 EFI_FIRMWARE_VOLUME2_PROTOCOL
*DataFwVolProtocol
;
598 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FwVolFilePathNode
;
599 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*AlignedDevPathNode
;
600 EFI_DEVICE_PATH_PROTOCOL
*FilePathNode
;
601 EFI_SECTION_TYPE SectionType
;
603 UINTN FileBufferSize
;
604 EFI_FV_FILETYPE FileType
;
605 EFI_FV_FILE_ATTRIBUTES Attrib
;
606 UINT32 AuthenticationStatus
;
607 UPDATE_CONFIG_DATA
*ConfigData
;
608 UPDATE_CONFIG_DATA
*UpdateConfigData
;
616 if (gST
->ConOut
!= NULL
) {
617 gST
->ConOut
->ClearScreen (gST
->ConOut
);
618 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_YELLOW
| EFI_BRIGHT
);
619 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
622 gHiiHandle
= HiiAddPackages (
625 UpdateDriverDxeStrings
,
628 ASSERT (gHiiHandle
!= NULL
);
631 // In order to look for the update data file and programmed image file
632 // from the same volume which this driver is dispatched from, we need
633 // to get the device path of this driver image. It is done by first
634 // locate the LoadedImageProtocol and then get its device path
636 Status
= gBS
->OpenProtocol (
638 &gEfiLoadedImageProtocolGuid
,
639 (VOID
**)&LoadedImageProtocol
,
642 EFI_OPEN_PROTOCOL_GET_PROTOCOL
644 if (EFI_ERROR (Status
)) {
648 // Get the firmware volume protocol where this file resides
650 Status
= gBS
->HandleProtocol (
651 LoadedImageProtocol
->DeviceHandle
,
652 &gEfiFirmwareVolume2ProtocolGuid
,
653 (VOID
**) &FwVolProtocol
655 if (EFI_ERROR (Status
)) {
656 return EFI_NOT_FOUND
;
660 // Shall do some extra check to see if it is really contained in the FV?
661 // Should be able to find the section of this driver in the the FV.
663 FilePathNode
= LoadedImageProtocol
->FilePath
;
664 FwVolFilePathNode
= NULL
;
665 while (!IsDevicePathEnd (FilePathNode
)) {
666 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)FilePathNode
)!= NULL
) {
667 FwVolFilePathNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) FilePathNode
;
670 FilePathNode
= NextDevicePathNode (FilePathNode
);
673 if (FwVolFilePathNode
!= NULL
) {
674 AlignedDevPathNode
= AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode
), FwVolFilePathNode
);
676 SectionType
= EFI_SECTION_PE32
;
679 Status
= FwVolProtocol
->ReadSection (
681 &(AlignedDevPathNode
->FvFileName
),
684 (VOID
**) &FileBuffer
,
686 &AuthenticationStatus
688 if (EFI_ERROR (Status
)) {
689 FreePool (AlignedDevPathNode
);
693 if (FileBuffer
!= NULL
) {
694 FreePool(FileBuffer
);
699 // Check the NameGuid of the udpate driver so that it can be
700 // used as the CallerId in fault tolerant write protocol
702 if (!CompareGuid (&gEfiCallerIdGuid
, &(AlignedDevPathNode
->FvFileName
))) {
703 FreePool (AlignedDevPathNode
);
704 return EFI_NOT_FOUND
;
706 FreePool (AlignedDevPathNode
);
708 return EFI_NOT_FOUND
;
712 // Now try to find the script file. The script file is usually
713 // a raw data file which does not contain any sections.
717 Status
= FwVolProtocol
->ReadFile (
719 &gEfiConfigFileNameGuid
,
720 (VOID
**) &FileBuffer
,
724 &AuthenticationStatus
726 if (EFI_ERROR (Status
)) {
729 if (FileType
!= EFI_FV_FILETYPE_RAW
) {
730 return EFI_NOT_FOUND
;
734 // Parse the configuration file.
738 Status
= ParseUpdateDataFile (
744 if (FileBuffer
!= NULL
) {
745 FreePool (FileBuffer
);
748 if (EFI_ERROR (Status
)) {
751 ASSERT (ConfigData
!= NULL
);
754 // Now find the update image. The update image should be put in a FV, and then
755 // encapsulated as a raw FFS file. This is to prevent the update image from
756 // being dispatched. So the raw data we get here should be an FV. We need to
757 // process this FV and read the files that is going to be updated.
761 Status
= FwVolProtocol
->ReadFile (
763 &gEfiUpdateDataFileGuid
,
764 (VOID
**) &FileBuffer
,
768 &AuthenticationStatus
770 if (EFI_ERROR (Status
)) {
773 if (FileType
!= EFI_FV_FILETYPE_RAW
) {
774 return EFI_NOT_FOUND
;
778 // FileBuffer should be an FV. Process the FV
780 DataFwVolProtocol
= NULL
;
781 Status
= ProcessUpdateImage (
786 if (EFI_ERROR (Status
)) {
787 FreePool (FileBuffer
);
794 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_PROCESS_DATA
), NULL
);
795 if (TmpStr
!= NULL
) {
801 // Execute the update
804 UpdateConfigData
= ConfigData
;
805 while (Index
< NumOfUpdates
) {
806 Status
= PerformUpdate (
811 // Shall updates be serialized so that if an update is not successfully completed,
812 // the remaining updates won't be performed.
814 if (EFI_ERROR (Status
)) {
822 if (EFI_ERROR (Status
)) {
823 if (ConfigData
!= NULL
) {
824 FreePool(ConfigData
);
833 gRT
->ResetSystem (EfiResetCold
, EFI_SUCCESS
, 0, NULL
);
836 // Hopefully it won't be reached