2 Implements write firmware file.
4 Copyright (c) 2006 - 2018, 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 Calculate the checksum for the FFS header.
22 @param FfsHeader FFS File Header which needs to calculate the checksum
27 IN EFI_FFS_FILE_HEADER
*FfsHeader
30 EFI_FFS_FILE_STATE State
;
34 // The state and the File checksum are not included
36 State
= FfsHeader
->State
;
39 FileChecksum
= FfsHeader
->IntegrityCheck
.Checksum
.File
;
40 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
42 FfsHeader
->IntegrityCheck
.Checksum
.Header
= 0;
44 if (IS_FFS_FILE2 (FfsHeader
)) {
45 FfsHeader
->IntegrityCheck
.Checksum
.Header
= CalculateCheckSum8 (
47 sizeof (EFI_FFS_FILE_HEADER2
)
50 FfsHeader
->IntegrityCheck
.Checksum
.Header
= CalculateCheckSum8 (
52 sizeof (EFI_FFS_FILE_HEADER
)
56 FfsHeader
->State
= State
;
57 FfsHeader
->IntegrityCheck
.Checksum
.File
= FileChecksum
;
63 Calculate the checksum for the FFS File.
65 @param FfsHeader FFS File Header which needs to calculate the checksum
66 @param ActualFileSize The whole Ffs File Length.
71 IN EFI_FFS_FILE_HEADER
*FfsHeader
,
72 IN UINTN ActualFileSize
75 if ((FfsHeader
->Attributes
& FFS_ATTRIB_CHECKSUM
) != 0) {
77 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
79 if (IS_FFS_FILE2 (FfsHeader
)) {
80 FfsHeader
->IntegrityCheck
.Checksum
.File
= CalculateCheckSum8 (
81 (UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER2
),
82 ActualFileSize
- sizeof (EFI_FFS_FILE_HEADER2
)
85 FfsHeader
->IntegrityCheck
.Checksum
.File
= CalculateCheckSum8 (
86 (UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER
),
87 ActualFileSize
- sizeof (EFI_FFS_FILE_HEADER
)
93 FfsHeader
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
101 Get the alignment value from File Attributes.
103 @param FfsAttributes FFS attribute
105 @return Alignment value.
109 GetRequiredAlignment (
110 IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
113 UINTN AlignmentValue
;
115 AlignmentValue
= FfsAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
;
117 if (AlignmentValue
<= 3) {
121 if (AlignmentValue
> 16) {
123 // Anyway, we won't reach this code
128 return (UINTN
)1 << AlignmentValue
;
133 Calculate the leading Pad file size to meet the alignment requirement.
135 @param FvDevice Cached Firmware Volume.
136 @param StartAddress The starting address to write the FFS File.
137 @param BufferSize The FFS File Buffer Size.
138 @param RequiredAlignment FFS File Data alignment requirement.
140 @return The required Pad File Size.
144 CalculatePadFileSize (
145 IN FV_DEVICE
*FvDevice
,
146 IN EFI_PHYSICAL_ADDRESS StartAddress
,
148 IN UINTN RequiredAlignment
155 if (BufferSize
> 0x00FFFFFF) {
156 DataStartPos
= (UINTN
) StartAddress
+ sizeof (EFI_FFS_FILE_HEADER2
);
158 DataStartPos
= (UINTN
) StartAddress
+ sizeof (EFI_FFS_FILE_HEADER
);
160 RelativePos
= DataStartPos
- (UINTN
) FvDevice
->CachedFv
;
164 while ((RelativePos
& (RequiredAlignment
- 1)) != 0) {
169 // If padsize is 0, no pad file needed;
170 // If padsize is great than 24, then pad file can be created
172 if ((PadSize
== 0) || (PadSize
>= sizeof (EFI_FFS_FILE_HEADER
))) {
177 // Perhaps following method can save space
179 RelativePos
= DataStartPos
- (UINTN
) FvDevice
->CachedFv
+ sizeof (EFI_FFS_FILE_HEADER
);
180 PadSize
= sizeof (EFI_FFS_FILE_HEADER
);
182 while ((RelativePos
& (RequiredAlignment
- 1)) != 0) {
191 Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
193 @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
194 @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
198 FvFileAttrib2FfsFileAttrib (
199 IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib
,
200 OUT UINT8
*FfsFileAttrib
203 UINT8 FvFileAlignment
;
204 UINT8 FfsFileAlignment
;
205 UINT8 FfsFileAlignment2
;
207 FvFileAlignment
= (UINT8
) (FvFileAttrib
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
208 FfsFileAlignment
= 0;
209 FfsFileAlignment2
= 0;
211 switch (FvFileAlignment
) {
228 FfsFileAlignment
= 0;
243 FfsFileAlignment
= 1;
254 FfsFileAlignment
= 2;
258 FfsFileAlignment
= 3;
269 FfsFileAlignment
= 4;
284 FfsFileAlignment
= 5;
288 FfsFileAlignment
= 6;
292 FfsFileAlignment
= 7;
296 FfsFileAlignment
= 0;
297 FfsFileAlignment2
= 1;
300 FfsFileAlignment
= 1;
301 FfsFileAlignment2
= 1;
304 FfsFileAlignment
= 2;
305 FfsFileAlignment2
= 1;
308 FfsFileAlignment
= 3;
309 FfsFileAlignment2
= 1;
312 FfsFileAlignment
= 4;
313 FfsFileAlignment2
= 1;
316 FfsFileAlignment
= 5;
317 FfsFileAlignment2
= 1;
320 FfsFileAlignment
= 6;
321 FfsFileAlignment2
= 1;
324 FfsFileAlignment
= 7;
325 FfsFileAlignment2
= 1;
329 *FfsFileAttrib
= (UINT8
) ((FfsFileAlignment
<< 3) | (FfsFileAlignment2
<< 1));
335 Locate a free space entry that can hold this FFS file.
337 @param FvDevice Cached Firmware Volume.
338 @param Size The FFS file size.
339 @param RequiredAlignment FFS File Data alignment requirement.
340 @param PadSize Pointer to the size of leading Pad File.
341 @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
343 @retval EFI_SUCCESS The free space entry is found.
344 @retval EFI_NOT_FOUND The free space entry can't be found.
348 FvLocateFreeSpaceEntry (
349 IN FV_DEVICE
*FvDevice
,
351 IN UINTN RequiredAlignment
,
353 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
356 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
360 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
361 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
364 // Loop the free space entry list to find one that can hold the
365 // required the file size
367 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
368 PadFileSize
= CalculatePadFileSize (
370 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceListEntry
->StartingAddress
,
374 if (FreeSpaceListEntry
->Length
>= Size
+ PadFileSize
) {
375 *FreeSpaceEntry
= FreeSpaceListEntry
;
376 *PadSize
= PadFileSize
;
380 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
383 return EFI_NOT_FOUND
;
388 Locate Pad File for writing, this is got from FV Cache.
390 @param FvDevice Cached Firmware Volume.
391 @param Size The required FFS file size.
392 @param RequiredAlignment FFS File Data alignment requirement.
393 @param PadSize Pointer to the size of leading Pad File.
394 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
396 @retval EFI_SUCCESS The required pad file is found.
397 @retval EFI_NOT_FOUND The required pad file can't be found.
402 IN FV_DEVICE
*FvDevice
,
404 IN UINTN RequiredAlignment
,
406 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
409 FFS_FILE_LIST_ENTRY
*FileEntry
;
410 EFI_FFS_FILE_STATE FileState
;
411 EFI_FFS_FILE_HEADER
*FileHeader
;
416 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
419 // travel through the whole file list to get the pad file entry
421 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
423 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
424 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
426 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
428 // we find one valid pad file, check its free area length
430 if (IS_FFS_FILE2 (FileHeader
)) {
431 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
432 PadAreaLength
= FFS_FILE2_SIZE (FileHeader
) - HeaderSize
;
434 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
435 PadAreaLength
= FFS_FILE_SIZE (FileHeader
) - HeaderSize
;
438 PadFileSize
= CalculatePadFileSize (
440 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ HeaderSize
,
444 if (PadAreaLength
>= (Size
+ PadFileSize
)) {
445 *PadSize
= PadFileSize
;
446 *PadFileEntry
= FileEntry
;
451 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
454 return EFI_NOT_FOUND
;
458 Locate a suitable pad file for multiple file writing.
460 @param FvDevice Cached Firmware Volume.
461 @param NumOfFiles The number of Files that needed updating
462 @param BufferSize The array of each file size.
463 @param RequiredAlignment The array of of FFS File Data alignment requirement.
464 @param PadSize The array of size of each leading Pad File.
465 @param TotalSizeNeeded The totalsize that can hold these files.
466 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
468 @retval EFI_SUCCESS The required pad file is found.
469 @retval EFI_NOT_FOUND The required pad file can't be found.
473 FvSearchSuitablePadFile (
474 IN FV_DEVICE
*FvDevice
,
476 IN UINTN
*BufferSize
,
477 IN UINTN
*RequiredAlignment
,
479 OUT UINTN
*TotalSizeNeeded
,
480 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
483 FFS_FILE_LIST_ENTRY
*FileEntry
;
484 EFI_FFS_FILE_STATE FileState
;
485 EFI_FFS_FILE_HEADER
*FileHeader
;
491 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
494 // travel through the whole file list to get the pad file entry
496 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
498 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
499 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
501 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
503 // we find one valid pad file, check its length
505 if (IS_FFS_FILE2 (FileHeader
)) {
506 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
507 PadAreaLength
= FFS_FILE2_SIZE (FileHeader
) - HeaderSize
;
509 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
510 PadAreaLength
= FFS_FILE_SIZE (FileHeader
) - HeaderSize
;
514 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
515 PadSize
[Index
] = CalculatePadFileSize (
517 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ HeaderSize
+ TotalSize
,
519 RequiredAlignment
[Index
]
521 TotalSize
+= PadSize
[Index
];
522 TotalSize
+= BufferSize
[Index
];
524 if (TotalSize
> PadAreaLength
) {
529 if (PadAreaLength
>= TotalSize
) {
530 *PadFileEntry
= FileEntry
;
531 *TotalSizeNeeded
= TotalSize
;
536 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
539 return EFI_NOT_FOUND
;
543 Locate a Free Space entry which can hold these files, including
544 meeting the alignment requirements.
546 @param FvDevice Cached Firmware Volume.
547 @param NumOfFiles The number of Files that needed updating
548 @param BufferSize The array of each file size.
549 @param RequiredAlignment The array of of FFS File Data alignment requirement.
550 @param PadSize The array of size of each leading Pad File.
551 @param TotalSizeNeeded The got total size that can hold these files.
552 @param FreeSpaceEntry The Free Space Entry that can hold these files.
554 @retval EFI_SUCCESS The free space entry is found.
555 @retval EFI_NOT_FOUND The free space entry can't be found.
559 FvSearchSuitableFreeSpace (
560 IN FV_DEVICE
*FvDevice
,
562 IN UINTN
*BufferSize
,
563 IN UINTN
*RequiredAlignment
,
565 OUT UINTN
*TotalSizeNeeded
,
566 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
569 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
575 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
577 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
579 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
581 StartAddr
= FreeSpaceListEntry
->StartingAddress
;
584 // Calculate the totalsize we need
586 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
588 // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
589 // have had its leading pad file.
591 PadSize
[Index
] = CalculatePadFileSize (
593 (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartAddr
+ TotalSize
,
595 RequiredAlignment
[Index
]
598 TotalSize
+= PadSize
[Index
];
599 TotalSize
+= BufferSize
[Index
];
601 if (TotalSize
> FreeSpaceListEntry
->Length
) {
606 if (FreeSpaceListEntry
->Length
>= TotalSize
) {
607 *FreeSpaceEntry
= FreeSpaceListEntry
;
608 *TotalSizeNeeded
= TotalSize
;
612 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
615 return EFI_NOT_FOUND
;
619 Calculate the length of the remaining space in FV.
621 @param FvDevice Cached Firmware Volume
622 @param Offset Current offset to FV base address.
623 @param Lba LBA number for the current offset.
624 @param LOffset Offset in block for the current offset.
626 @return the length of remaining space.
630 CalculateRemainingLength (
631 IN FV_DEVICE
*FvDevice
,
643 Link
= FvDevice
->LbaHeader
.ForwardLink
;
644 LbaEntry
= (LBA_ENTRY
*) Link
;
646 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
647 if (Count
> Offset
) {
651 Count
+= LbaEntry
->BlockLength
;
653 Link
= LbaEntry
->Link
.ForwardLink
;
654 LbaEntry
= (LBA_ENTRY
*) Link
;
657 if (Count
<= Offset
) {
661 Link
= LbaEntry
->Link
.BackLink
;
662 LbaEntry
= (LBA_ENTRY
*) Link
;
665 *LOffset
= (UINTN
) (LbaEntry
->BlockLength
- (Count
- Offset
));
668 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
670 Count
+= LbaEntry
->BlockLength
;
672 Link
= LbaEntry
->Link
.ForwardLink
;
673 LbaEntry
= (LBA_ENTRY
*) Link
;
682 Writes data beginning at Lba:Offset from FV. The write terminates either
683 when *NumBytes of data have been written, or when the firmware end is
684 reached. *NumBytes is updated to reflect the actual number of bytes
687 @param FvDevice Cached Firmware Volume
688 @param Offset Offset in the block at which to begin write
689 @param NumBytes At input, indicates the requested write size.
690 At output, indicates the actual number of bytes written.
691 @param Buffer Buffer containing source data for the write.
693 @retval EFI_SUCCESS Data is successfully written into FV.
694 @return error Data is failed written.
699 IN FV_DEVICE
*FvDevice
,
701 IN OUT UINTN
*NumBytes
,
706 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
709 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
710 UINTN RemainingLength
;
715 RemainingLength
= CalculateRemainingLength (FvDevice
, Offset
, &Lba
, &LOffset
);
716 if ((UINTN
) (*NumBytes
) > RemainingLength
) {
717 *NumBytes
= (UINTN
) RemainingLength
;
718 return EFI_INVALID_PARAMETER
;
723 Status
= Fvb
->GetAttributes (
727 if (EFI_ERROR (Status
)) {
731 if ((FvbAttributes
& EFI_FV2_WRITE_STATUS
) == 0) {
732 return EFI_ACCESS_DENIED
;
735 RemainingLength
= *NumBytes
;
736 WriteLength
= RemainingLength
;
740 Status
= Fvb
->Write (
747 if (!EFI_ERROR (Status
)) {
751 if (Status
== EFI_BAD_BUFFER_SIZE
) {
754 TmpBuffer
+= WriteLength
;
755 RemainingLength
-= WriteLength
;
756 WriteLength
= (UINTN
) RemainingLength
;
769 Create a new FFS file into Firmware Volume device.
771 @param FvDevice Cached Firmware Volume.
772 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
773 a File Header which is in init state).
774 @param BufferSize The size of FfsFileBuffer.
775 @param ActualFileSize The actual file length, it may not be multiples of 8.
776 @param FileName The FFS File Name.
777 @param FileType The FFS File Type.
778 @param FileAttributes The Attributes of the FFS File to be created.
780 @retval EFI_SUCCESS FFS fle is added into FV.
781 @retval EFI_INVALID_PARAMETER File type is not valid.
782 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
783 @retval EFI_NOT_FOUND FV has no enough space for the added file.
788 IN FV_DEVICE
*FvDevice
,
789 IN UINT8
*FfsFileBuffer
,
791 IN UINTN ActualFileSize
,
792 IN EFI_GUID
*FileName
,
793 IN EFI_FV_FILETYPE FileType
,
794 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
798 EFI_FFS_FILE_HEADER
*FileHeader
;
799 EFI_PHYSICAL_ADDRESS BufferPtr
;
801 UINTN NumBytesWritten
;
803 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
804 UINTN RequiredAlignment
;
806 FFS_FILE_LIST_ENTRY
*PadFileEntry
;
807 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute
;
808 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
812 // File Type: 0x0E~0xE0 are reserved
814 if ((FileType
> EFI_FV_FILETYPE_SMM_CORE
) && (FileType
< 0xE0)) {
815 return EFI_INVALID_PARAMETER
;
819 // First find a free space that can hold this image.
820 // Check alignment, FFS at least must be aligned at 8-byte boundary
822 RequiredAlignment
= GetRequiredAlignment (FileAttributes
);
824 Status
= FvLocateFreeSpaceEntry (
831 if (EFI_ERROR (Status
)) {
833 // Maybe we need to find a PAD file that can hold this image
835 Status
= FvCreateNewFileInsidePadFile (
848 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
851 // If we need a leading PAD File, create it first.
853 if (PadFileSize
!= 0) {
854 Status
= FvCreatePadFileInFreeSpace (
857 PadFileSize
- sizeof (EFI_FFS_FILE_HEADER
),
860 if (EFI_ERROR (Status
)) {
865 // Maybe we create a pad file, so re-get the free space starting address
868 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
871 // File creation step 1: Allocate File Header,
872 // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
873 // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
875 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileBuffer
;
876 if (ActualFileSize
> 0x00FFFFFF) {
877 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
879 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
881 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, FileHeader
);
883 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
884 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
886 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
893 if (EFI_ERROR (Status
)) {
897 // update header 2 cache
900 (UINT8
*) (UINTN
) BufferPtr
,
906 // update Free Space Entry, now need to substract the file header length
908 FreeSpaceEntry
->StartingAddress
+= HeaderSize
;
909 FreeSpaceEntry
->Length
-= HeaderSize
;
911 CopyGuid (&FileHeader
->Name
, FileName
);
912 FileHeader
->Type
= FileType
;
915 // Convert FvFileAttribute to FfsFileAttributes
917 FvFileAttrib2FfsFileAttrib (FileAttributes
, &TmpFileAttribute
);
919 FileHeader
->Attributes
= TmpFileAttribute
;
922 // File size is including the FFS File Header.
924 if (ActualFileSize
> 0x00FFFFFF) {
925 ((EFI_FFS_FILE_HEADER2
*) FileHeader
)->ExtendedSize
= (UINT32
) ActualFileSize
;
926 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
927 FileHeader
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
929 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
930 *(UINT32
*) FileHeader
->Size
|= ActualFileSize
;
933 SetHeaderChecksum (FileHeader
);
935 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
937 NumBytesWritten
= HeaderSize
;
944 if (EFI_ERROR (Status
)) {
948 // update header 2 cache
951 (UINT8
*) (UINTN
) BufferPtr
,
959 // File creation step 2:
960 // MARK EFI_FILE_HEADER_VALID bit to TRUE,
961 // Write IntegrityCheck.File, File Data
963 SetFileState (EFI_FILE_HEADER_VALID
, FileHeader
);
965 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
966 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
968 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
975 if (EFI_ERROR (Status
)) {
979 // update header 2 cache
982 (UINT8
*) (UINTN
) BufferPtr
,
988 // update Free Space Entry, now need to substract the file data length
990 FreeSpaceEntry
->StartingAddress
+= (BufferSize
- HeaderSize
);
991 FreeSpaceEntry
->Length
-= (BufferSize
- HeaderSize
);
994 // Calculate File Checksum
996 SetFileChecksum (FileHeader
, ActualFileSize
);
998 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
1000 NumBytesWritten
= BufferSize
;
1007 if (EFI_ERROR (Status
)) {
1011 // each time write block successfully, write also to cache
1014 (UINT8
*) (UINTN
) BufferPtr
,
1020 // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
1022 SetFileState (EFI_FILE_DATA_VALID
, FileHeader
);
1024 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
1025 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1027 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1034 if (EFI_ERROR (Status
)) {
1038 // update header 2 cache
1041 (UINT8
*) (UINTN
) BufferPtr
,
1047 // If successfully, insert an FfsFileEntry at the end of ffs file list
1050 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
1051 ASSERT (FfsFileEntry
!= NULL
);
1052 FfsFileEntry
->FfsHeader
= (UINT8
*) (UINTN
) BufferPtr
;
1053 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
1056 // Set cache file to this file
1058 FvDevice
->CurrentFfsFile
= FfsFileEntry
;
1064 Update a File, so after successful update, there are 2 files existing
1065 in FV, one is marked for deleted, and another one is valid.
1067 @param FvDevice Cached Firmware Volume.
1068 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
1069 a File Header which is in init state).
1070 @param BufferSize The size of FfsFileBuffer.
1071 @param ActualFileSize The actual file length, it may not be multiples of 8.
1072 @param FileName The FFS File Name.
1073 @param NewFileType The FFS File Type.
1074 @param NewFileAttributes The Attributes of the FFS File to be created.
1076 @retval EFI_SUCCESS FFS fle is updated into FV.
1077 @retval EFI_INVALID_PARAMETER File type is not valid.
1078 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
1079 @retval EFI_NOT_FOUND FV has no enough space for the added file.
1080 FFS with same file name is not found in FV.
1085 IN FV_DEVICE
*FvDevice
,
1086 IN UINT8
*FfsFileBuffer
,
1087 IN UINTN BufferSize
,
1088 IN UINTN ActualFileSize
,
1089 IN EFI_GUID
*FileName
,
1090 IN EFI_FV_FILETYPE NewFileType
,
1091 IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
1095 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1096 UINTN NumBytesWritten
;
1097 EFI_FV_FILETYPE OldFileType
;
1098 EFI_FV_FILE_ATTRIBUTES OldFileAttributes
;
1100 EFI_FFS_FILE_HEADER
*OldFileHeader
;
1102 UINTN OldStateOffset
;
1103 FFS_FILE_LIST_ENTRY
*OldFfsFileEntry
;
1105 EFI_GUID FileNameGuid
;
1110 // Step 1, find old file,
1111 // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
1115 // Check if the file was read last time.
1117 OldFileHeader
= NULL
;
1118 OldFfsFileEntry
= FvDevice
->CurrentFfsFile
;
1120 if (OldFfsFileEntry
!= NULL
) {
1121 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1124 if ((OldFfsFileEntry
== NULL
) || (!CompareGuid (&OldFileHeader
->Name
, FileName
))) {
1128 Status
= Fv
->GetNextFile (
1136 if (EFI_ERROR (Status
)) {
1139 } while (!CompareGuid (&FileNameGuid
, FileName
));
1142 // Get FfsFileEntry from the search key
1144 OldFfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1147 // Double check file state before being ready to be removed
1149 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1152 // Mark the cache file to invalid
1154 FvDevice
->CurrentFfsFile
= NULL
;
1157 // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
1159 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1161 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1162 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1164 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1169 &OldFileHeader
->State
1171 if (EFI_ERROR (Status
)) {
1173 // if failed, write the bit back in the cache, its XOR operation.
1175 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1181 // Step 2, Create New Files
1183 Status
= FvCreateNewFile (
1192 if (EFI_ERROR (Status
)) {
1197 // If successfully, remove this file entry,
1198 // although delete file may fail.
1200 (OldFfsFileEntry
->Link
.BackLink
)->ForwardLink
= OldFfsFileEntry
->Link
.ForwardLink
;
1201 (OldFfsFileEntry
->Link
.ForwardLink
)->BackLink
= OldFfsFileEntry
->Link
.BackLink
;
1202 FreePool (OldFfsFileEntry
);
1205 // Step 3: Delete old files,
1206 // by marking EFI_FILE_DELETED to TRUE
1208 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1210 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1211 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1213 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1218 &OldFileHeader
->State
1220 if (EFI_ERROR (Status
)) {
1222 // if failed, write the bit back in the cache, its XOR operation.
1224 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1233 Deleted a given file from FV device.
1235 @param FvDevice Cached Firmware Volume.
1236 @param NameGuid The FFS File Name.
1238 @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
1239 @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
1244 IN FV_DEVICE
*FvDevice
,
1245 IN EFI_GUID
*NameGuid
1250 EFI_GUID FileNameGuid
;
1251 EFI_FV_FILETYPE FileType
;
1252 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1254 EFI_FFS_FILE_HEADER
*FileHeader
;
1255 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
1256 EFI_FFS_FILE_STATE FileState
;
1257 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1260 UINTN NumBytesWritten
;
1265 // Check if the file was read last time.
1268 FfsFileEntry
= FvDevice
->CurrentFfsFile
;
1270 if (FfsFileEntry
!= NULL
) {
1271 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1274 if ((FfsFileEntry
== NULL
) || (!CompareGuid (&FileHeader
->Name
, NameGuid
))) {
1276 // Next search for the file using GetNextFile
1281 Status
= Fv
->GetNextFile (
1289 if (EFI_ERROR (Status
)) {
1292 } while (!CompareGuid (&FileNameGuid
, NameGuid
));
1295 // Get FfsFileEntry from the search key
1297 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1300 // Double check file state before being ready to be removed
1302 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1305 // Mark the cache file to NULL
1307 FvDevice
->CurrentFfsFile
= NULL
;
1310 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
1312 if (FileState
== EFI_FILE_HEADER_INVALID
) {
1313 return EFI_NOT_FOUND
;
1316 if (FileState
== EFI_FILE_DELETED
) {
1317 return EFI_NOT_FOUND
;
1320 // Delete File: Mark EFI_FILE_DELETED to TRUE
1322 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1324 Offset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
- FvDevice
->CachedFv
);
1325 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1327 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1334 if (EFI_ERROR (Status
)) {
1336 // if failed, write the bit back in the cache, its XOR operation.
1338 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1343 // If successfully, remove this file entry
1345 FvDevice
->CurrentFfsFile
= NULL
;
1347 (FfsFileEntry
->Link
.BackLink
)->ForwardLink
= FfsFileEntry
->Link
.ForwardLink
;
1348 (FfsFileEntry
->Link
.ForwardLink
)->BackLink
= FfsFileEntry
->Link
.BackLink
;
1349 FreePool (FfsFileEntry
);
1355 Writes one or more files to the firmware volume.
1357 @param This Indicates the calling context.
1358 @param NumberOfFiles Number of files.
1359 @param WritePolicy WritePolicy indicates the level of reliability
1360 for the write in the event of a power failure or
1361 other system failure during the write operation.
1362 @param FileData FileData is an pointer to an array of
1363 EFI_FV_WRITE_DATA. Each element of array
1364 FileData represents a file to be written.
1366 @retval EFI_SUCCESS Files successfully written to firmware volume
1367 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
1368 @retval EFI_DEVICE_ERROR Device error.
1369 @retval EFI_WRITE_PROTECTED Write protected.
1370 @retval EFI_NOT_FOUND Not found.
1371 @retval EFI_INVALID_PARAMETER Invalid parameter.
1372 @retval EFI_UNSUPPORTED This function not supported.
1378 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL
*This
,
1379 IN UINT32 NumberOfFiles
,
1380 IN EFI_FV_WRITE_POLICY WritePolicy
,
1381 IN EFI_FV_WRITE_FILE_DATA
*FileData
1390 UINT8 ErasePolarity
;
1391 FV_DEVICE
*FvDevice
;
1392 EFI_FV_FILETYPE FileType
;
1393 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1395 BOOLEAN CreateNewFile
[MAX_FILES
];
1397 EFI_FV_ATTRIBUTES FvAttributes
;
1398 UINT32 AuthenticationStatus
;
1401 if (NumberOfFiles
> MAX_FILES
) {
1402 return EFI_UNSUPPORTED
;
1405 Status
= EFI_SUCCESS
;
1407 SetMem (CreateNewFile
, NumberOfFiles
, TRUE
);
1409 FvDevice
= FV_DEVICE_FROM_THIS (This
);
1412 // First check the volume attributes.
1414 Status
= This
->GetVolumeAttributes (
1418 if (EFI_ERROR (Status
)) {
1422 // Can we have write right?
1424 if ((FvAttributes
& EFI_FV2_WRITE_STATUS
) == 0) {
1425 return EFI_WRITE_PROTECTED
;
1428 ErasePolarity
= FvDevice
->ErasePolarity
;
1431 // Loop for all files
1434 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1436 if ((FileData
[Index1
].BufferSize
+ sizeof (EFI_FFS_FILE_HEADER
) > 0x00FFFFFF) && !FvDevice
->IsFfs3Fv
) {
1438 // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
1440 DEBUG ((EFI_D_ERROR
, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
1441 return EFI_INVALID_PARAMETER
;
1444 if (FileData
[Index1
].BufferSize
== 0) {
1446 // Here we will delete this file
1448 Status
= This
->ReadFile (
1450 FileData
[Index1
].NameGuid
,
1455 &AuthenticationStatus
1457 if (!EFI_ERROR (Status
)) {
1464 if (FileData
[Index1
].Type
== EFI_FV_FILETYPE_FFS_PAD
) {
1466 // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
1467 // "Standard firmware file system services will not return the handle of any pad files,
1468 // nor will they permit explicit creation of such files."
1470 return EFI_INVALID_PARAMETER
;
1474 if ((NumDelete
!= NumberOfFiles
) && (NumDelete
!= 0)) {
1476 // A delete was request with a multiple file write
1478 return EFI_INVALID_PARAMETER
;
1481 if (NumDelete
== NumberOfFiles
) {
1482 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1486 Status
= FvDeleteFile (FvDevice
, FileData
[Index1
].NameGuid
);
1487 if (EFI_ERROR (Status
)) {
1495 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1496 Status
= This
->ReadFile (
1498 FileData
[Index1
].NameGuid
,
1503 &AuthenticationStatus
1505 if (!EFI_ERROR (Status
)) {
1506 CreateNewFile
[Index1
] = FALSE
;
1507 } else if (Status
== EFI_NOT_FOUND
) {
1508 CreateNewFile
[Index1
] = TRUE
;
1513 // Checking alignment
1515 if ((FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
) != 0) {
1516 UINT8 FFSAlignmentValue
;
1517 UINT8 FvAlignmentValue
;
1519 FFSAlignmentValue
= (UINT8
) (FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
1520 FvAlignmentValue
= (UINT8
) (((UINT32
) (FvAttributes
& EFI_FV2_ALIGNMENT
)) >> 16);
1522 if (FFSAlignmentValue
> FvAlignmentValue
) {
1523 return EFI_INVALID_PARAMETER
;
1528 if ((WritePolicy
!= EFI_FV_RELIABLE_WRITE
) && (WritePolicy
!= EFI_FV_UNRELIABLE_WRITE
)) {
1529 return EFI_INVALID_PARAMETER
;
1532 // Checking the reliable write is supported by FV
1535 if ((WritePolicy
== EFI_FV_RELIABLE_WRITE
) && (NumberOfFiles
> 1)) {
1537 // Only for multiple files, reliable write is meaningful
1539 Status
= FvCreateMultipleFiles (
1549 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1551 // Making Buffersize QWORD boundary, and add file tail.
1553 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
1554 ActualSize
= FileData
[Index1
].BufferSize
+ HeaderSize
;
1555 if (ActualSize
> 0x00FFFFFF) {
1556 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
1557 ActualSize
= FileData
[Index1
].BufferSize
+ HeaderSize
;
1559 BufferSize
= ActualSize
;
1561 while ((BufferSize
& 0x07) != 0) {
1565 FileBuffer
= AllocateZeroPool (BufferSize
);
1566 if (FileBuffer
== NULL
) {
1570 // Copy File Data into FileBuffer
1573 FileBuffer
+ HeaderSize
,
1574 FileData
[Index1
].Buffer
,
1575 FileData
[Index1
].BufferSize
1578 if (ErasePolarity
== 1) {
1580 // Fill the file header and padding byte with Erase Byte
1582 for (Index2
= 0; Index2
< HeaderSize
; Index2
++) {
1583 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1586 for (Index2
= ActualSize
; Index2
< BufferSize
; Index2
++) {
1587 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1591 if (CreateNewFile
[Index1
]) {
1592 Status
= FvCreateNewFile (
1597 FileData
[Index1
].NameGuid
,
1598 FileData
[Index1
].Type
,
1599 FileData
[Index1
].FileAttributes
1602 Status
= FvUpdateFile (
1607 FileData
[Index1
].NameGuid
,
1608 FileData
[Index1
].Type
,
1609 FileData
[Index1
].FileAttributes
1613 FreePool (FileBuffer
);
1615 if (EFI_ERROR (Status
)) {