]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
IntelFrameworkModulePkg: Clean up source files
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / FwVolWrite.c
1 /** @file
2 Implements write firmware file.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5
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
11
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.
14
15 **/
16
17 #include "FwVolDriver.h"
18
19 /**
20 Calculate the checksum for the FFS header.
21
22 @param FfsHeader FFS File Header which needs to calculate the checksum
23
24 **/
25 VOID
26 SetHeaderChecksum (
27 IN EFI_FFS_FILE_HEADER *FfsHeader
28 )
29 {
30 EFI_FFS_FILE_STATE State;
31 UINT8 FileChecksum;
32
33 //
34 // The state and the File checksum are not included
35 //
36 State = FfsHeader->State;
37 FfsHeader->State = 0;
38
39 FileChecksum = FfsHeader->IntegrityCheck.Checksum.File;
40 FfsHeader->IntegrityCheck.Checksum.File = 0;
41
42 FfsHeader->IntegrityCheck.Checksum.Header = 0;
43
44 if (IS_FFS_FILE2 (FfsHeader)) {
45 FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
46 (UINT8 *) FfsHeader,
47 sizeof (EFI_FFS_FILE_HEADER2)
48 );
49 } else {
50 FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
51 (UINT8 *) FfsHeader,
52 sizeof (EFI_FFS_FILE_HEADER)
53 );
54 }
55
56 FfsHeader->State = State;
57 FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;
58
59 return ;
60 }
61
62 /**
63 Calculate the checksum for the FFS File.
64
65 @param FfsHeader FFS File Header which needs to calculate the checksum
66 @param ActualFileSize The whole Ffs File Length.
67
68 **/
69 VOID
70 SetFileChecksum (
71 IN EFI_FFS_FILE_HEADER *FfsHeader,
72 IN UINTN ActualFileSize
73 )
74 {
75 if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
76
77 FfsHeader->IntegrityCheck.Checksum.File = 0;
78
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)
83 );
84 } else {
85 FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
86 (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER),
87 ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)
88 );
89 }
90
91 } else {
92
93 FfsHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
94
95 }
96
97 return ;
98 }
99
100 /**
101 Get the alignment value from File Attributes.
102
103 @param FfsAttributes FFS attribute
104
105 @return Alignment value.
106
107 **/
108 UINTN
109 GetRequiredAlignment (
110 IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
111 )
112 {
113 UINTN AlignmentValue;
114
115 AlignmentValue = FfsAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;
116
117 if (AlignmentValue <= 3) {
118 return 0x08;
119 }
120
121 if (AlignmentValue > 16) {
122 //
123 // Anyway, we won't reach this code
124 //
125 return 0x08;
126 }
127
128 return (UINTN)1 << AlignmentValue;
129
130 }
131
132 /**
133 Calculate the leading Pad file size to meet the alignment requirement.
134
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.
139
140 @return The required Pad File Size.
141
142 **/
143 UINTN
144 CalculatePadFileSize (
145 IN FV_DEVICE *FvDevice,
146 IN EFI_PHYSICAL_ADDRESS StartAddress,
147 IN UINTN BufferSize,
148 IN UINTN RequiredAlignment
149 )
150 {
151 UINTN DataStartPos;
152 UINTN RelativePos;
153 UINTN PadSize;
154
155 if (BufferSize > 0x00FFFFFF) {
156 DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER2);
157 } else {
158 DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER);
159 }
160 RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv;
161
162 PadSize = 0;
163
164 while ((RelativePos & (RequiredAlignment - 1)) != 0) {
165 RelativePos++;
166 PadSize++;
167 }
168 //
169 // If padsize is 0, no pad file needed;
170 // If padsize is great than 24, then pad file can be created
171 //
172 if ((PadSize == 0) || (PadSize >= sizeof (EFI_FFS_FILE_HEADER))) {
173 return PadSize;
174 }
175
176 //
177 // Perhaps following method can save space
178 //
179 RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv + sizeof (EFI_FFS_FILE_HEADER);
180 PadSize = sizeof (EFI_FFS_FILE_HEADER);
181
182 while ((RelativePos & (RequiredAlignment - 1)) != 0) {
183 RelativePos++;
184 PadSize++;
185 }
186
187 return PadSize;
188 }
189
190 /**
191 Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
192
193 @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
194 @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
195
196 **/
197 VOID
198 FvFileAttrib2FfsFileAttrib (
199 IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,
200 OUT UINT8 *FfsFileAttrib
201 )
202 {
203 UINT8 FvFileAlignment;
204 UINT8 FfsFileAlignment;
205 UINT8 FfsFileAlignment2;
206
207 FvFileAlignment = (UINT8) (FvFileAttrib & EFI_FV_FILE_ATTRIB_ALIGNMENT);
208 FfsFileAlignment = 0;
209 FfsFileAlignment2 = 0;
210
211 switch (FvFileAlignment) {
212 case 0:
213 //
214 // fall through
215 //
216 case 1:
217 //
218 // fall through
219 //
220 case 2:
221 //
222 // fall through
223 //
224 case 3:
225 //
226 // fall through
227 //
228 FfsFileAlignment = 0;
229 break;
230
231 case 4:
232 //
233 // fall through
234 //
235 case 5:
236 //
237 // fall through
238 //
239 case 6:
240 //
241 // fall through
242 //
243 FfsFileAlignment = 1;
244 break;
245
246 case 7:
247 //
248 // fall through
249 //
250 case 8:
251 //
252 // fall through
253 //
254 FfsFileAlignment = 2;
255 break;
256
257 case 9:
258 FfsFileAlignment = 3;
259 break;
260
261 case 10:
262 //
263 // fall through
264 //
265 case 11:
266 //
267 // fall through
268 //
269 FfsFileAlignment = 4;
270 break;
271
272 case 12:
273 //
274 // fall through
275 //
276 case 13:
277 //
278 // fall through
279 //
280 case 14:
281 //
282 // fall through
283 //
284 FfsFileAlignment = 5;
285 break;
286
287 case 15:
288 FfsFileAlignment = 6;
289 break;
290
291 case 16:
292 FfsFileAlignment = 7;
293 break;
294
295 case 17:
296 FfsFileAlignment = 0;
297 FfsFileAlignment2 = 1;
298 break;
299 case 18:
300 FfsFileAlignment = 1;
301 FfsFileAlignment2 = 1;
302 break;
303 case 19:
304 FfsFileAlignment = 2;
305 FfsFileAlignment2 = 1;
306 break;
307 case 20:
308 FfsFileAlignment = 3;
309 FfsFileAlignment2 = 1;
310 break;
311 case 21:
312 FfsFileAlignment = 4;
313 FfsFileAlignment2 = 1;
314 break;
315 case 22:
316 FfsFileAlignment = 5;
317 FfsFileAlignment2 = 1;
318 break;
319 case 23:
320 FfsFileAlignment = 6;
321 FfsFileAlignment2 = 1;
322 break;
323 case 24:
324 FfsFileAlignment = 7;
325 FfsFileAlignment2 = 1;
326 break;
327 }
328
329 *FfsFileAttrib = (UINT8) ((FfsFileAlignment << 3) | (FfsFileAlignment2 << 1));
330
331 return ;
332 }
333
334 /**
335 Locate a free space entry that can hold this FFS file.
336
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.
342
343 @retval EFI_SUCCESS The free space entry is found.
344 @retval EFI_NOT_FOUND The free space entry can't be found.
345
346 **/
347 EFI_STATUS
348 FvLocateFreeSpaceEntry (
349 IN FV_DEVICE *FvDevice,
350 IN UINTN Size,
351 IN UINTN RequiredAlignment,
352 OUT UINTN *PadSize,
353 OUT FREE_SPACE_ENTRY **FreeSpaceEntry
354 )
355 {
356 FREE_SPACE_ENTRY *FreeSpaceListEntry;
357 LIST_ENTRY *Link;
358 UINTN PadFileSize;
359
360 Link = FvDevice->FreeSpaceHeader.ForwardLink;
361 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
362
363 //
364 // Loop the free space entry list to find one that can hold the
365 // required the file size
366 //
367 while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
368 PadFileSize = CalculatePadFileSize (
369 FvDevice,
370 (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,
371 Size,
372 RequiredAlignment
373 );
374 if (FreeSpaceListEntry->Length >= Size + PadFileSize) {
375 *FreeSpaceEntry = FreeSpaceListEntry;
376 *PadSize = PadFileSize;
377 return EFI_SUCCESS;
378 }
379
380 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
381 }
382
383 return EFI_NOT_FOUND;
384
385 }
386
387 /**
388 Locate Pad File for writing, this is got from FV Cache.
389
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.
395
396 @retval EFI_SUCCESS The required pad file is found.
397 @retval EFI_NOT_FOUND The required pad file can't be found.
398
399 **/
400 EFI_STATUS
401 FvLocatePadFile (
402 IN FV_DEVICE *FvDevice,
403 IN UINTN Size,
404 IN UINTN RequiredAlignment,
405 OUT UINTN *PadSize,
406 OUT FFS_FILE_LIST_ENTRY **PadFileEntry
407 )
408 {
409 FFS_FILE_LIST_ENTRY *FileEntry;
410 EFI_FFS_FILE_STATE FileState;
411 EFI_FFS_FILE_HEADER *FileHeader;
412 UINTN PadAreaLength;
413 UINTN PadFileSize;
414 UINTN HeaderSize;
415
416 FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
417
418 //
419 // travel through the whole file list to get the pad file entry
420 //
421 while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
422
423 FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
424 FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
425
426 if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
427 //
428 // we find one valid pad file, check its free area length
429 //
430 if (IS_FFS_FILE2 (FileHeader)) {
431 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
432 PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
433 } else {
434 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
435 PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
436 }
437
438 PadFileSize = CalculatePadFileSize (
439 FvDevice,
440 (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize,
441 Size,
442 RequiredAlignment
443 );
444 if (PadAreaLength >= (Size + PadFileSize)) {
445 *PadSize = PadFileSize;
446 *PadFileEntry = FileEntry;
447 return EFI_SUCCESS;
448 }
449 }
450
451 FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
452 }
453
454 return EFI_NOT_FOUND;
455 }
456
457 /**
458 Locate a suitable pad file for multiple file writing.
459
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.
467
468 @retval EFI_SUCCESS The required pad file is found.
469 @retval EFI_NOT_FOUND The required pad file can't be found.
470
471 **/
472 EFI_STATUS
473 FvSearchSuitablePadFile (
474 IN FV_DEVICE *FvDevice,
475 IN UINTN NumOfFiles,
476 IN UINTN *BufferSize,
477 IN UINTN *RequiredAlignment,
478 OUT UINTN *PadSize,
479 OUT UINTN *TotalSizeNeeded,
480 OUT FFS_FILE_LIST_ENTRY **PadFileEntry
481 )
482 {
483 FFS_FILE_LIST_ENTRY *FileEntry;
484 EFI_FFS_FILE_STATE FileState;
485 EFI_FFS_FILE_HEADER *FileHeader;
486 UINTN PadAreaLength;
487 UINTN TotalSize;
488 UINTN Index;
489 UINTN HeaderSize;
490
491 FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
492
493 //
494 // travel through the whole file list to get the pad file entry
495 //
496 while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
497
498 FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
499 FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
500
501 if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
502 //
503 // we find one valid pad file, check its length
504 //
505 if (IS_FFS_FILE2 (FileHeader)) {
506 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
507 PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
508 } else {
509 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
510 PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
511 }
512 TotalSize = 0;
513
514 for (Index = 0; Index < NumOfFiles; Index++) {
515 PadSize[Index] = CalculatePadFileSize (
516 FvDevice,
517 (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize + TotalSize,
518 BufferSize[Index],
519 RequiredAlignment[Index]
520 );
521 TotalSize += PadSize[Index];
522 TotalSize += BufferSize[Index];
523
524 if (TotalSize > PadAreaLength) {
525 break;
526 }
527 }
528
529 if (PadAreaLength >= TotalSize) {
530 *PadFileEntry = FileEntry;
531 *TotalSizeNeeded = TotalSize;
532 return EFI_SUCCESS;
533 }
534 }
535
536 FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
537 }
538
539 return EFI_NOT_FOUND;
540 }
541
542 /**
543 Locate a Free Space entry which can hold these files, including
544 meeting the alignment requirements.
545
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.
553
554 @retval EFI_SUCCESS The free space entry is found.
555 @retval EFI_NOT_FOUND The free space entry can't be found.
556
557 **/
558 EFI_STATUS
559 FvSearchSuitableFreeSpace (
560 IN FV_DEVICE *FvDevice,
561 IN UINTN NumOfFiles,
562 IN UINTN *BufferSize,
563 IN UINTN *RequiredAlignment,
564 OUT UINTN *PadSize,
565 OUT UINTN *TotalSizeNeeded,
566 OUT FREE_SPACE_ENTRY **FreeSpaceEntry
567 )
568 {
569 FREE_SPACE_ENTRY *FreeSpaceListEntry;
570 LIST_ENTRY *Link;
571 UINTN TotalSize;
572 UINTN Index;
573 UINT8 *StartAddr;
574
575 Link = FvDevice->FreeSpaceHeader.ForwardLink;
576
577 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
578
579 while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
580 TotalSize = 0;
581 StartAddr = FreeSpaceListEntry->StartingAddress;
582
583 //
584 // Calculate the totalsize we need
585 //
586 for (Index = 0; Index < NumOfFiles; Index++) {
587 //
588 // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
589 // have had its leading pad file.
590 //
591 PadSize[Index] = CalculatePadFileSize (
592 FvDevice,
593 (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,
594 BufferSize[Index],
595 RequiredAlignment[Index]
596 );
597
598 TotalSize += PadSize[Index];
599 TotalSize += BufferSize[Index];
600
601 if (TotalSize > FreeSpaceListEntry->Length) {
602 break;
603 }
604 }
605
606 if (FreeSpaceListEntry->Length >= TotalSize) {
607 *FreeSpaceEntry = FreeSpaceListEntry;
608 *TotalSizeNeeded = TotalSize;
609 return EFI_SUCCESS;
610 }
611
612 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
613 }
614
615 return EFI_NOT_FOUND;
616 }
617
618 /**
619 Calculate the length of the remaining space in FV.
620
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.
625
626 @return the length of remaining space.
627
628 **/
629 UINTN
630 CalculateRemainingLength (
631 IN FV_DEVICE *FvDevice,
632 IN UINTN Offset,
633 OUT EFI_LBA *Lba,
634 OUT UINTN *LOffset
635 )
636 {
637 LIST_ENTRY *Link;
638 LBA_ENTRY *LbaEntry;
639 UINTN Count;
640
641 Count = 0;
642 *Lba = 0;
643 Link = FvDevice->LbaHeader.ForwardLink;
644 LbaEntry = (LBA_ENTRY *) Link;
645
646 while (&LbaEntry->Link != &FvDevice->LbaHeader) {
647 if (Count > Offset) {
648 break;
649 }
650
651 Count += LbaEntry->BlockLength;
652 (*Lba)++;
653 Link = LbaEntry->Link.ForwardLink;
654 LbaEntry = (LBA_ENTRY *) Link;
655 }
656
657 if (Count <= Offset) {
658 return 0;
659 }
660
661 Link = LbaEntry->Link.BackLink;
662 LbaEntry = (LBA_ENTRY *) Link;
663
664 (*Lba)--;
665 *LOffset = (UINTN) (LbaEntry->BlockLength - (Count - Offset));
666
667 Count = 0;
668 while (&LbaEntry->Link != &FvDevice->LbaHeader) {
669
670 Count += LbaEntry->BlockLength;
671
672 Link = LbaEntry->Link.ForwardLink;
673 LbaEntry = (LBA_ENTRY *) Link;
674 }
675
676 Count -= *LOffset;
677
678 return Count;
679 }
680
681 /**
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
685 written.
686
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.
692
693 @retval EFI_SUCCESS Data is successfully written into FV.
694 @return error Data is failed written.
695
696 **/
697 EFI_STATUS
698 FvcWrite (
699 IN FV_DEVICE *FvDevice,
700 IN UINTN Offset,
701 IN OUT UINTN *NumBytes,
702 IN UINT8 *Buffer
703 )
704 {
705 EFI_STATUS Status;
706 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
707 EFI_LBA Lba;
708 UINTN LOffset;
709 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
710 UINTN RemainingLength;
711 UINTN WriteLength;
712 UINT8 *TmpBuffer;
713
714 LOffset = 0;
715 RemainingLength = CalculateRemainingLength (FvDevice, Offset, &Lba, &LOffset);
716 if ((UINTN) (*NumBytes) > RemainingLength) {
717 *NumBytes = (UINTN) RemainingLength;
718 return EFI_INVALID_PARAMETER;
719 }
720
721 Fvb = FvDevice->Fvb;
722
723 Status = Fvb->GetAttributes (
724 Fvb,
725 &FvbAttributes
726 );
727 if (EFI_ERROR (Status)) {
728 return Status;
729 }
730
731 if ((FvbAttributes & EFI_FV2_WRITE_STATUS) == 0) {
732 return EFI_ACCESS_DENIED;
733 }
734
735 RemainingLength = *NumBytes;
736 WriteLength = RemainingLength;
737 TmpBuffer = Buffer;
738
739 do {
740 Status = Fvb->Write (
741 Fvb,
742 Lba,
743 LOffset,
744 &WriteLength,
745 TmpBuffer
746 );
747 if (!EFI_ERROR (Status)) {
748 goto Done;
749 }
750
751 if (Status == EFI_BAD_BUFFER_SIZE) {
752 Lba++;
753 LOffset = 0;
754 TmpBuffer += WriteLength;
755 RemainingLength -= WriteLength;
756 WriteLength = (UINTN) RemainingLength;
757
758 continue;
759 } else {
760 return Status;
761 }
762 } while (1);
763
764 Done:
765 return EFI_SUCCESS;
766 }
767
768 /**
769 Create a new FFS file into Firmware Volume device.
770
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.
779
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.
784
785 **/
786 EFI_STATUS
787 FvCreateNewFile (
788 IN FV_DEVICE *FvDevice,
789 IN UINT8 *FfsFileBuffer,
790 IN UINTN BufferSize,
791 IN UINTN ActualFileSize,
792 IN EFI_GUID *FileName,
793 IN EFI_FV_FILETYPE FileType,
794 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
795 )
796 {
797 EFI_STATUS Status;
798 EFI_FFS_FILE_HEADER *FileHeader;
799 EFI_PHYSICAL_ADDRESS BufferPtr;
800 UINTN Offset;
801 UINTN NumBytesWritten;
802 UINTN StateOffset;
803 FREE_SPACE_ENTRY *FreeSpaceEntry;
804 UINTN RequiredAlignment;
805 UINTN PadFileSize;
806 FFS_FILE_LIST_ENTRY *PadFileEntry;
807 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
808 FFS_FILE_LIST_ENTRY *FfsFileEntry;
809 UINTN HeaderSize;
810
811 //
812 // File Type: 0x0E~0xE0 are reserved
813 //
814 if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
815 return EFI_INVALID_PARAMETER;
816 }
817
818 //
819 // First find a free space that can hold this image.
820 // Check alignment, FFS at least must be aligned at 8-byte boundary
821 //
822 RequiredAlignment = GetRequiredAlignment (FileAttributes);
823
824 Status = FvLocateFreeSpaceEntry (
825 FvDevice,
826 BufferSize,
827 RequiredAlignment,
828 &PadFileSize,
829 &FreeSpaceEntry
830 );
831 if (EFI_ERROR (Status)) {
832 //
833 // Maybe we need to find a PAD file that can hold this image
834 //
835 Status = FvCreateNewFileInsidePadFile (
836 FvDevice,
837 FfsFileBuffer,
838 BufferSize,
839 ActualFileSize,
840 FileName,
841 FileType,
842 FileAttributes
843 );
844
845 return Status;
846 }
847
848 BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
849
850 //
851 // If we need a leading PAD File, create it first.
852 //
853 if (PadFileSize != 0) {
854 Status = FvCreatePadFileInFreeSpace (
855 FvDevice,
856 FreeSpaceEntry,
857 PadFileSize - sizeof (EFI_FFS_FILE_HEADER),
858 &PadFileEntry
859 );
860 if (EFI_ERROR (Status)) {
861 return Status;
862 }
863 }
864 //
865 // Maybe we create a pad file, so re-get the free space starting address
866 // and length
867 //
868 BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
869
870 //
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
874 //
875 FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
876 if (ActualFileSize > 0x00FFFFFF) {
877 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
878 } else {
879 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
880 }
881 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, FileHeader);
882
883 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
884 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
885
886 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
887 Status = FvcWrite (
888 FvDevice,
889 StateOffset,
890 &NumBytesWritten,
891 &FileHeader->State
892 );
893 if (EFI_ERROR (Status)) {
894 return Status;
895 }
896 //
897 // update header 2 cache
898 //
899 CopyMem (
900 (UINT8 *) (UINTN) BufferPtr,
901 FileHeader,
902 HeaderSize
903 );
904
905 //
906 // update Free Space Entry, now need to substract the file header length
907 //
908 FreeSpaceEntry->StartingAddress += HeaderSize;
909 FreeSpaceEntry->Length -= HeaderSize;
910
911 CopyGuid (&FileHeader->Name, FileName);
912 FileHeader->Type = FileType;
913
914 //
915 // Convert FvFileAttribute to FfsFileAttributes
916 //
917 FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
918
919 FileHeader->Attributes = TmpFileAttribute;
920
921 //
922 // File size is including the FFS File Header.
923 //
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;
928 } else {
929 *(UINT32 *) FileHeader->Size &= 0xFF000000;
930 *(UINT32 *) FileHeader->Size |= ActualFileSize;
931 }
932
933 SetHeaderChecksum (FileHeader);
934
935 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
936
937 NumBytesWritten = HeaderSize;
938 Status = FvcWrite (
939 FvDevice,
940 Offset,
941 &NumBytesWritten,
942 (UINT8 *) FileHeader
943 );
944 if (EFI_ERROR (Status)) {
945 return Status;
946 }
947 //
948 // update header 2 cache
949 //
950 CopyMem (
951 (UINT8 *) (UINTN) BufferPtr,
952 FileHeader,
953 HeaderSize
954 );
955
956 //
957 // end of step 1
958 //
959 // File creation step 2:
960 // MARK EFI_FILE_HEADER_VALID bit to TRUE,
961 // Write IntegrityCheck.File, File Data
962 //
963 SetFileState (EFI_FILE_HEADER_VALID, FileHeader);
964
965 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
966 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
967
968 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
969 Status = FvcWrite (
970 FvDevice,
971 StateOffset,
972 &NumBytesWritten,
973 &FileHeader->State
974 );
975 if (EFI_ERROR (Status)) {
976 return Status;
977 }
978 //
979 // update header 2 cache
980 //
981 CopyMem (
982 (UINT8 *) (UINTN) BufferPtr,
983 FileHeader,
984 HeaderSize
985 );
986
987 //
988 // update Free Space Entry, now need to substract the file data length
989 //
990 FreeSpaceEntry->StartingAddress += (BufferSize - HeaderSize);
991 FreeSpaceEntry->Length -= (BufferSize - HeaderSize);
992
993 //
994 // Calculate File Checksum
995 //
996 SetFileChecksum (FileHeader, ActualFileSize);
997
998 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
999
1000 NumBytesWritten = BufferSize;
1001 Status = FvcWrite (
1002 FvDevice,
1003 Offset,
1004 &NumBytesWritten,
1005 FfsFileBuffer
1006 );
1007 if (EFI_ERROR (Status)) {
1008 return Status;
1009 }
1010 //
1011 // each time write block successfully, write also to cache
1012 //
1013 CopyMem (
1014 (UINT8 *) (UINTN) BufferPtr,
1015 FfsFileBuffer,
1016 NumBytesWritten
1017 );
1018
1019 //
1020 // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
1021 //
1022 SetFileState (EFI_FILE_DATA_VALID, FileHeader);
1023
1024 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
1025 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
1026
1027 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1028 Status = FvcWrite (
1029 FvDevice,
1030 StateOffset,
1031 &NumBytesWritten,
1032 &FileHeader->State
1033 );
1034 if (EFI_ERROR (Status)) {
1035 return Status;
1036 }
1037 //
1038 // update header 2 cache
1039 //
1040 CopyMem (
1041 (UINT8 *) (UINTN) BufferPtr,
1042 FileHeader,
1043 HeaderSize
1044 );
1045
1046 //
1047 // If successfully, insert an FfsFileEntry at the end of ffs file list
1048 //
1049
1050 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
1051 ASSERT (FfsFileEntry != NULL);
1052 FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) BufferPtr;
1053 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
1054
1055 //
1056 // Set cache file to this file
1057 //
1058 FvDevice->CurrentFfsFile = FfsFileEntry;
1059
1060 return EFI_SUCCESS;
1061 }
1062
1063 /**
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.
1066
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.
1075
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.
1081
1082 **/
1083 EFI_STATUS
1084 FvUpdateFile (
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
1092 )
1093 {
1094 EFI_STATUS Status;
1095 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1096 UINTN NumBytesWritten;
1097 EFI_FV_FILETYPE OldFileType;
1098 EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
1099 UINTN OldFileSize;
1100 EFI_FFS_FILE_HEADER *OldFileHeader;
1101 UINTN OldOffset;
1102 UINTN OldStateOffset;
1103 FFS_FILE_LIST_ENTRY *OldFfsFileEntry;
1104 UINTN Key;
1105 EFI_GUID FileNameGuid;
1106
1107 Fv = &FvDevice->Fv;
1108
1109 //
1110 // Step 1, find old file,
1111 // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
1112 //
1113
1114 //
1115 // Check if the file was read last time.
1116 //
1117 OldFileHeader = NULL;
1118 OldFfsFileEntry = FvDevice->CurrentFfsFile;
1119
1120 if (OldFfsFileEntry != NULL) {
1121 OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
1122 }
1123
1124 if ((OldFfsFileEntry == NULL) || (!CompareGuid (&OldFileHeader->Name, FileName))) {
1125 Key = 0;
1126 do {
1127 OldFileType = 0;
1128 Status = Fv->GetNextFile (
1129 Fv,
1130 &Key,
1131 &OldFileType,
1132 &FileNameGuid,
1133 &OldFileAttributes,
1134 &OldFileSize
1135 );
1136 if (EFI_ERROR (Status)) {
1137 return Status;
1138 }
1139 } while (!CompareGuid (&FileNameGuid, FileName));
1140
1141 //
1142 // Get FfsFileEntry from the search key
1143 //
1144 OldFfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
1145
1146 //
1147 // Double check file state before being ready to be removed
1148 //
1149 OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
1150 } else {
1151 //
1152 // Mark the cache file to invalid
1153 //
1154 FvDevice->CurrentFfsFile = NULL;
1155 }
1156 //
1157 // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
1158 //
1159 SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
1160
1161 OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
1162 OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
1163
1164 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1165 Status = FvcWrite (
1166 FvDevice,
1167 OldStateOffset,
1168 &NumBytesWritten,
1169 &OldFileHeader->State
1170 );
1171 if (EFI_ERROR (Status)) {
1172 //
1173 // if failed, write the bit back in the cache, its XOR operation.
1174 //
1175 SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
1176
1177 return Status;
1178 }
1179
1180 //
1181 // Step 2, Create New Files
1182 //
1183 Status = FvCreateNewFile (
1184 FvDevice,
1185 FfsFileBuffer,
1186 BufferSize,
1187 ActualFileSize,
1188 FileName,
1189 NewFileType,
1190 NewFileAttributes
1191 );
1192 if (EFI_ERROR (Status)) {
1193 return Status;
1194 }
1195
1196 //
1197 // If successfully, remove this file entry,
1198 // although delete file may fail.
1199 //
1200 (OldFfsFileEntry->Link.BackLink)->ForwardLink = OldFfsFileEntry->Link.ForwardLink;
1201 (OldFfsFileEntry->Link.ForwardLink)->BackLink = OldFfsFileEntry->Link.BackLink;
1202 FreePool (OldFfsFileEntry);
1203
1204 //
1205 // Step 3: Delete old files,
1206 // by marking EFI_FILE_DELETED to TRUE
1207 //
1208 SetFileState (EFI_FILE_DELETED, OldFileHeader);
1209
1210 OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
1211 OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
1212
1213 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1214 Status = FvcWrite (
1215 FvDevice,
1216 OldStateOffset,
1217 &NumBytesWritten,
1218 &OldFileHeader->State
1219 );
1220 if (EFI_ERROR (Status)) {
1221 //
1222 // if failed, write the bit back in the cache, its XOR operation.
1223 //
1224 SetFileState (EFI_FILE_DELETED, OldFileHeader);
1225
1226 return Status;
1227 }
1228
1229 return EFI_SUCCESS;
1230 }
1231
1232 /**
1233 Deleted a given file from FV device.
1234
1235 @param FvDevice Cached Firmware Volume.
1236 @param NameGuid The FFS File Name.
1237
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.
1240
1241 **/
1242 EFI_STATUS
1243 FvDeleteFile (
1244 IN FV_DEVICE *FvDevice,
1245 IN EFI_GUID *NameGuid
1246 )
1247 {
1248 EFI_STATUS Status;
1249 UINTN Key;
1250 EFI_GUID FileNameGuid;
1251 EFI_FV_FILETYPE FileType;
1252 EFI_FV_FILE_ATTRIBUTES FileAttributes;
1253 UINTN FileSize;
1254 EFI_FFS_FILE_HEADER *FileHeader;
1255 FFS_FILE_LIST_ENTRY *FfsFileEntry;
1256 EFI_FFS_FILE_STATE FileState;
1257 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1258 UINTN Offset;
1259 UINTN StateOffset;
1260 UINTN NumBytesWritten;
1261
1262 Fv = &FvDevice->Fv;
1263
1264 //
1265 // Check if the file was read last time.
1266 //
1267 FileHeader = NULL;
1268 FfsFileEntry = FvDevice->CurrentFfsFile;
1269
1270 if (FfsFileEntry != NULL) {
1271 FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
1272 }
1273
1274 if ((FfsFileEntry == NULL) || (!CompareGuid (&FileHeader->Name, NameGuid))) {
1275 //
1276 // Next search for the file using GetNextFile
1277 //
1278 Key = 0;
1279 do {
1280 FileType = 0;
1281 Status = Fv->GetNextFile (
1282 Fv,
1283 &Key,
1284 &FileType,
1285 &FileNameGuid,
1286 &FileAttributes,
1287 &FileSize
1288 );
1289 if (EFI_ERROR (Status)) {
1290 return Status;
1291 }
1292 } while (!CompareGuid (&FileNameGuid, NameGuid));
1293
1294 //
1295 // Get FfsFileEntry from the search key
1296 //
1297 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
1298
1299 //
1300 // Double check file state before being ready to be removed
1301 //
1302 FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
1303 } else {
1304 //
1305 // Mark the cache file to NULL
1306 //
1307 FvDevice->CurrentFfsFile = NULL;
1308 }
1309
1310 FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
1311
1312 if (FileState == EFI_FILE_HEADER_INVALID) {
1313 return EFI_NOT_FOUND;
1314 }
1315
1316 if (FileState == EFI_FILE_DELETED) {
1317 return EFI_NOT_FOUND;
1318 }
1319 //
1320 // Delete File: Mark EFI_FILE_DELETED to TRUE
1321 //
1322 SetFileState (EFI_FILE_DELETED, FileHeader);
1323
1324 Offset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader - FvDevice->CachedFv);
1325 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
1326
1327 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1328 Status = FvcWrite (
1329 FvDevice,
1330 StateOffset,
1331 &NumBytesWritten,
1332 &FileHeader->State
1333 );
1334 if (EFI_ERROR (Status)) {
1335 //
1336 // if failed, write the bit back in the cache, its XOR operation.
1337 //
1338 SetFileState (EFI_FILE_DELETED, FileHeader);
1339
1340 return Status;
1341 }
1342 //
1343 // If successfully, remove this file entry
1344 //
1345 FvDevice->CurrentFfsFile = NULL;
1346
1347 (FfsFileEntry->Link.BackLink)->ForwardLink = FfsFileEntry->Link.ForwardLink;
1348 (FfsFileEntry->Link.ForwardLink)->BackLink = FfsFileEntry->Link.BackLink;
1349 FreePool (FfsFileEntry);
1350
1351 return EFI_SUCCESS;
1352 }
1353
1354 /**
1355 Writes one or more files to the firmware volume.
1356
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.
1365
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.
1373
1374 **/
1375 EFI_STATUS
1376 EFIAPI
1377 FvWriteFile (
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
1382 )
1383 {
1384 EFI_STATUS Status;
1385 UINTN Index1;
1386 UINTN Index2;
1387 UINT8 *FileBuffer;
1388 UINTN BufferSize;
1389 UINTN ActualSize;
1390 UINT8 ErasePolarity;
1391 FV_DEVICE *FvDevice;
1392 EFI_FV_FILETYPE FileType;
1393 EFI_FV_FILE_ATTRIBUTES FileAttributes;
1394 UINTN Size;
1395 BOOLEAN CreateNewFile[MAX_FILES];
1396 UINTN NumDelete;
1397 EFI_FV_ATTRIBUTES FvAttributes;
1398 UINT32 AuthenticationStatus;
1399 UINTN HeaderSize;
1400
1401 if (NumberOfFiles > MAX_FILES) {
1402 return EFI_UNSUPPORTED;
1403 }
1404
1405 Status = EFI_SUCCESS;
1406
1407 SetMem (CreateNewFile, NumberOfFiles, TRUE);
1408
1409 FvDevice = FV_DEVICE_FROM_THIS (This);
1410
1411 //
1412 // First check the volume attributes.
1413 //
1414 Status = This->GetVolumeAttributes (
1415 This,
1416 &FvAttributes
1417 );
1418 if (EFI_ERROR (Status)) {
1419 return Status;
1420 }
1421 //
1422 // Can we have write right?
1423 //
1424 if ((FvAttributes & EFI_FV2_WRITE_STATUS) == 0) {
1425 return EFI_WRITE_PROTECTED;
1426 }
1427
1428 ErasePolarity = FvDevice->ErasePolarity;
1429
1430 //
1431 // Loop for all files
1432 //
1433 NumDelete = 0;
1434 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1435
1436 if ((FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER) > 0x00FFFFFF) && !FvDevice->IsFfs3Fv) {
1437 //
1438 // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
1439 //
1440 DEBUG ((EFI_D_ERROR, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
1441 return EFI_INVALID_PARAMETER;
1442 }
1443
1444 if (FileData[Index1].BufferSize == 0) {
1445 //
1446 // Here we will delete this file
1447 //
1448 Status = This->ReadFile (
1449 This,
1450 FileData[Index1].NameGuid,
1451 NULL,
1452 &Size,
1453 &FileType,
1454 &FileAttributes,
1455 &AuthenticationStatus
1456 );
1457 if (!EFI_ERROR (Status)) {
1458 NumDelete++;
1459 } else {
1460 return Status;
1461 }
1462 }
1463
1464 if (FileData[Index1].Type == EFI_FV_FILETYPE_FFS_PAD) {
1465 //
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."
1469 //
1470 return EFI_INVALID_PARAMETER;
1471 }
1472 }
1473
1474 if ((NumDelete != NumberOfFiles) && (NumDelete != 0)) {
1475 //
1476 // A delete was request with a multiple file write
1477 //
1478 return EFI_INVALID_PARAMETER;
1479 }
1480
1481 if (NumDelete == NumberOfFiles) {
1482 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1483 //
1484 // Delete Files
1485 //
1486 Status = FvDeleteFile (FvDevice, FileData[Index1].NameGuid);
1487 if (EFI_ERROR (Status)) {
1488 return Status;
1489 }
1490 }
1491
1492 return EFI_SUCCESS;
1493 }
1494
1495 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1496 Status = This->ReadFile (
1497 This,
1498 FileData[Index1].NameGuid,
1499 NULL,
1500 &Size,
1501 &FileType,
1502 &FileAttributes,
1503 &AuthenticationStatus
1504 );
1505 if (!EFI_ERROR (Status)) {
1506 CreateNewFile[Index1] = FALSE;
1507 } else if (Status == EFI_NOT_FOUND) {
1508 CreateNewFile[Index1] = TRUE;
1509 } else {
1510 return Status;
1511 }
1512 //
1513 // Checking alignment
1514 //
1515 if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) {
1516 UINT8 FFSAlignmentValue;
1517 UINT8 FvAlignmentValue;
1518
1519 FFSAlignmentValue = (UINT8) (FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT);
1520 FvAlignmentValue = (UINT8) (((UINT32) (FvAttributes & EFI_FV2_ALIGNMENT)) >> 16);
1521
1522 if (FFSAlignmentValue > FvAlignmentValue) {
1523 return EFI_INVALID_PARAMETER;
1524 }
1525 }
1526 }
1527
1528 if ((WritePolicy != EFI_FV_RELIABLE_WRITE) && (WritePolicy != EFI_FV_UNRELIABLE_WRITE)) {
1529 return EFI_INVALID_PARAMETER;
1530 }
1531 //
1532 // Checking the reliable write is supported by FV
1533 //
1534
1535 if ((WritePolicy == EFI_FV_RELIABLE_WRITE) && (NumberOfFiles > 1)) {
1536 //
1537 // Only for multiple files, reliable write is meaningful
1538 //
1539 Status = FvCreateMultipleFiles (
1540 FvDevice,
1541 NumberOfFiles,
1542 FileData,
1543 CreateNewFile
1544 );
1545
1546 return Status;
1547 }
1548
1549 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1550 //
1551 // Making Buffersize QWORD boundary, and add file tail.
1552 //
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;
1558 }
1559 BufferSize = ActualSize;
1560
1561 while ((BufferSize & 0x07) != 0) {
1562 BufferSize++;
1563 }
1564
1565 FileBuffer = AllocateZeroPool (BufferSize);
1566 if (FileBuffer == NULL) {
1567 return Status;
1568 }
1569 //
1570 // Copy File Data into FileBuffer
1571 //
1572 CopyMem (
1573 FileBuffer + HeaderSize,
1574 FileData[Index1].Buffer,
1575 FileData[Index1].BufferSize
1576 );
1577
1578 if (ErasePolarity == 1) {
1579 //
1580 // Fill the file header and padding byte with Erase Byte
1581 //
1582 for (Index2 = 0; Index2 < HeaderSize; Index2++) {
1583 FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
1584 }
1585
1586 for (Index2 = ActualSize; Index2 < BufferSize; Index2++) {
1587 FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
1588 }
1589 }
1590
1591 if (CreateNewFile[Index1]) {
1592 Status = FvCreateNewFile (
1593 FvDevice,
1594 FileBuffer,
1595 BufferSize,
1596 ActualSize,
1597 FileData[Index1].NameGuid,
1598 FileData[Index1].Type,
1599 FileData[Index1].FileAttributes
1600 );
1601 } else {
1602 Status = FvUpdateFile (
1603 FvDevice,
1604 FileBuffer,
1605 BufferSize,
1606 ActualSize,
1607 FileData[Index1].NameGuid,
1608 FileData[Index1].Type,
1609 FileData[Index1].FileAttributes
1610 );
1611 }
1612
1613 FreePool (FileBuffer);
1614
1615 if (EFI_ERROR (Status)) {
1616 return Status;
1617 }
1618 }
1619
1620 return EFI_SUCCESS;
1621 }