• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Implements functions to read firmware file.
3 
4   Copyright (c) 2006 - 2012, 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 Required Alignment             Alignment Value in FFS         Alignment Value in
21 (bytes)                        Attributes Field               Firmware Volume Interfaces
22 1                                    0                                     0
23 16                                   1                                     4
24 128                                  2                                     7
25 512                                  3                                     9
26 1 KB                                 4                                     10
27 4 KB                                 5                                     12
28 32 KB                                6                                     15
29 64 KB                                7                                     16
30 **/
31 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
32 
33 /**
34   Convert the FFS File Attributes to FV File Attributes.
35 
36   @param  FfsAttributes              The attributes of UINT8 type.
37 
38   @return The attributes of EFI_FV_FILE_ATTRIBUTES
39 
40 **/
41 EFI_FV_FILE_ATTRIBUTES
FfsAttributes2FvFileAttributes(IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes)42 FfsAttributes2FvFileAttributes (
43   IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
44   )
45 {
46   UINT8                     DataAlignment;
47   EFI_FV_FILE_ATTRIBUTES    FileAttribute;
48 
49   DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
50   ASSERT (DataAlignment < 8);
51 
52   FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
53 
54   if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
55     FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
56   }
57 
58   return FileAttribute;
59 }
60 
61 /**
62   Given the input key, search for the next matching file in the volume.
63 
64   @param  This                       Indicates the calling context.
65   @param  Key                        Key is a pointer to a caller allocated
66                                      buffer that contains implementation specific
67                                      data that is used to track where to begin
68                                      the search for the next file. The size of
69                                      the buffer must be at least This->KeySize
70                                      bytes long. To reinitialize the search and
71                                      begin from the beginning of the firmware
72                                      volume, the entire buffer must be cleared to
73                                      zero. Other than clearing the buffer to
74                                      initiate a new search, the caller must not
75                                      modify the data in the buffer between calls
76                                      to GetNextFile().
77   @param  FileType                   FileType is a pointer to a caller allocated
78                                      EFI_FV_FILETYPE. The GetNextFile() API can
79                                      filter it's search for files based on the
80                                      value of *FileType input. A *FileType input
81                                      of 0 causes GetNextFile() to search for
82                                      files of all types.  If a file is found, the
83                                      file's type is returned in *FileType.
84                                      *FileType is not modified if no file is
85                                      found.
86   @param  NameGuid                   NameGuid is a pointer to a caller allocated
87                                      EFI_GUID. If a file is found, the file's
88                                      name is returned in *NameGuid.  *NameGuid is
89                                      not modified if no file is found.
90   @param  Attributes                 Attributes is a pointer to a caller
91                                      allocated EFI_FV_FILE_ATTRIBUTES.  If a file
92                                      is found, the file's attributes are returned
93                                      in *Attributes. *Attributes is not modified
94                                      if no file is found.
95   @param  Size                       Size is a pointer to a caller allocated
96                                      UINTN. If a file is found, the file's size
97                                      is returned in *Size. *Size is not modified
98                                      if no file is found.
99 
100   @retval EFI_SUCCESS                Successfully find the file.
101   @retval EFI_DEVICE_ERROR           Device error.
102   @retval EFI_ACCESS_DENIED          Fv could not read.
103   @retval EFI_NOT_FOUND              No matching file found.
104   @retval EFI_INVALID_PARAMETER      Invalid parameter
105 
106 **/
107 EFI_STATUS
108 EFIAPI
FvGetNextFile(IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL * This,IN OUT VOID * Key,IN OUT EFI_FV_FILETYPE * FileType,OUT EFI_GUID * NameGuid,OUT EFI_FV_FILE_ATTRIBUTES * Attributes,OUT UINTN * Size)109 FvGetNextFile (
110   IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL   *This,
111   IN OUT VOID                       *Key,
112   IN OUT EFI_FV_FILETYPE            *FileType,
113   OUT EFI_GUID                      *NameGuid,
114   OUT EFI_FV_FILE_ATTRIBUTES        *Attributes,
115   OUT UINTN                         *Size
116   )
117 {
118   EFI_STATUS          Status;
119   FV_DEVICE           *FvDevice;
120   EFI_FV_ATTRIBUTES   FvAttributes;
121   EFI_FFS_FILE_HEADER *FfsFileHeader;
122   UINTN               *KeyValue;
123   LIST_ENTRY      *Link;
124   FFS_FILE_LIST_ENTRY *FfsFileEntry;
125 
126   FvDevice  = FV_DEVICE_FROM_THIS (This);
127 
128   Status    = This->GetVolumeAttributes (This, &FvAttributes);
129   if (EFI_ERROR (Status)) {
130     return Status;
131   }
132 
133   KeyValue      = (UINTN *) Key;
134   FfsFileHeader = NULL;
135 
136   //
137   // Check if read operation is enabled
138   //
139   if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
140     return EFI_ACCESS_DENIED;
141   }
142 
143   if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
144     //
145     // File type needs to be in 0 - 0x0D
146     //
147     return EFI_NOT_FOUND;
148   }
149 
150   do {
151     if (*KeyValue == 0) {
152       //
153       // Search for 1st matching file
154       //
155       Link = &FvDevice->FfsFileListHeader;
156       if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
157         return EFI_NOT_FOUND;
158       }
159 
160       FfsFileEntry  = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
161       FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
162 
163       //
164       // remember the key
165       //
166       *KeyValue = (UINTN) FfsFileEntry;
167 
168       //
169       // we ignore pad files
170       //
171       if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
172         continue;
173       }
174 
175       if (*FileType == 0) {
176         break;
177       }
178 
179       if (*FileType == FfsFileHeader->Type) {
180         break;
181       }
182 
183     } else {
184       //
185       // Getting link from last Ffs
186       //
187       Link = (LIST_ENTRY *) (*KeyValue);
188       if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
189         return EFI_NOT_FOUND;
190       }
191 
192       FfsFileEntry  = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
193       FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
194 
195       //
196       // remember the key
197       //
198       *KeyValue = (UINTN) FfsFileEntry;
199 
200       //
201       // we ignore pad files
202       //
203       if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
204         continue;
205       }
206 
207       if (*FileType == EFI_FV_FILETYPE_ALL) {
208         break;
209       }
210 
211       if (*FileType == FfsFileHeader->Type) {
212         break;
213       }
214     }
215   } while (Link->ForwardLink != &FvDevice->FfsFileListHeader);
216 
217   //
218   // Cache this file entry
219   //
220   FvDevice->CurrentFfsFile  = FfsFileEntry;
221 
222   *FileType                 = FfsFileHeader->Type;
223   CopyGuid (NameGuid, &FfsFileHeader->Name);
224   *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
225    if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
226      *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
227    }
228 
229   //
230   // we need to substract the header size
231   //
232   if (IS_FFS_FILE2 (FfsFileHeader)) {
233     *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
234   } else {
235     *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
236   }
237 
238   if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
239     //
240     // specially deal with VTF file
241     //
242     UINT8   *SrcPtr;
243     UINT32  Tmp;
244 
245     if (IS_FFS_FILE2 (FfsFileHeader)) {
246       SrcPtr = ((UINT8 *) FfsFileHeader) + sizeof (EFI_FFS_FILE_HEADER2);
247     } else {
248       SrcPtr = ((UINT8 *) FfsFileHeader) + sizeof (EFI_FFS_FILE_HEADER);
249     }
250 
251     while (*Size >= 4) {
252       Tmp = *(UINT32 *) SrcPtr;
253       if (Tmp == 0) {
254         SrcPtr += 4;
255         (*Size) -= 4;
256       } else {
257         break;
258       }
259     }
260   }
261 
262   return EFI_SUCCESS;
263 }
264 
265 /**
266   Locates a file in the firmware volume and
267   copies it to the supplied buffer.
268 
269   @param  This                       Indicates the calling context.
270   @param  NameGuid                   Pointer to an EFI_GUID, which is the
271                                      filename.
272   @param  Buffer                     Buffer is a pointer to pointer to a buffer
273                                      in which the file or section contents or are
274                                      returned.
275   @param  BufferSize                 BufferSize is a pointer to caller allocated
276                                      UINTN. On input *BufferSize indicates the
277                                      size in bytes of the memory region pointed
278                                      to by Buffer. On output, *BufferSize
279                                      contains the number of bytes required to
280                                      read the file.
281   @param  FoundType                  FoundType is a pointer to a caller allocated
282                                      EFI_FV_FILETYPE that on successful return
283                                      from Read() contains the type of file read.
284                                      This output reflects the file type
285                                      irrespective of the value of the SectionType
286                                      input.
287   @param  FileAttributes             FileAttributes is a pointer to a caller
288                                      allocated EFI_FV_FILE_ATTRIBUTES.  On
289                                      successful return from Read(),
290                                      *FileAttributes contains the attributes of
291                                      the file read.
292   @param  AuthenticationStatus       AuthenticationStatus is a pointer to a
293                                      caller allocated UINTN in which the
294                                      authentication status is returned.
295 
296   @retval EFI_SUCCESS                Successfully read to memory buffer.
297   @retval EFI_WARN_BUFFER_TOO_SMALL  Buffer too small.
298   @retval EFI_NOT_FOUND              Not found.
299   @retval EFI_DEVICE_ERROR           Device error.
300   @retval EFI_ACCESS_DENIED          Could not read.
301   @retval EFI_INVALID_PARAMETER      Invalid parameter.
302   @retval EFI_OUT_OF_RESOURCES       Not enough buffer to be allocated.
303 
304 **/
305 EFI_STATUS
306 EFIAPI
FvReadFile(IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL * This,IN CONST EFI_GUID * NameGuid,IN OUT VOID ** Buffer,IN OUT UINTN * BufferSize,OUT EFI_FV_FILETYPE * FoundType,OUT EFI_FV_FILE_ATTRIBUTES * FileAttributes,OUT UINT32 * AuthenticationStatus)307 FvReadFile (
308   IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL   *This,
309   IN CONST EFI_GUID                       *NameGuid,
310   IN OUT VOID                       **Buffer,
311   IN OUT UINTN                      *BufferSize,
312   OUT EFI_FV_FILETYPE               *FoundType,
313   OUT EFI_FV_FILE_ATTRIBUTES        *FileAttributes,
314   OUT UINT32                        *AuthenticationStatus
315   )
316 {
317   EFI_STATUS              Status;
318   FV_DEVICE               *FvDevice;
319   UINTN                   Key;
320   EFI_GUID                SearchNameGuid;
321   EFI_FV_ATTRIBUTES       FvAttributes;
322   EFI_FV_FILETYPE         LocalFoundType;
323   EFI_FV_FILE_ATTRIBUTES  LocalAttributes;
324   UINTN                   FileSize;
325   UINT8                   *SrcPtr;
326   FFS_FILE_LIST_ENTRY     *FfsFileEntry;
327   EFI_FFS_FILE_HEADER     *FfsHeader;
328   UINT8                   *FileBuffer;
329 
330   if (NULL == This || NULL == NameGuid) {
331     return EFI_INVALID_PARAMETER;
332   }
333 
334   FvDevice  = FV_DEVICE_FROM_THIS (This);
335 
336   Status    = This->GetVolumeAttributes (This, &FvAttributes);
337   if (EFI_ERROR (Status)) {
338     return Status;
339   }
340   //
341   // First check to see that FV is enabled for reads...
342   //
343   if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
344     return EFI_ACCESS_DENIED;
345   }
346 
347   FfsHeader = NULL;
348 
349   //
350   // Check if the file was read last time.
351   //
352   FfsFileEntry = FvDevice->CurrentFfsFile;
353 
354   if (FfsFileEntry != NULL) {
355     FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
356   }
357 
358   if ((FfsFileEntry == NULL) || (!CompareGuid (&FfsHeader->Name, NameGuid))) {
359     //
360     // If not match or no file cached, search this file
361     //
362     Key = 0;
363     do {
364       LocalFoundType = 0;
365       Status = This->GetNextFile (
366                       This,
367                       &Key,
368                       &LocalFoundType,
369                       &SearchNameGuid,
370                       &LocalAttributes,
371                       &FileSize
372                       );
373       if (EFI_ERROR (Status)) {
374         return EFI_NOT_FOUND;
375       }
376     } while (!CompareGuid (&SearchNameGuid, NameGuid));
377 
378     //
379     // Get file entry
380     //
381     FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
382 
383     //
384     // Update the cache
385     //
386     FvDevice->CurrentFfsFile  = FfsFileEntry;
387 
388     FfsHeader                 = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
389 
390   } else {
391     //
392     // Get File Size of the cached file
393     //
394     if (IS_FFS_FILE2 (FfsHeader)) {
395       FileSize = FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2);
396     } else {
397       FileSize = FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER);
398     }
399   }
400   //
401   // Get file info
402   //
403   *FoundType            = FfsHeader->Type;
404   *FileAttributes       = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
405    if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
406      *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
407    }
408   *AuthenticationStatus = 0;
409 
410   //
411   // If Buffer is NULL, we only want to get some information
412   //
413   if (Buffer == NULL) {
414     *BufferSize = FileSize;
415     return EFI_SUCCESS;
416   }
417 
418   if (IS_FFS_FILE2 (FfsHeader)) {
419     SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
420   } else {
421     SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
422   }
423 
424   if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
425     //
426     // specially deal with VTF file
427     //
428     UINT32  Tmp;
429 
430     while (FileSize >= 4) {
431       Tmp = *(UINT32 *) SrcPtr;
432       if (Tmp == 0) {
433         SrcPtr += 4;
434         FileSize -= 4;
435       } else {
436         break;
437       }
438     }
439   }
440   //
441   // If we drop out of the above loop, we've found the correct file header...
442   //
443   if (*Buffer == NULL) {
444     FileBuffer = AllocateCopyPool (FileSize, SrcPtr);
445     if (FileBuffer == NULL) {
446       return EFI_OUT_OF_RESOURCES;
447     }
448 
449     *BufferSize = FileSize;
450     *Buffer     = FileBuffer;
451 
452     return EFI_SUCCESS;
453   }
454   //
455   // If the user's buffer is smaller than the file size, then copy as much
456   // as we can and return an appropriate status.
457   //
458   if (FileSize > *BufferSize) {
459     CopyMem (*Buffer, SrcPtr, *BufferSize);
460     *BufferSize = FileSize;
461     return EFI_WARN_BUFFER_TOO_SMALL;
462   }
463   //
464   // User's buffer size is ok, so copy the entire file to their buffer.
465   //
466   *BufferSize = FileSize;
467   CopyMem (*Buffer, SrcPtr, *BufferSize);
468 
469   return EFI_SUCCESS;
470 }
471 
472 /**
473   Locates a section in a given FFS File and
474   copies it to the supplied buffer (not including section header).
475 
476   @param  This                       Indicates the calling context.
477   @param  NameGuid                   Pointer to an EFI_GUID, which is the
478                                      filename.
479   @param  SectionType                Indicates the section type to return.
480   @param  SectionInstance            Indicates which instance of sections with a
481                                      type of SectionType to return.
482   @param  Buffer                     Buffer is a pointer to pointer to a buffer
483                                      in which the file or section contents or are
484                                      returned.
485   @param  BufferSize                 BufferSize is a pointer to caller allocated
486                                      UINTN.
487   @param  AuthenticationStatus       AuthenticationStatus is a pointer to a
488                                      caller allocated UINT32 in which the
489                                      authentication status is returned.
490 
491   @retval EFI_SUCCESS                Successfully read the file section into
492                                      buffer.
493   @retval EFI_WARN_BUFFER_TOO_SMALL  Buffer too small.
494   @retval EFI_NOT_FOUND              Section not found.
495   @retval EFI_DEVICE_ERROR           Device error.
496   @retval EFI_ACCESS_DENIED          Could not read.
497   @retval EFI_INVALID_PARAMETER      Invalid parameter.
498 
499 **/
500 EFI_STATUS
501 EFIAPI
FvReadFileSection(IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL * This,IN CONST EFI_GUID * NameGuid,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,IN OUT VOID ** Buffer,IN OUT UINTN * BufferSize,OUT UINT32 * AuthenticationStatus)502 FvReadFileSection (
503   IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL   *This,
504   IN CONST EFI_GUID                       *NameGuid,
505   IN EFI_SECTION_TYPE               SectionType,
506   IN UINTN                          SectionInstance,
507   IN OUT VOID                       **Buffer,
508   IN OUT UINTN                      *BufferSize,
509   OUT UINT32                        *AuthenticationStatus
510   )
511 {
512   EFI_STATUS                      Status;
513   FV_DEVICE                       *FvDevice;
514   EFI_FV_ATTRIBUTES               FvAttributes;
515   EFI_FV_FILETYPE                 FileType;
516   EFI_FV_FILE_ATTRIBUTES          FileAttributes;
517   UINTN                           FileSize;
518   UINT8                           *FileBuffer;
519   EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
520   UINTN                           StreamHandle;
521 
522   if (NULL == This || NULL == NameGuid || Buffer == NULL) {
523     return EFI_INVALID_PARAMETER;
524   }
525 
526   FvDevice  = FV_DEVICE_FROM_THIS (This);
527 
528   Status    = This->GetVolumeAttributes (This, &FvAttributes);
529   if (EFI_ERROR (Status)) {
530     return Status;
531   }
532   //
533   // First check to see that FV is enabled for reads...
534   //
535   if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
536     return EFI_ACCESS_DENIED;
537   }
538   //
539   // Read the whole file into buffer
540   //
541   FileBuffer = NULL;
542   Status = This->ReadFile (
543                   This,
544                   NameGuid,
545                   (VOID **) &FileBuffer,
546                   &FileSize,
547                   &FileType,
548                   &FileAttributes,
549                   AuthenticationStatus
550                   );
551 
552   if (EFI_ERROR (Status)) {
553     return Status;
554   }
555   //
556   // Check to see that the file actually HAS sections before we go any further.
557   //
558   if (FileType == EFI_FV_FILETYPE_RAW) {
559     FreePool (FileBuffer);
560     return EFI_NOT_FOUND;
561   }
562   //
563   // Located the protocol
564   //
565   Status = gBS->LocateProtocol (
566                   &gEfiSectionExtractionProtocolGuid,
567                   NULL,
568                   (VOID **) &Sep
569                   );
570   if (EFI_ERROR (Status)) {
571     FreePool (FileBuffer);
572     return Status;
573   }
574 
575   Status = Sep->OpenSectionStream (
576                   Sep,
577                   FileSize,
578                   FileBuffer,
579                   &StreamHandle
580                   );
581 
582   if (EFI_ERROR (Status)) {
583     FreePool (FileBuffer);
584     return Status;
585   }
586 
587   if (SectionType == 0) {
588     //
589     // We need the whole section stream
590     //
591     Status = Sep->GetSection (
592                     Sep,
593                     StreamHandle,
594                     NULL,
595                     NULL,
596                     0,
597                     Buffer,
598                     BufferSize,
599                     AuthenticationStatus
600                     );
601   } else {
602     Status = Sep->GetSection (
603                     Sep,
604                     StreamHandle,
605                     &SectionType,
606                     NULL,
607                     SectionInstance,
608                     Buffer,
609                     BufferSize,
610                     AuthenticationStatus
611                     );
612   }
613 
614   if (!EFI_ERROR (Status)) {
615     //
616     // Inherit the authentication status.
617     //
618     *AuthenticationStatus |= FvDevice->AuthenticationStatus;
619   }
620 
621   //
622   // Handle AuthenticationStatus if necessary
623   //
624   Sep->CloseSectionStream (Sep, StreamHandle);
625 
626   FreePool (FileBuffer);
627 
628   return Status;
629 }
630