2 Implements write firmware file.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "FwVolDriver.h"
13 Calculate the checksum for the FFS header.
15 @param FfsHeader FFS File Header which needs to calculate the checksum
20 IN EFI_FFS_FILE_HEADER
*FfsHeader
23 EFI_FFS_FILE_STATE State
;
27 // The state and the File checksum are not included
29 State
= FfsHeader
->State
;
32 FileChecksum
= FfsHeader
->IntegrityCheck
.Checksum
.File
;
33 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
35 FfsHeader
->IntegrityCheck
.Checksum
.Header
= 0;
37 if (IS_FFS_FILE2 (FfsHeader
)) {
38 FfsHeader
->IntegrityCheck
.Checksum
.Header
= CalculateCheckSum8 (
40 sizeof (EFI_FFS_FILE_HEADER2
)
43 FfsHeader
->IntegrityCheck
.Checksum
.Header
= CalculateCheckSum8 (
45 sizeof (EFI_FFS_FILE_HEADER
)
49 FfsHeader
->State
= State
;
50 FfsHeader
->IntegrityCheck
.Checksum
.File
= FileChecksum
;
56 Calculate the checksum for the FFS File.
58 @param FfsHeader FFS File Header which needs to calculate the checksum
59 @param ActualFileSize The whole Ffs File Length.
64 IN EFI_FFS_FILE_HEADER
*FfsHeader
,
65 IN UINTN ActualFileSize
68 if ((FfsHeader
->Attributes
& FFS_ATTRIB_CHECKSUM
) != 0) {
70 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
72 if (IS_FFS_FILE2 (FfsHeader
)) {
73 FfsHeader
->IntegrityCheck
.Checksum
.File
= CalculateCheckSum8 (
74 (UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER2
),
75 ActualFileSize
- sizeof (EFI_FFS_FILE_HEADER2
)
78 FfsHeader
->IntegrityCheck
.Checksum
.File
= CalculateCheckSum8 (
79 (UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER
),
80 ActualFileSize
- sizeof (EFI_FFS_FILE_HEADER
)
86 FfsHeader
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
94 Get the alignment value from File Attributes.
96 @param FfsAttributes FFS attribute
98 @return Alignment value.
102 GetRequiredAlignment (
103 IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
106 UINTN AlignmentValue
;
108 AlignmentValue
= FfsAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
;
110 if (AlignmentValue
<= 3) {
114 if (AlignmentValue
> 16) {
116 // Anyway, we won't reach this code
121 return (UINTN
)1 << AlignmentValue
;
126 Calculate the leading Pad file size to meet the alignment requirement.
128 @param FvDevice Cached Firmware Volume.
129 @param StartAddress The starting address to write the FFS File.
130 @param BufferSize The FFS File Buffer Size.
131 @param RequiredAlignment FFS File Data alignment requirement.
133 @return The required Pad File Size.
137 CalculatePadFileSize (
138 IN FV_DEVICE
*FvDevice
,
139 IN EFI_PHYSICAL_ADDRESS StartAddress
,
141 IN UINTN RequiredAlignment
148 if (BufferSize
> 0x00FFFFFF) {
149 DataStartPos
= (UINTN
) StartAddress
+ sizeof (EFI_FFS_FILE_HEADER2
);
151 DataStartPos
= (UINTN
) StartAddress
+ sizeof (EFI_FFS_FILE_HEADER
);
153 RelativePos
= DataStartPos
- (UINTN
) FvDevice
->CachedFv
;
157 while ((RelativePos
& (RequiredAlignment
- 1)) != 0) {
162 // If padsize is 0, no pad file needed;
163 // If padsize is great than 24, then pad file can be created
165 if ((PadSize
== 0) || (PadSize
>= sizeof (EFI_FFS_FILE_HEADER
))) {
170 // Perhaps following method can save space
172 RelativePos
= DataStartPos
- (UINTN
) FvDevice
->CachedFv
+ sizeof (EFI_FFS_FILE_HEADER
);
173 PadSize
= sizeof (EFI_FFS_FILE_HEADER
);
175 while ((RelativePos
& (RequiredAlignment
- 1)) != 0) {
184 Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
186 @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
187 @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
191 FvFileAttrib2FfsFileAttrib (
192 IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib
,
193 OUT UINT8
*FfsFileAttrib
196 UINT8 FvFileAlignment
;
197 UINT8 FfsFileAlignment
;
198 UINT8 FfsFileAlignment2
;
200 FvFileAlignment
= (UINT8
) (FvFileAttrib
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
201 FfsFileAlignment
= 0;
202 FfsFileAlignment2
= 0;
204 switch (FvFileAlignment
) {
221 FfsFileAlignment
= 0;
236 FfsFileAlignment
= 1;
247 FfsFileAlignment
= 2;
251 FfsFileAlignment
= 3;
262 FfsFileAlignment
= 4;
277 FfsFileAlignment
= 5;
281 FfsFileAlignment
= 6;
285 FfsFileAlignment
= 7;
289 FfsFileAlignment
= 0;
290 FfsFileAlignment2
= 1;
293 FfsFileAlignment
= 1;
294 FfsFileAlignment2
= 1;
297 FfsFileAlignment
= 2;
298 FfsFileAlignment2
= 1;
301 FfsFileAlignment
= 3;
302 FfsFileAlignment2
= 1;
305 FfsFileAlignment
= 4;
306 FfsFileAlignment2
= 1;
309 FfsFileAlignment
= 5;
310 FfsFileAlignment2
= 1;
313 FfsFileAlignment
= 6;
314 FfsFileAlignment2
= 1;
317 FfsFileAlignment
= 7;
318 FfsFileAlignment2
= 1;
322 *FfsFileAttrib
= (UINT8
) ((FfsFileAlignment
<< 3) | (FfsFileAlignment2
<< 1));
328 Locate a free space entry that can hold this FFS file.
330 @param FvDevice Cached Firmware Volume.
331 @param Size The FFS file size.
332 @param RequiredAlignment FFS File Data alignment requirement.
333 @param PadSize Pointer to the size of leading Pad File.
334 @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
336 @retval EFI_SUCCESS The free space entry is found.
337 @retval EFI_NOT_FOUND The free space entry can't be found.
341 FvLocateFreeSpaceEntry (
342 IN FV_DEVICE
*FvDevice
,
344 IN UINTN RequiredAlignment
,
346 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
349 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
353 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
354 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
357 // Loop the free space entry list to find one that can hold the
358 // required the file size
360 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
361 PadFileSize
= CalculatePadFileSize (
363 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceListEntry
->StartingAddress
,
367 if (FreeSpaceListEntry
->Length
>= Size
+ PadFileSize
) {
368 *FreeSpaceEntry
= FreeSpaceListEntry
;
369 *PadSize
= PadFileSize
;
373 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
376 return EFI_NOT_FOUND
;
381 Locate Pad File for writing, this is got from FV Cache.
383 @param FvDevice Cached Firmware Volume.
384 @param Size The required FFS file size.
385 @param RequiredAlignment FFS File Data alignment requirement.
386 @param PadSize Pointer to the size of leading Pad File.
387 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
389 @retval EFI_SUCCESS The required pad file is found.
390 @retval EFI_NOT_FOUND The required pad file can't be found.
395 IN FV_DEVICE
*FvDevice
,
397 IN UINTN RequiredAlignment
,
399 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
402 FFS_FILE_LIST_ENTRY
*FileEntry
;
403 EFI_FFS_FILE_STATE FileState
;
404 EFI_FFS_FILE_HEADER
*FileHeader
;
409 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
412 // travel through the whole file list to get the pad file entry
414 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
416 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
417 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
419 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
421 // we find one valid pad file, check its free area length
423 if (IS_FFS_FILE2 (FileHeader
)) {
424 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
425 PadAreaLength
= FFS_FILE2_SIZE (FileHeader
) - HeaderSize
;
427 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
428 PadAreaLength
= FFS_FILE_SIZE (FileHeader
) - HeaderSize
;
431 PadFileSize
= CalculatePadFileSize (
433 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ HeaderSize
,
437 if (PadAreaLength
>= (Size
+ PadFileSize
)) {
438 *PadSize
= PadFileSize
;
439 *PadFileEntry
= FileEntry
;
444 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
447 return EFI_NOT_FOUND
;
451 Locate a suitable pad file for multiple file writing.
453 @param FvDevice Cached Firmware Volume.
454 @param NumOfFiles The number of Files that needed updating
455 @param BufferSize The array of each file size.
456 @param RequiredAlignment The array of of FFS File Data alignment requirement.
457 @param PadSize The array of size of each leading Pad File.
458 @param TotalSizeNeeded The totalsize that can hold these files.
459 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
461 @retval EFI_SUCCESS The required pad file is found.
462 @retval EFI_NOT_FOUND The required pad file can't be found.
466 FvSearchSuitablePadFile (
467 IN FV_DEVICE
*FvDevice
,
469 IN UINTN
*BufferSize
,
470 IN UINTN
*RequiredAlignment
,
472 OUT UINTN
*TotalSizeNeeded
,
473 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
476 FFS_FILE_LIST_ENTRY
*FileEntry
;
477 EFI_FFS_FILE_STATE FileState
;
478 EFI_FFS_FILE_HEADER
*FileHeader
;
484 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
487 // travel through the whole file list to get the pad file entry
489 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
491 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
492 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
494 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
496 // we find one valid pad file, check its length
498 if (IS_FFS_FILE2 (FileHeader
)) {
499 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
500 PadAreaLength
= FFS_FILE2_SIZE (FileHeader
) - HeaderSize
;
502 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
503 PadAreaLength
= FFS_FILE_SIZE (FileHeader
) - HeaderSize
;
507 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
508 PadSize
[Index
] = CalculatePadFileSize (
510 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ HeaderSize
+ TotalSize
,
512 RequiredAlignment
[Index
]
514 TotalSize
+= PadSize
[Index
];
515 TotalSize
+= BufferSize
[Index
];
517 if (TotalSize
> PadAreaLength
) {
522 if (PadAreaLength
>= TotalSize
) {
523 *PadFileEntry
= FileEntry
;
524 *TotalSizeNeeded
= TotalSize
;
529 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
532 return EFI_NOT_FOUND
;
536 Locate a Free Space entry which can hold these files, including
537 meeting the alignment requirements.
539 @param FvDevice Cached Firmware Volume.
540 @param NumOfFiles The number of Files that needed updating
541 @param BufferSize The array of each file size.
542 @param RequiredAlignment The array of of FFS File Data alignment requirement.
543 @param PadSize The array of size of each leading Pad File.
544 @param TotalSizeNeeded The got total size that can hold these files.
545 @param FreeSpaceEntry The Free Space Entry that can hold these files.
547 @retval EFI_SUCCESS The free space entry is found.
548 @retval EFI_NOT_FOUND The free space entry can't be found.
552 FvSearchSuitableFreeSpace (
553 IN FV_DEVICE
*FvDevice
,
555 IN UINTN
*BufferSize
,
556 IN UINTN
*RequiredAlignment
,
558 OUT UINTN
*TotalSizeNeeded
,
559 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
562 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
568 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
570 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
572 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
574 StartAddr
= FreeSpaceListEntry
->StartingAddress
;
577 // Calculate the totalsize we need
579 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
581 // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
582 // have had its leading pad file.
584 PadSize
[Index
] = CalculatePadFileSize (
586 (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartAddr
+ TotalSize
,
588 RequiredAlignment
[Index
]
591 TotalSize
+= PadSize
[Index
];
592 TotalSize
+= BufferSize
[Index
];
594 if (TotalSize
> FreeSpaceListEntry
->Length
) {
599 if (FreeSpaceListEntry
->Length
>= TotalSize
) {
600 *FreeSpaceEntry
= FreeSpaceListEntry
;
601 *TotalSizeNeeded
= TotalSize
;
605 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
608 return EFI_NOT_FOUND
;
612 Calculate the length of the remaining space in FV.
614 @param FvDevice Cached Firmware Volume
615 @param Offset Current offset to FV base address.
616 @param Lba LBA number for the current offset.
617 @param LOffset Offset in block for the current offset.
619 @return the length of remaining space.
623 CalculateRemainingLength (
624 IN FV_DEVICE
*FvDevice
,
636 Link
= FvDevice
->LbaHeader
.ForwardLink
;
637 LbaEntry
= (LBA_ENTRY
*) Link
;
639 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
640 if (Count
> Offset
) {
644 Count
+= LbaEntry
->BlockLength
;
646 Link
= LbaEntry
->Link
.ForwardLink
;
647 LbaEntry
= (LBA_ENTRY
*) Link
;
650 if (Count
<= Offset
) {
654 Link
= LbaEntry
->Link
.BackLink
;
655 LbaEntry
= (LBA_ENTRY
*) Link
;
658 *LOffset
= (UINTN
) (LbaEntry
->BlockLength
- (Count
- Offset
));
661 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
663 Count
+= LbaEntry
->BlockLength
;
665 Link
= LbaEntry
->Link
.ForwardLink
;
666 LbaEntry
= (LBA_ENTRY
*) Link
;
675 Writes data beginning at Lba:Offset from FV. The write terminates either
676 when *NumBytes of data have been written, or when the firmware end is
677 reached. *NumBytes is updated to reflect the actual number of bytes
680 @param FvDevice Cached Firmware Volume
681 @param Offset Offset in the block at which to begin write
682 @param NumBytes At input, indicates the requested write size.
683 At output, indicates the actual number of bytes written.
684 @param Buffer Buffer containing source data for the write.
686 @retval EFI_SUCCESS Data is successfully written into FV.
687 @return error Data is failed written.
692 IN FV_DEVICE
*FvDevice
,
694 IN OUT UINTN
*NumBytes
,
699 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
702 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
703 UINTN RemainingLength
;
708 RemainingLength
= CalculateRemainingLength (FvDevice
, Offset
, &Lba
, &LOffset
);
709 if ((UINTN
) (*NumBytes
) > RemainingLength
) {
710 *NumBytes
= (UINTN
) RemainingLength
;
711 return EFI_INVALID_PARAMETER
;
716 Status
= Fvb
->GetAttributes (
720 if (EFI_ERROR (Status
)) {
724 if ((FvbAttributes
& EFI_FV2_WRITE_STATUS
) == 0) {
725 return EFI_ACCESS_DENIED
;
728 RemainingLength
= *NumBytes
;
729 WriteLength
= RemainingLength
;
733 Status
= Fvb
->Write (
740 if (!EFI_ERROR (Status
)) {
744 if (Status
== EFI_BAD_BUFFER_SIZE
) {
747 TmpBuffer
+= WriteLength
;
748 RemainingLength
-= WriteLength
;
749 WriteLength
= (UINTN
) RemainingLength
;
762 Create a new FFS file into Firmware Volume device.
764 @param FvDevice Cached Firmware Volume.
765 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
766 a File Header which is in init state).
767 @param BufferSize The size of FfsFileBuffer.
768 @param ActualFileSize The actual file length, it may not be multiples of 8.
769 @param FileName The FFS File Name.
770 @param FileType The FFS File Type.
771 @param FileAttributes The Attributes of the FFS File to be created.
773 @retval EFI_SUCCESS FFS fle is added into FV.
774 @retval EFI_INVALID_PARAMETER File type is not valid.
775 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
776 @retval EFI_NOT_FOUND FV has no enough space for the added file.
781 IN FV_DEVICE
*FvDevice
,
782 IN UINT8
*FfsFileBuffer
,
784 IN UINTN ActualFileSize
,
785 IN EFI_GUID
*FileName
,
786 IN EFI_FV_FILETYPE FileType
,
787 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
791 EFI_FFS_FILE_HEADER
*FileHeader
;
792 EFI_PHYSICAL_ADDRESS BufferPtr
;
794 UINTN NumBytesWritten
;
796 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
797 UINTN RequiredAlignment
;
799 FFS_FILE_LIST_ENTRY
*PadFileEntry
;
800 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute
;
801 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
805 // File Type: 0x0E~0xE0 are reserved
807 if ((FileType
> EFI_FV_FILETYPE_SMM_CORE
) && (FileType
< 0xE0)) {
808 return EFI_INVALID_PARAMETER
;
812 // First find a free space that can hold this image.
813 // Check alignment, FFS at least must be aligned at 8-byte boundary
815 RequiredAlignment
= GetRequiredAlignment (FileAttributes
);
817 Status
= FvLocateFreeSpaceEntry (
824 if (EFI_ERROR (Status
)) {
826 // Maybe we need to find a PAD file that can hold this image
828 Status
= FvCreateNewFileInsidePadFile (
841 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
844 // If we need a leading PAD File, create it first.
846 if (PadFileSize
!= 0) {
847 Status
= FvCreatePadFileInFreeSpace (
850 PadFileSize
- sizeof (EFI_FFS_FILE_HEADER
),
853 if (EFI_ERROR (Status
)) {
858 // Maybe we create a pad file, so re-get the free space starting address
861 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
864 // File creation step 1: Allocate File Header,
865 // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
866 // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
868 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileBuffer
;
869 if (ActualFileSize
> 0x00FFFFFF) {
870 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
872 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
874 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, FileHeader
);
876 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
877 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
879 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
886 if (EFI_ERROR (Status
)) {
890 // update header 2 cache
893 (UINT8
*) (UINTN
) BufferPtr
,
899 // update Free Space Entry, now need to substract the file header length
901 FreeSpaceEntry
->StartingAddress
+= HeaderSize
;
902 FreeSpaceEntry
->Length
-= HeaderSize
;
904 CopyGuid (&FileHeader
->Name
, FileName
);
905 FileHeader
->Type
= FileType
;
908 // Convert FvFileAttribute to FfsFileAttributes
910 FvFileAttrib2FfsFileAttrib (FileAttributes
, &TmpFileAttribute
);
912 FileHeader
->Attributes
= TmpFileAttribute
;
915 // File size is including the FFS File Header.
917 if (ActualFileSize
> 0x00FFFFFF) {
918 ((EFI_FFS_FILE_HEADER2
*) FileHeader
)->ExtendedSize
= (UINT32
) ActualFileSize
;
919 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
920 FileHeader
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
922 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
923 *(UINT32
*) FileHeader
->Size
|= ActualFileSize
;
926 SetHeaderChecksum (FileHeader
);
928 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
930 NumBytesWritten
= HeaderSize
;
937 if (EFI_ERROR (Status
)) {
941 // update header 2 cache
944 (UINT8
*) (UINTN
) BufferPtr
,
952 // File creation step 2:
953 // MARK EFI_FILE_HEADER_VALID bit to TRUE,
954 // Write IntegrityCheck.File, File Data
956 SetFileState (EFI_FILE_HEADER_VALID
, FileHeader
);
958 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
959 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
961 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
968 if (EFI_ERROR (Status
)) {
972 // update header 2 cache
975 (UINT8
*) (UINTN
) BufferPtr
,
981 // update Free Space Entry, now need to substract the file data length
983 FreeSpaceEntry
->StartingAddress
+= (BufferSize
- HeaderSize
);
984 FreeSpaceEntry
->Length
-= (BufferSize
- HeaderSize
);
987 // Calculate File Checksum
989 SetFileChecksum (FileHeader
, ActualFileSize
);
991 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
993 NumBytesWritten
= BufferSize
;
1000 if (EFI_ERROR (Status
)) {
1004 // each time write block successfully, write also to cache
1007 (UINT8
*) (UINTN
) BufferPtr
,
1013 // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
1015 SetFileState (EFI_FILE_DATA_VALID
, FileHeader
);
1017 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
1018 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1020 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1027 if (EFI_ERROR (Status
)) {
1031 // update header 2 cache
1034 (UINT8
*) (UINTN
) BufferPtr
,
1040 // If successfully, insert an FfsFileEntry at the end of ffs file list
1043 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
1044 ASSERT (FfsFileEntry
!= NULL
);
1045 FfsFileEntry
->FfsHeader
= (UINT8
*) (UINTN
) BufferPtr
;
1046 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
1049 // Set cache file to this file
1051 FvDevice
->CurrentFfsFile
= FfsFileEntry
;
1057 Update a File, so after successful update, there are 2 files existing
1058 in FV, one is marked for deleted, and another one is valid.
1060 @param FvDevice Cached Firmware Volume.
1061 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
1062 a File Header which is in init state).
1063 @param BufferSize The size of FfsFileBuffer.
1064 @param ActualFileSize The actual file length, it may not be multiples of 8.
1065 @param FileName The FFS File Name.
1066 @param NewFileType The FFS File Type.
1067 @param NewFileAttributes The Attributes of the FFS File to be created.
1069 @retval EFI_SUCCESS FFS fle is updated into FV.
1070 @retval EFI_INVALID_PARAMETER File type is not valid.
1071 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
1072 @retval EFI_NOT_FOUND FV has no enough space for the added file.
1073 FFS with same file name is not found in FV.
1078 IN FV_DEVICE
*FvDevice
,
1079 IN UINT8
*FfsFileBuffer
,
1080 IN UINTN BufferSize
,
1081 IN UINTN ActualFileSize
,
1082 IN EFI_GUID
*FileName
,
1083 IN EFI_FV_FILETYPE NewFileType
,
1084 IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
1088 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1089 UINTN NumBytesWritten
;
1090 EFI_FV_FILETYPE OldFileType
;
1091 EFI_FV_FILE_ATTRIBUTES OldFileAttributes
;
1093 EFI_FFS_FILE_HEADER
*OldFileHeader
;
1095 UINTN OldStateOffset
;
1096 FFS_FILE_LIST_ENTRY
*OldFfsFileEntry
;
1098 EFI_GUID FileNameGuid
;
1103 // Step 1, find old file,
1104 // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
1108 // Check if the file was read last time.
1110 OldFileHeader
= NULL
;
1111 OldFfsFileEntry
= FvDevice
->CurrentFfsFile
;
1113 if (OldFfsFileEntry
!= NULL
) {
1114 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1117 if ((OldFfsFileEntry
== NULL
) || (!CompareGuid (&OldFileHeader
->Name
, FileName
))) {
1121 Status
= Fv
->GetNextFile (
1129 if (EFI_ERROR (Status
)) {
1132 } while (!CompareGuid (&FileNameGuid
, FileName
));
1135 // Get FfsFileEntry from the search key
1137 OldFfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1140 // Double check file state before being ready to be removed
1142 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1145 // Mark the cache file to invalid
1147 FvDevice
->CurrentFfsFile
= NULL
;
1150 // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
1152 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1154 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1155 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1157 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1162 &OldFileHeader
->State
1164 if (EFI_ERROR (Status
)) {
1166 // if failed, write the bit back in the cache, its XOR operation.
1168 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1174 // Step 2, Create New Files
1176 Status
= FvCreateNewFile (
1185 if (EFI_ERROR (Status
)) {
1190 // If successfully, remove this file entry,
1191 // although delete file may fail.
1193 (OldFfsFileEntry
->Link
.BackLink
)->ForwardLink
= OldFfsFileEntry
->Link
.ForwardLink
;
1194 (OldFfsFileEntry
->Link
.ForwardLink
)->BackLink
= OldFfsFileEntry
->Link
.BackLink
;
1195 FreePool (OldFfsFileEntry
);
1198 // Step 3: Delete old files,
1199 // by marking EFI_FILE_DELETED to TRUE
1201 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1203 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1204 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1206 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1211 &OldFileHeader
->State
1213 if (EFI_ERROR (Status
)) {
1215 // if failed, write the bit back in the cache, its XOR operation.
1217 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1226 Deleted a given file from FV device.
1228 @param FvDevice Cached Firmware Volume.
1229 @param NameGuid The FFS File Name.
1231 @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
1232 @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
1237 IN FV_DEVICE
*FvDevice
,
1238 IN EFI_GUID
*NameGuid
1243 EFI_GUID FileNameGuid
;
1244 EFI_FV_FILETYPE FileType
;
1245 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1247 EFI_FFS_FILE_HEADER
*FileHeader
;
1248 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
1249 EFI_FFS_FILE_STATE FileState
;
1250 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1253 UINTN NumBytesWritten
;
1258 // Check if the file was read last time.
1261 FfsFileEntry
= FvDevice
->CurrentFfsFile
;
1263 if (FfsFileEntry
!= NULL
) {
1264 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1267 if ((FfsFileEntry
== NULL
) || (!CompareGuid (&FileHeader
->Name
, NameGuid
))) {
1269 // Next search for the file using GetNextFile
1274 Status
= Fv
->GetNextFile (
1282 if (EFI_ERROR (Status
)) {
1285 } while (!CompareGuid (&FileNameGuid
, NameGuid
));
1288 // Get FfsFileEntry from the search key
1290 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1293 // Double check file state before being ready to be removed
1295 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1298 // Mark the cache file to NULL
1300 FvDevice
->CurrentFfsFile
= NULL
;
1303 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
1305 if (FileState
== EFI_FILE_HEADER_INVALID
) {
1306 return EFI_NOT_FOUND
;
1309 if (FileState
== EFI_FILE_DELETED
) {
1310 return EFI_NOT_FOUND
;
1313 // Delete File: Mark EFI_FILE_DELETED to TRUE
1315 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1317 Offset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
- FvDevice
->CachedFv
);
1318 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1320 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1327 if (EFI_ERROR (Status
)) {
1329 // if failed, write the bit back in the cache, its XOR operation.
1331 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1336 // If successfully, remove this file entry
1338 FvDevice
->CurrentFfsFile
= NULL
;
1340 (FfsFileEntry
->Link
.BackLink
)->ForwardLink
= FfsFileEntry
->Link
.ForwardLink
;
1341 (FfsFileEntry
->Link
.ForwardLink
)->BackLink
= FfsFileEntry
->Link
.BackLink
;
1342 FreePool (FfsFileEntry
);
1348 Writes one or more files to the firmware volume.
1350 @param This Indicates the calling context.
1351 @param NumberOfFiles Number of files.
1352 @param WritePolicy WritePolicy indicates the level of reliability
1353 for the write in the event of a power failure or
1354 other system failure during the write operation.
1355 @param FileData FileData is an pointer to an array of
1356 EFI_FV_WRITE_DATA. Each element of array
1357 FileData represents a file to be written.
1359 @retval EFI_SUCCESS Files successfully written to firmware volume
1360 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
1361 @retval EFI_DEVICE_ERROR Device error.
1362 @retval EFI_WRITE_PROTECTED Write protected.
1363 @retval EFI_NOT_FOUND Not found.
1364 @retval EFI_INVALID_PARAMETER Invalid parameter.
1365 @retval EFI_UNSUPPORTED This function not supported.
1371 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL
*This
,
1372 IN UINT32 NumberOfFiles
,
1373 IN EFI_FV_WRITE_POLICY WritePolicy
,
1374 IN EFI_FV_WRITE_FILE_DATA
*FileData
1383 UINT8 ErasePolarity
;
1384 FV_DEVICE
*FvDevice
;
1385 EFI_FV_FILETYPE FileType
;
1386 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1388 BOOLEAN CreateNewFile
[MAX_FILES
];
1390 EFI_FV_ATTRIBUTES FvAttributes
;
1391 UINT32 AuthenticationStatus
;
1394 if (NumberOfFiles
> MAX_FILES
) {
1395 return EFI_UNSUPPORTED
;
1398 Status
= EFI_SUCCESS
;
1400 SetMem (CreateNewFile
, NumberOfFiles
, TRUE
);
1402 FvDevice
= FV_DEVICE_FROM_THIS (This
);
1405 // First check the volume attributes.
1407 Status
= This
->GetVolumeAttributes (
1411 if (EFI_ERROR (Status
)) {
1415 // Can we have write right?
1417 if ((FvAttributes
& EFI_FV2_WRITE_STATUS
) == 0) {
1418 return EFI_WRITE_PROTECTED
;
1421 ErasePolarity
= FvDevice
->ErasePolarity
;
1424 // Loop for all files
1427 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1429 if ((FileData
[Index1
].BufferSize
+ sizeof (EFI_FFS_FILE_HEADER
) > 0x00FFFFFF) && !FvDevice
->IsFfs3Fv
) {
1431 // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
1433 DEBUG ((EFI_D_ERROR
, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
1434 return EFI_INVALID_PARAMETER
;
1437 if (FileData
[Index1
].BufferSize
== 0) {
1439 // Here we will delete this file
1441 Status
= This
->ReadFile (
1443 FileData
[Index1
].NameGuid
,
1448 &AuthenticationStatus
1450 if (!EFI_ERROR (Status
)) {
1457 if (FileData
[Index1
].Type
== EFI_FV_FILETYPE_FFS_PAD
) {
1459 // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
1460 // "Standard firmware file system services will not return the handle of any pad files,
1461 // nor will they permit explicit creation of such files."
1463 return EFI_INVALID_PARAMETER
;
1467 if ((NumDelete
!= NumberOfFiles
) && (NumDelete
!= 0)) {
1469 // A delete was request with a multiple file write
1471 return EFI_INVALID_PARAMETER
;
1474 if (NumDelete
== NumberOfFiles
) {
1475 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1479 Status
= FvDeleteFile (FvDevice
, FileData
[Index1
].NameGuid
);
1480 if (EFI_ERROR (Status
)) {
1488 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1489 Status
= This
->ReadFile (
1491 FileData
[Index1
].NameGuid
,
1496 &AuthenticationStatus
1498 if (!EFI_ERROR (Status
)) {
1499 CreateNewFile
[Index1
] = FALSE
;
1500 } else if (Status
== EFI_NOT_FOUND
) {
1501 CreateNewFile
[Index1
] = TRUE
;
1506 // Checking alignment
1508 if ((FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
) != 0) {
1509 UINT8 FFSAlignmentValue
;
1510 UINT8 FvAlignmentValue
;
1512 FFSAlignmentValue
= (UINT8
) (FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
1513 FvAlignmentValue
= (UINT8
) (((UINT32
) (FvAttributes
& EFI_FV2_ALIGNMENT
)) >> 16);
1515 if (FFSAlignmentValue
> FvAlignmentValue
) {
1516 return EFI_INVALID_PARAMETER
;
1521 if ((WritePolicy
!= EFI_FV_RELIABLE_WRITE
) && (WritePolicy
!= EFI_FV_UNRELIABLE_WRITE
)) {
1522 return EFI_INVALID_PARAMETER
;
1525 // Checking the reliable write is supported by FV
1528 if ((WritePolicy
== EFI_FV_RELIABLE_WRITE
) && (NumberOfFiles
> 1)) {
1530 // Only for multiple files, reliable write is meaningful
1532 Status
= FvCreateMultipleFiles (
1542 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1544 // Making Buffersize QWORD boundary, and add file tail.
1546 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
1547 ActualSize
= FileData
[Index1
].BufferSize
+ HeaderSize
;
1548 if (ActualSize
> 0x00FFFFFF) {
1549 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
1550 ActualSize
= FileData
[Index1
].BufferSize
+ HeaderSize
;
1552 BufferSize
= ActualSize
;
1554 while ((BufferSize
& 0x07) != 0) {
1558 FileBuffer
= AllocateZeroPool (BufferSize
);
1559 if (FileBuffer
== NULL
) {
1563 // Copy File Data into FileBuffer
1566 FileBuffer
+ HeaderSize
,
1567 FileData
[Index1
].Buffer
,
1568 FileData
[Index1
].BufferSize
1571 if (ErasePolarity
== 1) {
1573 // Fill the file header and padding byte with Erase Byte
1575 for (Index2
= 0; Index2
< HeaderSize
; Index2
++) {
1576 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1579 for (Index2
= ActualSize
; Index2
< BufferSize
; Index2
++) {
1580 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1584 if (CreateNewFile
[Index1
]) {
1585 Status
= FvCreateNewFile (
1590 FileData
[Index1
].NameGuid
,
1591 FileData
[Index1
].Type
,
1592 FileData
[Index1
].FileAttributes
1595 Status
= FvUpdateFile (
1600 FileData
[Index1
].NameGuid
,
1601 FileData
[Index1
].Type
,
1602 FileData
[Index1
].FileAttributes
1606 FreePool (FileBuffer
);
1608 if (EFI_ERROR (Status
)) {