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