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
SetFileState(IN UINT8 State,IN EFI_FFS_FILE_HEADER * FfsHeader)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
GetFileState(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)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
Buffer2LbaEntry(IN FV_DEVICE * FvDevice,IN EFI_PHYSICAL_ADDRESS BufferAddress,OUT LBA_ENTRY ** LbaListEntry)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
Buffer2Lba(IN FV_DEVICE * FvDevice,IN EFI_PHYSICAL_ADDRESS BufferAddress,OUT EFI_LBA * Lba,OUT UINTN * Offset)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
IsBufferErased(IN UINT8 ErasePolarity,IN UINT8 * Buffer,IN UINTN BufferSize)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
VerifyFvHeaderChecksum(IN EFI_FIRMWARE_VOLUME_HEADER * FvHeader)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
VerifyHeaderChecksum(IN EFI_FFS_FILE_HEADER * FfsHeader)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
VerifyFileChecksum(IN EFI_FFS_FILE_HEADER * FfsHeader)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
IsValidFFSHeader(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)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
GetNextPossibleFileHeader(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)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 *
DuplicateFileExist(IN FV_DEVICE * FvDevice,IN EFI_FFS_FILE_HEADER * FfsHeader,IN EFI_FFS_FILE_STATE StateBit)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
UpdateHeaderBit(IN FV_DEVICE * FvDevice,IN EFI_FFS_FILE_HEADER * FfsHeader,IN EFI_FFS_FILE_STATE State)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
IsValidFFSFile(IN FV_DEVICE * FvDevice,IN EFI_FFS_FILE_HEADER * FfsHeader)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