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 - 2011, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions
10 of the BSD License which accompanies this distribution. The
11 full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include "UpdateDriver.h"
21 EFI_GUID UpdateDataGuid
= EFI_UPDATE_DATA_FILE_GUID
;
22 EFI_HII_HANDLE gHiiHandle
;
25 Update the whole FV, or certain files in the FV.
27 @param ConfigData Pointer to the config data on updating file.
28 @param ImageBuffer Image buffer to be updated.
29 @param ImageSize Image size.
30 @param FileType FFS file type.
31 @param FileAttributes FFS file attribute.
33 @retval EFI_NOT_FOUND The matched FVB protocol is not found.
34 @retval EFI_SUCCESS The image buffer is updated into FV.
38 PerformUpdateOnFirmwareVolume (
39 IN UPDATE_CONFIG_DATA
*ConfigData
,
40 IN UINT8
*ImageBuffer
,
42 IN EFI_FV_FILETYPE FileType
,
43 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
48 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
51 EFI_HANDLE
*HandleBuffer
;
52 EFI_PHYSICAL_ADDRESS BaseAddress
;
53 EFI_FVB_ATTRIBUTES_2 Attributes
;
56 // Locate all Fvb protocol
59 Status
= gBS
->LocateHandleBuffer (
61 &gEfiFirmwareVolumeBlockProtocolGuid
,
66 if ((EFI_ERROR (Status
)) || (NumOfHandles
== 0) || (HandleBuffer
== NULL
)) {
67 if (HandleBuffer
!= NULL
) {
68 FreePool (HandleBuffer
);
74 // Check the FVB protocol one by one
78 for (Index
= 0; Index
< NumOfHandles
; Index
++) {
79 Status
= gBS
->HandleProtocol (
81 &gEfiFirmwareVolumeBlockProtocolGuid
,
82 (VOID
**) &FvbProtocol
84 if (EFI_ERROR (Status
)) {
89 // Ensure this FVB protocol supported Write operation.
91 Status
= FvbProtocol
->GetAttributes (FvbProtocol
, &Attributes
);
92 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
96 Status
= FvbProtocol
->GetPhysicalAddress (
100 if (EFI_ERROR (Status
)) {
103 if (BaseAddress
== ConfigData
->BaseAddress
) {
110 if (HandleBuffer
!= NULL
) {
111 FreePool (HandleBuffer
);
114 return EFI_NOT_FOUND
;
118 // Now we have got the corresponding FVB protocol. Use the FVB protocol
119 // to update the whole FV, or certain files in the FV.
121 if (ConfigData
->UpdateType
== UpdateWholeFV
) {
122 if (FileType
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
123 Status
= EFI_INVALID_PARAMETER
;
125 Status
= PerformUpdateOnWholeFv (
133 } else if (ConfigData
->UpdateType
== UpdateFvFile
) {
134 Status
= PerformUpdateOnFvFile (
145 if (HandleBuffer
!= NULL
) {
146 FreePool (HandleBuffer
);
154 Update the file directly into flash area.
156 @param ConfigData Pointer to the config data on updating file.
157 @param ImageBuffer Image buffer to be updated.
158 @param ImageSize Image size.
160 @retval EFI_SUCCESS The file is updated into flash area.
161 @retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found.
165 PerformUpdateOnFlashArea (
166 IN UPDATE_CONFIG_DATA
*ConfigData
,
167 IN UINT8
*ImageBuffer
,
173 EFI_PHYSICAL_ADDRESS FlashAddress
;
176 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
179 EFI_HANDLE
*HandleBuffer
;
180 EFI_PHYSICAL_ADDRESS BaseAddress
;
181 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
182 EFI_HANDLE FvbHandle
;
185 EFI_FVB_ATTRIBUTES_2 Attributes
;
187 SizeLeft
= ImageSize
;
188 PtrImage
= ImageBuffer
;
189 FlashAddress
= ConfigData
->BaseAddress
;
190 Status
= EFI_SUCCESS
;
196 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_FLASH_RANGE
), NULL
);
197 if (TmpStr
!= NULL
) {
198 Print (TmpStr
, FlashAddress
, ((UINT64
)SizeLeft
+ FlashAddress
));
203 // Locate all Fvb protocol
205 Status
= gBS
->LocateHandleBuffer (
207 &gEfiFirmwareVolumeBlockProtocolGuid
,
212 if ((EFI_ERROR (Status
)) || (NumOfHandles
== 0) || (HandleBuffer
== NULL
)) {
213 if (HandleBuffer
!= NULL
) {
214 FreePool (HandleBuffer
);
216 return EFI_NOT_FOUND
;
219 while (SizeLeft
> 0) {
221 // First get the FVB protocols. If the flash area is a FV, or sub FV,
222 // we can directly locate all the FVB protocol. Otherwise we should use
223 // implementation specific method to get the alternate FVB protocol
229 // Check the FVB protocol one by one
231 for (Index
= 0; Index
< NumOfHandles
; Index
++) {
232 Status
= gBS
->HandleProtocol (
234 &gEfiFirmwareVolumeBlockProtocolGuid
,
235 (VOID
**) &FvbProtocol
237 if (EFI_ERROR (Status
)) {
242 // Ensure this FVB protocol supported Write operation.
244 Status
= FvbProtocol
->GetAttributes (FvbProtocol
, &Attributes
);
245 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
249 Status
= FvbProtocol
->GetPhysicalAddress (
253 if (EFI_ERROR (Status
)) {
256 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)BaseAddress
;
259 // This sub area entry falls in the range of the FV
261 if ((FlashAddress
>= BaseAddress
) && (FlashAddress
< (BaseAddress
+ FwVolHeader
->FvLength
))) {
268 if (HandleBuffer
!= NULL
) {
269 FreePool (HandleBuffer
);
272 return EFI_NOT_FOUND
;
275 FvbHandle
= HandleBuffer
[Index
];
279 // If the flash area is boot required, the update must be fault tolerant
281 if (ConfigData
->FaultTolerant
) {
283 // Finally we are here. We have got the corresponding FVB protocol. Now
284 // we need to convert the physical address to LBA and offset and call
285 // FTW write. Also check if the flash range is larger than the FV.
287 Status
= FaultTolerantUpdateOnPartFv (
298 // Finally we are here. We have got the corresponding FVB protocol. Now
299 // we need to convert the physical address to LBA and offset and call
300 // FVB write. Also check if the flash range is larger than the FV.
302 Status
= NonFaultTolerantUpdateOnPartFv (
312 if (EFI_ERROR (Status
)) {
317 // As part of the FV has been replaced, the FV driver shall re-parse
318 // the firmware volume. So re-install FVB protocol here
320 Status
= gBS
->ReinstallProtocolInterface (
322 &gEfiFirmwareVolumeBlockProtocolGuid
,
327 if (EFI_ERROR (Status
)) {
332 // Check if we are done with the update
334 SizeLeft
= SizeLeft
- SizeUpdated
;
335 FlashAddress
= FlashAddress
+ SizeUpdated
;
336 PtrImage
= PtrImage
+ SizeUpdated
;
339 if (HandleBuffer
!= NULL
) {
340 FreePool (HandleBuffer
);
348 Find the updated file, and program it into the flash area based on the config data.
350 @param FwVolProtocol Pointer to FV protocol that contains the updated file.
351 @param ConfigData Pointer to the Config Data on updating file.
353 @retval EFI_INVALID_PARAMETER The update operation is not valid.
354 @retval EFI_NOT_FOUND The updated file is not found.
355 @retval EFI_SUCCESS The file is updated into the flash area.
360 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVolProtocol
,
361 IN UPDATE_CONFIG_DATA
*ConfigData
366 UINTN FileBufferSize
;
367 EFI_FV_FILETYPE FileType
;
368 EFI_FV_FILE_ATTRIBUTES Attrib
;
369 EFI_SECTION_TYPE SectionType
;
370 UINT32 AuthenticationStatus
;
372 BOOLEAN StartToUpdate
;
374 Status
= EFI_SUCCESS
;
377 Status
= FwVolProtocol
->ReadFile (
379 &(ConfigData
->FileGuid
),
380 (VOID
**) &FileBuffer
,
384 &AuthenticationStatus
386 if (EFI_ERROR (Status
)) {
390 StartToUpdate
= FALSE
;
393 // Check if the update image is the one we require
394 // and then perform the update
396 switch (ConfigData
->UpdateType
) {
401 // For UpdateWholeFv, the update file shall be a firmware volume
404 if (FileType
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
405 DEBUG ((EFI_D_UPDATE
, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n"));
406 Status
= EFI_INVALID_PARAMETER
;
408 if (FileBuffer
!= NULL
) {
409 FreePool (FileBuffer
);
411 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
414 Status
= FwVolProtocol
->ReadSection (
416 &(ConfigData
->FileGuid
),
419 (VOID
**) &FileBuffer
,
421 &AuthenticationStatus
423 if (!EFI_ERROR (Status
)) {
425 // Execute the update. For UpdateWholeFv, the update
426 // will always execute on a whole FV
428 StartToUpdate
= TRUE
;
429 Status
= PerformUpdateOnFirmwareVolume (
438 DEBUG ((EFI_D_UPDATE
, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n"));
446 // For UpdateFvRange, the update file shall be a raw file
447 // which does not contain any sections. The contents of the file
448 // will be directly programmed.
450 if (FileType
!= EFI_FV_FILETYPE_RAW
) {
451 DEBUG ((EFI_D_UPDATE
, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n"));
452 Status
= EFI_INVALID_PARAMETER
;
455 // For UpdateFvRange, the update may be performed on a sub area
456 // of a certain FV, or a flash area that is not FV, or part of FV.
457 // The update may also go across more than one FVs.
459 StartToUpdate
= TRUE
;
460 Status
= PerformUpdateOnFlashArea (
471 // No check will be done the the file got. The contents of the file
472 // will be directly programmed.
473 // Though UpdateFvFile will only update a single file, but the update
474 // will always execute on a FV
476 StartToUpdate
= TRUE
;
477 Status
= PerformUpdateOnFirmwareVolume (
487 Status
= EFI_INVALID_PARAMETER
;
491 if (EFI_ERROR (Status
)) {
492 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_DRIVER_ABORTED
), NULL
);
494 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_DRIVER_DONE
), NULL
);
496 if (TmpStr
!= NULL
) {
502 if (FileBuffer
!= NULL
) {
503 FreePool(FileBuffer
);
511 Process the input firmware volume by using DXE service ProcessFirmwareVolume.
513 @param DataBuffer Point to the FV image to be processed.
514 @param BufferSize Size of the FV image buffer.
515 @param FwVolProtocol Point to the installed FV protocol for the input FV image.
517 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
518 @retval EFI_VOLUME_CORRUPTED FV image is corrupted.
519 @retval EFI_SUCCESS FV image is processed and FV protocol is installed.
526 EFI_FIRMWARE_VOLUME2_PROTOCOL
**FwVolProtocol
529 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
530 EFI_HANDLE FwVolHandle
;
532 UINT8
*ProcessedDataBuffer
;
535 ProcessedDataBuffer
= NULL
;
536 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) DataBuffer
;
537 if (FwVolHeader
->FvLength
!= BufferSize
) {
538 return EFI_VOLUME_CORRUPTED
;
541 FvAlignment
= 1 << ((FwVolHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16);
543 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
545 if (FvAlignment
< 8) {
549 // Check FvImage Align is required.
551 if (((UINTN
) FwVolHeader
% FvAlignment
) == 0) {
552 ProcessedDataBuffer
= DataBuffer
;
555 // Allocate new aligned buffer to store DataBuffer.
557 ProcessedDataBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), (UINTN
) FvAlignment
);
558 if (ProcessedDataBuffer
== NULL
) {
559 return EFI_OUT_OF_RESOURCES
;
561 CopyMem (ProcessedDataBuffer
, DataBuffer
, BufferSize
);
564 // Process the firmware volume
566 gDS
->ProcessFirmwareVolume (
573 // Get the FwVol protocol
575 Status
= gBS
->HandleProtocol (
577 &gEfiFirmwareVolume2ProtocolGuid
,
578 (VOID
**) FwVolProtocol
585 Find the image in the same FV and program it in a target Firmware Volume device.
586 After update image, it will reset system and no return.
588 @param ImageHandle A handle for the image that is initializing this driver
589 @param SystemTable A pointer to the EFI system table
591 @retval EFI_ABORTED System reset failed.
592 @retval EFI_NOT_FOUND The updated image is not found in the same FV.
597 InitializeUpdateDriver (
598 IN EFI_HANDLE ImageHandle
,
599 IN EFI_SYSTEM_TABLE
*SystemTable
603 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImageProtocol
;
604 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVolProtocol
;
605 EFI_FIRMWARE_VOLUME2_PROTOCOL
*DataFwVolProtocol
;
606 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FwVolFilePathNode
;
607 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*AlignedDevPathNode
;
608 EFI_DEVICE_PATH_PROTOCOL
*FilePathNode
;
609 EFI_SECTION_TYPE SectionType
;
611 UINTN FileBufferSize
;
612 EFI_FV_FILETYPE FileType
;
613 EFI_FV_FILE_ATTRIBUTES Attrib
;
614 UINT32 AuthenticationStatus
;
615 UPDATE_CONFIG_DATA
*ConfigData
;
616 UPDATE_CONFIG_DATA
*UpdateConfigData
;
624 if (gST
->ConOut
!= NULL
) {
625 gST
->ConOut
->ClearScreen (gST
->ConOut
);
626 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_YELLOW
| EFI_BRIGHT
);
627 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
630 gHiiHandle
= HiiAddPackages (
633 UpdateDriverDxeStrings
,
636 ASSERT (gHiiHandle
!= NULL
);
639 // In order to look for the update data file and programmed image file
640 // from the same volume which this driver is dispatched from, we need
641 // to get the device path of this driver image. It is done by first
642 // locate the LoadedImageProtocol and then get its device path
644 Status
= gBS
->OpenProtocol (
646 &gEfiLoadedImageProtocolGuid
,
647 (VOID
**)&LoadedImageProtocol
,
650 EFI_OPEN_PROTOCOL_GET_PROTOCOL
652 if (EFI_ERROR (Status
)) {
656 // Get the firmware volume protocol where this file resides
658 Status
= gBS
->HandleProtocol (
659 LoadedImageProtocol
->DeviceHandle
,
660 &gEfiFirmwareVolume2ProtocolGuid
,
661 (VOID
**) &FwVolProtocol
663 if (EFI_ERROR (Status
)) {
664 return EFI_NOT_FOUND
;
668 // Shall do some extra check to see if it is really contained in the FV?
669 // Should be able to find the section of this driver in the the FV.
671 FilePathNode
= LoadedImageProtocol
->FilePath
;
672 FwVolFilePathNode
= NULL
;
673 while (!IsDevicePathEnd (FilePathNode
)) {
674 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)FilePathNode
)!= NULL
) {
675 FwVolFilePathNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) FilePathNode
;
678 FilePathNode
= NextDevicePathNode (FilePathNode
);
681 if (FwVolFilePathNode
!= NULL
) {
682 AlignedDevPathNode
= AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode
), FwVolFilePathNode
);
684 SectionType
= EFI_SECTION_PE32
;
687 Status
= FwVolProtocol
->ReadSection (
689 &(AlignedDevPathNode
->FvFileName
),
692 (VOID
**) &FileBuffer
,
694 &AuthenticationStatus
696 if (EFI_ERROR (Status
)) {
697 FreePool (AlignedDevPathNode
);
701 if (FileBuffer
!= NULL
) {
702 FreePool(FileBuffer
);
707 // Check the NameGuid of the udpate driver so that it can be
708 // used as the CallerId in fault tolerant write protocol
710 if (!CompareGuid (&gEfiCallerIdGuid
, &(AlignedDevPathNode
->FvFileName
))) {
711 FreePool (AlignedDevPathNode
);
712 return EFI_NOT_FOUND
;
714 FreePool (AlignedDevPathNode
);
716 return EFI_NOT_FOUND
;
720 // Now try to find the script file. The script file is usually
721 // a raw data file which does not contain any sections.
725 Status
= FwVolProtocol
->ReadFile (
727 &gEfiConfigFileNameGuid
,
728 (VOID
**) &FileBuffer
,
732 &AuthenticationStatus
734 if (EFI_ERROR (Status
)) {
737 if (FileType
!= EFI_FV_FILETYPE_RAW
) {
738 return EFI_NOT_FOUND
;
742 // Parse the configuration file.
746 Status
= ParseUpdateDataFile (
752 if (FileBuffer
!= NULL
) {
753 FreePool (FileBuffer
);
756 if (EFI_ERROR (Status
)) {
761 // Now find the update image. The update image should be put in a FV, and then
762 // encapsulated as a raw FFS file. This is to prevent the update image from
763 // being dispatched. So the raw data we get here should be an FV. We need to
764 // process this FV and read the files that is going to be updated.
768 Status
= FwVolProtocol
->ReadFile (
771 (VOID
**) &FileBuffer
,
775 &AuthenticationStatus
777 if (EFI_ERROR (Status
)) {
780 if (FileType
!= EFI_FV_FILETYPE_RAW
) {
781 return EFI_NOT_FOUND
;
785 // FileBuffer should be an FV. Process the FV
787 DataFwVolProtocol
= NULL
;
788 Status
= ProcessUpdateImage (
793 if (EFI_ERROR (Status
)) {
794 FreePool (FileBuffer
);
801 TmpStr
= HiiGetString (gHiiHandle
, STRING_TOKEN(UPDATE_PROCESS_DATA
), NULL
);
802 if (TmpStr
!= NULL
) {
808 // Execute the update
811 UpdateConfigData
= ConfigData
;
812 while (Index
< NumOfUpdates
) {
813 Status
= PerformUpdate (
818 // Shall updates be serialized so that if an update is not successfully completed,
819 // the remaining updates won't be performed.
821 if (EFI_ERROR (Status
)) {
829 if (EFI_ERROR (Status
)) {
830 if (ConfigData
!= NULL
) {
831 FreePool(ConfigData
);
840 gRT
->ResetSystem (EfiResetCold
, EFI_SUCCESS
, 0, NULL
);
843 // Hopefully it won't be reached