2 Implements write firmware file.
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "FwVolDriver.h"
20 Caculate the checksum for the FFS header.
22 @param FfsHeader FFS File Header which needs to caculate the checksum
27 IN EFI_FFS_FILE_HEADER
*FfsHeader
30 EFI_FFS_FILE_STATE State
;
35 // The state and the File checksum are not included
37 State
= FfsHeader
->State
;
40 FileChecksum
= FfsHeader
->IntegrityCheck
.Checksum
.File
;
41 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
43 FfsHeader
->IntegrityCheck
.Checksum
.Header
= 0;
45 HeaderChecksum
= CalculateSum8 (
47 sizeof (EFI_FFS_FILE_HEADER
)
50 FfsHeader
->IntegrityCheck
.Checksum
.Header
= (UINT8
) (~HeaderChecksum
+ 1);
52 FfsHeader
->State
= State
;
53 FfsHeader
->IntegrityCheck
.Checksum
.File
= FileChecksum
;
59 Caculate the checksum for the FFS File.
61 @param FfsHeader FFS File Header which needs to caculate the checksum
62 @param ActualFileSize The whole Ffs File Length.
67 IN EFI_FFS_FILE_HEADER
*FfsHeader
,
68 IN UINTN ActualFileSize
71 EFI_FFS_FILE_STATE State
;
74 if ((FfsHeader
->Attributes
& FFS_ATTRIB_CHECKSUM
) != 0) {
76 // The file state is not included
78 State
= FfsHeader
->State
;
81 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
86 FileChecksum
= CalculateSum8 (
87 (UINT8
*)(FfsHeader
+ 1),
88 ActualFileSize
- sizeof (EFI_FFS_FILE_HEADER
)
91 FfsHeader
->IntegrityCheck
.Checksum
.File
= (UINT8
) (~FileChecksum
+ 1);
93 FfsHeader
->State
= State
;
97 FfsHeader
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
105 Get the alignment value from File Attributes.
107 @param FfsAttributes FFS attribute
109 @return Alignment value.
113 GetRequiredAlignment (
114 IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
117 UINTN AlignmentValue
;
119 AlignmentValue
= FfsAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
;
121 if (AlignmentValue
<= 3) {
125 if (AlignmentValue
> 16) {
127 // Anyway, we won't reach this code
132 return (UINTN
)1 << AlignmentValue
;
137 Caculate the leading Pad file size to meet the alignment requirement.
139 @param FvDevice Cached Firmware Volume.
140 @param StartAddress The starting address to write the FFS File.
141 @param RequiredAlignment FFS File Data alignment requirement.
143 @return The required Pad File Size.
147 CaculatePadFileSize (
148 IN FV_DEVICE
*FvDevice
,
149 IN EFI_PHYSICAL_ADDRESS StartAddress
,
150 IN UINTN RequiredAlignment
157 DataStartPos
= (UINTN
) StartAddress
+ sizeof (EFI_FFS_FILE_HEADER
);
158 RelativePos
= DataStartPos
- (UINTN
) FvDevice
->CachedFv
;
162 while ((RelativePos
& (RequiredAlignment
- 1)) != 0) {
167 // If padsize is 0, no pad file needed;
168 // If padsize is great than 24, then pad file can be created
170 if ((PadSize
== 0) || (PadSize
>= sizeof (EFI_FFS_FILE_HEADER
))) {
175 // Perhaps following method can save space
177 RelativePos
= DataStartPos
- (UINTN
) FvDevice
->CachedFv
+ sizeof (EFI_FFS_FILE_HEADER
);
178 PadSize
= sizeof (EFI_FFS_FILE_HEADER
);
180 while ((RelativePos
& (RequiredAlignment
- 1)) != 0) {
189 Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
191 @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
192 @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
196 FvFileAttrib2FfsFileAttrib (
197 IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib
,
198 OUT UINT8
*FfsFileAttrib
201 UINT8 FvFileAlignment
;
202 UINT8 FfsFileAlignment
;
204 FvFileAlignment
= (UINT8
) (FvFileAttrib
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
205 FfsFileAlignment
= 0;
207 switch (FvFileAlignment
) {
224 FfsFileAlignment
= 0;
239 FfsFileAlignment
= 1;
250 FfsFileAlignment
= 2;
254 FfsFileAlignment
= 3;
265 FfsFileAlignment
= 4;
280 FfsFileAlignment
= 5;
284 FfsFileAlignment
= 6;
288 FfsFileAlignment
= 7;
292 *FfsFileAttrib
= (UINT8
) (FfsFileAlignment
<< 3);
298 Locate a free space entry that can hold this FFS file.
300 @param FvDevice Cached Firmware Volume.
301 @param Size The FFS file size.
302 @param RequiredAlignment FFS File Data alignment requirement.
303 @param PadSize Pointer to the size of leading Pad File.
304 @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
306 @retval EFI_SUCCESS The free space entry is found.
307 @retval EFI_NOT_FOUND The free space entry can't be found.
311 FvLocateFreeSpaceEntry (
312 IN FV_DEVICE
*FvDevice
,
314 IN UINTN RequiredAlignment
,
316 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
319 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
323 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
324 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
327 // Loop the free space entry list to find one that can hold the
328 // required the file size
330 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
331 PadFileSize
= CaculatePadFileSize (
333 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceListEntry
->StartingAddress
,
336 if (FreeSpaceListEntry
->Length
>= Size
+ PadFileSize
) {
337 *FreeSpaceEntry
= FreeSpaceListEntry
;
338 *PadSize
= PadFileSize
;
342 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
345 return EFI_NOT_FOUND
;
350 Locate a free space that can hold this file.
352 @param FvDevice Cached Firmware Volume.
353 @param Size On input, it is the required size.
354 On output, it is the actual size of free space.
355 @param RequiredAlignment FFS File Data alignment requirement.
356 @param PadSize Pointer to the size of leading Pad File.
357 @param StartingAddress The starting address of the Free Space Entry
358 that meets the requirement.
360 @retval EFI_SUCCESS The free space is found.
361 @retval EFI_NOT_FOUND The free space can't be found.
366 IN FV_DEVICE
*FvDevice
,
368 IN UINTN RequiredAlignment
,
370 OUT EFI_PHYSICAL_ADDRESS
*StartingAddress
374 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
377 // First find the free space entry
379 Status
= FvLocateFreeSpaceEntry (
387 if (EFI_ERROR (Status
)) {
391 *Size
= FreeSpaceEntry
->Length
;
392 *StartingAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
398 Locate Pad File for writing, this is got from FV Cache.
400 @param FvDevice Cached Firmware Volume.
401 @param Size The required FFS file size.
402 @param RequiredAlignment FFS File Data alignment requirement.
403 @param PadSize Pointer to the size of leading Pad File.
404 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
406 @retval EFI_SUCCESS The required pad file is found.
407 @retval EFI_NOT_FOUND The required pad file can't be found.
412 IN FV_DEVICE
*FvDevice
,
414 IN UINTN RequiredAlignment
,
416 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
419 FFS_FILE_LIST_ENTRY
*FileEntry
;
420 EFI_FFS_FILE_STATE FileState
;
421 EFI_FFS_FILE_HEADER
*FileHeader
;
426 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
429 // travel through the whole file list to get the pad file entry
431 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
433 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
434 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
436 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
438 // we find one valid pad file, check its free area length
440 FileLength
= *(UINT32
*) FileHeader
->Size
& 0x00FFFFFF;
441 PadAreaLength
= FileLength
- sizeof (EFI_FFS_FILE_HEADER
);
443 PadFileSize
= CaculatePadFileSize (
445 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ sizeof (EFI_FFS_FILE_HEADER
),
448 if (PadAreaLength
>= (Size
+ PadFileSize
)) {
449 *PadSize
= PadFileSize
;
450 *PadFileEntry
= FileEntry
;
455 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
458 return EFI_NOT_FOUND
;
462 Locate a suitable pad file for multiple file writing.
464 @param FvDevice Cached Firmware Volume.
465 @param NumOfFiles The number of Files that needed updating
466 @param BufferSize The array of each file size.
467 @param RequiredAlignment The array of of FFS File Data alignment requirement.
468 @param PadSize The array of size of each leading Pad File.
469 @param TotalSizeNeeded The totalsize that can hold these files.
470 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
472 @retval EFI_SUCCESS The required pad file is found.
473 @retval EFI_NOT_FOUND The required pad file can't be found.
477 FvSearchSuitablePadFile (
478 IN FV_DEVICE
*FvDevice
,
480 IN UINTN
*BufferSize
,
481 IN UINTN
*RequiredAlignment
,
483 OUT UINTN
*TotalSizeNeeded
,
484 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
487 FFS_FILE_LIST_ENTRY
*FileEntry
;
488 EFI_FFS_FILE_STATE FileState
;
489 EFI_FFS_FILE_HEADER
*FileHeader
;
495 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
498 // travel through the whole file list to get the pad file entry
500 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
502 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
503 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
505 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
507 // we find one valid pad file, check its length
509 FileLength
= *(UINT32
*) FileHeader
->Size
& 0x00FFFFFF;
510 PadAreaLength
= FileLength
- sizeof (EFI_FFS_FILE_HEADER
);
513 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
514 PadSize
[Index
] = CaculatePadFileSize (
516 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ sizeof (EFI_FFS_FILE_HEADER
) + TotalSize
,
517 RequiredAlignment
[Index
]
519 TotalSize
+= PadSize
[Index
];
520 TotalSize
+= BufferSize
[Index
];
522 if (TotalSize
> PadAreaLength
) {
527 if (PadAreaLength
>= TotalSize
) {
528 *PadFileEntry
= FileEntry
;
529 *TotalSizeNeeded
= TotalSize
;
534 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
537 return EFI_NOT_FOUND
;
541 Locate a Free Space entry which can hold these files, including
542 meeting the alignment requirements.
544 @param FvDevice Cached Firmware Volume.
545 @param NumOfFiles The number of Files that needed updating
546 @param BufferSize The array of each file size.
547 @param RequiredAlignment The array of of FFS File Data alignment requirement.
548 @param PadSize The array of size of each leading Pad File.
549 @param TotalSizeNeeded The got total size that can hold these files.
550 @param FreeSpaceEntry The Free Space Entry that can hold these files.
552 @retval EFI_SUCCESS The free space entry is found.
553 @retval EFI_NOT_FOUND The free space entry can't be found.
557 FvSearchSuitableFreeSpace (
558 IN FV_DEVICE
*FvDevice
,
560 IN UINTN
*BufferSize
,
561 IN UINTN
*RequiredAlignment
,
563 OUT UINTN
*TotalSizeNeeded
,
564 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
567 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
573 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
575 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
577 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
579 StartAddr
= FreeSpaceListEntry
->StartingAddress
;
582 // Caculate the totalsize we need
584 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
586 // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
587 // have had its leading pad file.
589 PadSize
[Index
] = CaculatePadFileSize (
591 (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartAddr
+ TotalSize
,
592 RequiredAlignment
[Index
]
595 TotalSize
+= PadSize
[Index
];
596 TotalSize
+= BufferSize
[Index
];
598 if (TotalSize
> FreeSpaceListEntry
->Length
) {
603 if (FreeSpaceListEntry
->Length
>= TotalSize
) {
604 *FreeSpaceEntry
= FreeSpaceListEntry
;
605 *TotalSizeNeeded
= TotalSize
;
609 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
612 return EFI_NOT_FOUND
;
616 Calculate the length of the remaining space in FV.
618 @param FvDevice Cached Firmware Volume
619 @param Offset Current offset to FV base address.
620 @param Lba LBA number for the current offset.
621 @param LOffset Offset in block for the current offset.
623 @return the length of remaining space.
627 CalculateRemainingLength (
628 IN FV_DEVICE
*FvDevice
,
640 Link
= FvDevice
->LbaHeader
.ForwardLink
;
641 LbaEntry
= (LBA_ENTRY
*) Link
;
643 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
644 if (Count
> Offset
) {
648 Count
+= LbaEntry
->BlockLength
;
650 Link
= LbaEntry
->Link
.ForwardLink
;
651 LbaEntry
= (LBA_ENTRY
*) Link
;
654 if (Count
<= Offset
) {
658 Link
= LbaEntry
->Link
.BackLink
;
659 LbaEntry
= (LBA_ENTRY
*) Link
;
662 *LOffset
= (UINTN
) (LbaEntry
->BlockLength
- (Count
- Offset
));
665 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
667 Count
+= LbaEntry
->BlockLength
;
669 Link
= LbaEntry
->Link
.ForwardLink
;
670 LbaEntry
= (LBA_ENTRY
*) Link
;
679 Writes data beginning at Lba:Offset from FV. The write terminates either
680 when *NumBytes of data have been written, or when the firmware end is
681 reached. *NumBytes is updated to reflect the actual number of bytes
684 @param FvDevice Cached Firmware Volume
685 @param Offset Offset in the block at which to begin write
686 @param NumBytes At input, indicates the requested write size.
687 At output, indicates the actual number of bytes written.
688 @param Buffer Buffer containing source data for the write.
690 @retval EFI_SUCCESS Data is successfully written into FV.
691 @return error Data is failed written.
696 IN FV_DEVICE
*FvDevice
,
698 IN OUT UINTN
*NumBytes
,
703 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
706 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
707 UINTN RemainingLength
;
712 RemainingLength
= CalculateRemainingLength (FvDevice
, Offset
, &Lba
, &LOffset
);
713 if ((UINTN
) (*NumBytes
) > RemainingLength
) {
714 *NumBytes
= (UINTN
) RemainingLength
;
715 return EFI_INVALID_PARAMETER
;
720 Status
= Fvb
->GetAttributes (
724 if (EFI_ERROR (Status
)) {
728 if ((FvbAttributes
& EFI_FV2_WRITE_STATUS
) != 0) {
729 return EFI_ACCESS_DENIED
;
732 RemainingLength
= *NumBytes
;
733 WriteLength
= RemainingLength
;
737 Status
= Fvb
->Write (
744 if (!EFI_ERROR (Status
)) {
748 if (Status
== EFI_BAD_BUFFER_SIZE
) {
751 TmpBuffer
+= WriteLength
;
752 RemainingLength
-= WriteLength
;
753 WriteLength
= (UINTN
) RemainingLength
;
766 Create a new FFS file into Firmware Volume device.
768 @param FvDevice Cached Firmware Volume.
769 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
770 a File Header which is in init state).
771 @param BufferSize The size of FfsFileBuffer.
772 @param ActualFileSize The actual file length, it may not be multiples of 8.
773 @param FileName The FFS File Name.
774 @param FileType The FFS File Type.
775 @param FileAttributes The Attributes of the FFS File to be created.
777 @retval EFI_SUCCESS FFS fle is added into FV.
778 @retval EFI_INVALID_PARAMETER File type is not valid.
779 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
780 @retval EFI_NOT_FOUND FV has no enough space for the added file.
785 IN FV_DEVICE
*FvDevice
,
786 IN UINT8
*FfsFileBuffer
,
788 IN UINTN ActualFileSize
,
789 IN EFI_GUID
*FileName
,
790 IN EFI_FV_FILETYPE FileType
,
791 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
795 EFI_FFS_FILE_HEADER
*FileHeader
;
796 EFI_PHYSICAL_ADDRESS BufferPtr
;
798 UINTN NumBytesWritten
;
800 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
801 UINTN RequiredAlignment
;
803 FFS_FILE_LIST_ENTRY
*PadFileEntry
;
804 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute
;
805 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
808 // File Type: 0x0E~0xE0 are reserved
810 if ((FileType
> EFI_FV_FILETYPE_SMM_CORE
) && (FileType
< 0xE0)) {
811 return EFI_INVALID_PARAMETER
;
815 // First find a free space that can hold this image.
816 // Check alignment, FFS at least must be aligned at 8-byte boundry
818 RequiredAlignment
= GetRequiredAlignment (FileAttributes
);
820 Status
= FvLocateFreeSpaceEntry (
827 if (EFI_ERROR (Status
)) {
829 // Maybe we need to find a PAD file that can hold this image
831 Status
= FvCreateNewFileInsidePadFile (
844 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
847 // If we need a leading PAD File, create it first.
849 if (PadFileSize
!= 0) {
850 Status
= FvCreatePadFileInFreeSpace (
853 PadFileSize
- sizeof (EFI_FFS_FILE_HEADER
),
856 if (EFI_ERROR (Status
)) {
861 // Maybe we create a pad file, so re-get the free space starting address
864 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
867 // File creation step 1: Allocate File Header,
868 // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
869 // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
871 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileBuffer
;
872 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, FileHeader
);
874 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
875 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
877 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
884 if (EFI_ERROR (Status
)) {
888 // update header 2 cache
891 (UINT8
*) (UINTN
) BufferPtr
,
893 sizeof (EFI_FFS_FILE_HEADER
)
897 // update Free Space Entry, now need to substract the EFI_FFS_FILE_HEADER
899 FreeSpaceEntry
->StartingAddress
+= sizeof (EFI_FFS_FILE_HEADER
);
900 FreeSpaceEntry
->Length
-= sizeof (EFI_FFS_FILE_HEADER
);
902 CopyGuid (&FileHeader
->Name
, FileName
);
903 FileHeader
->Type
= FileType
;
906 // Convert FvFileAttribute to FfsFileAttributes
908 FvFileAttrib2FfsFileAttrib (FileAttributes
, &TmpFileAttribute
);
910 FileHeader
->Attributes
= TmpFileAttribute
;
913 // File size is including the FFS File Header.
915 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
916 *(UINT32
*) FileHeader
->Size
|= ActualFileSize
;
918 SetHeaderChecksum (FileHeader
);
920 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
922 NumBytesWritten
= sizeof (EFI_FFS_FILE_HEADER
);
929 if (EFI_ERROR (Status
)) {
933 // update header 2 cache
936 (UINT8
*) (UINTN
) BufferPtr
,
938 sizeof (EFI_FFS_FILE_HEADER
)
944 // File creation step 2:
945 // MARK EFI_FILE_HEADER_VALID bit to TRUE,
946 // Write IntegrityCheck.File, File Data
948 SetFileState (EFI_FILE_HEADER_VALID
, FileHeader
);
950 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
951 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
953 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
960 if (EFI_ERROR (Status
)) {
964 // update header 2 cache
967 (UINT8
*) (UINTN
) BufferPtr
,
969 sizeof (EFI_FFS_FILE_HEADER
)
973 // update Free Space Entry, now need to substract the file data length
975 FreeSpaceEntry
->StartingAddress
+= (BufferSize
- sizeof (EFI_FFS_FILE_HEADER
));
976 FreeSpaceEntry
->Length
-= (BufferSize
- sizeof (EFI_FFS_FILE_HEADER
));
979 // Caculate File Checksum
981 SetFileChecksum (FileHeader
, ActualFileSize
);
983 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
985 NumBytesWritten
= BufferSize
;
992 if (EFI_ERROR (Status
)) {
996 // each time write block successfully, write also to cache
999 (UINT8
*) (UINTN
) BufferPtr
,
1005 // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
1007 SetFileState (EFI_FILE_DATA_VALID
, FileHeader
);
1009 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
1010 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1012 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1019 if (EFI_ERROR (Status
)) {
1023 // update header 2 cache
1026 (UINT8
*) (UINTN
) BufferPtr
,
1028 sizeof (EFI_FFS_FILE_HEADER
)
1032 // If successfully, insert an FfsFileEntry at the end of ffs file list
1035 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
1036 ASSERT (FfsFileEntry
!= NULL
);
1037 FfsFileEntry
->FfsHeader
= (UINT8
*) (UINTN
) BufferPtr
;
1038 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
1041 // Set cache file to this file
1043 FvDevice
->CurrentFfsFile
= FfsFileEntry
;
1049 Update a File, so after successful update, there are 2 files existing
1050 in FV, one is marked for deleted, and another one is valid.
1052 @param FvDevice Cached Firmware Volume.
1053 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
1054 a File Header which is in init state).
1055 @param BufferSize The size of FfsFileBuffer.
1056 @param ActualFileSize The actual file length, it may not be multiples of 8.
1057 @param FileName The FFS File Name.
1058 @param NewFileType The FFS File Type.
1059 @param NewFileAttributes The Attributes of the FFS File to be created.
1061 @retval EFI_SUCCESS FFS fle is updated into FV.
1062 @retval EFI_INVALID_PARAMETER File type is not valid.
1063 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
1064 @retval EFI_NOT_FOUND FV has no enough space for the added file.
1065 FFS with same file name is not found in FV.
1070 IN FV_DEVICE
*FvDevice
,
1071 IN UINT8
*FfsFileBuffer
,
1072 IN UINTN BufferSize
,
1073 IN UINTN ActualFileSize
,
1074 IN EFI_GUID
*FileName
,
1075 IN EFI_FV_FILETYPE NewFileType
,
1076 IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
1080 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1081 UINTN NumBytesWritten
;
1082 EFI_FV_FILETYPE OldFileType
;
1083 EFI_FV_FILE_ATTRIBUTES OldFileAttributes
;
1085 EFI_FFS_FILE_HEADER
*OldFileHeader
;
1087 UINTN OldStateOffset
;
1088 FFS_FILE_LIST_ENTRY
*OldFfsFileEntry
;
1090 EFI_GUID FileNameGuid
;
1095 // Step 1, find old file,
1096 // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
1100 // Check if the file was read last time.
1102 OldFileHeader
= NULL
;
1103 OldFfsFileEntry
= FvDevice
->CurrentFfsFile
;
1105 if (OldFfsFileEntry
!= NULL
) {
1106 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1109 if ((OldFfsFileEntry
== NULL
) || (!CompareGuid (&OldFileHeader
->Name
, FileName
))) {
1113 Status
= Fv
->GetNextFile (
1121 if (EFI_ERROR (Status
)) {
1124 } while (!CompareGuid (&FileNameGuid
, FileName
));
1127 // Get FfsFileEntry from the search key
1129 OldFfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1132 // Double check file state before being ready to be removed
1134 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1137 // Mark the cache file to invalid
1139 FvDevice
->CurrentFfsFile
= NULL
;
1142 // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
1144 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1146 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1147 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1149 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1154 &OldFileHeader
->State
1156 if (EFI_ERROR (Status
)) {
1158 // if failed, write the bit back in the cache, its XOR operation.
1160 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1166 // Step 2, Create New Files
1168 Status
= FvCreateNewFile (
1177 if (EFI_ERROR (Status
)) {
1182 // If successfully, remove this file entry,
1183 // although delete file may fail.
1185 (OldFfsFileEntry
->Link
.BackLink
)->ForwardLink
= OldFfsFileEntry
->Link
.ForwardLink
;
1186 (OldFfsFileEntry
->Link
.ForwardLink
)->BackLink
= OldFfsFileEntry
->Link
.BackLink
;
1187 FreePool (OldFfsFileEntry
);
1190 // Step 3: Delete old files,
1191 // by marking EFI_FILE_DELETED to TRUE
1193 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1195 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1196 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1198 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1203 &OldFileHeader
->State
1205 if (EFI_ERROR (Status
)) {
1207 // if failed, write the bit back in the cache, its XOR operation.
1209 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1218 Deleted a given file from FV device.
1220 @param FvDevice Cached Firmware Volume.
1221 @param NameGuid The FFS File Name.
1223 @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
1224 @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
1229 IN FV_DEVICE
*FvDevice
,
1230 IN EFI_GUID
*NameGuid
1235 EFI_GUID FileNameGuid
;
1236 EFI_FV_FILETYPE FileType
;
1237 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1239 EFI_FFS_FILE_HEADER
*FileHeader
;
1240 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
1241 EFI_FFS_FILE_STATE FileState
;
1242 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1245 UINTN NumBytesWritten
;
1250 // Check if the file was read last time.
1253 FfsFileEntry
= FvDevice
->CurrentFfsFile
;
1255 if (FfsFileEntry
!= NULL
) {
1256 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1259 if ((FfsFileEntry
== NULL
) || (!CompareGuid (&FileHeader
->Name
, NameGuid
))) {
1261 // Next search for the file using GetNextFile
1266 Status
= Fv
->GetNextFile (
1274 if (EFI_ERROR (Status
)) {
1277 } while (!CompareGuid (&FileNameGuid
, NameGuid
));
1280 // Get FfsFileEntry from the search key
1282 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1285 // Double check file state before being ready to be removed
1287 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1290 // Mark the cache file to NULL
1292 FvDevice
->CurrentFfsFile
= NULL
;
1295 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
1297 if (FileState
== EFI_FILE_HEADER_INVALID
) {
1298 return EFI_NOT_FOUND
;
1301 if (FileState
== EFI_FILE_DELETED
) {
1302 return EFI_NOT_FOUND
;
1305 // Delete File: Mark EFI_FILE_DELETED to TRUE
1307 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1309 Offset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
- FvDevice
->CachedFv
);
1310 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1312 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1319 if (EFI_ERROR (Status
)) {
1321 // if failed, write the bit back in the cache, its XOR operation.
1323 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1328 // If successfully, remove this file entry
1330 FvDevice
->CurrentFfsFile
= NULL
;
1332 (FfsFileEntry
->Link
.BackLink
)->ForwardLink
= FfsFileEntry
->Link
.ForwardLink
;
1333 (FfsFileEntry
->Link
.ForwardLink
)->BackLink
= FfsFileEntry
->Link
.BackLink
;
1334 FreePool (FfsFileEntry
);
1340 Writes one or more files to the firmware volume.
1342 @param This Indicates the calling context.
1343 @param NumberOfFiles Number of files.
1344 @param WritePolicy WritePolicy indicates the level of reliability
1345 for the write in the event of a power failure or
1346 other system failure during the write operation.
1347 @param FileData FileData is an pointer to an array of
1348 EFI_FV_WRITE_DATA. Each element of array
1349 FileData represents a file to be written.
1351 @retval EFI_SUCCESS Files successfully written to firmware volume
1352 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
1353 @retval EFI_DEVICE_ERROR Device error.
1354 @retval EFI_WRITE_PROTECTED Write protected.
1355 @retval EFI_NOT_FOUND Not found.
1356 @retval EFI_INVALID_PARAMETER Invalid parameter.
1357 @retval EFI_UNSUPPORTED This function not supported.
1363 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL
*This
,
1364 IN UINT32 NumberOfFiles
,
1365 IN EFI_FV_WRITE_POLICY WritePolicy
,
1366 IN EFI_FV_WRITE_FILE_DATA
*FileData
1375 UINT8 ErasePolarity
;
1376 FV_DEVICE
*FvDevice
;
1377 EFI_FV_FILETYPE FileType
;
1378 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1380 BOOLEAN CreateNewFile
[MAX_FILES
];
1382 EFI_FV_ATTRIBUTES FvAttributes
;
1383 UINT32 AuthenticationStatus
;
1385 if (NumberOfFiles
> MAX_FILES
) {
1386 return EFI_UNSUPPORTED
;
1389 Status
= EFI_SUCCESS
;
1391 SetMem (CreateNewFile
, NumberOfFiles
, TRUE
);
1393 FvDevice
= FV_DEVICE_FROM_THIS (This
);
1396 // First check the volume attributes.
1398 Status
= This
->GetVolumeAttributes (
1402 if (EFI_ERROR (Status
)) {
1406 // Can we have write right?
1408 if ((FvAttributes
& EFI_FV2_WRITE_STATUS
) != 0) {
1409 return EFI_WRITE_PROTECTED
;
1412 ErasePolarity
= FvDevice
->ErasePolarity
;
1415 // Loop for all files
1418 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1419 if (FileData
[Index1
].BufferSize
== 0) {
1421 // Here we will delete this file
1423 Status
= This
->ReadFile (
1425 FileData
[Index1
].NameGuid
,
1430 &AuthenticationStatus
1432 if (!EFI_ERROR (Status
)) {
1439 if (FileData
[Index1
].Type
== EFI_FV_FILETYPE_FFS_PAD
) {
1441 // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
1442 // "Standard firmware file system services will not return the handle of any pad files,
1443 // nor will they permit explicit creation of such files."
1445 return EFI_INVALID_PARAMETER
;
1449 if ((NumDelete
!= NumberOfFiles
) && (NumDelete
!= 0)) {
1451 // A delete was request with a multiple file write
1453 return EFI_INVALID_PARAMETER
;
1456 if (NumDelete
== NumberOfFiles
) {
1457 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1461 Status
= FvDeleteFile (FvDevice
, FileData
[Index1
].NameGuid
);
1462 if (EFI_ERROR (Status
)) {
1470 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1471 Status
= This
->ReadFile (
1473 FileData
[Index1
].NameGuid
,
1478 &AuthenticationStatus
1480 if (!EFI_ERROR (Status
)) {
1481 CreateNewFile
[Index1
] = FALSE
;
1482 } else if (Status
== EFI_NOT_FOUND
) {
1483 CreateNewFile
[Index1
] = TRUE
;
1488 // Checking alignment
1490 if ((FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
) != 0) {
1491 UINT8 FFSAlignmentValue
;
1492 UINT8 FvAlignmentValue
;
1494 FFSAlignmentValue
= (UINT8
) (FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
1495 FvAlignmentValue
= (UINT8
) (((UINT32
) (FvAttributes
& EFI_FV2_ALIGNMENT
)) >> 16);
1497 if (FFSAlignmentValue
> FvAlignmentValue
) {
1498 return EFI_INVALID_PARAMETER
;
1503 if ((WritePolicy
!= EFI_FV_RELIABLE_WRITE
) && (WritePolicy
!= EFI_FV_UNRELIABLE_WRITE
)) {
1504 return EFI_INVALID_PARAMETER
;
1507 // Checking the reliable write is supported by FV
1510 if ((WritePolicy
== EFI_FV_RELIABLE_WRITE
) && (NumberOfFiles
> 1)) {
1512 // Only for multiple files, reliable write is meaningful
1514 Status
= FvCreateMultipleFiles (
1524 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1526 // Making Buffersize QWORD boundry, and add file tail.
1528 ActualSize
= FileData
[Index1
].BufferSize
+ sizeof (EFI_FFS_FILE_HEADER
);
1529 BufferSize
= ActualSize
;
1531 while ((BufferSize
& 0x07) != 0) {
1535 FileBuffer
= AllocateZeroPool (BufferSize
);
1536 if (FileBuffer
== NULL
) {
1540 // Copy File Data into FileBuffer
1543 FileBuffer
+ sizeof (EFI_FFS_FILE_HEADER
),
1544 FileData
[Index1
].Buffer
,
1545 FileData
[Index1
].BufferSize
1548 if (ErasePolarity
== 1) {
1550 // Fill the file header and padding byte with Erase Byte
1552 for (Index2
= 0; Index2
< sizeof (EFI_FFS_FILE_HEADER
); Index2
++) {
1553 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1556 for (Index2
= ActualSize
; Index2
< BufferSize
; Index2
++) {
1557 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1561 if (CreateNewFile
[Index1
]) {
1562 Status
= FvCreateNewFile (
1567 FileData
[Index1
].NameGuid
,
1568 FileData
[Index1
].Type
,
1569 FileData
[Index1
].FileAttributes
1572 Status
= FvUpdateFile (
1577 FileData
[Index1
].NameGuid
,
1578 FileData
[Index1
].Type
,
1579 FileData
[Index1
].FileAttributes
1583 FreePool (FileBuffer
);
1585 if (EFI_ERROR (Status
)) {