2 Implements functions to pad 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 Calculate the checksum for a PAD file.
22 @param PadFileHeader The Pad File to be caculeted the checksum.
27 IN EFI_FFS_FILE_HEADER
*PadFileHeader
32 if ((PadFileHeader
->Attributes
& FFS_ATTRIB_CHECKSUM
) != 0) {
34 PadFileLength
= *(UINT32
*) PadFileHeader
->Size
& 0x00FFFFFF;
37 // Calculate checksum of Pad File Data
39 PadFileHeader
->IntegrityCheck
.Checksum
.File
=
40 CalculateCheckSum8 ((UINT8
*) PadFileHeader
+ sizeof (EFI_FFS_FILE_HEADER
), PadFileLength
- sizeof (EFI_FFS_FILE_HEADER
));
44 PadFileHeader
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
52 Create a PAD File in the Free Space.
54 @param FvDevice Firmware Volume Device.
55 @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.
56 @param Size Pad file Size, not include the header.
57 @param PadFileEntry The Ffs File Entry that points to this Pad File.
59 @retval EFI_SUCCESS Successfully create a PAD file.
60 @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.
61 @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.
62 @retval EFI_DEVICE_ERROR Free space is not erased.
65 FvCreatePadFileInFreeSpace (
66 IN FV_DEVICE
*FvDevice
,
67 IN FREE_SPACE_ENTRY
*FreeSpaceEntry
,
69 OUT FFS_FILE_LIST_ENTRY
**PadFileEntry
73 EFI_FFS_FILE_HEADER
*PadFileHeader
;
75 UINTN NumBytesWritten
;
78 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
80 if (FreeSpaceEntry
->Length
< Size
+ sizeof (EFI_FFS_FILE_HEADER
)) {
81 return EFI_OUT_OF_RESOURCES
;
84 if ((Size
& 0x07) != 0) {
85 return EFI_INVALID_PARAMETER
;
88 StartPos
= FreeSpaceEntry
->StartingAddress
;
91 // First double check the space
94 FvDevice
->ErasePolarity
,
96 Size
+ sizeof (EFI_FFS_FILE_HEADER
)
98 return EFI_DEVICE_ERROR
;
101 PadFileHeader
= (EFI_FFS_FILE_HEADER
*) StartPos
;
104 // Create File Step 1
106 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, PadFileHeader
);
108 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
109 StateOffset
= Offset
+ (UINT8
*) &PadFileHeader
->State
- (UINT8
*) PadFileHeader
;
111 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
116 &PadFileHeader
->State
118 if (EFI_ERROR (Status
)) {
119 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, PadFileHeader
);
123 // Update Free Space Entry, since header is allocated
125 FreeSpaceEntry
->Length
-= sizeof (EFI_FFS_FILE_HEADER
);
126 FreeSpaceEntry
->StartingAddress
+= sizeof (EFI_FFS_FILE_HEADER
);
129 // Fill File Name Guid, here we assign a NULL-GUID to Pad files
131 ZeroMem (&PadFileHeader
->Name
, sizeof (EFI_GUID
));
134 // Fill File Type, checksum(0), Attributes(0), Size
136 PadFileHeader
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
137 PadFileHeader
->Attributes
= 0;
138 *(UINT32
*) PadFileHeader
->Size
&= 0xFF000000;
139 *(UINT32
*) PadFileHeader
->Size
|= (Size
+ sizeof (EFI_FFS_FILE_HEADER
));
141 SetHeaderChecksum (PadFileHeader
);
142 SetPadFileChecksum (PadFileHeader
);
144 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
146 NumBytesWritten
= sizeof (EFI_FFS_FILE_HEADER
);
151 (UINT8
*) PadFileHeader
153 if (EFI_ERROR (Status
)) {
158 // Step 2, then Mark header valid, since no data write,
159 // mark the data valid at the same time.
161 SetFileState (EFI_FILE_HEADER_VALID
, PadFileHeader
);
162 SetFileState (EFI_FILE_DATA_VALID
, PadFileHeader
);
164 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
165 StateOffset
= Offset
+ (UINT8
*) &PadFileHeader
->State
- (UINT8
*) PadFileHeader
;
167 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
172 &PadFileHeader
->State
174 if (EFI_ERROR (Status
)) {
175 SetFileState (EFI_FILE_HEADER_VALID
, PadFileHeader
);
176 SetFileState (EFI_FILE_DATA_VALID
, PadFileHeader
);
180 // Update Free Space Entry, since header is allocated
182 FreeSpaceEntry
->Length
-= Size
;
183 FreeSpaceEntry
->StartingAddress
+= Size
;
186 // If successfully, insert an FfsFileEntry at the end of ffs file list
188 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
189 ASSERT (FfsFileEntry
!= NULL
);
191 FfsFileEntry
->FfsHeader
= (UINT8
*) (UINTN
) StartPos
;
192 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
194 *PadFileEntry
= FfsFileEntry
;
195 FvDevice
->CurrentFfsFile
= FfsFileEntry
;
201 Fill pad file header within firmware cache.
203 @param PadFileHeader The start of the Pad File Buffer.
204 @param PadFileLength The length of the pad file including the header.
209 IN EFI_FFS_FILE_HEADER
*PadFileHeader
,
210 IN UINTN PadFileLength
214 // Fill File Name Guid, here we assign a NULL-GUID to Pad files
216 ZeroMem (&PadFileHeader
->Name
, sizeof (EFI_GUID
));
219 // Fill File Type, checksum(0), Attributes(0), Size
221 PadFileHeader
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
222 PadFileHeader
->Attributes
= 0;
223 *(UINT32
*) PadFileHeader
->Size
&= 0xFF000000;
224 *(UINT32
*) PadFileHeader
->Size
|= PadFileLength
;
226 SetHeaderChecksum (PadFileHeader
);
227 SetPadFileChecksum (PadFileHeader
);
230 // Set File State to 0x00000111
232 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, PadFileHeader
);
233 SetFileState (EFI_FILE_HEADER_VALID
, PadFileHeader
);
234 SetFileState (EFI_FILE_DATA_VALID
, PadFileHeader
);
240 Create entire FFS file.
242 @param FileHeader Starting Address of a Buffer that hold the FFS File image.
243 @param FfsFileBuffer The source buffer that contains the File Data.
244 @param BufferSize The length of FfsFileBuffer.
245 @param ActualFileSize Size of FFS file.
246 @param FileName The Guid of Ffs File.
247 @param FileType The type of the written Ffs File.
248 @param FileAttributes The attributes of the written Ffs File.
250 @retval EFI_INVALID_PARAMETER File type is not valid.
251 @retval EFI_SUCCESS FFS file is successfully created.
256 OUT EFI_FFS_FILE_HEADER
*FileHeader
,
257 IN UINT8
*FfsFileBuffer
,
259 IN UINTN ActualFileSize
,
260 IN EFI_GUID
*FileName
,
261 IN EFI_FV_FILETYPE FileType
,
262 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
265 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute
;
266 EFI_FFS_FILE_HEADER
*TmpFileHeader
;
269 // File Type value 0x0E~0xE0 are reserved
271 if ((FileType
> EFI_FV_FILETYPE_SMM_CORE
) && (FileType
< 0xE0)) {
272 return EFI_INVALID_PARAMETER
;
275 TmpFileHeader
= (EFI_FFS_FILE_HEADER
*) FfsFileBuffer
;
277 // First fill all fields ready in FfsFileBuffer
279 CopyGuid (&TmpFileHeader
->Name
, FileName
);
280 TmpFileHeader
->Type
= FileType
;
283 // Convert the FileAttributes to FFSFileAttributes
285 FvFileAttrib2FfsFileAttrib (FileAttributes
, &TmpFileAttribute
);
287 TmpFileHeader
->Attributes
= TmpFileAttribute
;
289 *(UINT32
*) TmpFileHeader
->Size
&= 0xFF000000;
290 *(UINT32
*) TmpFileHeader
->Size
|= ActualFileSize
;
292 SetHeaderChecksum (TmpFileHeader
);
293 SetFileChecksum (TmpFileHeader
, ActualFileSize
);
295 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, TmpFileHeader
);
296 SetFileState (EFI_FILE_HEADER_VALID
, TmpFileHeader
);
297 SetFileState (EFI_FILE_DATA_VALID
, TmpFileHeader
);
300 // Copy data from FfsFileBuffer to FileHeader(cache)
302 CopyMem (FileHeader
, FfsFileBuffer
, BufferSize
);
308 Fill some other extra space using 0xFF(Erase Value).
310 @param ErasePolarity Fv erase value.
311 @param FileHeader Point to the start of FFS File.
312 @param ExtraLength The pading length.
317 IN UINT8 ErasePolarity
,
318 IN EFI_FFS_FILE_HEADER
*FileHeader
,
326 FileLength
= *(UINT32
*) FileHeader
->Size
& 0x00FFFFFF;
327 Ptr
= (UINT8
*) FileHeader
+ FileLength
;
329 if (ErasePolarity
== 0) {
335 // Fill the non-used space with Padding Byte
337 SetMem (Ptr
, ExtraLength
, PadingByte
);
343 Free File List entry pointed by FileListHead.
345 @param FileListHeader FileListEntry Header.
350 IN LIST_ENTRY
*FileListHead
353 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
354 LIST_ENTRY
*NextEntry
;
356 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) (FileListHead
->ForwardLink
);
359 // Loop the whole list entry to free resources
361 while (&FfsFileEntry
->Link
!= FileListHead
) {
362 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
363 FreePool (FfsFileEntry
);
364 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
371 Create a new file within a PAD file area.
373 @param FvDevice Firmware Volume Device.
374 @param FfsFileBuffer A buffer that holds an FFS file,(it contains a File Header which is in init state).
375 @param BufferSize The size of FfsFileBuffer.
376 @param ActualFileSize The actual file length, it may not be multiples of 8.
377 @param FileName The FFS File Name.
378 @param FileType The FFS File Type.
379 @param FileAttributes The Attributes of the FFS File to be created.
381 @retval EFI_SUCCESS Successfully create a new file within the found PAD file area.
382 @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.
383 @retval other errors New file is created failed.
387 FvCreateNewFileInsidePadFile (
388 IN FV_DEVICE
*FvDevice
,
389 IN UINT8
*FfsFileBuffer
,
391 IN UINTN ActualFileSize
,
392 IN EFI_GUID
*FileName
,
393 IN EFI_FV_FILETYPE FileType
,
394 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
397 UINTN RequiredAlignment
;
398 FFS_FILE_LIST_ENTRY
*PadFileEntry
;
402 EFI_FFS_FILE_HEADER
*FileHeader
;
403 EFI_FFS_FILE_HEADER
*OldPadFileHeader
;
404 EFI_FFS_FILE_HEADER
*PadFileHeader
;
405 EFI_FFS_FILE_HEADER
*TailPadFileHeader
;
408 UINTN NumBytesWritten
;
410 LIST_ENTRY NewFileList
;
411 FFS_FILE_LIST_ENTRY
*NewFileListEntry
;
412 FFS_FILE_LIST_ENTRY
*FfsEntry
;
413 FFS_FILE_LIST_ENTRY
*NextFfsEntry
;
416 // First get the required alignment from the File Attributes
418 RequiredAlignment
= GetRequiredAlignment (FileAttributes
);
421 // Find a suitable PAD File
423 Status
= FvLocatePadFile (
431 if (EFI_ERROR (Status
)) {
432 return EFI_OUT_OF_RESOURCES
;
435 OldPadFileHeader
= (EFI_FFS_FILE_HEADER
*) PadFileEntry
->FfsHeader
;
438 // Step 1: Update Pad File Header
440 SetFileState (EFI_FILE_MARKED_FOR_UPDATE
, OldPadFileHeader
);
442 StartPos
= PadFileEntry
->FfsHeader
;
444 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
445 StateOffset
= Offset
+ (UINT8
*) &OldPadFileHeader
->State
- (UINT8
*) OldPadFileHeader
;
447 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
452 &OldPadFileHeader
->State
454 if (EFI_ERROR (Status
)) {
455 SetFileState (EFI_FILE_HEADER_CONSTRUCTION
, OldPadFileHeader
);
460 // Step 2: Update Pad area
462 InitializeListHead (&NewFileList
);
464 PadAreaLength
= (*(UINT32
*) OldPadFileHeader
->Size
& 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER
);
466 PadFileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) OldPadFileHeader
+ sizeof (EFI_FFS_FILE_HEADER
));
468 if (RequiredAlignment
!= 8) {
470 // Insert a PAD file before to achieve required alignment
472 FvFillPadFile (PadFileHeader
, PadSize
);
473 NewFileListEntry
= AllocatePool (sizeof (FFS_FILE_LIST_ENTRY
));
474 ASSERT (NewFileListEntry
!= NULL
);
475 NewFileListEntry
->FfsHeader
= (UINT8
*) PadFileHeader
;
476 InsertTailList (&NewFileList
, &NewFileListEntry
->Link
);
479 FileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) PadFileHeader
+ PadSize
);
481 Status
= FvFillFfsFile (
490 if (EFI_ERROR (Status
)) {
494 NewFileListEntry
= AllocatePool (sizeof (FFS_FILE_LIST_ENTRY
));
495 ASSERT (NewFileListEntry
!= NULL
);
497 NewFileListEntry
->FfsHeader
= (UINT8
*) FileHeader
;
498 InsertTailList (&NewFileList
, &NewFileListEntry
->Link
);
500 FvDevice
->CurrentFfsFile
= NewFileListEntry
;
502 if (PadAreaLength
> (BufferSize
+ PadSize
)) {
503 if ((PadAreaLength
- BufferSize
- PadSize
) >= sizeof (EFI_FFS_FILE_HEADER
)) {
505 // we can insert another PAD file
507 TailPadFileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FileHeader
+ BufferSize
);
508 FvFillPadFile (TailPadFileHeader
, PadAreaLength
- BufferSize
- PadSize
);
510 NewFileListEntry
= AllocatePool (sizeof (FFS_FILE_LIST_ENTRY
));
511 ASSERT (NewFileListEntry
!= NULL
);
513 NewFileListEntry
->FfsHeader
= (UINT8
*) TailPadFileHeader
;
514 InsertTailList (&NewFileList
, &NewFileListEntry
->Link
);
517 // because left size cannot hold another PAD file header,
518 // adjust the writing file size (just in cache)
521 FvDevice
->ErasePolarity
,
523 PadAreaLength
- BufferSize
- PadSize
528 // Start writing to FV
530 StartPos
= (UINT8
*) OldPadFileHeader
+ sizeof (EFI_FFS_FILE_HEADER
);
532 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
534 NumBytesWritten
= PadAreaLength
;
541 if (EFI_ERROR (Status
)) {
542 FreeFileList (&NewFileList
);
547 // Step 3: Mark Pad file header as EFI_FILE_HEADER_INVALID
549 SetFileState (EFI_FILE_HEADER_INVALID
, OldPadFileHeader
);
551 StartPos
= PadFileEntry
->FfsHeader
;
553 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
554 StateOffset
= Offset
+ (UINT8
*) &OldPadFileHeader
->State
- (UINT8
*) OldPadFileHeader
;
556 NumBytesWritten
= sizeof (EFI_FFS_FILE_STATE
);
561 &OldPadFileHeader
->State
563 if (EFI_ERROR (Status
)) {
564 SetFileState (EFI_FILE_HEADER_INVALID
, OldPadFileHeader
);
569 // If all successfully, update FFS_FILE_LIST
573 // Delete old pad file entry
575 FfsEntry
= (FFS_FILE_LIST_ENTRY
*) PadFileEntry
->Link
.BackLink
;
576 NextFfsEntry
= (FFS_FILE_LIST_ENTRY
*) PadFileEntry
->Link
.ForwardLink
;
578 FreePool (PadFileEntry
);
580 FfsEntry
->Link
.ForwardLink
= NewFileList
.ForwardLink
;
581 (NewFileList
.ForwardLink
)->BackLink
= &FfsEntry
->Link
;
582 NextFfsEntry
->Link
.BackLink
= NewFileList
.BackLink
;
583 (NewFileList
.BackLink
)->ForwardLink
= &NextFfsEntry
->Link
;
591 @param NumOfFiles Number of FfsBuffer.
592 @param FfsBuffer An array of pointer to an FFS File Buffer
602 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
603 if (FfsBuffer
[Index
] != NULL
) {
604 FreePool (FfsBuffer
[Index
]);
610 Create multiple files within a PAD File area.
612 @param FvDevice Firmware Volume Device.
613 @param PadFileEntry The pad file entry to be written in.
614 @param NumOfFiles Total File number to be written.
615 @param BufferSize The array of buffer size of each FfsBuffer.
616 @param ActualFileSize The array of actual file size.
617 @param PadSize The array of leading pad file size for each FFS File
618 @param FfsBuffer The array of Ffs Buffer pointer.
619 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
620 used to get name, attributes, type, etc.
622 @retval EFI_SUCCESS Add the input multiple files into PAD file area.
623 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
624 @retval other error Files can't be added into PAD file area.
628 FvCreateMultipleFilesInsidePadFile (
629 IN FV_DEVICE
*FvDevice
,
630 IN FFS_FILE_LIST_ENTRY
*PadFileEntry
,
632 IN UINTN
*BufferSize
,
633 IN UINTN
*ActualFileSize
,
635 IN UINT8
**FfsBuffer
,
636 IN EFI_FV_WRITE_FILE_DATA
*FileData
640 EFI_FFS_FILE_HEADER
*OldPadFileHeader
;
642 EFI_FFS_FILE_HEADER
*PadFileHeader
;
643 EFI_FFS_FILE_HEADER
*FileHeader
;
644 EFI_FFS_FILE_HEADER
*TailPadFileHeader
;
647 LIST_ENTRY NewFileList
;
648 FFS_FILE_LIST_ENTRY
*NewFileListEntry
;
650 UINTN NumBytesWritten
;
652 FFS_FILE_LIST_ENTRY
*FfsEntry
;
653 FFS_FILE_LIST_ENTRY
*NextFfsEntry
;
655 InitializeListHead (&NewFileList
);
657 NewFileListEntry
= NULL
;
659 OldPadFileHeader
= (EFI_FFS_FILE_HEADER
*) PadFileEntry
->FfsHeader
;
660 PadAreaLength
= (*(UINT32
*) OldPadFileHeader
->Size
& 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER
);
662 Status
= UpdateHeaderBit (
665 EFI_FILE_MARKED_FOR_UPDATE
667 if (EFI_ERROR (Status
)) {
674 PadFileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) OldPadFileHeader
+ sizeof (EFI_FFS_FILE_HEADER
));
675 FileHeader
= PadFileHeader
;
677 for (Index
= 0; Index
< NumOfFiles
; Index
++) {
678 if (PadSize
[Index
] != 0) {
679 FvFillPadFile (PadFileHeader
, PadSize
[Index
]);
680 NewFileListEntry
= AllocatePool (sizeof (FFS_FILE_LIST_ENTRY
));
681 if (NewFileListEntry
== NULL
) {
682 return EFI_OUT_OF_RESOURCES
;
685 NewFileListEntry
->FfsHeader
= (UINT8
*) PadFileHeader
;
686 InsertTailList (&NewFileList
, &NewFileListEntry
->Link
);
689 FileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) PadFileHeader
+ PadSize
[Index
]);
690 Status
= FvFillFfsFile (
694 ActualFileSize
[Index
],
695 FileData
[Index
].NameGuid
,
696 FileData
[Index
].Type
,
697 FileData
[Index
].FileAttributes
699 if (EFI_ERROR (Status
)) {
703 NewFileListEntry
= AllocatePool (sizeof (FFS_FILE_LIST_ENTRY
));
704 if (NewFileListEntry
== NULL
) {
705 FreeFileList (&NewFileList
);
706 return EFI_OUT_OF_RESOURCES
;
709 NewFileListEntry
->FfsHeader
= (UINT8
*) FileHeader
;
710 InsertTailList (&NewFileList
, &NewFileListEntry
->Link
);
712 PadFileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FileHeader
+ BufferSize
[Index
]);
713 TotalSize
+= PadSize
[Index
];
714 TotalSize
+= BufferSize
[Index
];
717 FvDevice
->CurrentFfsFile
= NewFileListEntry
;
719 // Maybe we need a tail pad file
721 if (PadAreaLength
> TotalSize
) {
722 if ((PadAreaLength
- TotalSize
) >= sizeof (EFI_FFS_FILE_HEADER
)) {
724 // we can insert another PAD file
726 TailPadFileHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FileHeader
+ BufferSize
[NumOfFiles
- 1]);
727 FvFillPadFile (TailPadFileHeader
, PadAreaLength
- TotalSize
);
729 NewFileListEntry
= AllocatePool (sizeof (FFS_FILE_LIST_ENTRY
));
730 if (NewFileListEntry
== NULL
) {
731 FreeFileList (&NewFileList
);
732 return EFI_OUT_OF_RESOURCES
;
735 NewFileListEntry
->FfsHeader
= (UINT8
*) TailPadFileHeader
;
736 InsertTailList (&NewFileList
, &NewFileListEntry
->Link
);
739 // because left size cannot hold another PAD file header,
740 // adjust the writing file size (just in cache)
743 FvDevice
->ErasePolarity
,
745 PadAreaLength
- TotalSize
750 // Start writing to FV
752 StartPos
= (UINT8
*) OldPadFileHeader
+ sizeof (EFI_FFS_FILE_HEADER
);
754 Offset
= (UINTN
) (StartPos
- FvDevice
->CachedFv
);
756 NumBytesWritten
= PadAreaLength
;
763 if (EFI_ERROR (Status
)) {
764 FreeFileList (&NewFileList
);
768 Status
= UpdateHeaderBit (
771 EFI_FILE_HEADER_INVALID
773 if (EFI_ERROR (Status
)) {
774 FreeFileList (&NewFileList
);
779 // Update File List Link
783 // First delete old pad file entry
785 FfsEntry
= (FFS_FILE_LIST_ENTRY
*) PadFileEntry
->Link
.BackLink
;
786 NextFfsEntry
= (FFS_FILE_LIST_ENTRY
*) PadFileEntry
->Link
.ForwardLink
;
788 FreePool (PadFileEntry
);
790 FfsEntry
->Link
.ForwardLink
= NewFileList
.ForwardLink
;
791 (NewFileList
.ForwardLink
)->BackLink
= &FfsEntry
->Link
;
792 NextFfsEntry
->Link
.BackLink
= NewFileList
.BackLink
;
793 (NewFileList
.BackLink
)->ForwardLink
= &NextFfsEntry
->Link
;
799 Write multiple files into FV in reliable method.
801 @param FvDevice Firmware Volume Device.
802 @param NumOfFiles Total File number to be written.
803 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
804 used to get name, attributes, type, etc
805 @param FileOperation The array of operation for each file.
807 @retval EFI_SUCCESS Files are added into FV.
808 @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.
809 @retval EFI_INVALID_PARAMETER File number is less than or equal to 1.
810 @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.
814 FvCreateMultipleFiles (
815 IN FV_DEVICE
*FvDevice
,
817 IN EFI_FV_WRITE_FILE_DATA
*FileData
,
818 IN BOOLEAN
*FileOperation
822 UINT8
*FfsBuffer
[MAX_FILES
];
825 UINTN BufferSize
[MAX_FILES
];
826 UINTN ActualFileSize
[MAX_FILES
];
827 UINTN RequiredAlignment
[MAX_FILES
];
828 UINTN PadSize
[MAX_FILES
];
829 FFS_FILE_LIST_ENTRY
*PadFileEntry
;
830 UINTN TotalSizeNeeded
;
831 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
832 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
834 EFI_GUID FileNameGuid
;
835 EFI_FV_FILETYPE OldFileType
;
836 EFI_FV_FILE_ATTRIBUTES OldFileAttributes
;
838 FFS_FILE_LIST_ENTRY
*OldFfsFileEntry
[MAX_FILES
];
839 EFI_FFS_FILE_HEADER
*OldFileHeader
[MAX_FILES
];
840 BOOLEAN IsCreateFile
;
843 // To use this function, we must ensure that the NumOfFiles is great
846 if (NumOfFiles
<= 1) {
847 return EFI_INVALID_PARAMETER
;
850 if (NumOfFiles
> MAX_FILES
) {
851 return EFI_UNSUPPORTED
;
856 SetMem (FfsBuffer
, NumOfFiles
, 0);
857 SetMem (RequiredAlignment
, NumOfFiles
, 8);
858 SetMem (PadSize
, NumOfFiles
, 0);
859 ZeroMem (OldFfsFileEntry
, sizeof (OldFfsFileEntry
));
860 ZeroMem (OldFileHeader
, sizeof (OldFileHeader
));
865 for (Index1
= 0; Index1
< NumOfFiles
; Index1
++) {
866 ActualFileSize
[Index1
] = FileData
[Index1
].BufferSize
+ sizeof (EFI_FFS_FILE_HEADER
);
867 BufferSize
[Index1
] = ActualFileSize
[Index1
];
869 if (BufferSize
[Index1
] == sizeof (EFI_FFS_FILE_HEADER
)) {
871 // clear file attributes, zero-length file does not have any attributes
873 FileData
[Index1
].FileAttributes
= 0;
876 while ((BufferSize
[Index1
] & 0x07) != 0) {
877 BufferSize
[Index1
]++;
880 FfsBuffer
[Index1
] = AllocateZeroPool (BufferSize
[Index1
]);
883 // Copy File Data into FileBuffer
886 FfsBuffer
[Index1
] + sizeof (EFI_FFS_FILE_HEADER
),
887 FileData
[Index1
].Buffer
,
888 FileData
[Index1
].BufferSize
891 if (FvDevice
->ErasePolarity
== 1) {
892 for (Index2
= 0; Index2
< sizeof (EFI_FFS_FILE_HEADER
); Index2
++) {
893 FfsBuffer
[Index1
][Index2
] = (UINT8
)~FfsBuffer
[Index1
][Index2
];
897 if ((FileData
[Index1
].FileAttributes
& FFS_ATTRIB_DATA_ALIGNMENT
) != 0) {
898 RequiredAlignment
[Index1
] = GetRequiredAlignment (FileData
[Index1
].FileAttributes
);
901 // If update file, mark the original file header to
902 // EFI_FILE_MARKED_FOR_UPDATE
904 IsCreateFile
= FileOperation
[Index1
];
910 Status
= Fv
->GetNextFile (
918 if (EFI_ERROR (Status
)) {
919 FreeFfsBuffer (NumOfFiles
, FfsBuffer
);
922 } while (!CompareGuid (&FileNameGuid
, FileData
[Index1
].NameGuid
));
925 // Get FfsFileEntry from the search key
927 OldFfsFileEntry
[Index1
] = (FFS_FILE_LIST_ENTRY
*) Key
;
928 OldFileHeader
[Index1
] = (EFI_FFS_FILE_HEADER
*) OldFfsFileEntry
[Index1
]->FfsHeader
;
929 Status
= UpdateHeaderBit (
931 OldFileHeader
[Index1
],
932 EFI_FILE_MARKED_FOR_UPDATE
934 if (EFI_ERROR (Status
)) {
935 FreeFfsBuffer (NumOfFiles
, FfsBuffer
);
941 // First to search a suitable pad file that can hold so
944 Status
= FvSearchSuitablePadFile (
954 if (Status
== EFI_NOT_FOUND
) {
956 // Try to find a free space that can hold these files
957 // and create a suitable PAD file in this free space
959 Status
= FvSearchSuitableFreeSpace (
968 if (EFI_ERROR (Status
)) {
969 FreeFfsBuffer (NumOfFiles
, FfsBuffer
);
970 return EFI_OUT_OF_RESOURCES
;
973 // Create a PAD file in that space
975 Status
= FvCreatePadFileInFreeSpace (
982 if (EFI_ERROR (Status
)) {
983 FreeFfsBuffer (NumOfFiles
, FfsBuffer
);
988 // Create multiple files inside such a pad file
989 // to achieve lock-step update
991 Status
= FvCreateMultipleFilesInsidePadFile (
1002 FreeFfsBuffer (NumOfFiles
, FfsBuffer
);
1004 if (EFI_ERROR (Status
)) {
1008 // Delete those updated files
1010 for (Index1
= 0; Index1
< NumOfFiles
; Index1
++) {
1011 IsCreateFile
= FileOperation
[Index1
];
1012 if (!IsCreateFile
&& OldFfsFileEntry
[Index1
] != NULL
) {
1013 (OldFfsFileEntry
[Index1
]->Link
.BackLink
)->ForwardLink
= OldFfsFileEntry
[Index1
]->Link
.ForwardLink
;
1014 (OldFfsFileEntry
[Index1
]->Link
.ForwardLink
)->BackLink
= OldFfsFileEntry
[Index1
]->Link
.BackLink
;
1015 FreePool (OldFfsFileEntry
[Index1
]);
1019 // Set those files' state to EFI_FILE_DELETED
1021 for (Index1
= 0; Index1
< NumOfFiles
; Index1
++) {
1022 IsCreateFile
= FileOperation
[Index1
];
1023 if (!IsCreateFile
&& OldFileHeader
[Index1
] != NULL
) {
1024 Status
= UpdateHeaderBit (FvDevice
, OldFileHeader
[Index1
], EFI_FILE_DELETED
);
1025 if (EFI_ERROR (Status
)) {