Home | History | Annotate | Download | only in FwVolDxe
      1 /** @file
      2   FFS file access utilities.
      3 
      4   Copyright (c) 2006 - 2011, 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 #define PHYSICAL_ADDRESS_TO_POINTER(Address)  ((VOID *) ((UINTN) Address))
     20 
     21 /**
     22   Set File State in the FfsHeader.
     23 
     24   @param  State          File state to be set into FFS header.
     25   @param  FfsHeader      Points to the FFS file header
     26 
     27 **/
     28 VOID
     29 SetFileState (
     30   IN UINT8                State,
     31   IN EFI_FFS_FILE_HEADER  *FfsHeader
     32   )
     33 {
     34   //
     35   // Set File State in the FfsHeader
     36   //
     37   FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);
     38   return ;
     39 }
     40 
     41 /**
     42   Get the FFS file state by checking the highest bit set in the header's state field.
     43 
     44   @param  ErasePolarity  Erase polarity attribute of the firmware volume
     45   @param  FfsHeader      Points to the FFS file header
     46 
     47   @return FFS File state
     48 
     49 **/
     50 EFI_FFS_FILE_STATE
     51 GetFileState (
     52   IN UINT8                ErasePolarity,
     53   IN EFI_FFS_FILE_HEADER  *FfsHeader
     54   )
     55 {
     56   EFI_FFS_FILE_STATE  FileState;
     57   UINT8               HighestBit;
     58 
     59   FileState = FfsHeader->State;
     60 
     61   if (ErasePolarity != 0) {
     62     FileState = (EFI_FFS_FILE_STATE)~FileState;
     63   }
     64 
     65   HighestBit = 0x80;
     66   while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
     67     HighestBit >>= 1;
     68   }
     69 
     70   return (EFI_FFS_FILE_STATE) HighestBit;
     71 }
     72 
     73 /**
     74   Convert the Buffer Address to LBA Entry Address.
     75 
     76   @param FvDevice        Cached FvDevice
     77   @param BufferAddress   Address of Buffer
     78   @param LbaListEntry    Pointer to the got LBA entry that contains the address.
     79 
     80   @retval EFI_NOT_FOUND  Buffer address is out of FvDevice.
     81   @retval EFI_SUCCESS    LBA entry is found for Buffer address.
     82 
     83 **/
     84 EFI_STATUS
     85 Buffer2LbaEntry (
     86   IN     FV_DEVICE              *FvDevice,
     87   IN     EFI_PHYSICAL_ADDRESS   BufferAddress,
     88   OUT LBA_ENTRY                 **LbaListEntry
     89   )
     90 {
     91   LBA_ENTRY   *LbaEntry;
     92   LIST_ENTRY  *Link;
     93 
     94   Link      = FvDevice->LbaHeader.ForwardLink;
     95   LbaEntry  = (LBA_ENTRY *) Link;
     96 
     97   //
     98   // Locate LBA which contains the address
     99   //
    100   while (&LbaEntry->Link != &FvDevice->LbaHeader) {
    101     if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {
    102       break;
    103     }
    104 
    105     Link      = LbaEntry->Link.ForwardLink;
    106     LbaEntry  = (LBA_ENTRY *) Link;
    107   }
    108 
    109   if (&LbaEntry->Link == &FvDevice->LbaHeader) {
    110     return EFI_NOT_FOUND;
    111   }
    112 
    113   Link      = LbaEntry->Link.BackLink;
    114   LbaEntry  = (LBA_ENTRY *) Link;
    115 
    116   if (&LbaEntry->Link == &FvDevice->LbaHeader) {
    117     return EFI_NOT_FOUND;
    118   }
    119 
    120   *LbaListEntry = LbaEntry;
    121 
    122   return EFI_SUCCESS;
    123 }
    124 
    125 /**
    126   Convert the Buffer Address to LBA Address & Offset.
    127 
    128   @param FvDevice        Cached FvDevice
    129   @param BufferAddress   Address of Buffer
    130   @param Lba             Pointer to the gob Lba value
    131   @param Offset          Pointer to the got Offset
    132 
    133   @retval EFI_NOT_FOUND  Buffer address is out of FvDevice.
    134   @retval EFI_SUCCESS    LBA and Offset is found for Buffer address.
    135 
    136 **/
    137 EFI_STATUS
    138 Buffer2Lba (
    139   IN     FV_DEVICE              *FvDevice,
    140   IN     EFI_PHYSICAL_ADDRESS   BufferAddress,
    141   OUT EFI_LBA                   *Lba,
    142   OUT UINTN                     *Offset
    143   )
    144 {
    145   LBA_ENTRY   *LbaEntry;
    146   EFI_STATUS  Status;
    147 
    148   LbaEntry = NULL;
    149 
    150   Status = Buffer2LbaEntry (
    151             FvDevice,
    152             BufferAddress,
    153             &LbaEntry
    154             );
    155   if (EFI_ERROR (Status)) {
    156     return Status;
    157   }
    158 
    159   *Lba    = LbaEntry->LbaIndex;
    160   *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;
    161 
    162   return EFI_SUCCESS;
    163 }
    164 
    165 /**
    166   Check if a block of buffer is erased.
    167 
    168   @param  ErasePolarity  Erase polarity attribute of the firmware volume
    169   @param  Buffer         The buffer to be checked
    170   @param  BufferSize     Size of the buffer in bytes
    171 
    172   @retval TRUE           The block of buffer is erased
    173   @retval FALSE          The block of buffer is not erased
    174 
    175 **/
    176 BOOLEAN
    177 IsBufferErased (
    178   IN UINT8    ErasePolarity,
    179   IN UINT8    *Buffer,
    180   IN UINTN    BufferSize
    181   )
    182 {
    183   UINTN Count;
    184   UINT8 EraseByte;
    185 
    186   if (ErasePolarity == 1) {
    187     EraseByte = 0xFF;
    188   } else {
    189     EraseByte = 0;
    190   }
    191 
    192   for (Count = 0; Count < BufferSize; Count++) {
    193     if (Buffer[Count] != EraseByte) {
    194       return FALSE;
    195     }
    196   }
    197 
    198   return TRUE;
    199 }
    200 
    201 /**
    202   Verify checksum of the firmware volume header.
    203 
    204   @param  FvHeader       Points to the firmware volume header to be checked
    205 
    206   @retval TRUE           Checksum verification passed
    207   @retval FALSE          Checksum verification failed
    208 
    209 **/
    210 BOOLEAN
    211 VerifyFvHeaderChecksum (
    212   IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
    213   )
    214 {
    215   UINT16  Checksum;
    216 
    217   Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);
    218 
    219   if (Checksum == 0) {
    220     return TRUE;
    221   } else {
    222     return FALSE;
    223   }
    224 }
    225 
    226 /**
    227   Verify checksum of the FFS file header.
    228 
    229   @param  FfsHeader      Points to the FFS file header to be checked
    230 
    231   @retval TRUE           Checksum verification passed
    232   @retval FALSE          Checksum verification failed
    233 
    234 **/
    235 BOOLEAN
    236 VerifyHeaderChecksum (
    237   IN EFI_FFS_FILE_HEADER  *FfsHeader
    238   )
    239 {
    240   UINT8 HeaderChecksum;
    241 
    242   if (IS_FFS_FILE2 (FfsHeader)) {
    243     HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
    244   } else {
    245     HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
    246   }
    247   HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
    248 
    249   if (HeaderChecksum == 0) {
    250     return TRUE;
    251   } else {
    252     return FALSE;
    253   }
    254 }
    255 
    256 /**
    257   Verify checksum of the FFS file data.
    258 
    259   @param  FfsHeader      Points to the FFS file header to be checked
    260 
    261   @retval TRUE           Checksum verification passed
    262   @retval FALSE          Checksum verification failed
    263 
    264 **/
    265 BOOLEAN
    266 VerifyFileChecksum (
    267   IN EFI_FFS_FILE_HEADER  *FfsHeader
    268   )
    269 {
    270   UINT8                   FileChecksum;
    271   EFI_FV_FILE_ATTRIBUTES  Attributes;
    272 
    273   Attributes = FfsHeader->Attributes;
    274 
    275   if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
    276 
    277     //
    278     // Check checksum of FFS data
    279     //
    280     if (IS_FFS_FILE2 (FfsHeader)) {
    281       FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));
    282     } else {
    283       FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));
    284     }
    285     FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);
    286 
    287     if (FileChecksum == 0) {
    288       return TRUE;
    289     } else {
    290       return FALSE;
    291     }
    292 
    293   } else {
    294 
    295     if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
    296       return FALSE;
    297     } else {
    298       return TRUE;
    299     }
    300   }
    301 
    302 }
    303 
    304 /**
    305   Check if it's a valid FFS file header.
    306 
    307   @param  ErasePolarity  Erase polarity attribute of the firmware volume
    308   @param  FfsHeader      Points to the FFS file header to be checked
    309 
    310   @retval TRUE           Valid FFS file header
    311   @retval FALSE          Invalid FFS file header
    312 
    313 **/
    314 BOOLEAN
    315 IsValidFFSHeader (
    316   IN UINT8                ErasePolarity,
    317   IN EFI_FFS_FILE_HEADER  *FfsHeader
    318   )
    319 {
    320   EFI_FFS_FILE_STATE  FileState;
    321 
    322   //
    323   // Check if it is a free space
    324   //
    325   if (IsBufferErased (
    326         ErasePolarity,
    327         (UINT8 *) FfsHeader,
    328         sizeof (EFI_FFS_FILE_HEADER)
    329         )) {
    330     return FALSE;
    331   }
    332 
    333   FileState = GetFileState (ErasePolarity, FfsHeader);
    334 
    335   switch (FileState) {
    336   case EFI_FILE_HEADER_CONSTRUCTION:
    337     //
    338     // fall through
    339     //
    340   case EFI_FILE_HEADER_INVALID:
    341     return FALSE;
    342 
    343   case EFI_FILE_HEADER_VALID:
    344     //
    345     // fall through
    346     //
    347   case EFI_FILE_DATA_VALID:
    348     //
    349     // fall through
    350     //
    351   case EFI_FILE_MARKED_FOR_UPDATE:
    352     //
    353     // fall through
    354     //
    355   case EFI_FILE_DELETED:
    356     //
    357     // Here we need to verify header checksum
    358     //
    359     if (!VerifyHeaderChecksum (FfsHeader)) {
    360       return FALSE;
    361     }
    362     break;
    363 
    364   default:
    365     //
    366     // return
    367     //
    368     return FALSE;
    369   }
    370 
    371   return TRUE;
    372 }
    373 
    374 /**
    375   Get next possible of Firmware File System Header.
    376 
    377   @param  ErasePolarity  Erase polarity attribute of the firmware volume
    378   @param  FfsHeader      Points to the FFS file header to be skipped.
    379 
    380   @return  Pointer to next FFS header.
    381 
    382 **/
    383 EFI_PHYSICAL_ADDRESS
    384 GetNextPossibleFileHeader (
    385   IN UINT8                ErasePolarity,
    386   IN EFI_FFS_FILE_HEADER  *FfsHeader
    387   )
    388 {
    389   UINT32  FileLength;
    390   UINT32  SkipLength;
    391 
    392   if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {
    393     //
    394     // Skip this header
    395     //
    396     if (IS_FFS_FILE2 (FfsHeader)) {
    397       return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2);
    398     } else {
    399       return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);
    400     }
    401   }
    402 
    403   if (IS_FFS_FILE2 (FfsHeader)) {
    404     FileLength = FFS_FILE2_SIZE (FfsHeader);
    405   } else {
    406     FileLength = FFS_FILE_SIZE (FfsHeader);
    407   }
    408 
    409   //
    410   // Since FileLength is not multiple of 8, we need skip some bytes
    411   // to get next possible header
    412   //
    413   SkipLength = FileLength;
    414   while ((SkipLength & 0x07) != 0) {
    415     SkipLength++;
    416   }
    417 
    418   return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;
    419 }
    420 
    421 /**
    422   Search FFS file with the same FFS name in FV Cache.
    423 
    424   @param  FvDevice     Cached FV image.
    425   @param  FfsHeader    Points to the FFS file header to be skipped.
    426   @param  StateBit     FFS file state bit to be checked.
    427 
    428   @return  Pointer to next found FFS header. NULL will return if no found.
    429 
    430 **/
    431 EFI_FFS_FILE_HEADER *
    432 DuplicateFileExist (
    433   IN FV_DEVICE            *FvDevice,
    434   IN EFI_FFS_FILE_HEADER  *FfsHeader,
    435   IN EFI_FFS_FILE_STATE   StateBit
    436   )
    437 {
    438   UINT8               *Ptr;
    439   EFI_FFS_FILE_HEADER *NextFfsFile;
    440 
    441   //
    442   // Search duplicate file, not from the beginning of FV,
    443   // just search the next ocurrence of this file
    444   //
    445   NextFfsFile = FfsHeader;
    446 
    447   do {
    448     Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (
    449                       GetNextPossibleFileHeader (FvDevice->ErasePolarity,
    450                       NextFfsFile)
    451                       );
    452     NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;
    453 
    454     if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <
    455         sizeof (EFI_FFS_FILE_HEADER)
    456           ) {
    457       break;
    458     }
    459 
    460     if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {
    461       continue;
    462     }
    463 
    464     if (!VerifyFileChecksum (NextFfsFile)) {
    465       continue;
    466     }
    467 
    468     if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {
    469       if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {
    470         return NextFfsFile;
    471       }
    472     }
    473   } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);
    474 
    475   return NULL;
    476 }
    477 
    478 /**
    479   Change FFS file header state and write to FV.
    480 
    481   @param  FvDevice     Cached FV image.
    482   @param  FfsHeader    Points to the FFS file header to be updated.
    483   @param  State        FFS file state to be set.
    484 
    485   @retval EFI_SUCCESS  File state is writen into FV.
    486   @retval others       File state can't be writen into FV.
    487 
    488 **/
    489 EFI_STATUS
    490 UpdateHeaderBit (
    491   IN FV_DEVICE            *FvDevice,
    492   IN EFI_FFS_FILE_HEADER  *FfsHeader,
    493   IN EFI_FFS_FILE_STATE   State
    494   )
    495 {
    496   EFI_STATUS  Status;
    497   EFI_LBA     Lba;
    498   UINTN       Offset;
    499   UINTN       NumBytesWritten;
    500 
    501   Lba    = 0;
    502   Offset = 0;
    503 
    504   SetFileState (State, FfsHeader);
    505 
    506   Buffer2Lba (
    507     FvDevice,
    508     (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),
    509     &Lba,
    510     &Offset
    511     );
    512   //
    513   // Write the state byte into FV
    514   //
    515   NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
    516   Status = FvDevice->Fvb->Write (
    517                             FvDevice->Fvb,
    518                             Lba,
    519                             Offset,
    520                             &NumBytesWritten,
    521                             &FfsHeader->State
    522                             );
    523   return Status;
    524 }
    525 
    526 /**
    527   Check if it's a valid FFS file.
    528   Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
    529 
    530   @param  FvDevice       Cached FV image.
    531   @param  FfsHeader      Points to the FFS file to be checked
    532 
    533   @retval TRUE           Valid FFS file
    534   @retval FALSE          Invalid FFS file
    535 
    536 **/
    537 BOOLEAN
    538 IsValidFFSFile (
    539   IN FV_DEVICE            *FvDevice,
    540   IN EFI_FFS_FILE_HEADER  *FfsHeader
    541   )
    542 {
    543   EFI_FFS_FILE_STATE  FileState;
    544   UINT8               ErasePolarity;
    545 
    546   ErasePolarity = FvDevice->ErasePolarity;
    547 
    548   FileState     = GetFileState (ErasePolarity, FfsHeader);
    549 
    550   switch (FileState) {
    551   case EFI_FILE_DATA_VALID:
    552     if (!VerifyFileChecksum (FfsHeader)) {
    553       return FALSE;
    554     }
    555 
    556     if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
    557       break;
    558     }
    559     //
    560     // Check if there is another duplicated file with the EFI_FILE_DATA_VALID
    561     //
    562     if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
    563       return FALSE;
    564     }
    565 
    566     break;
    567 
    568   case EFI_FILE_MARKED_FOR_UPDATE:
    569     if (!VerifyFileChecksum (FfsHeader)) {
    570       return FALSE;
    571     }
    572 
    573     if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
    574       //
    575       // since its data area is not unperturbed, it cannot be reclaimed,
    576       // marked it as deleted
    577       //
    578       UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
    579       return TRUE;
    580 
    581     } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
    582       //
    583       // Here the found file is more recent than this file,
    584       // mark it as deleted
    585       //
    586       UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
    587       return TRUE;
    588 
    589     } else {
    590       return TRUE;
    591     }
    592 
    593     break;
    594 
    595   case EFI_FILE_DELETED:
    596     if (!VerifyFileChecksum (FfsHeader)) {
    597       return FALSE;
    598     }
    599 
    600     break;
    601 
    602   default:
    603     return FALSE;
    604   }
    605 
    606   return TRUE;
    607 }
    608 
    609