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
;
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 Caculate the checksum for the FFS File.
65 @param FfsHeader FFS File Header which needs to caculate 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 Caculate 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 CaculatePadFileSize (
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
;
206 FvFileAlignment
= (UINT8
) (FvFileAttrib
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
207 FfsFileAlignment
= 0;
209 switch (FvFileAlignment
) {
226 FfsFileAlignment
= 0;
241 FfsFileAlignment
= 1;
252 FfsFileAlignment
= 2;
256 FfsFileAlignment
= 3;
267 FfsFileAlignment
= 4;
282 FfsFileAlignment
= 5;
286 FfsFileAlignment
= 6;
290 FfsFileAlignment
= 7;
294 *FfsFileAttrib
= (UINT8
) (FfsFileAlignment
<< 3);
300 Locate a free space entry that can hold this FFS file.
302 @param FvDevice Cached Firmware Volume.
303 @param Size The FFS file size.
304 @param RequiredAlignment FFS File Data alignment requirement.
305 @param PadSize Pointer to the size of leading Pad File.
306 @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
308 @retval EFI_SUCCESS The free space entry is found.
309 @retval EFI_NOT_FOUND The free space entry can't be found.
313 FvLocateFreeSpaceEntry (
314 IN FV_DEVICE
*FvDevice
,
316 IN UINTN RequiredAlignment
,
318 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
321 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
325 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
326 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
329 // Loop the free space entry list to find one that can hold the
330 // required the file size
332 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
333 PadFileSize
= CaculatePadFileSize (
335 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceListEntry
->StartingAddress
,
339 if (FreeSpaceListEntry
->Length
>= Size
+ PadFileSize
) {
340 *FreeSpaceEntry
= FreeSpaceListEntry
;
341 *PadSize
= PadFileSize
;
345 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
348 return EFI_NOT_FOUND
;
353 Locate Pad File for writing, this is got from FV Cache.
355 @param FvDevice Cached Firmware Volume.
356 @param Size The required FFS file size.
357 @param RequiredAlignment FFS File Data alignment requirement.
358 @param PadSize Pointer to the size of leading Pad File.
359 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
361 @retval EFI_SUCCESS The required pad file is found.
362 @retval EFI_NOT_FOUND The required pad file can't be found.
367 IN FV_DEVICE
*FvDevice
,
369 IN UINTN RequiredAlignment
,
371 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
374 FFS_FILE_LIST_ENTRY
*FileEntry
;
375 EFI_FFS_FILE_STATE FileState
;
376 EFI_FFS_FILE_HEADER
*FileHeader
;
381 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
384 // travel through the whole file list to get the pad file entry
386 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
388 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
389 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
391 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
393 // we find one valid pad file, check its free area length
395 if (IS_FFS_FILE2 (FileHeader
)) {
396 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
397 PadAreaLength
= FFS_FILE2_SIZE (FileHeader
) - HeaderSize
;
399 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
400 PadAreaLength
= FFS_FILE_SIZE (FileHeader
) - HeaderSize
;
403 PadFileSize
= CaculatePadFileSize (
405 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ HeaderSize
,
409 if (PadAreaLength
>= (Size
+ PadFileSize
)) {
410 *PadSize
= PadFileSize
;
411 *PadFileEntry
= FileEntry
;
416 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
419 return EFI_NOT_FOUND
;
423 Locate a suitable pad file for multiple file writing.
425 @param FvDevice Cached Firmware Volume.
426 @param NumOfFiles The number of Files that needed updating
427 @param BufferSize The array of each file size.
428 @param RequiredAlignment The array of of FFS File Data alignment requirement.
429 @param PadSize The array of size of each leading Pad File.
430 @param TotalSizeNeeded The totalsize that can hold these files.
431 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
433 @retval EFI_SUCCESS The required pad file is found.
434 @retval EFI_NOT_FOUND The required pad file can't be found.
438 FvSearchSuitablePadFile (
439 IN FV_DEVICE
*FvDevice
,
441 IN UINTN
*BufferSize
,
442 IN UINTN
*RequiredAlignment
,
444 OUT UINTN
*TotalSizeNeeded
,
445 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
448 FFS_FILE_LIST_ENTRY
*FileEntry
;
449 EFI_FFS_FILE_STATE FileState
;
450 EFI_FFS_FILE_HEADER
*FileHeader
;
456 FileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
459 // travel through the whole file list to get the pad file entry
461 while (FileEntry
!= (FFS_FILE_LIST_ENTRY
*) &FvDevice
->FfsFileListHeader
) {
463 FileHeader
= (EFI_FFS_FILE_HEADER
*) FileEntry
->FfsHeader
;
464 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
466 if ((FileHeader
->Type
== EFI_FV_FILETYPE_FFS_PAD
) && (FileState
== EFI_FILE_DATA_VALID
)) {
468 // we find one valid pad file, check its length
470 if (IS_FFS_FILE2 (FileHeader
)) {
471 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
472 PadAreaLength
= FFS_FILE2_SIZE (FileHeader
) - HeaderSize
;
474 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
475 PadAreaLength
= FFS_FILE_SIZE (FileHeader
) - HeaderSize
;
479 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
480 PadSize
[Index
] = CaculatePadFileSize (
482 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
+ HeaderSize
+ TotalSize
,
484 RequiredAlignment
[Index
]
486 TotalSize
+= PadSize
[Index
];
487 TotalSize
+= BufferSize
[Index
];
489 if (TotalSize
> PadAreaLength
) {
494 if (PadAreaLength
>= TotalSize
) {
495 *PadFileEntry
= FileEntry
;
496 *TotalSizeNeeded
= TotalSize
;
501 FileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileEntry
->Link
.ForwardLink
);
504 return EFI_NOT_FOUND
;
508 Locate a Free Space entry which can hold these files, including
509 meeting the alignment requirements.
511 @param FvDevice Cached Firmware Volume.
512 @param NumOfFiles The number of Files that needed updating
513 @param BufferSize The array of each file size.
514 @param RequiredAlignment The array of of FFS File Data alignment requirement.
515 @param PadSize The array of size of each leading Pad File.
516 @param TotalSizeNeeded The got total size that can hold these files.
517 @param FreeSpaceEntry The Free Space Entry that can hold these files.
519 @retval EFI_SUCCESS The free space entry is found.
520 @retval EFI_NOT_FOUND The free space entry can't be found.
524 FvSearchSuitableFreeSpace (
525 IN FV_DEVICE
*FvDevice
,
527 IN UINTN
*BufferSize
,
528 IN UINTN
*RequiredAlignment
,
530 OUT UINTN
*TotalSizeNeeded
,
531 OUT FREE_SPACE_ENTRY
**FreeSpaceEntry
534 FREE_SPACE_ENTRY
*FreeSpaceListEntry
;
540 Link
= FvDevice
->FreeSpaceHeader
.ForwardLink
;
542 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) Link
;
544 while ((LIST_ENTRY
*) FreeSpaceListEntry
!= &FvDevice
->FreeSpaceHeader
) {
546 StartAddr
= FreeSpaceListEntry
->StartingAddress
;
549 // Caculate the totalsize we need
551 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
553 // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
554 // have had its leading pad file.
556 PadSize
[Index
] = CaculatePadFileSize (
558 (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartAddr
+ TotalSize
,
560 RequiredAlignment
[Index
]
563 TotalSize
+= PadSize
[Index
];
564 TotalSize
+= BufferSize
[Index
];
566 if (TotalSize
> FreeSpaceListEntry
->Length
) {
571 if (FreeSpaceListEntry
->Length
>= TotalSize
) {
572 *FreeSpaceEntry
= FreeSpaceListEntry
;
573 *TotalSizeNeeded
= TotalSize
;
577 FreeSpaceListEntry
= (FREE_SPACE_ENTRY
*) FreeSpaceListEntry
->Link
.ForwardLink
;
580 return EFI_NOT_FOUND
;
584 Calculate the length of the remaining space in FV.
586 @param FvDevice Cached Firmware Volume
587 @param Offset Current offset to FV base address.
588 @param Lba LBA number for the current offset.
589 @param LOffset Offset in block for the current offset.
591 @return the length of remaining space.
595 CalculateRemainingLength (
596 IN FV_DEVICE
*FvDevice
,
608 Link
= FvDevice
->LbaHeader
.ForwardLink
;
609 LbaEntry
= (LBA_ENTRY
*) Link
;
611 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
612 if (Count
> Offset
) {
616 Count
+= LbaEntry
->BlockLength
;
618 Link
= LbaEntry
->Link
.ForwardLink
;
619 LbaEntry
= (LBA_ENTRY
*) Link
;
622 if (Count
<= Offset
) {
626 Link
= LbaEntry
->Link
.BackLink
;
627 LbaEntry
= (LBA_ENTRY
*) Link
;
630 *LOffset
= (UINTN
) (LbaEntry
->BlockLength
- (Count
- Offset
));
633 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
635 Count
+= LbaEntry
->BlockLength
;
637 Link
= LbaEntry
->Link
.ForwardLink
;
638 LbaEntry
= (LBA_ENTRY
*) Link
;
647 Writes data beginning at Lba:Offset from FV. The write terminates either
648 when *NumBytes of data have been written, or when the firmware end is
649 reached. *NumBytes is updated to reflect the actual number of bytes
652 @param FvDevice Cached Firmware Volume
653 @param Offset Offset in the block at which to begin write
654 @param NumBytes At input, indicates the requested write size.
655 At output, indicates the actual number of bytes written.
656 @param Buffer Buffer containing source data for the write.
658 @retval EFI_SUCCESS Data is successfully written into FV.
659 @return error Data is failed written.
664 IN FV_DEVICE
*FvDevice
,
666 IN OUT UINTN
*NumBytes
,
671 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
674 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
675 UINTN RemainingLength
;
680 RemainingLength
= CalculateRemainingLength (FvDevice
, Offset
, &Lba
, &LOffset
);
681 if ((UINTN
) (*NumBytes
) > RemainingLength
) {
682 *NumBytes
= (UINTN
) RemainingLength
;
683 return EFI_INVALID_PARAMETER
;
688 Status
= Fvb
->GetAttributes (
692 if (EFI_ERROR (Status
)) {
696 if ((FvbAttributes
& EFI_FV2_WRITE_STATUS
) == 0) {
697 return EFI_ACCESS_DENIED
;
700 RemainingLength
= *NumBytes
;
701 WriteLength
= RemainingLength
;
705 Status
= Fvb
->Write (
712 if (!EFI_ERROR (Status
)) {
716 if (Status
== EFI_BAD_BUFFER_SIZE
) {
719 TmpBuffer
+= WriteLength
;
720 RemainingLength
-= WriteLength
;
721 WriteLength
= (UINTN
) RemainingLength
;
734 Create a new FFS file into Firmware Volume device.
736 @param FvDevice Cached Firmware Volume.
737 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
738 a File Header which is in init state).
739 @param BufferSize The size of FfsFileBuffer.
740 @param ActualFileSize The actual file length, it may not be multiples of 8.
741 @param FileName The FFS File Name.
742 @param FileType The FFS File Type.
743 @param FileAttributes The Attributes of the FFS File to be created.
745 @retval EFI_SUCCESS FFS fle is added into FV.
746 @retval EFI_INVALID_PARAMETER File type is not valid.
747 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
748 @retval EFI_NOT_FOUND FV has no enough space for the added file.
753 IN FV_DEVICE
*FvDevice
,
754 IN UINT8
*FfsFileBuffer
,
756 IN UINTN ActualFileSize
,
757 IN EFI_GUID
*FileName
,
758 IN EFI_FV_FILETYPE FileType
,
759 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
763 EFI_FFS_FILE_HEADER
*FileHeader
;
764 EFI_PHYSICAL_ADDRESS BufferPtr
;
766 UINTN NumBytesWritten
;
768 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
769 UINTN RequiredAlignment
;
771 FFS_FILE_LIST_ENTRY
*PadFileEntry
;
772 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute
;
773 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
777 // File Type: 0x0E~0xE0 are reserved
779 if ((FileType
> EFI_FV_FILETYPE_SMM_CORE
) && (FileType
< 0xE0)) {
780 return EFI_INVALID_PARAMETER
;
784 // First find a free space that can hold this image.
785 // Check alignment, FFS at least must be aligned at 8-byte boundry
787 RequiredAlignment
= GetRequiredAlignment (FileAttributes
);
789 Status
= FvLocateFreeSpaceEntry (
796 if (EFI_ERROR (Status
)) {
798 // Maybe we need to find a PAD file that can hold this image
800 Status
= FvCreateNewFileInsidePadFile (
813 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
816 // If we need a leading PAD File, create it first.
818 if (PadFileSize
!= 0) {
819 Status
= FvCreatePadFileInFreeSpace (
822 PadFileSize
- sizeof (EFI_FFS_FILE_HEADER
),
825 if (EFI_ERROR (Status
)) {
830 // Maybe we create a pad file, so re-get the free space starting address
833 BufferPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FreeSpaceEntry
->StartingAddress
;
836 // File creation step 1: Allocate File Header,
837 // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
838 // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
840 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileBuffer
;
841 if (ActualFileSize
> 0x00FFFFFF) {
842 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
844 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
846 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, FileHeader
);
848 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
849 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
851 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
858 if (EFI_ERROR (Status
)) {
862 // update header 2 cache
865 (UINT8
*) (UINTN
) BufferPtr
,
871 // update Free Space Entry, now need to substract the file header length
873 FreeSpaceEntry
->StartingAddress
+= HeaderSize
;
874 FreeSpaceEntry
->Length
-= HeaderSize
;
876 CopyGuid (&FileHeader
->Name
, FileName
);
877 FileHeader
->Type
= FileType
;
880 // Convert FvFileAttribute to FfsFileAttributes
882 FvFileAttrib2FfsFileAttrib (FileAttributes
, &TmpFileAttribute
);
884 FileHeader
->Attributes
= TmpFileAttribute
;
887 // File size is including the FFS File Header.
889 if (ActualFileSize
> 0x00FFFFFF) {
890 ((EFI_FFS_FILE_HEADER2
*) FileHeader
)->ExtendedSize
= (UINT32
) ActualFileSize
;
891 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
892 FileHeader
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
894 *(UINT32
*) FileHeader
->Size
&= 0xFF000000;
895 *(UINT32
*) FileHeader
->Size
|= ActualFileSize
;
898 SetHeaderChecksum (FileHeader
);
900 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
902 NumBytesWritten
= HeaderSize
;
909 if (EFI_ERROR (Status
)) {
913 // update header 2 cache
916 (UINT8
*) (UINTN
) BufferPtr
,
924 // File creation step 2:
925 // MARK EFI_FILE_HEADER_VALID bit to TRUE,
926 // Write IntegrityCheck.File, File Data
928 SetFileState (EFI_FILE_HEADER_VALID
, FileHeader
);
930 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
931 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
933 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
940 if (EFI_ERROR (Status
)) {
944 // update header 2 cache
947 (UINT8
*) (UINTN
) BufferPtr
,
953 // update Free Space Entry, now need to substract the file data length
955 FreeSpaceEntry
->StartingAddress
+= (BufferSize
- HeaderSize
);
956 FreeSpaceEntry
->Length
-= (BufferSize
- HeaderSize
);
959 // Caculate File Checksum
961 SetFileChecksum (FileHeader
, ActualFileSize
);
963 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
965 NumBytesWritten
= BufferSize
;
972 if (EFI_ERROR (Status
)) {
976 // each time write block successfully, write also to cache
979 (UINT8
*) (UINTN
) BufferPtr
,
985 // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
987 SetFileState (EFI_FILE_DATA_VALID
, FileHeader
);
989 Offset
= (UINTN
) (BufferPtr
- FvDevice
->CachedFv
);
990 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
992 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
999 if (EFI_ERROR (Status
)) {
1003 // update header 2 cache
1006 (UINT8
*) (UINTN
) BufferPtr
,
1012 // If successfully, insert an FfsFileEntry at the end of ffs file list
1015 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
1016 ASSERT (FfsFileEntry
!= NULL
);
1017 FfsFileEntry
->FfsHeader
= (UINT8
*) (UINTN
) BufferPtr
;
1018 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
1021 // Set cache file to this file
1023 FvDevice
->CurrentFfsFile
= FfsFileEntry
;
1029 Update a File, so after successful update, there are 2 files existing
1030 in FV, one is marked for deleted, and another one is valid.
1032 @param FvDevice Cached Firmware Volume.
1033 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
1034 a File Header which is in init state).
1035 @param BufferSize The size of FfsFileBuffer.
1036 @param ActualFileSize The actual file length, it may not be multiples of 8.
1037 @param FileName The FFS File Name.
1038 @param NewFileType The FFS File Type.
1039 @param NewFileAttributes The Attributes of the FFS File to be created.
1041 @retval EFI_SUCCESS FFS fle is updated into FV.
1042 @retval EFI_INVALID_PARAMETER File type is not valid.
1043 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
1044 @retval EFI_NOT_FOUND FV has no enough space for the added file.
1045 FFS with same file name is not found in FV.
1050 IN FV_DEVICE
*FvDevice
,
1051 IN UINT8
*FfsFileBuffer
,
1052 IN UINTN BufferSize
,
1053 IN UINTN ActualFileSize
,
1054 IN EFI_GUID
*FileName
,
1055 IN EFI_FV_FILETYPE NewFileType
,
1056 IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
1060 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1061 UINTN NumBytesWritten
;
1062 EFI_FV_FILETYPE OldFileType
;
1063 EFI_FV_FILE_ATTRIBUTES OldFileAttributes
;
1065 EFI_FFS_FILE_HEADER
*OldFileHeader
;
1067 UINTN OldStateOffset
;
1068 FFS_FILE_LIST_ENTRY
*OldFfsFileEntry
;
1070 EFI_GUID FileNameGuid
;
1075 // Step 1, find old file,
1076 // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
1080 // Check if the file was read last time.
1082 OldFileHeader
= NULL
;
1083 OldFfsFileEntry
= FvDevice
->CurrentFfsFile
;
1085 if (OldFfsFileEntry
!= NULL
) {
1086 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1089 if ((OldFfsFileEntry
== NULL
) || (!CompareGuid (&OldFileHeader
->Name
, FileName
))) {
1093 Status
= Fv
->GetNextFile (
1101 if (EFI_ERROR (Status
)) {
1104 } while (!CompareGuid (&FileNameGuid
, FileName
));
1107 // Get FfsFileEntry from the search key
1109 OldFfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1112 // Double check file state before being ready to be removed
1114 OldFileHeader
= (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
->FfsHeader
;
1117 // Mark the cache file to invalid
1119 FvDevice
->CurrentFfsFile
= NULL
;
1122 // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
1124 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1126 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1127 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1129 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1134 &OldFileHeader
->State
1136 if (EFI_ERROR (Status
)) {
1138 // if failed, write the bit back in the cache, its XOR operation.
1140 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldFileHeader
);
1146 // Step 2, Create New Files
1148 Status
= FvCreateNewFile (
1157 if (EFI_ERROR (Status
)) {
1162 // If successfully, remove this file entry,
1163 // although delete file may fail.
1165 (OldFfsFileEntry
->Link
.BackLink
)->ForwardLink
= OldFfsFileEntry
->Link
.ForwardLink
;
1166 (OldFfsFileEntry
->Link
.ForwardLink
)->BackLink
= OldFfsFileEntry
->Link
.BackLink
;
1167 FreePool (OldFfsFileEntry
);
1170 // Step 3: Delete old files,
1171 // by marking EFI_FILE_DELETED to TRUE
1173 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1175 OldOffset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) OldFileHeader
- FvDevice
->CachedFv
);
1176 OldStateOffset
= OldOffset
+ (UINT8
*) &OldFileHeader
->State
- (UINT8
*) OldFileHeader
;
1178 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1183 &OldFileHeader
->State
1185 if (EFI_ERROR (Status
)) {
1187 // if failed, write the bit back in the cache, its XOR operation.
1189 SetFileState (EFI_FILE_DELETED
, OldFileHeader
);
1198 Deleted a given file from FV device.
1200 @param FvDevice Cached Firmware Volume.
1201 @param NameGuid The FFS File Name.
1203 @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
1204 @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
1209 IN FV_DEVICE
*FvDevice
,
1210 IN EFI_GUID
*NameGuid
1215 EFI_GUID FileNameGuid
;
1216 EFI_FV_FILETYPE FileType
;
1217 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1219 EFI_FFS_FILE_HEADER
*FileHeader
;
1220 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
1221 EFI_FFS_FILE_STATE FileState
;
1222 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1225 UINTN NumBytesWritten
;
1230 // Check if the file was read last time.
1233 FfsFileEntry
= FvDevice
->CurrentFfsFile
;
1235 if (FfsFileEntry
!= NULL
) {
1236 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1239 if ((FfsFileEntry
== NULL
) || (!CompareGuid (&FileHeader
->Name
, NameGuid
))) {
1241 // Next search for the file using GetNextFile
1246 Status
= Fv
->GetNextFile (
1254 if (EFI_ERROR (Status
)) {
1257 } while (!CompareGuid (&FileNameGuid
, NameGuid
));
1260 // Get FfsFileEntry from the search key
1262 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) Key
;
1265 // Double check file state before being ready to be removed
1267 FileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileEntry
->FfsHeader
;
1270 // Mark the cache file to NULL
1272 FvDevice
->CurrentFfsFile
= NULL
;
1275 FileState
= GetFileState (FvDevice
->ErasePolarity
, FileHeader
);
1277 if (FileState
== EFI_FILE_HEADER_INVALID
) {
1278 return EFI_NOT_FOUND
;
1281 if (FileState
== EFI_FILE_DELETED
) {
1282 return EFI_NOT_FOUND
;
1285 // Delete File: Mark EFI_FILE_DELETED to TRUE
1287 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1289 Offset
= (UINTN
) ((EFI_PHYSICAL_ADDRESS
) (UINTN
) FileHeader
- FvDevice
->CachedFv
);
1290 StateOffset
= Offset
+ (UINT8
*) &FileHeader
->State
- (UINT8
*) FileHeader
;
1292 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
1299 if (EFI_ERROR (Status
)) {
1301 // if failed, write the bit back in the cache, its XOR operation.
1303 SetFileState (EFI_FILE_DELETED
, FileHeader
);
1308 // If successfully, remove this file entry
1310 FvDevice
->CurrentFfsFile
= NULL
;
1312 (FfsFileEntry
->Link
.BackLink
)->ForwardLink
= FfsFileEntry
->Link
.ForwardLink
;
1313 (FfsFileEntry
->Link
.ForwardLink
)->BackLink
= FfsFileEntry
->Link
.BackLink
;
1314 FreePool (FfsFileEntry
);
1320 Writes one or more files to the firmware volume.
1322 @param This Indicates the calling context.
1323 @param NumberOfFiles Number of files.
1324 @param WritePolicy WritePolicy indicates the level of reliability
1325 for the write in the event of a power failure or
1326 other system failure during the write operation.
1327 @param FileData FileData is an pointer to an array of
1328 EFI_FV_WRITE_DATA. Each element of array
1329 FileData represents a file to be written.
1331 @retval EFI_SUCCESS Files successfully written to firmware volume
1332 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
1333 @retval EFI_DEVICE_ERROR Device error.
1334 @retval EFI_WRITE_PROTECTED Write protected.
1335 @retval EFI_NOT_FOUND Not found.
1336 @retval EFI_INVALID_PARAMETER Invalid parameter.
1337 @retval EFI_UNSUPPORTED This function not supported.
1343 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL
*This
,
1344 IN UINT32 NumberOfFiles
,
1345 IN EFI_FV_WRITE_POLICY WritePolicy
,
1346 IN EFI_FV_WRITE_FILE_DATA
*FileData
1355 UINT8 ErasePolarity
;
1356 FV_DEVICE
*FvDevice
;
1357 EFI_FV_FILETYPE FileType
;
1358 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
1360 BOOLEAN CreateNewFile
[MAX_FILES
];
1362 EFI_FV_ATTRIBUTES FvAttributes
;
1363 UINT32 AuthenticationStatus
;
1366 if (NumberOfFiles
> MAX_FILES
) {
1367 return EFI_UNSUPPORTED
;
1370 Status
= EFI_SUCCESS
;
1372 SetMem (CreateNewFile
, NumberOfFiles
, TRUE
);
1374 FvDevice
= FV_DEVICE_FROM_THIS (This
);
1377 // First check the volume attributes.
1379 Status
= This
->GetVolumeAttributes (
1383 if (EFI_ERROR (Status
)) {
1387 // Can we have write right?
1389 if ((FvAttributes
& EFI_FV2_WRITE_STATUS
) == 0) {
1390 return EFI_WRITE_PROTECTED
;
1393 ErasePolarity
= FvDevice
->ErasePolarity
;
1396 // Loop for all files
1399 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1401 if ((FileData
[Index1
].BufferSize
+ sizeof (EFI_FFS_FILE_HEADER
) > 0x00FFFFFF) && !FvDevice
->IsFfs3Fv
) {
1403 // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
1405 DEBUG ((EFI_D_ERROR
, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
1406 return EFI_INVALID_PARAMETER
;
1409 if (FileData
[Index1
].BufferSize
== 0) {
1411 // Here we will delete this file
1413 Status
= This
->ReadFile (
1415 FileData
[Index1
].NameGuid
,
1420 &AuthenticationStatus
1422 if (!EFI_ERROR (Status
)) {
1429 if (FileData
[Index1
].Type
== EFI_FV_FILETYPE_FFS_PAD
) {
1431 // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
1432 // "Standard firmware file system services will not return the handle of any pad files,
1433 // nor will they permit explicit creation of such files."
1435 return EFI_INVALID_PARAMETER
;
1439 if ((NumDelete
!= NumberOfFiles
) && (NumDelete
!= 0)) {
1441 // A delete was request with a multiple file write
1443 return EFI_INVALID_PARAMETER
;
1446 if (NumDelete
== NumberOfFiles
) {
1447 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1451 Status
= FvDeleteFile (FvDevice
, FileData
[Index1
].NameGuid
);
1452 if (EFI_ERROR (Status
)) {
1460 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1461 Status
= This
->ReadFile (
1463 FileData
[Index1
].NameGuid
,
1468 &AuthenticationStatus
1470 if (!EFI_ERROR (Status
)) {
1471 CreateNewFile
[Index1
] = FALSE
;
1472 } else if (Status
== EFI_NOT_FOUND
) {
1473 CreateNewFile
[Index1
] = TRUE
;
1478 // Checking alignment
1480 if ((FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
) != 0) {
1481 UINT8 FFSAlignmentValue
;
1482 UINT8 FvAlignmentValue
;
1484 FFSAlignmentValue
= (UINT8
) (FileData
[Index1
].FileAttributes
& EFI_FV_FILE_ATTRIB_ALIGNMENT
);
1485 FvAlignmentValue
= (UINT8
) (((UINT32
) (FvAttributes
& EFI_FV2_ALIGNMENT
)) >> 16);
1487 if (FFSAlignmentValue
> FvAlignmentValue
) {
1488 return EFI_INVALID_PARAMETER
;
1493 if ((WritePolicy
!= EFI_FV_RELIABLE_WRITE
) && (WritePolicy
!= EFI_FV_UNRELIABLE_WRITE
)) {
1494 return EFI_INVALID_PARAMETER
;
1497 // Checking the reliable write is supported by FV
1500 if ((WritePolicy
== EFI_FV_RELIABLE_WRITE
) && (NumberOfFiles
> 1)) {
1502 // Only for multiple files, reliable write is meaningful
1504 Status
= FvCreateMultipleFiles (
1514 for (Index1
= 0; Index1
< NumberOfFiles
; Index1
++) {
1516 // Making Buffersize QWORD boundry, and add file tail.
1518 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
1519 ActualSize
= FileData
[Index1
].BufferSize
+ HeaderSize
;
1520 if (ActualSize
> 0x00FFFFFF) {
1521 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
1522 ActualSize
= FileData
[Index1
].BufferSize
+ HeaderSize
;
1524 BufferSize
= ActualSize
;
1526 while ((BufferSize
& 0x07) != 0) {
1530 FileBuffer
= AllocateZeroPool (BufferSize
);
1531 if (FileBuffer
== NULL
) {
1535 // Copy File Data into FileBuffer
1538 FileBuffer
+ HeaderSize
,
1539 FileData
[Index1
].Buffer
,
1540 FileData
[Index1
].BufferSize
1543 if (ErasePolarity
== 1) {
1545 // Fill the file header and padding byte with Erase Byte
1547 for (Index2
= 0; Index2
< HeaderSize
; Index2
++) {
1548 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1551 for (Index2
= ActualSize
; Index2
< BufferSize
; Index2
++) {
1552 FileBuffer
[Index2
] = (UINT8
)~FileBuffer
[Index2
];
1556 if (CreateNewFile
[Index1
]) {
1557 Status
= FvCreateNewFile (
1562 FileData
[Index1
].NameGuid
,
1563 FileData
[Index1
].Type
,
1564 FileData
[Index1
].FileAttributes
1567 Status
= FvUpdateFile (
1572 FileData
[Index1
].NameGuid
,
1573 FileData
[Index1
].Type
,
1574 FileData
[Index1
].FileAttributes
1578 FreePool (FileBuffer
);
1580 if (EFI_ERROR (Status
)) {