• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Implements functions to read firmware file.
3 
4   Copyright (c) 2006 - 2016, 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   //
409   // Inherit the authentication status.
410   //
411   *AuthenticationStatus = FvDevice->AuthenticationStatus;
412 
413   //
414   // If Buffer is NULL, we only want to get some information
415   //
416   if (Buffer == NULL) {
417     *BufferSize = FileSize;
418     return EFI_SUCCESS;
419   }
420 
421   if (IS_FFS_FILE2 (FfsHeader)) {
422     SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
423   } else {
424     SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
425   }
426 
427   if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
428     //
429     // specially deal with VTF file
430     //
431     UINT32  Tmp;
432 
433     while (FileSize >= 4) {
434       Tmp = *(UINT32 *) SrcPtr;
435       if (Tmp == 0) {
436         SrcPtr += 4;
437         FileSize -= 4;
438       } else {
439         break;
440       }
441     }
442   }
443   //
444   // If we drop out of the above loop, we've found the correct file header...
445   //
446   if (*Buffer == NULL) {
447     FileBuffer = AllocateCopyPool (FileSize, SrcPtr);
448     if (FileBuffer == NULL) {
449       return EFI_OUT_OF_RESOURCES;
450     }
451 
452     *BufferSize = FileSize;
453     *Buffer     = FileBuffer;
454 
455     return EFI_SUCCESS;
456   }
457   //
458   // If the user's buffer is smaller than the file size, then copy as much
459   // as we can and return an appropriate status.
460   //
461   if (FileSize > *BufferSize) {
462     CopyMem (*Buffer, SrcPtr, *BufferSize);
463     *BufferSize = FileSize;
464     return EFI_WARN_BUFFER_TOO_SMALL;
465   }
466   //
467   // User's buffer size is ok, so copy the entire file to their buffer.
468   //
469   *BufferSize = FileSize;
470   CopyMem (*Buffer, SrcPtr, *BufferSize);
471 
472   return EFI_SUCCESS;
473 }
474 
475 /**
476   Locates a section in a given FFS File and
477   copies it to the supplied buffer (not including section header).
478 
479   @param  This                       Indicates the calling context.
480   @param  NameGuid                   Pointer to an EFI_GUID, which is the
481                                      filename.
482   @param  SectionType                Indicates the section type to return.
483   @param  SectionInstance            Indicates which instance of sections with a
484                                      type of SectionType to return.
485   @param  Buffer                     Buffer is a pointer to pointer to a buffer
486                                      in which the file or section contents or are
487                                      returned.
488   @param  BufferSize                 BufferSize is a pointer to caller allocated
489                                      UINTN.
490   @param  AuthenticationStatus       AuthenticationStatus is a pointer to a
491                                      caller allocated UINT32 in which the
492                                      authentication status is returned.
493 
494   @retval EFI_SUCCESS                Successfully read the file section into
495                                      buffer.
496   @retval EFI_WARN_BUFFER_TOO_SMALL  Buffer too small.
497   @retval EFI_NOT_FOUND              Section not found.
498   @retval EFI_DEVICE_ERROR           Device error.
499   @retval EFI_ACCESS_DENIED          Could not read.
500   @retval EFI_INVALID_PARAMETER      Invalid parameter.
501 
502 **/
503 EFI_STATUS
504 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)505 FvReadFileSection (
506   IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL   *This,
507   IN CONST EFI_GUID                       *NameGuid,
508   IN EFI_SECTION_TYPE               SectionType,
509   IN UINTN                          SectionInstance,
510   IN OUT VOID                       **Buffer,
511   IN OUT UINTN                      *BufferSize,
512   OUT UINT32                        *AuthenticationStatus
513   )
514 {
515   EFI_STATUS                      Status;
516   FV_DEVICE                       *FvDevice;
517   EFI_FV_ATTRIBUTES               FvAttributes;
518   EFI_FV_FILETYPE                 FileType;
519   EFI_FV_FILE_ATTRIBUTES          FileAttributes;
520   UINTN                           FileSize;
521   UINT8                           *FileBuffer;
522   EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
523   UINTN                           StreamHandle;
524 
525   if (NULL == This || NULL == NameGuid || Buffer == NULL) {
526     return EFI_INVALID_PARAMETER;
527   }
528 
529   FvDevice  = FV_DEVICE_FROM_THIS (This);
530 
531   Status    = This->GetVolumeAttributes (This, &FvAttributes);
532   if (EFI_ERROR (Status)) {
533     return Status;
534   }
535   //
536   // First check to see that FV is enabled for reads...
537   //
538   if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
539     return EFI_ACCESS_DENIED;
540   }
541   //
542   // Read the whole file into buffer
543   //
544   FileBuffer = NULL;
545   Status = This->ReadFile (
546                   This,
547                   NameGuid,
548                   (VOID **) &FileBuffer,
549                   &FileSize,
550                   &FileType,
551                   &FileAttributes,
552                   AuthenticationStatus
553                   );
554 
555   if (EFI_ERROR (Status)) {
556     return Status;
557   }
558   //
559   // Check to see that the file actually HAS sections before we go any further.
560   //
561   if (FileType == EFI_FV_FILETYPE_RAW) {
562     FreePool (FileBuffer);
563     return EFI_NOT_FOUND;
564   }
565   //
566   // Located the protocol
567   //
568   Status = gBS->LocateProtocol (
569                   &gEfiSectionExtractionProtocolGuid,
570                   NULL,
571                   (VOID **) &Sep
572                   );
573   if (EFI_ERROR (Status)) {
574     FreePool (FileBuffer);
575     return Status;
576   }
577 
578   Status = Sep->OpenSectionStream (
579                   Sep,
580                   FileSize,
581                   FileBuffer,
582                   &StreamHandle
583                   );
584 
585   if (EFI_ERROR (Status)) {
586     FreePool (FileBuffer);
587     return Status;
588   }
589 
590   if (SectionType == 0) {
591     //
592     // We need the whole section stream
593     //
594     Status = Sep->GetSection (
595                     Sep,
596                     StreamHandle,
597                     NULL,
598                     NULL,
599                     0,
600                     Buffer,
601                     BufferSize,
602                     AuthenticationStatus
603                     );
604   } else {
605     Status = Sep->GetSection (
606                     Sep,
607                     StreamHandle,
608                     &SectionType,
609                     NULL,
610                     SectionInstance,
611                     Buffer,
612                     BufferSize,
613                     AuthenticationStatus
614                     );
615   }
616 
617   if (!EFI_ERROR (Status)) {
618     //
619     // Inherit the authentication status.
620     //
621     *AuthenticationStatus |= FvDevice->AuthenticationStatus;
622   }
623 
624   //
625   // Handle AuthenticationStatus if necessary
626   //
627   Sep->CloseSectionStream (Sep, StreamHandle);
628 
629   FreePool (FileBuffer);
630 
631   return Status;
632 }
633