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