1 /** @file
2   MDE DXE Services Library provides functions that simplify the development of DXE Drivers.
3   These functions help access data from sections of FFS files or from file path.
4 
5   Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6   (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include <PiDxe.h>
12 #include <Library/DebugLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/DevicePathLib.h>
16 #include <Library/UefiLib.h>
17 #include <Library/DxeServicesLib.h>
18 #include <Protocol/FirmwareVolume2.h>
19 #include <Protocol/LoadedImage.h>
20 #include <Protocol/LoadFile2.h>
21 #include <Protocol/LoadFile.h>
22 #include <Protocol/SimpleFileSystem.h>
23 #include <Guid/FileInfo.h>
24 
25 /**
26   Identify the device handle from which the Image is loaded from. As this device handle is passed to
27   GetSectionFromFv as the identifier for a Firmware Volume, an EFI_FIRMWARE_VOLUME2_PROTOCOL
28   protocol instance should be located successfully by calling gBS->HandleProtocol ().
29 
30   This function locates the EFI_LOADED_IMAGE_PROTOCOL instance installed
31   on ImageHandle. It then returns EFI_LOADED_IMAGE_PROTOCOL.DeviceHandle.
32 
33   If ImageHandle is NULL, then ASSERT ();
34   If failed to locate a EFI_LOADED_IMAGE_PROTOCOL on ImageHandle, then ASSERT ();
35 
36   @param  ImageHandle         The firmware allocated handle for UEFI image.
37 
38   @retval  EFI_HANDLE         The device handle from which the Image is loaded from.
39 
40 **/
41 EFI_HANDLE
InternalImageHandleToFvHandle(EFI_HANDLE ImageHandle)42 InternalImageHandleToFvHandle (
43   EFI_HANDLE ImageHandle
44   )
45 {
46   EFI_STATUS                    Status;
47   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
48 
49   ASSERT (ImageHandle != NULL);
50 
51   Status = gBS->HandleProtocol (
52              ImageHandle,
53              &gEfiLoadedImageProtocolGuid,
54              (VOID **) &LoadedImage
55              );
56 
57   ASSERT_EFI_ERROR (Status);
58 
59   //
60   // The LoadedImage->DeviceHandle may be NULL.
61   // For example for DxeCore, there is LoadedImage protocol installed for it, but the
62   // LoadedImage->DeviceHandle could not be initialized before the FV2 (contain DxeCore)
63   // protocol is installed.
64   //
65   return LoadedImage->DeviceHandle;
66 
67 }
68 
69 /**
70   Allocate and fill a buffer from a Firmware Section identified by a Firmware File GUID name, a Firmware
71   Section type and instance number from the specified Firmware Volume.
72 
73   This functions first locate the EFI_FIRMWARE_VOLUME2_PROTOCOL protocol instance on FvHandle in order to
74   carry out the Firmware Volume read operation. The function then reads the Firmware Section found specified
75   by NameGuid, SectionType and SectionInstance.
76 
77   The details of this search order is defined in description of EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection ()
78   found in PI Specification.
79 
80   If SectionType is EFI_SECTION_TE, EFI_SECTION_TE is used as section type to start the search. If EFI_SECTION_TE section
81   is not found, EFI_SECTION_PE32 will be used to try the search again. If no EFI_SECTION_PE32 section is found, EFI_NOT_FOUND
82   is returned.
83 
84   The data and size is returned by Buffer and Size. The caller is responsible to free the Buffer allocated
85   by this function. This function can be only called at TPL_NOTIFY and below.
86 
87   If NameGuid is NULL, then ASSERT();
88   If Buffer is NULL, then ASSERT();
89   If Size is NULL, then ASSERT().
90 
91   @param  FvHandle                The device handle that contains a instance of
92                                   EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
93   @param  NameGuid                The GUID name of a Firmware File.
94   @param  SectionType             The Firmware Section type.
95   @param  SectionInstance         The instance number of Firmware Section to
96                                   read from starting from 0.
97   @param  Buffer                  On output, Buffer contains the data read
98                                   from the section in the Firmware File found.
99   @param  Size                    On output, the size of Buffer.
100 
101   @retval  EFI_SUCCESS            The image is found and data and size is returned.
102   @retval  EFI_NOT_FOUND          The image specified by NameGuid and SectionType
103                                   can't be found.
104   @retval  EFI_OUT_OF_RESOURCES   There were not enough resources to allocate the
105                                   output data buffer or complete the operations.
106   @retval  EFI_DEVICE_ERROR       A hardware error occurs during reading from the
107                                   Firmware Volume.
108   @retval  EFI_ACCESS_DENIED      The firmware volume containing the searched
109                                   Firmware File is configured to disallow reads.
110 
111 **/
112 EFI_STATUS
InternalGetSectionFromFv(IN EFI_HANDLE FvHandle,IN CONST EFI_GUID * NameGuid,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,OUT VOID ** Buffer,OUT UINTN * Size)113 InternalGetSectionFromFv (
114   IN  EFI_HANDLE                    FvHandle,
115   IN  CONST EFI_GUID                *NameGuid,
116   IN  EFI_SECTION_TYPE              SectionType,
117   IN  UINTN                         SectionInstance,
118   OUT VOID                          **Buffer,
119   OUT UINTN                         *Size
120   )
121 {
122   EFI_STATUS                    Status;
123   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
124   UINT32                        AuthenticationStatus;
125 
126   ASSERT (NameGuid != NULL);
127   ASSERT (Buffer != NULL);
128   ASSERT (Size != NULL);
129 
130   if (FvHandle == NULL) {
131     //
132     // Return EFI_NOT_FOUND directly for NULL FvHandle.
133     //
134     return EFI_NOT_FOUND;
135   }
136 
137   Status = gBS->HandleProtocol (
138                   FvHandle,
139                   &gEfiFirmwareVolume2ProtocolGuid,
140                   (VOID **) &Fv
141                   );
142   if (EFI_ERROR (Status)) {
143     return EFI_NOT_FOUND;
144   }
145 
146   //
147   // Read desired section content in NameGuid file
148   //
149   *Buffer     = NULL;
150   *Size       = 0;
151   Status      = Fv->ReadSection (
152                       Fv,
153                       NameGuid,
154                       SectionType,
155                       SectionInstance,
156                       Buffer,
157                       Size,
158                       &AuthenticationStatus
159                       );
160 
161   if (EFI_ERROR (Status) && (SectionType == EFI_SECTION_TE)) {
162     //
163     // Try reading PE32 section, if the required section is TE type
164     //
165     *Buffer = NULL;
166     *Size   = 0;
167     Status  = Fv->ReadSection (
168                     Fv,
169                     NameGuid,
170                     EFI_SECTION_PE32,
171                     SectionInstance,
172                     Buffer,
173                     Size,
174                     &AuthenticationStatus
175                     );
176   }
177 
178   return Status;
179 }
180 
181 /**
182   Searches all the available firmware volumes and returns the first matching FFS section.
183 
184   This function searches all the firmware volumes for FFS files with FV file type specified by FileType
185   The order that the firmware volumes is searched is not deterministic. For each available FV a search
186   is made for FFS file of type FileType. If the FV contains more than one FFS file with the same FileType,
187   the FileInstance instance will be the matched FFS file. For each FFS file found a search
188   is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances
189   of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
190   Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
191   It is the caller's responsibility to use FreePool() to free the allocated buffer.
192   See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections
193   are retrieved from an FFS file based on SectionType and SectionInstance.
194 
195   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
196   the search will be retried with a section type of EFI_SECTION_PE32.
197   This function must be called with a TPL <= TPL_NOTIFY.
198 
199   If Buffer is NULL, then ASSERT().
200   If Size is NULL, then ASSERT().
201 
202   @param  FileType             Indicates the FV file type to search for within all
203                                available FVs.
204   @param  FileInstance         Indicates which file instance within all available
205                                FVs specified by FileType.
206                                FileInstance starts from zero.
207   @param  SectionType          Indicates the FFS section type to search for
208                                within the FFS file
209                                specified by FileType with FileInstance.
210   @param  SectionInstance      Indicates which section instance within the FFS file
211                                specified by FileType with FileInstance to retrieve.
212                                SectionInstance starts from zero.
213   @param  Buffer               On output, a pointer to a callee allocated buffer
214                                containing the FFS file section that was found.
215                                Is it the caller's responsibility to free this
216                                buffer using FreePool().
217   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
218 
219   @retval  EFI_SUCCESS          The specified FFS section was returned.
220   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
221   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
222                                 the matching FFS section.
223   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a
224                                 device error.
225   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because
226                                 the firmware volume that
227                                 contains the matching FFS section does not allow reads.
228 **/
229 EFI_STATUS
230 EFIAPI
GetSectionFromAnyFvByFileType(IN EFI_FV_FILETYPE FileType,IN UINTN FileInstance,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,OUT VOID ** Buffer,OUT UINTN * Size)231 GetSectionFromAnyFvByFileType  (
232   IN  EFI_FV_FILETYPE               FileType,
233   IN  UINTN                         FileInstance,
234   IN  EFI_SECTION_TYPE              SectionType,
235   IN  UINTN                         SectionInstance,
236   OUT VOID                          **Buffer,
237   OUT UINTN                         *Size
238   )
239 {
240   EFI_STATUS                    Status;
241   EFI_HANDLE                    *HandleBuffer;
242   UINTN                         HandleCount;
243   UINTN                         IndexFv;
244   UINTN                         IndexFile;
245   UINTN                         Key;
246   EFI_GUID                      NameGuid;
247   EFI_FV_FILE_ATTRIBUTES        Attributes;
248   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
249 
250   ASSERT (Buffer != NULL);
251   ASSERT (Size != NULL);
252 
253   //
254   // Locate all available FVs.
255   //
256   HandleBuffer = NULL;
257   Status = gBS->LocateHandleBuffer (
258                   ByProtocol,
259                   &gEfiFirmwareVolume2ProtocolGuid,
260                   NULL,
261                   &HandleCount,
262                   &HandleBuffer
263                   );
264   if (EFI_ERROR (Status)) {
265     return Status;
266   }
267 
268   //
269   // Go through FVs one by one to find the required section data.
270   //
271   for (IndexFv = 0; IndexFv < HandleCount; IndexFv++) {
272     Status = gBS->HandleProtocol (
273                     HandleBuffer[IndexFv],
274                     &gEfiFirmwareVolume2ProtocolGuid,
275                     (VOID **)&Fv
276                     );
277     if (EFI_ERROR (Status)) {
278       continue;
279     }
280 
281     //
282     // Use Firmware Volume 2 Protocol to search for a file of type FileType in all FVs.
283     //
284     IndexFile = FileInstance + 1;
285     Key = 0;
286     do {
287       Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, Size);
288       if (EFI_ERROR (Status)) {
289         break;
290       }
291       IndexFile --;
292     } while (IndexFile > 0);
293 
294     //
295     // Fv File with the required FV file type is found.
296     // Search the section file in the found FV file.
297     //
298     if (IndexFile == 0) {
299       Status = InternalGetSectionFromFv (
300                  HandleBuffer[IndexFv],
301                  &NameGuid,
302                  SectionType,
303                  SectionInstance,
304                  Buffer,
305                  Size
306                  );
307 
308       if (!EFI_ERROR (Status)) {
309         goto Done;
310       }
311     }
312   }
313 
314   //
315   // The required FFS section file is not found.
316   //
317   if (IndexFv == HandleCount) {
318     Status = EFI_NOT_FOUND;
319   }
320 
321 Done:
322   if (HandleBuffer != NULL) {
323     FreePool(HandleBuffer);
324   }
325 
326   return Status;
327 }
328 
329 /**
330   Searches all the availables firmware volumes and returns the first matching FFS section.
331 
332   This function searches all the firmware volumes for FFS files with an FFS filename specified by NameGuid.
333   The order that the firmware volumes is searched is not deterministic. For each FFS file found a search
334   is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances
335   of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
336   Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
337   It is the caller's responsibility to use FreePool() to free the allocated buffer.
338   See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections
339   are retrieved from an FFS file based on SectionType and SectionInstance.
340 
341   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
342   the search will be retried with a section type of EFI_SECTION_PE32.
343   This function must be called with a TPL <= TPL_NOTIFY.
344 
345   If NameGuid is NULL, then ASSERT().
346   If Buffer is NULL, then ASSERT().
347   If Size is NULL, then ASSERT().
348 
349 
350   @param  NameGuid             A pointer to to the FFS filename GUID to search for
351                                within any of the firmware volumes in the platform.
352   @param  SectionType          Indicates the FFS section type to search for within
353                                the FFS file specified by NameGuid.
354   @param  SectionInstance      Indicates which section instance within the FFS file
355                                specified by NameGuid to retrieve.
356   @param  Buffer               On output, a pointer to a callee allocated buffer
357                                containing the FFS file section that was found.
358                                Is it the caller's responsibility to free this buffer
359                                using FreePool().
360   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
361 
362   @retval  EFI_SUCCESS          The specified FFS section was returned.
363   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
364   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to
365                                 retrieve the matching FFS section.
366   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a
367                                 device error.
368   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because the
369                                 firmware volume that
370                                 contains the matching FFS section does not allow reads.
371 **/
372 EFI_STATUS
373 EFIAPI
GetSectionFromAnyFv(IN CONST EFI_GUID * NameGuid,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,OUT VOID ** Buffer,OUT UINTN * Size)374 GetSectionFromAnyFv  (
375   IN CONST  EFI_GUID           *NameGuid,
376   IN        EFI_SECTION_TYPE   SectionType,
377   IN        UINTN              SectionInstance,
378   OUT       VOID               **Buffer,
379   OUT       UINTN              *Size
380   )
381 {
382   EFI_STATUS                    Status;
383   EFI_HANDLE                    *HandleBuffer;
384   UINTN                         HandleCount;
385   UINTN                         Index;
386   EFI_HANDLE                    FvHandle;
387 
388   //
389   // Search the FV that contain the caller's FFS first.
390   // FV builder can choose to build FFS into the this FV
391   // so that this implementation of GetSectionFromAnyFv
392   // will locate the FFS faster.
393   //
394   FvHandle = InternalImageHandleToFvHandle (gImageHandle);
395   Status = InternalGetSectionFromFv (
396              FvHandle,
397              NameGuid,
398              SectionType,
399              SectionInstance,
400              Buffer,
401              Size
402              );
403   if (!EFI_ERROR (Status)) {
404     return EFI_SUCCESS;
405   }
406 
407   HandleBuffer = NULL;
408   Status = gBS->LocateHandleBuffer (
409                   ByProtocol,
410                   &gEfiFirmwareVolume2ProtocolGuid,
411                   NULL,
412                   &HandleCount,
413                   &HandleBuffer
414                   );
415   if (EFI_ERROR (Status)) {
416     goto Done;
417   }
418 
419   for (Index = 0; Index < HandleCount; Index++) {
420     //
421     // Skip the FV that contain the caller's FFS
422     //
423     if (HandleBuffer[Index] != FvHandle) {
424       Status = InternalGetSectionFromFv (
425                  HandleBuffer[Index],
426                  NameGuid,
427                  SectionType,
428                  SectionInstance,
429                  Buffer,
430                  Size
431                  );
432 
433       if (!EFI_ERROR (Status)) {
434         goto Done;
435       }
436     }
437 
438   }
439 
440   if (Index == HandleCount) {
441     Status = EFI_NOT_FOUND;
442   }
443 
444 Done:
445 
446   if (HandleBuffer != NULL) {
447     FreePool(HandleBuffer);
448   }
449   return Status;
450 
451 }
452 
453 /**
454   Searches the firmware volume that the currently executing module was loaded from and returns the first matching FFS section.
455 
456   This function searches the firmware volume that the currently executing module was loaded
457   from for an FFS file with an FFS filename specified by NameGuid. If the FFS file is found a search
458   is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance
459   instances of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
460   Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
461   It is the caller's responsibility to use FreePool() to free the allocated buffer.
462   See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections are retrieved from
463   an FFS file based on SectionType and SectionInstance.
464 
465   If the currently executing module was not loaded from a firmware volume, then EFI_NOT_FOUND is returned.
466   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
467   the search will be retried with a section type of EFI_SECTION_PE32.
468 
469   This function must be called with a TPL <= TPL_NOTIFY.
470   If NameGuid is NULL, then ASSERT().
471   If Buffer is NULL, then ASSERT().
472   If Size is NULL, then ASSERT().
473 
474   @param  NameGuid             A pointer to to the FFS filename GUID to search for
475                                within the firmware volumes that the currently
476                                executing module was loaded from.
477   @param  SectionType          Indicates the FFS section type to search for within
478                                the FFS file specified by NameGuid.
479   @param  SectionInstance      Indicates which section instance within the FFS file
480                                specified by NameGuid to retrieve.
481   @param  Buffer               On output, a pointer to a callee allocated buffer
482                                containing the FFS file section that was found.
483                                Is it the caller's responsibility to free this buffer
484                                using FreePool().
485   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
486 
487 
488   @retval  EFI_SUCCESS          The specified FFS section was returned.
489   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
490   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
491                                 the matching FFS section.
492   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a
493                                 device error.
494   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because the
495                                 firmware volume that contains the matching FFS
496                                 section does not allow reads.
497 **/
498 EFI_STATUS
499 EFIAPI
GetSectionFromFv(IN CONST EFI_GUID * NameGuid,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,OUT VOID ** Buffer,OUT UINTN * Size)500 GetSectionFromFv (
501   IN  CONST EFI_GUID                *NameGuid,
502   IN  EFI_SECTION_TYPE              SectionType,
503   IN  UINTN                         SectionInstance,
504   OUT VOID                          **Buffer,
505   OUT UINTN                         *Size
506     )
507 {
508   return InternalGetSectionFromFv (
509            InternalImageHandleToFvHandle(gImageHandle),
510            NameGuid,
511            SectionType,
512            SectionInstance,
513            Buffer,
514            Size
515            );
516 }
517 
518 
519 /**
520   Searches the FFS file the currently executing module was loaded from and returns the first matching FFS section.
521 
522   This function searches the FFS file that the currently executing module was loaded from for a FFS sections of type SectionType.
523   If the FFS file contains at least SectionInstance instances of the FFS section specified by SectionType,
524   then the SectionInstance instance is returned in Buffer. Buffer is allocated using AllocatePool(),
525   and the size of the allocated buffer is returned in Size. It is the caller's responsibility
526   to use FreePool() to free the allocated buffer. See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for
527   details on how sections are retrieved from an FFS file based on SectionType and SectionInstance.
528 
529   If the currently executing module was not loaded from an FFS file, then EFI_NOT_FOUND is returned.
530   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
531   the search will be retried with a section type of EFI_SECTION_PE32.
532   This function must be called with a TPL <= TPL_NOTIFY.
533 
534   If Buffer is NULL, then ASSERT().
535   If Size is NULL, then ASSERT().
536 
537 
538   @param  SectionType          Indicates the FFS section type to search for within
539                                the FFS file that the currently executing module
540                                was loaded from.
541   @param  SectionInstance      Indicates which section instance to retrieve within
542                                the FFS file that the currently executing module
543                                was loaded from.
544   @param  Buffer               On output, a pointer to a callee allocated buffer
545                                containing the FFS file section that was found.
546                                Is it the caller's responsibility to free this buffer
547                                using FreePool().
548   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
549 
550   @retval  EFI_SUCCESS          The specified FFS section was returned.
551   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
552   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
553                                 the matching FFS section.
554   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a
555                                 device error.
556   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because the
557                                 firmware volume that contains the matching FFS
558                                 section does not allow reads.
559 
560 **/
561 EFI_STATUS
562 EFIAPI
GetSectionFromFfs(IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,OUT VOID ** Buffer,OUT UINTN * Size)563 GetSectionFromFfs (
564   IN  EFI_SECTION_TYPE              SectionType,
565   IN  UINTN                         SectionInstance,
566   OUT VOID                          **Buffer,
567   OUT UINTN                         *Size
568     )
569 {
570   return InternalGetSectionFromFv(
571            InternalImageHandleToFvHandle(gImageHandle),
572            &gEfiCallerIdGuid,
573            SectionType,
574            SectionInstance,
575            Buffer,
576            Size
577            );
578 }
579 
580 
581 /**
582   Get the image file buffer data and buffer size by its device path.
583 
584   Access the file either from a firmware volume, from a file system interface,
585   or from the load file interface.
586 
587   Allocate memory to store the found image. The caller is responsible to free memory.
588 
589   If FilePath is NULL, then NULL is returned.
590   If FileSize is NULL, then NULL is returned.
591   If AuthenticationStatus is NULL, then NULL is returned.
592 
593   @param[in]       BootPolicy           Policy for Open Image File.If TRUE, indicates
594                                         that the request originates from the boot
595                                         manager, and that the boot manager is
596                                         attempting to load FilePath as a boot
597                                         selection. If FALSE, then FilePath must
598                                         match an exact file to be loaded.
599   @param[in]       FilePath             The pointer to the device path of the file
600                                         that is abstracted to the file buffer.
601   @param[out]      FileSize             The pointer to the size of the abstracted
602                                         file buffer.
603   @param[out]      AuthenticationStatus Pointer to the authentication status.
604 
605   @retval NULL   FilePath is NULL, or FileSize is NULL, or AuthenticationStatus is NULL, or the file can't be found.
606   @retval other  The abstracted file buffer. The caller is responsible to free memory.
607 **/
608 VOID *
609 EFIAPI
GetFileBufferByFilePath(IN BOOLEAN BootPolicy,IN CONST EFI_DEVICE_PATH_PROTOCOL * FilePath,OUT UINTN * FileSize,OUT UINT32 * AuthenticationStatus)610 GetFileBufferByFilePath (
611   IN BOOLEAN                           BootPolicy,
612   IN CONST EFI_DEVICE_PATH_PROTOCOL    *FilePath,
613   OUT      UINTN                       *FileSize,
614   OUT UINT32                           *AuthenticationStatus
615   )
616 {
617   EFI_DEVICE_PATH_PROTOCOL          *DevicePathNode;
618   EFI_DEVICE_PATH_PROTOCOL          *OrigDevicePathNode;
619   EFI_DEVICE_PATH_PROTOCOL          *TempDevicePathNode;
620   EFI_HANDLE                        Handle;
621   EFI_GUID                          *FvNameGuid;
622   EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;
623   EFI_SECTION_TYPE                  SectionType;
624   UINT8                             *ImageBuffer;
625   UINTN                             ImageBufferSize;
626   EFI_FV_FILETYPE                   Type;
627   EFI_FV_FILE_ATTRIBUTES            Attrib;
628   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Volume;
629   EFI_FILE_HANDLE                   FileHandle;
630   EFI_FILE_HANDLE                   LastHandle;
631   EFI_FILE_INFO                     *FileInfo;
632   UINTN                             FileInfoSize;
633   EFI_LOAD_FILE_PROTOCOL            *LoadFile;
634   EFI_LOAD_FILE2_PROTOCOL           *LoadFile2;
635   EFI_STATUS                        Status;
636 
637   //
638   // Check input File device path.
639   //
640   if (FilePath == NULL || FileSize == NULL || AuthenticationStatus == NULL) {
641     return NULL;
642   }
643 
644   //
645   // Init local variable
646   //
647   TempDevicePathNode  = NULL;
648   FvNameGuid          = NULL;
649   FileInfo            = NULL;
650   FileHandle          = NULL;
651   ImageBuffer         = NULL;
652   ImageBufferSize     = 0;
653   *AuthenticationStatus = 0;
654 
655   //
656   // Copy File Device Path
657   //
658   OrigDevicePathNode = DuplicateDevicePath (FilePath);
659   if (OrigDevicePathNode == NULL) {
660     return NULL;
661   }
662 
663   //
664   // Check whether this device path support FV2 protocol.
665   // Is so, this device path may contain a Image.
666   //
667   DevicePathNode = OrigDevicePathNode;
668   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);
669   if (!EFI_ERROR (Status)) {
670     //
671     // For FwVol File system there is only a single file name that is a GUID.
672     //
673     FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePathNode);
674     if (FvNameGuid == NULL) {
675       Status = EFI_INVALID_PARAMETER;
676     } else {
677       //
678       // Read image from the firmware file
679       //
680       Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol);
681       if (!EFI_ERROR (Status)) {
682         SectionType = EFI_SECTION_PE32;
683         ImageBuffer = NULL;
684         Status = FwVol->ReadSection (
685                           FwVol,
686                           FvNameGuid,
687                           SectionType,
688                           0,
689                           (VOID **)&ImageBuffer,
690                           &ImageBufferSize,
691                           AuthenticationStatus
692                           );
693         if (EFI_ERROR (Status)) {
694           //
695           // Try a raw file, since a PE32 SECTION does not exist
696           //
697           if (ImageBuffer != NULL) {
698             FreePool (ImageBuffer);
699             *AuthenticationStatus = 0;
700           }
701           ImageBuffer = NULL;
702           Status = FwVol->ReadFile (
703                             FwVol,
704                             FvNameGuid,
705                             (VOID **)&ImageBuffer,
706                             &ImageBufferSize,
707                             &Type,
708                             &Attrib,
709                             AuthenticationStatus
710                             );
711         }
712       }
713     }
714     if (!EFI_ERROR (Status)) {
715       goto Finish;
716     }
717   }
718 
719   //
720   // Attempt to access the file via a file system interface
721   //
722   DevicePathNode = OrigDevicePathNode;
723   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
724   if (!EFI_ERROR (Status)) {
725     Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
726     if (!EFI_ERROR (Status)) {
727       //
728       // Open the Volume to get the File System handle
729       //
730       Status = Volume->OpenVolume (Volume, &FileHandle);
731       if (!EFI_ERROR (Status)) {
732         //
733         // Duplicate the device path to avoid the access to unaligned device path node.
734         // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
735         // nodes, It assures the fields in device path nodes are 2 byte aligned.
736         //
737         TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
738         if (TempDevicePathNode == NULL) {
739           FileHandle->Close (FileHandle);
740           //
741           // Setting Status to an EFI_ERROR value will cause the rest of
742           // the file system support below to be skipped.
743           //
744           Status = EFI_OUT_OF_RESOURCES;
745         }
746         //
747         // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
748         // directory information and filename can be separate. The goal is to inch
749         // our way down each device path node and close the previous node
750         //
751         DevicePathNode = TempDevicePathNode;
752         while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
753           if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
754               DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
755             Status = EFI_UNSUPPORTED;
756             break;
757           }
758 
759           LastHandle = FileHandle;
760           FileHandle = NULL;
761 
762           Status = LastHandle->Open (
763                                 LastHandle,
764                                 &FileHandle,
765                                 ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
766                                 EFI_FILE_MODE_READ,
767                                 0
768                                 );
769 
770           //
771           // Close the previous node
772           //
773           LastHandle->Close (LastHandle);
774 
775           DevicePathNode = NextDevicePathNode (DevicePathNode);
776         }
777 
778         if (!EFI_ERROR (Status)) {
779           //
780           // We have found the file. Now we need to read it. Before we can read the file we need to
781           // figure out how big the file is.
782           //
783           FileInfo = NULL;
784           FileInfoSize = 0;
785           Status = FileHandle->GetInfo (
786                                 FileHandle,
787                                 &gEfiFileInfoGuid,
788                                 &FileInfoSize,
789                                 FileInfo
790                                 );
791 
792           if (Status == EFI_BUFFER_TOO_SMALL) {
793             FileInfo = AllocatePool (FileInfoSize);
794             if (FileInfo == NULL) {
795               Status = EFI_OUT_OF_RESOURCES;
796             } else {
797               Status = FileHandle->GetInfo (
798                                     FileHandle,
799                                     &gEfiFileInfoGuid,
800                                     &FileInfoSize,
801                                     FileInfo
802                                     );
803             }
804           }
805 
806           if (!EFI_ERROR (Status) && (FileInfo != NULL)) {
807             if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
808               //
809               // Allocate space for the file
810               //
811               ImageBuffer = AllocatePool ((UINTN)FileInfo->FileSize);
812               if (ImageBuffer == NULL) {
813                 Status = EFI_OUT_OF_RESOURCES;
814               } else {
815                 //
816                 // Read the file into the buffer we allocated
817                 //
818                 ImageBufferSize = (UINTN)FileInfo->FileSize;
819                 Status          = FileHandle->Read (FileHandle, &ImageBufferSize, ImageBuffer);
820               }
821             }
822           }
823         }
824         //
825         // Close the file and Free FileInfo and TempDevicePathNode since we are done
826         //
827         if (FileInfo != NULL) {
828           FreePool (FileInfo);
829         }
830         if (FileHandle != NULL) {
831           FileHandle->Close (FileHandle);
832         }
833         if (TempDevicePathNode != NULL) {
834           FreePool (TempDevicePathNode);
835         }
836       }
837     }
838     if (!EFI_ERROR (Status)) {
839       goto Finish;
840     }
841   }
842 
843   //
844   // Attempt to access the file via LoadFile2 interface
845   //
846   if (!BootPolicy) {
847     DevicePathNode = OrigDevicePathNode;
848     Status = gBS->LocateDevicePath (&gEfiLoadFile2ProtocolGuid, &DevicePathNode, &Handle);
849     if (!EFI_ERROR (Status)) {
850       Status = gBS->HandleProtocol (Handle, &gEfiLoadFile2ProtocolGuid, (VOID**)&LoadFile2);
851       if (!EFI_ERROR (Status)) {
852         //
853         // Call LoadFile2 with the correct buffer size
854         //
855         ImageBufferSize = 0;
856         ImageBuffer     = NULL;
857         Status = LoadFile2->LoadFile (
858                              LoadFile2,
859                              DevicePathNode,
860                              FALSE,
861                              &ImageBufferSize,
862                              ImageBuffer
863                              );
864         if (Status == EFI_BUFFER_TOO_SMALL) {
865           ImageBuffer = AllocatePool (ImageBufferSize);
866           if (ImageBuffer == NULL) {
867             Status = EFI_OUT_OF_RESOURCES;
868           } else {
869             Status = LoadFile2->LoadFile (
870                                  LoadFile2,
871                                  DevicePathNode,
872                                  FALSE,
873                                  &ImageBufferSize,
874                                  ImageBuffer
875                                  );
876           }
877         }
878       }
879       if (!EFI_ERROR (Status)) {
880         goto Finish;
881       }
882     }
883   }
884 
885   //
886   // Attempt to access the file via LoadFile interface
887   //
888   DevicePathNode = OrigDevicePathNode;
889   Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &DevicePathNode, &Handle);
890   if (!EFI_ERROR (Status)) {
891     Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID**)&LoadFile);
892     if (!EFI_ERROR (Status)) {
893       //
894       // Call LoadFile with the correct buffer size
895       //
896       ImageBufferSize = 0;
897       ImageBuffer     = NULL;
898       Status = LoadFile->LoadFile (
899                            LoadFile,
900                            DevicePathNode,
901                            BootPolicy,
902                            &ImageBufferSize,
903                            ImageBuffer
904                            );
905       if (Status == EFI_BUFFER_TOO_SMALL) {
906         ImageBuffer = AllocatePool (ImageBufferSize);
907         if (ImageBuffer == NULL) {
908           Status = EFI_OUT_OF_RESOURCES;
909         } else {
910           Status = LoadFile->LoadFile (
911                                LoadFile,
912                                DevicePathNode,
913                                BootPolicy,
914                                &ImageBufferSize,
915                                ImageBuffer
916                                );
917         }
918       }
919     }
920   }
921 
922 Finish:
923 
924   if (EFI_ERROR (Status)) {
925     if (ImageBuffer != NULL) {
926       FreePool (ImageBuffer);
927       ImageBuffer = NULL;
928     }
929     *FileSize = 0;
930   } else {
931     *FileSize = ImageBufferSize;
932   }
933 
934   FreePool (OrigDevicePathNode);
935 
936   return ImageBuffer;
937 }
938 
939 /**
940   Searches all the available firmware volumes and returns the file device path of first matching
941   FFS section.
942 
943   This function searches all the firmware volumes for FFS files with an FFS filename specified by NameGuid.
944   The order that the firmware volumes is searched is not deterministic. For each FFS file found a search
945   is made for FFS sections of type SectionType.
946 
947   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
948   the search will be retried with a section type of EFI_SECTION_PE32.
949   This function must be called with a TPL <= TPL_NOTIFY.
950 
951   If NameGuid is NULL, then ASSERT().
952 
953    @param  NameGuid             A pointer to to the FFS filename GUID to search for
954                                 within any of the firmware volumes in the platform.
955    @param  SectionType          Indicates the FFS section type to search for within
956                                 the FFS file specified by NameGuid.
957    @param  SectionInstance      Indicates which section instance within the FFS file
958                                 specified by NameGuid to retrieve.
959    @param  FvFileDevicePath     Device path for the target FFS
960                                 file.
961 
962    @retval  EFI_SUCCESS           The specified file device path of FFS section was returned.
963    @retval  EFI_NOT_FOUND         The specified file device path of FFS section could not be found.
964    @retval  EFI_DEVICE_ERROR      The FFS section could not be retrieves due to a
965                                   device error.
966    @retval  EFI_ACCESS_DENIED     The FFS section could not be retrieves because the
967                                   firmware volume that contains the matching FFS section does not
968                                   allow reads.
969    @retval  EFI_INVALID_PARAMETER FvFileDevicePath is NULL.
970 
971 **/
972 EFI_STATUS
973 EFIAPI
GetFileDevicePathFromAnyFv(IN CONST EFI_GUID * NameGuid,IN EFI_SECTION_TYPE SectionType,IN UINTN SectionInstance,OUT EFI_DEVICE_PATH_PROTOCOL ** FvFileDevicePath)974 GetFileDevicePathFromAnyFv (
975   IN CONST  EFI_GUID                  *NameGuid,
976   IN        EFI_SECTION_TYPE          SectionType,
977   IN        UINTN                     SectionInstance,
978   OUT       EFI_DEVICE_PATH_PROTOCOL  **FvFileDevicePath
979   )
980 {
981   EFI_STATUS                        Status;
982   EFI_HANDLE                        *HandleBuffer;
983   UINTN                             HandleCount;
984   UINTN                             Index;
985   EFI_HANDLE                        FvHandle;
986   EFI_DEVICE_PATH_PROTOCOL          *FvDevicePath;
987   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *TempFvFileDevicePath;
988   VOID                              *Buffer;
989   UINTN                             Size;
990 
991   if (FvFileDevicePath == NULL) {
992     return EFI_INVALID_PARAMETER;
993   }
994 
995   HandleBuffer         = NULL;
996   FvDevicePath         = NULL;
997   TempFvFileDevicePath = NULL;
998   Buffer               = NULL;
999   Size                 = 0;
1000 
1001   //
1002   // Search the FV that contain the caller's FFS first.
1003   // FV builder can choose to build FFS into the this FV
1004   // so that this implementation of GetSectionFromAnyFv
1005   // will locate the FFS faster.
1006   //
1007   FvHandle = InternalImageHandleToFvHandle (gImageHandle);
1008   Status = InternalGetSectionFromFv (
1009              FvHandle,
1010              NameGuid,
1011              SectionType,
1012              SectionInstance,
1013              &Buffer,
1014              &Size
1015              );
1016   if (!EFI_ERROR (Status)) {
1017     goto Done;
1018   }
1019 
1020   Status = gBS->LocateHandleBuffer (
1021                   ByProtocol,
1022                   &gEfiFirmwareVolume2ProtocolGuid,
1023                   NULL,
1024                   &HandleCount,
1025                   &HandleBuffer
1026                   );
1027   if (EFI_ERROR (Status)) {
1028     goto Done;
1029   }
1030 
1031   for (Index = 0; Index < HandleCount; Index++) {
1032     //
1033     // Skip the FV that contain the caller's FFS
1034     //
1035     if (HandleBuffer[Index] != FvHandle) {
1036       Status = InternalGetSectionFromFv (
1037                  HandleBuffer[Index],
1038                  NameGuid,
1039                  SectionType,
1040                  SectionInstance,
1041                  &Buffer,
1042                  &Size
1043                  );
1044 
1045       if (!EFI_ERROR (Status)) {
1046         //
1047         // Update FvHandle to the current handle.
1048         //
1049         FvHandle = HandleBuffer[Index];
1050         goto Done;
1051       }
1052     }
1053   }
1054 
1055   if (Index == HandleCount) {
1056     Status = EFI_NOT_FOUND;
1057   }
1058 
1059 Done:
1060   if (Status == EFI_SUCCESS) {
1061     //
1062     // Build a device path to the file in the FV to pass into gBS->LoadImage
1063     //
1064     Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
1065     if (EFI_ERROR (Status)) {
1066       *FvFileDevicePath = NULL;
1067     } else {
1068       TempFvFileDevicePath = AllocateZeroPool (sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);
1069       if (TempFvFileDevicePath == NULL) {
1070         *FvFileDevicePath = NULL;
1071         return EFI_OUT_OF_RESOURCES;
1072       }
1073       EfiInitializeFwVolDevicepathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH*)TempFvFileDevicePath, NameGuid);
1074       SetDevicePathEndNode (NextDevicePathNode (TempFvFileDevicePath));
1075       *FvFileDevicePath = AppendDevicePath (
1076                             FvDevicePath,
1077                             (EFI_DEVICE_PATH_PROTOCOL *)TempFvFileDevicePath
1078                             );
1079       FreePool (TempFvFileDevicePath);
1080     }
1081   }
1082 
1083   if (Buffer != NULL) {
1084     FreePool (Buffer);
1085   }
1086 
1087   if (HandleBuffer != NULL) {
1088     FreePool (HandleBuffer);
1089   }
1090 
1091   return Status;
1092 }
1093