1 /** @file
2   Implements functions to read firmware file
3 
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "DxeMain.h"
16 #include "FwVolDriver.h"
17 
18 /**
19 Required Alignment             Alignment Value in FFS         Alignment Value in
20 (bytes)                        Attributes Field               Firmware Volume Interfaces
21 1                                    0                                     0
22 16                                   1                                     4
23 128                                  2                                     7
24 512                                  3                                     9
25 1 KB                                 4                                     10
26 4 KB                                 5                                     12
27 32 KB                                6                                     15
28 64 KB                                7                                     16
29 **/
30 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
31 
32 /**
33   Convert the FFS File Attributes to FV File Attributes
34 
35   @param  FfsAttributes              The attributes of UINT8 type.
36 
37   @return The attributes of EFI_FV_FILE_ATTRIBUTES
38 
39 **/
40 EFI_FV_FILE_ATTRIBUTES
FfsAttributes2FvFileAttributes(IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes)41 FfsAttributes2FvFileAttributes (
42   IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
43   )
44 {
45   UINT8                     DataAlignment;
46   EFI_FV_FILE_ATTRIBUTES    FileAttribute;
47 
48   DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
49   ASSERT (DataAlignment < 8);
50 
51   FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
52 
53   if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
54     FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
55   }
56 
57   return FileAttribute;
58 }
59 
60 /**
61   Given the input key, search for the next matching file in the volume.
62 
63   @param  This                       Indicates the calling context.
64   @param  Key                        Key is a pointer to a caller allocated
65                                      buffer that contains implementation specific
66                                      data that is used to track where to begin
67                                      the search for the next file. The size of
68                                      the buffer must be at least This->KeySize
69                                      bytes long. To reinitialize the search and
70                                      begin from the beginning of the firmware
71                                      volume, the entire buffer must be cleared to
72                                      zero. Other than clearing the buffer to
73                                      initiate a new search, the caller must not
74                                      modify the data in the buffer between calls
75                                      to GetNextFile().
76   @param  FileType                   FileType is a pointer to a caller allocated
77                                      EFI_FV_FILETYPE. The GetNextFile() API can
78                                      filter it's search for files based on the
79                                      value of *FileType input. A *FileType input
80                                      of 0 causes GetNextFile() to search for
81                                      files of all types.  If a file is found, the
82                                      file's type is returned in *FileType.
83                                      *FileType is not modified if no file is
84                                      found.
85   @param  NameGuid                   NameGuid is a pointer to a caller allocated
86                                      EFI_GUID. If a file is found, the file's
87                                      name is returned in *NameGuid.  *NameGuid is
88                                      not modified if no file is found.
89   @param  Attributes                 Attributes is a pointer to a caller
90                                      allocated EFI_FV_FILE_ATTRIBUTES.  If a file
91                                      is found, the file's attributes are returned
92                                      in *Attributes. *Attributes is not modified
93                                      if no file is found.
94   @param  Size                       Size is a pointer to a caller allocated
95                                      UINTN. If a file is found, the file's size
96                                      is returned in *Size. *Size is not modified
97                                      if no file is found.
98 
99   @retval EFI_SUCCESS                Successfully find the file.
100   @retval EFI_DEVICE_ERROR           Device error.
101   @retval EFI_ACCESS_DENIED          Fv could not read.
102   @retval EFI_NOT_FOUND              No matching file found.
103   @retval EFI_INVALID_PARAMETER      Invalid parameter
104 
105 **/
106 EFI_STATUS
107 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)108 FvGetNextFile (
109   IN CONST   EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
110   IN OUT     VOID                          *Key,
111   IN OUT     EFI_FV_FILETYPE               *FileType,
112   OUT        EFI_GUID                      *NameGuid,
113   OUT        EFI_FV_FILE_ATTRIBUTES        *Attributes,
114   OUT        UINTN                         *Size
115   )
116 {
117   EFI_STATUS                                  Status;
118   FV_DEVICE                                   *FvDevice;
119   EFI_FV_ATTRIBUTES                           FvAttributes;
120   EFI_FFS_FILE_HEADER                         *FfsFileHeader;
121   UINTN                                       *KeyValue;
122   LIST_ENTRY                                  *Link;
123   FFS_FILE_LIST_ENTRY                         *FfsFileEntry;
124 
125   FvDevice = FV_DEVICE_FROM_THIS (This);
126 
127   Status = FvGetVolumeAttributes (This, &FvAttributes);
128   if (EFI_ERROR (Status)){
129     return Status;
130   }
131 
132   //
133   // Check if read operation is enabled
134   //
135   if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
136     return EFI_ACCESS_DENIED;
137   }
138 
139   if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
140     //
141     // File type needs to be in 0 - 0x0D
142     //
143     return EFI_NOT_FOUND;
144   }
145 
146   KeyValue = (UINTN *)Key;
147   for (;;) {
148     if (*KeyValue == 0) {
149       //
150       // Search for 1st matching file
151       //
152       Link = &FvDevice->FfsFileListHeader;
153     } else {
154       //
155       // Key is pointer to FFsFileEntry, so get next one
156       //
157       Link = (LIST_ENTRY *)(*KeyValue);
158     }
159 
160     if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
161       //
162       // Next is end of list so we did not find data
163       //
164       return EFI_NOT_FOUND;
165     }
166 
167     FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
168     FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
169 
170     //
171     // remember the key
172     //
173     *KeyValue = (UINTN)FfsFileEntry;
174 
175     if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
176       //
177       // we ignore pad files
178       //
179       continue;
180     }
181 
182     if (*FileType == EFI_FV_FILETYPE_ALL) {
183       //
184       // Process all file types so we have a match
185       //
186       break;
187     }
188 
189     if (*FileType == FfsFileHeader->Type) {
190       //
191       // Found a matching file type
192       //
193       break;
194     }
195 
196   }
197 
198   //
199   // Return FileType, NameGuid, and Attributes
200   //
201   *FileType = FfsFileHeader->Type;
202   CopyGuid (NameGuid, &FfsFileHeader->Name);
203   *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
204   if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
205     *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
206   }
207 
208   //
209   // we need to substract the header size
210   //
211   if (IS_FFS_FILE2 (FfsFileHeader)) {
212     *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
213   } else {
214     *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
215   }
216 
217   return EFI_SUCCESS;
218 }
219 
220 
221 
222 /**
223   Locates a file in the firmware volume and
224   copies it to the supplied buffer.
225 
226   @param  This                       Indicates the calling context.
227   @param  NameGuid                   Pointer to an EFI_GUID, which is the
228                                      filename.
229   @param  Buffer                     Buffer is a pointer to pointer to a buffer
230                                      in which the file or section contents or are
231                                      returned.
232   @param  BufferSize                 BufferSize is a pointer to caller allocated
233                                      UINTN. On input *BufferSize indicates the
234                                      size in bytes of the memory region pointed
235                                      to by Buffer. On output, *BufferSize
236                                      contains the number of bytes required to
237                                      read the file.
238   @param  FoundType                  FoundType is a pointer to a caller allocated
239                                      EFI_FV_FILETYPE that on successful return
240                                      from Read() contains the type of file read.
241                                      This output reflects the file type
242                                      irrespective of the value of the SectionType
243                                      input.
244   @param  FileAttributes             FileAttributes is a pointer to a caller
245                                      allocated EFI_FV_FILE_ATTRIBUTES.  On
246                                      successful return from Read(),
247                                      *FileAttributes contains the attributes of
248                                      the file read.
249   @param  AuthenticationStatus       AuthenticationStatus is a pointer to a
250                                      caller allocated UINTN in which the
251                                      authentication status is returned.
252 
253   @retval EFI_SUCCESS                Successfully read to memory buffer.
254   @retval EFI_WARN_BUFFER_TOO_SMALL  Buffer too small.
255   @retval EFI_NOT_FOUND              Not found.
256   @retval EFI_DEVICE_ERROR           Device error.
257   @retval EFI_ACCESS_DENIED          Could not read.
258   @retval EFI_INVALID_PARAMETER      Invalid parameter.
259   @retval EFI_OUT_OF_RESOURCES       Not enough buffer to be allocated.
260 
261 **/
262 EFI_STATUS
263 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)264 FvReadFile (
265   IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
266   IN CONST EFI_GUID                      *NameGuid,
267   IN OUT   VOID                          **Buffer,
268   IN OUT   UINTN                         *BufferSize,
269   OUT      EFI_FV_FILETYPE               *FoundType,
270   OUT      EFI_FV_FILE_ATTRIBUTES        *FileAttributes,
271   OUT      UINT32                        *AuthenticationStatus
272   )
273 {
274   EFI_STATUS                        Status;
275   FV_DEVICE                         *FvDevice;
276   EFI_GUID                          SearchNameGuid;
277   EFI_FV_FILETYPE                   LocalFoundType;
278   EFI_FV_FILE_ATTRIBUTES            LocalAttributes;
279   UINTN                             FileSize;
280   UINT8                             *SrcPtr;
281   EFI_FFS_FILE_HEADER               *FfsHeader;
282   UINTN                             InputBufferSize;
283   UINTN                             WholeFileSize;
284 
285   if (NameGuid == NULL) {
286     return EFI_INVALID_PARAMETER;
287   }
288 
289   FvDevice = FV_DEVICE_FROM_THIS (This);
290 
291 
292   //
293   // Keep looking until we find the matching NameGuid.
294   // The Key is really a FfsFileEntry
295   //
296   FvDevice->LastKey = 0;
297   do {
298     LocalFoundType = 0;
299     Status = FvGetNextFile (
300               This,
301               &FvDevice->LastKey,
302               &LocalFoundType,
303               &SearchNameGuid,
304               &LocalAttributes,
305               &FileSize
306               );
307     if (EFI_ERROR (Status)) {
308       return EFI_NOT_FOUND;
309     }
310   } while (!CompareGuid (&SearchNameGuid, NameGuid));
311 
312   //
313   // Get a pointer to the header
314   //
315   FfsHeader = FvDevice->LastKey->FfsHeader;
316   if (FvDevice->IsMemoryMapped) {
317     //
318     // Memory mapped FV has not been cached, so here is to cache by file.
319     //
320     if (!FvDevice->LastKey->FileCached) {
321       //
322       // Cache FFS file to memory buffer.
323       //
324       WholeFileSize = IS_FFS_FILE2 (FfsHeader) ? FFS_FILE2_SIZE (FfsHeader): FFS_FILE_SIZE (FfsHeader);
325       FfsHeader = AllocateCopyPool (WholeFileSize, FfsHeader);
326       if (FfsHeader == NULL) {
327         return EFI_OUT_OF_RESOURCES;
328       }
329       //
330       // Let FfsHeader in FfsFileEntry point to the cached file buffer.
331       //
332       FvDevice->LastKey->FfsHeader = FfsHeader;
333       FvDevice->LastKey->FileCached = TRUE;
334     }
335   }
336 
337   //
338   // Remember callers buffer size
339   //
340   InputBufferSize = *BufferSize;
341 
342   //
343   // Calculate return values
344   //
345   *FoundType = FfsHeader->Type;
346   *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
347    if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
348      *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
349    }
350   *AuthenticationStatus = 0;
351   *BufferSize = FileSize;
352 
353   if (Buffer == NULL) {
354     //
355     // If Buffer is NULL, we only want to get the information collected so far
356     //
357     return EFI_SUCCESS;
358   }
359 
360   //
361   // Skip over file header
362   //
363   if (IS_FFS_FILE2 (FfsHeader)) {
364     SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
365   } else {
366     SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
367   }
368 
369   Status = EFI_SUCCESS;
370   if (*Buffer == NULL) {
371     //
372     // Caller passed in a pointer so allocate buffer for them
373     //
374     *Buffer = AllocatePool (FileSize);
375     if (*Buffer == NULL) {
376       return EFI_OUT_OF_RESOURCES;
377     }
378   } else if (FileSize > InputBufferSize) {
379     //
380     // Callers buffer was not big enough
381     //
382     Status = EFI_WARN_BUFFER_TOO_SMALL;
383     FileSize = InputBufferSize;
384   }
385 
386   //
387   // Copy data into callers buffer
388   //
389   CopyMem (*Buffer, SrcPtr, FileSize);
390 
391   return Status;
392 }
393 
394 
395 
396 /**
397   Locates a section in a given FFS File and
398   copies it to the supplied buffer (not including section header).
399 
400   @param  This                       Indicates the calling context.
401   @param  NameGuid                   Pointer to an EFI_GUID, which is the
402                                      filename.
403   @param  SectionType                Indicates the section type to return.
404   @param  SectionInstance            Indicates which instance of sections with a
405                                      type of SectionType to return.
406   @param  Buffer                     Buffer is a pointer to pointer to a buffer
407                                      in which the file or section contents or are
408                                      returned.
409   @param  BufferSize                 BufferSize is a pointer to caller allocated
410                                      UINTN.
411   @param  AuthenticationStatus       AuthenticationStatus is a pointer to a
412                                      caller allocated UINT32 in which the
413                                      authentication status is returned.
414 
415   @retval EFI_SUCCESS                Successfully read the file section into
416                                      buffer.
417   @retval EFI_WARN_BUFFER_TOO_SMALL  Buffer too small.
418   @retval EFI_NOT_FOUND              Section not found.
419   @retval EFI_DEVICE_ERROR           Device error.
420   @retval EFI_ACCESS_DENIED          Could not read.
421   @retval EFI_INVALID_PARAMETER      Invalid parameter.
422 
423 **/
424 EFI_STATUS
425 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)426 FvReadFileSection (
427   IN CONST  EFI_FIRMWARE_VOLUME2_PROTOCOL  *This,
428   IN CONST  EFI_GUID                       *NameGuid,
429   IN        EFI_SECTION_TYPE               SectionType,
430   IN        UINTN                          SectionInstance,
431   IN OUT    VOID                           **Buffer,
432   IN OUT    UINTN                          *BufferSize,
433   OUT       UINT32                         *AuthenticationStatus
434   )
435 {
436   EFI_STATUS                        Status;
437   FV_DEVICE                         *FvDevice;
438   EFI_FV_FILETYPE                   FileType;
439   EFI_FV_FILE_ATTRIBUTES            FileAttributes;
440   UINTN                             FileSize;
441   UINT8                             *FileBuffer;
442   FFS_FILE_LIST_ENTRY               *FfsEntry;
443 
444   if (NameGuid == NULL || Buffer == NULL) {
445     return EFI_INVALID_PARAMETER;
446   }
447 
448   FvDevice = FV_DEVICE_FROM_THIS (This);
449 
450   //
451   // Read the file
452   //
453   Status = FvReadFile (
454             This,
455             NameGuid,
456             NULL,
457             &FileSize,
458             &FileType,
459             &FileAttributes,
460             AuthenticationStatus
461             );
462   //
463   // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
464   //
465   FfsEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->LastKey;
466 
467   if (EFI_ERROR (Status)) {
468     return Status;
469   }
470   if (IS_FFS_FILE2 (FfsEntry->FfsHeader)) {
471     FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
472   } else {
473     FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
474   }
475   //
476   // Check to see that the file actually HAS sections before we go any further.
477   //
478   if (FileType == EFI_FV_FILETYPE_RAW) {
479     Status = EFI_NOT_FOUND;
480     goto Done;
481   }
482 
483   //
484   // Use FfsEntry to cache Section Extraction Protocol Information
485   //
486   if (FfsEntry->StreamHandle == 0) {
487     Status = OpenSectionStream (
488                FileSize,
489                FileBuffer,
490                &FfsEntry->StreamHandle
491                );
492     if (EFI_ERROR (Status)) {
493       goto Done;
494     }
495   }
496 
497   //
498   // If SectionType == 0 We need the whole section stream
499   //
500   Status = GetSection (
501              FfsEntry->StreamHandle,
502              (SectionType == 0) ? NULL : &SectionType,
503              NULL,
504              (SectionType == 0) ? 0 : SectionInstance,
505              Buffer,
506              BufferSize,
507              AuthenticationStatus,
508              FvDevice->IsFfs3Fv
509              );
510 
511   if (!EFI_ERROR (Status)) {
512     //
513     // Inherit the authentication status.
514     //
515     *AuthenticationStatus |= FvDevice->AuthenticationStatus;
516   }
517 
518   //
519   // Close of stream defered to close of FfsHeader list to allow SEP to cache data
520   //
521 
522 Done:
523   return Status;
524 }
525 
526 
527