Add new GetFileBufferByFilePath API into DxeServicesLib.
[efi/edk2/.git] / edk2 / MdePkg / Library / DxeServicesLib / DxeServicesLib.c
1 /** @file\r
2   MDE DXE Services Library provides functions that simplify the development of DXE Drivers.  \r
3   These functions help access data from sections of FFS files or from file path.\r
4 \r
5   Copyright (c) 2007 - 2009, Intel Corporation<BR>\r
6   All rights reserved. This program and the accompanying materials\r
7   are licensed and made available under the terms and conditions of the BSD License\r
8   which accompanies this distribution.  The full text of the license may be found at\r
9   http://opensource.org/licenses/bsd-license.php\r
10 \r
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include <PiDxe.h>\r
17 #include <Library/DebugLib.h>\r
18 #include <Library/MemoryAllocationLib.h>\r
19 #include <Library/UefiBootServicesTableLib.h>\r
20 #include <Library/DevicePathLib.h>\r
21 #include <Library/UefiLib.h>\r
22 #include <Library/DxeServicesLib.h>\r
23 #include <Protocol/FirmwareVolume2.h>\r
24 #include <Protocol/LoadedImage.h>\r
25 #include <Protocol/LoadFile2.h>\r
26 #include <Protocol/LoadFile.h>\r
27 #include <Protocol/SimpleFileSystem.h>\r
28 #include <Guid/FileInfo.h>\r
29 \r
30 /**\r
31   Identify the device handle from which the Image is loaded from. As this device handle is passed to\r
32   GetSectionFromFv as the identifier for a Firmware Volume, an EFI_FIRMWARE_VOLUME2_PROTOCOL \r
33   protocol instance should be located succesfully by calling gBS->HandleProtocol ().\r
34 \r
35   This function locates the EFI_LOADED_IMAGE_PROTOCOL instance installed\r
36   on ImageHandle. It then returns EFI_LOADED_IMAGE_PROTOCOL.DeviceHandle.\r
37   \r
38   If ImageHandle is NULL, then ASSERT ();\r
39   If failed to locate a EFI_LOADED_IMAGE_PROTOCOL on ImageHandle, then ASSERT ();\r
40   \r
41   @param  ImageHandle         The firmware allocated handle for UEFI image.\r
42 \r
43   @retval  EFI_HANDLE          The device handle from which the Image is loaded from.\r
44 \r
45 **/\r
46 EFI_HANDLE\r
47 InternalImageHandleToFvHandle (\r
48   EFI_HANDLE ImageHandle\r
49   )\r
50 {\r
51   EFI_STATUS                    Status;\r
52   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
53   \r
54   ASSERT (ImageHandle != NULL);\r
55 \r
56   Status = gBS->HandleProtocol (\r
57              (EFI_HANDLE *) ImageHandle,\r
58              &gEfiLoadedImageProtocolGuid,\r
59              (VOID **) &LoadedImage\r
60              );\r
61 \r
62   ASSERT_EFI_ERROR (Status);\r
63 \r
64   return LoadedImage->DeviceHandle;\r
65 \r
66 }\r
67 \r
68 /**\r
69   Allocate and fill a buffer from a Firmware Section identified by a Firmware File GUID name, a Firmware \r
70   Section type and instance number from the specified Firmware Volume.\r
71 \r
72   This functions first locate the EFI_FIRMWARE_VOLUME2_PROTOCOL protocol instance on FvHandle in order to \r
73   carry out the Firmware Volume read operation. The function then reads the Firmware Section found sepcifed \r
74   by NameGuid, SectionType and SectionInstance. \r
75   \r
76   The details of this search order is defined in description of EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection () \r
77   found in PI Specification.\r
78   \r
79   If SectionType is EFI_SECTION_TE, EFI_SECTION_TE is used as section type to start the search. If EFI_SECTION_TE section \r
80   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 \r
81   is returned.\r
82   \r
83   The data and size is returned by Buffer and Size. The caller is responsible to free the Buffer allocated \r
84   by this function. This function can be only called at TPL_NOTIFY and below.\r
85   \r
86   If FvHandle is NULL, then ASSERT ();\r
87   If NameGuid is NULL, then ASSERT();\r
88   If Buffer is NULL, then ASSERT();\r
89   If Size is NULL, then ASSERT().\r
90 \r
91   @param  FvHandle                The device handle that contains a instance of EFI_FIRMWARE_VOLUME2_PROTOCOL instance.\r
92   @param  NameGuid                The GUID name of a Firmware File.\r
93   @param  SectionType             The Firmware Section type.\r
94   @param  SectionInstance         The instance number of Firmware Section to read from starting from 0.\r
95   @param  Buffer                  On output, Buffer contains the the data read from the section in the Firmware File found.\r
96   @param  Size                    On output, the size of Buffer.\r
97 \r
98   @retval  EFI_SUCCESS            The image is found and data and size is returned.\r
99   @retval  EFI_NOT_FOUND          The image specified by NameGuid and SectionType can't be found.\r
100   @retval  EFI_OUT_OF_RESOURCES   There were not enough resources to allocate the output data buffer or complete the operations.\r
101   @retval  EFI_DEVICE_ERROR       A hardware error occurs during reading from the Firmware Volume.\r
102   @retval  EFI_ACCESS_DENIED      The firmware volume containing the searched Firmware File is configured to disallow reads.\r
103   \r
104 **/\r
105 EFI_STATUS\r
106 InternalGetSectionFromFv (\r
107   IN  EFI_HANDLE                    FvHandle,\r
108   IN  CONST EFI_GUID                *NameGuid,\r
109   IN  EFI_SECTION_TYPE              SectionType,\r
110   IN  UINTN                         SectionInstance,\r
111   OUT VOID                          **Buffer,\r
112   OUT UINTN                         *Size\r
113   )\r
114 {\r
115   EFI_STATUS                    Status;\r
116   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
117   UINT32                        AuthenticationStatus;\r
118 \r
119   ASSERT (NameGuid != NULL);\r
120   ASSERT (Buffer != NULL);\r
121   ASSERT (Size != NULL);\r
122   \r
123   ASSERT (FvHandle != NULL);\r
124 \r
125   Status = gBS->HandleProtocol (\r
126                   FvHandle,\r
127                   &gEfiFirmwareVolume2ProtocolGuid,\r
128                   (VOID **) &Fv\r
129                   );\r
130   if (EFI_ERROR (Status)) {\r
131     return EFI_NOT_FOUND;\r
132   }\r
133 \r
134   //\r
135   // Read desired section content in NameGuid file\r
136   //\r
137   *Buffer     = NULL;\r
138   *Size       = 0;\r
139   Status      = Fv->ReadSection (\r
140                       Fv,\r
141                       NameGuid,\r
142                       SectionType,\r
143                       SectionInstance,\r
144                       Buffer,\r
145                       Size,\r
146                       &AuthenticationStatus\r
147                       );\r
148 \r
149   if (EFI_ERROR (Status) && (SectionType == EFI_SECTION_TE)) {\r
150     //\r
151     // Try reading PE32 section, if the required section is TE type \r
152     //\r
153     *Buffer = NULL;\r
154     *Size   = 0;\r
155     Status  = Fv->ReadSection (\r
156                     Fv,\r
157                     NameGuid,\r
158                     EFI_SECTION_PE32,\r
159                     SectionInstance,\r
160                     Buffer,\r
161                     Size,\r
162                     &AuthenticationStatus\r
163                     );\r
164   }\r
165 \r
166   return Status;\r
167 }\r
168 \r
169 \r
170 \r
171 /**\r
172   Searches all the availables firmware volumes and returns the first matching FFS section. \r
173 \r
174   This function searches all the firmware volumes for FFS files with an FFS filename specified by NameGuid.  \r
175   The order that the firmware volumes is searched is not deterministic. For each FFS file found a search \r
176   is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances \r
177   of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer. \r
178   Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size. \r
179   It is the caller's responsibility to use FreePool() to free the allocated buffer.  \r
180   See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections \r
181   are retrieved from an FFS file based on SectionType and SectionInstance.\r
182 \r
183   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails, \r
184   the search will be retried with a section type of EFI_SECTION_PE32.\r
185   This function must be called with a TPL <= TPL_NOTIFY.\r
186 \r
187   If NameGuid is NULL, then ASSERT().\r
188   If Buffer is NULL, then ASSERT().\r
189   If Size is NULL, then ASSERT().\r
190 \r
191 \r
192   @param  NameGuid             A pointer to to the FFS filename GUID to search for within \r
193                                any of the firmware volumes in the platform. \r
194   @param  SectionType          Indicates the FFS section type to search for within the FFS file specified by NameGuid.\r
195   @param  SectionInstance      Indicates which section instance within the FFS file specified by NameGuid to retrieve.\r
196   @param  Buffer               On output, a pointer to a callee allocated buffer containing the FFS file section that was found.  \r
197                                Is it the caller's responsibility to free this buffer using FreePool().\r
198   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.\r
199 \r
200   @retval  EFI_SUCCESS          The specified FFS section was returned.\r
201   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.\r
202   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve the matching FFS section.\r
203   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a device error.\r
204   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because the firmware volume that \r
205                                 contains the matching FFS section does not allow reads.\r
206 **/\r
207 EFI_STATUS\r
208 EFIAPI\r
209 GetSectionFromAnyFv  (\r
210   IN CONST  EFI_GUID           *NameGuid,\r
211   IN        EFI_SECTION_TYPE   SectionType,\r
212   IN        UINTN              SectionInstance,\r
213   OUT       VOID               **Buffer,\r
214   OUT       UINTN              *Size\r
215   )\r
216 {\r
217   EFI_STATUS                    Status;\r
218   EFI_HANDLE                    *HandleBuffer;\r
219   UINTN                         HandleCount;\r
220   UINTN                         Index;\r
221   EFI_HANDLE                    FvHandle;\r
222 \r
223   //\r
224   // Search the FV that contain the caller's FFS first.\r
225   // FV builder can choose to build FFS into the this FV\r
226   // so that this implementation of GetSectionFromAnyFv\r
227   // will locate the FFS faster.\r
228   //\r
229   FvHandle = InternalImageHandleToFvHandle (gImageHandle);\r
230   Status = InternalGetSectionFromFv (\r
231              FvHandle,\r
232              NameGuid,\r
233              SectionType,\r
234              SectionInstance,\r
235              Buffer,\r
236              Size\r
237              );\r
238   if (!EFI_ERROR (Status)) {\r
239     return EFI_SUCCESS;\r
240   }\r
241 \r
242   HandleBuffer = NULL;\r
243   Status = gBS->LocateHandleBuffer (\r
244                   ByProtocol,\r
245                   &gEfiFirmwareVolume2ProtocolGuid,\r
246                   NULL,\r
247                   &HandleCount,\r
248                   &HandleBuffer\r
249                   );\r
250   if (EFI_ERROR (Status)) {\r
251     goto Done;\r
252   }\r
253 \r
254   for (Index = 0; Index < HandleCount; Index++) {\r
255     //\r
256     // Skip the FV that contain the caller's FFS\r
257     //\r
258     if (HandleBuffer[Index] != FvHandle) {\r
259       Status = InternalGetSectionFromFv (\r
260                  HandleBuffer[Index], \r
261                  NameGuid, \r
262                  SectionType, \r
263                  SectionInstance,\r
264                  Buffer, \r
265                  Size\r
266                  );\r
267 \r
268       if (!EFI_ERROR (Status)) {\r
269         goto Done;\r
270       }\r
271     }\r
272 \r
273   }\r
274 \r
275   if (Index == HandleCount) {\r
276     Status = EFI_NOT_FOUND;\r
277   }\r
278 \r
279 Done:\r
280   \r
281   if (HandleBuffer != NULL) {  \r
282     FreePool(HandleBuffer);\r
283   }\r
284   return Status;\r
285   \r
286 }\r
287 \r
288 /**\r
289   Searches the firmware volume that the currently executing module was loaded from and returns the first matching FFS section. \r
290 \r
291   This function searches the firmware volume that the currently executing module was loaded \r
292   from for an FFS file with an FFS filename specified by NameGuid. If the FFS file is found a search \r
293   is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance \r
294   instances of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.\r
295   Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size. \r
296   It is the caller's responsibility to use FreePool() to free the allocated buffer. \r
297   See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections are retrieved from \r
298   an FFS file based on SectionType and SectionInstance.\r
299 \r
300   If the currently executing module was not loaded from a firmware volume, then EFI_NOT_FOUND is returned.\r
301   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails, \r
302   the search will be retried with a section type of EFI_SECTION_PE32.\r
303   \r
304   This function must be called with a TPL <= TPL_NOTIFY.\r
305   If NameGuid is NULL, then ASSERT().\r
306   If Buffer is NULL, then ASSERT().\r
307   If Size is NULL, then ASSERT().\r
308 \r
309   @param  NameGuid             A pointer to to the FFS filename GUID to search for within \r
310                                the firmware volumes that the currently executing module was loaded from.\r
311   @param  SectionType          Indicates the FFS section type to search for within the FFS file specified by NameGuid.\r
312   @param  SectionInstance      Indicates which section instance within the FFS file specified by NameGuid to retrieve.\r
313   @param  Buffer               On output, a pointer to a callee allocated buffer containing the FFS file section that was found.  \r
314                                Is it the caller's responsibility to free this buffer using FreePool().\r
315   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.\r
316 \r
317 \r
318   @retval  EFI_SUCCESS          The specified FFS section was returned.\r
319   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.\r
320   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve the matching FFS section.\r
321   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a device error.\r
322   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because the firmware volume that \r
323                                 contains the matching FFS section does not allow reads.  \r
324 **/\r
325 EFI_STATUS\r
326 EFIAPI\r
327 GetSectionFromFv (\r
328   IN  CONST EFI_GUID                *NameGuid,\r
329   IN  EFI_SECTION_TYPE              SectionType,\r
330   IN  UINTN                         SectionInstance,\r
331   OUT VOID                          **Buffer,\r
332   OUT UINTN                         *Size\r
333     )\r
334 {\r
335   return InternalGetSectionFromFv (\r
336            InternalImageHandleToFvHandle(gImageHandle),\r
337            NameGuid,\r
338            SectionType,\r
339            SectionInstance,\r
340            Buffer,\r
341            Size\r
342            );\r
343 }\r
344 \r
345 \r
346 /**\r
347   Searches the FFS file the the currently executing module was loaded from and returns the first matching FFS section.\r
348 \r
349   This function searches the FFS file that the currently executing module was loaded from for a FFS sections of type SectionType.\r
350   If the FFS file contains at least SectionInstance instances of the FFS section specified by SectionType, \r
351   then the SectionInstance instance is returned in Buffer. Buffer is allocated using AllocatePool(), \r
352   and the size of the allocated buffer is returned in Size. It is the caller's responsibility \r
353   to use FreePool() to free the allocated buffer. See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for \r
354   details on how sections are retrieved from an FFS file based on SectionType and SectionInstance.\r
355 \r
356   If the currently executing module was not loaded from an FFS file, then EFI_NOT_FOUND is returned.\r
357   If SectionType is EFI_SECTION_TE, and the search with an FFS file fails, \r
358   the search will be retried with a section type of EFI_SECTION_PE32.\r
359   This function must be called with a TPL <= TPL_NOTIFY.\r
360   \r
361   If Buffer is NULL, then ASSERT().\r
362   If Size is NULL, then ASSERT().\r
363 \r
364 \r
365   @param  SectionType          Indicates the FFS section type to search for within the FFS file \r
366                                that the currently executing module was loaded from.\r
367   @param  SectionInstance      Indicates which section instance to retrieve within the FFS file \r
368                                that the currently executing module was loaded from.\r
369   @param  Buffer               On output, a pointer to a callee allocated buffer containing the FFS file section that was found.  \r
370                                Is it the caller's responsibility to free this buffer using FreePool().\r
371   @param  Size                 On output, a pointer to the size, in bytes, of Buffer.\r
372 \r
373   @retval  EFI_SUCCESS          The specified FFS section was returned.\r
374   @retval  EFI_NOT_FOUND        The specified FFS section could not be found.\r
375   @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve the matching FFS section.\r
376   @retval  EFI_DEVICE_ERROR     The FFS section could not be retrieves due to a device error.\r
377   @retval  EFI_ACCESS_DENIED    The FFS section could not be retrieves because the firmware volume that \r
378                                 contains the matching FFS section does not allow reads.  \r
379   \r
380 **/\r
381 EFI_STATUS\r
382 EFIAPI\r
383 GetSectionFromFfs (\r
384   IN  EFI_SECTION_TYPE              SectionType,\r
385   IN  UINTN                         SectionInstance,\r
386   OUT VOID                          **Buffer,\r
387   OUT UINTN                         *Size\r
388     )\r
389 {\r
390   return InternalGetSectionFromFv(\r
391            InternalImageHandleToFvHandle(gImageHandle),\r
392            &gEfiCallerIdGuid,\r
393            SectionType,\r
394            SectionInstance,\r
395            Buffer,\r
396            Size\r
397            );\r
398 }\r
399 \r
400 \r
401 /**\r
402   Get the image file buffer data and buffer size by its device path. \r
403   \r
404   Access the file either from a a firmware volume, from a file system interface, \r
405   or from the load file interface.\r
406   \r
407   Allocate memory to store the found image. The caller is responsible to free memory.\r
408 \r
409   If File is NULL, then NULL is returned.\r
410   If FileSize is NULL, then NULL is returned.\r
411   If AuthenticationStatus is NULL, then NULL is returned.\r
412 \r
413   @param[in]       BootPolicy \r
414                              Policy for Open Image File.If TRUE, indicates that the request \r
415                              originates from the boot manager, and that the boot manager is\r
416                              attempting to load FilePath as a boot selection. If FALSE, \r
417                              then FilePath must match an exact file to be loaded.\r
418   @param[in]       FilePath  Pointer to the device path of the file that is absracted to the file buffer.\r
419   @param[out]      FileSize  Pointer to the size of the abstracted file buffer.\r
420   @param[out]      AuthenticationStatus   \r
421                              Pointer to a caller-allocated UINT32 in which\r
422                              the authentication status is returned.\r
423 \r
424   @retval NULL   File is NULL, or FileSize is NULL. Or the file can't be found.\r
425   @retval other  The abstracted file buffer. The caller is responsible to free memory.\r
426 **/\r
427 VOID *\r
428 EFIAPI\r
429 GetFileBufferByFilePath (\r
430   IN BOOLEAN                           BootPolicy,\r
431   IN CONST EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
432   OUT      UINTN                       *FileSize,\r
433   OUT UINT32                           *AuthenticationStatus\r
434   )\r
435 {\r
436   EFI_DEVICE_PATH_PROTOCOL          *DevicePathNode;\r
437   EFI_DEVICE_PATH_PROTOCOL          *OrigDevicePathNode;\r
438   EFI_HANDLE                        Handle;\r
439   EFI_GUID                          *FvNameGuid;\r
440   EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;\r
441   EFI_SECTION_TYPE                  SectionType;\r
442   UINT8                             *ImageBuffer;\r
443   UINTN                             ImageBufferSize;\r
444   EFI_FV_FILETYPE                   Type;\r
445   EFI_FV_FILE_ATTRIBUTES            Attrib;\r
446   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Volume;\r
447   EFI_FILE_HANDLE                   FileHandle;\r
448   EFI_FILE_HANDLE                   LastHandle;\r
449   EFI_FILE_INFO                     *FileInfo;\r
450   UINTN                             FileInfoSize;\r
451   EFI_LOAD_FILE_PROTOCOL            *LoadFile;\r
452   EFI_LOAD_FILE2_PROTOCOL           *LoadFile2;\r
453   EFI_STATUS                        Status;\r
454 \r
455   //\r
456   // Check input File device path.\r
457   //\r
458   if (FilePath == NULL || FileSize == NULL || AuthenticationStatus == NULL) {\r
459     return NULL;\r
460   }\r
461 \r
462   //\r
463   // Init local variable\r
464   //\r
465   FvNameGuid          = NULL;\r
466   FileInfo            = NULL;\r
467   FileHandle          = NULL;\r
468   ImageBuffer         = NULL;\r
469   ImageBufferSize     = 0;\r
470   *AuthenticationStatus = 0;\r
471   \r
472   //\r
473   // Copy File Device Path\r
474   //\r
475   OrigDevicePathNode = DuplicateDevicePath (FilePath);\r
476   if (OrigDevicePathNode == NULL) {\r
477     return NULL;\r
478   }\r
479 \r
480   //\r
481   // Check whether this device path support FV2 protocol.\r
482   // Is so, this device path may contain a Image.\r
483   //\r
484   DevicePathNode = OrigDevicePathNode;\r
485   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);\r
486   if (!EFI_ERROR (Status)) {\r
487     //\r
488     // For FwVol File system there is only a single file name that is a GUID.\r
489     //\r
490     FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePathNode);\r
491     if (FvNameGuid == NULL) {\r
492       Status = EFI_INVALID_PARAMETER;\r
493     } else {\r
494       //\r
495       // Read image from the firmware file\r
496       //\r
497       Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol);\r
498       if (!EFI_ERROR (Status)) {\r
499         SectionType = EFI_SECTION_PE32;\r
500         ImageBuffer = NULL;\r
501         Status = FwVol->ReadSection (\r
502                           FwVol,\r
503                           FvNameGuid,\r
504                           SectionType,\r
505                           0,\r
506                           (VOID **)&ImageBuffer,\r
507                           &ImageBufferSize,\r
508                           AuthenticationStatus\r
509                           );\r
510         if (EFI_ERROR (Status)) {\r
511           //\r
512           // Try a raw file, since a PE32 SECTION does not exist\r
513           //\r
514           if (ImageBuffer != NULL) {\r
515             FreePool (ImageBuffer);\r
516             *AuthenticationStatus = 0;\r
517           }\r
518           ImageBuffer = NULL;\r
519           Status = FwVol->ReadFile (\r
520                             FwVol,\r
521                             FvNameGuid,\r
522                             (VOID **)&ImageBuffer,\r
523                             &ImageBufferSize,\r
524                             &Type,\r
525                             &Attrib,\r
526                             AuthenticationStatus\r
527                             );\r
528         }\r
529       }\r
530     }\r
531     goto Finish;\r
532   }\r
533 \r
534   //\r
535   // Attempt to access the file via a file system interface\r
536   //\r
537   DevicePathNode = OrigDevicePathNode;\r
538   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);\r
539   if (!EFI_ERROR (Status)) {\r
540     Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);\r
541     if (!EFI_ERROR (Status)) {\r
542       //\r
543       // Open the Volume to get the File System handle\r
544       //\r
545       Status = Volume->OpenVolume (Volume, &FileHandle);\r
546       if (!EFI_ERROR (Status)) {\r
547         //\r
548         // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the\r
549         // directory information and filename can be seperate. The goal is to inch\r
550         // our way down each device path node and close the previous node\r
551         //\r
552         while (!IsDevicePathEnd (DevicePathNode) && !EFI_ERROR (Status)) {\r
553           if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||\r
554               DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {\r
555             Status = EFI_UNSUPPORTED;\r
556             break;\r
557           }\r
558   \r
559           LastHandle = FileHandle;\r
560           FileHandle = NULL;\r
561   \r
562           Status = LastHandle->Open (\r
563                                 LastHandle,\r
564                                 &FileHandle,\r
565                                 ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,\r
566                                 EFI_FILE_MODE_READ,\r
567                                 0\r
568                                 );\r
569   \r
570           //\r
571           // Close the previous node\r
572           //\r
573           LastHandle->Close (LastHandle);\r
574   \r
575           DevicePathNode = NextDevicePathNode (DevicePathNode);\r
576         }\r
577   \r
578         if (!EFI_ERROR (Status)) {\r
579           //\r
580           // We have found the file. Now we need to read it. Before we can read the file we need to\r
581           // figure out how big the file is.\r
582           //\r
583           FileInfo = NULL;\r
584           FileInfoSize = 0;\r
585           Status = FileHandle->GetInfo (\r
586                                 FileHandle,\r
587                                 &gEfiFileInfoGuid,\r
588                                 &FileInfoSize,\r
589                                 FileInfo\r
590                                 );\r
591   \r
592           if (Status == EFI_BUFFER_TOO_SMALL) {\r
593             FileInfo = AllocatePool (FileInfoSize);\r
594             if (FileInfo == NULL) {\r
595               Status = EFI_OUT_OF_RESOURCES;\r
596             } else {\r
597               Status = FileHandle->GetInfo (\r
598                                     FileHandle,\r
599                                     &gEfiFileInfoGuid,\r
600                                     &FileInfoSize,\r
601                                     FileInfo\r
602                                     );\r
603             }\r
604           }\r
605           \r
606           if (!EFI_ERROR (Status)) {\r
607             //\r
608             // Allocate space for the file\r
609             //\r
610             ImageBuffer = AllocatePool ((UINTN)FileInfo->FileSize);\r
611             if (ImageBuffer == NULL) {\r
612               Status = EFI_OUT_OF_RESOURCES;\r
613             } else {\r
614               //\r
615               // Read the file into the buffer we allocated\r
616               //\r
617               ImageBufferSize = (UINTN)FileInfo->FileSize;\r
618               Status          = FileHandle->Read (FileHandle, &ImageBufferSize, ImageBuffer);\r
619             }\r
620           }\r
621         }\r
622         //\r
623         // Close the file and Free FileInfo since we are done\r
624         // \r
625         if (FileInfo != NULL) {\r
626           FreePool (FileInfo);\r
627         }\r
628         if (FileHandle != NULL) {\r
629           FileHandle->Close (FileHandle);\r
630         }\r
631       }\r
632     }\r
633     goto Finish;\r
634   }\r
635 \r
636   //\r
637   // Attempt to access the file via LoadFile2 interface\r
638   //\r
639   if (!BootPolicy) {\r
640     DevicePathNode = OrigDevicePathNode;\r
641     Status = gBS->LocateDevicePath (&gEfiLoadFile2ProtocolGuid, &DevicePathNode, &Handle);\r
642     if (!EFI_ERROR (Status)) {\r
643       Status = gBS->HandleProtocol (Handle, &gEfiLoadFile2ProtocolGuid, (VOID**)&LoadFile2);\r
644       if (!EFI_ERROR (Status)) {\r
645         //\r
646         // Call LoadFile2 with the correct buffer size\r
647         //\r
648         ImageBufferSize = 0;\r
649         ImageBuffer     = NULL;\r
650         Status = LoadFile2->LoadFile (\r
651                              LoadFile2,\r
652                              DevicePathNode,\r
653                              FALSE,\r
654                              &ImageBufferSize,\r
655                              ImageBuffer\r
656                              );\r
657         if (Status == EFI_BUFFER_TOO_SMALL) {\r
658           ImageBuffer = AllocatePool (ImageBufferSize);\r
659           if (ImageBuffer == NULL) {\r
660             Status = EFI_OUT_OF_RESOURCES;\r
661           } else {\r
662             Status = LoadFile2->LoadFile (\r
663                                  LoadFile2,\r
664                                  DevicePathNode,\r
665                                  BootPolicy,\r
666                                  &ImageBufferSize,\r
667                                  ImageBuffer\r
668                                  );\r
669           }\r
670         }\r
671       }\r
672       goto Finish;\r
673     }\r
674   }\r
675 \r
676   //\r
677   // Attempt to access the file via LoadFile interface\r
678   //\r
679   DevicePathNode = OrigDevicePathNode;\r
680   Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &DevicePathNode, &Handle);\r
681   if (!EFI_ERROR (Status)) {\r
682     Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID**)&LoadFile);\r
683     if (!EFI_ERROR (Status)) {\r
684       //\r
685       // Call LoadFile with the correct buffer size\r
686       //\r
687       ImageBufferSize = 0;\r
688       ImageBuffer     = NULL;\r
689       Status = LoadFile->LoadFile (\r
690                            LoadFile,\r
691                            DevicePathNode,\r
692                            BootPolicy,\r
693                            &ImageBufferSize,\r
694                            ImageBuffer\r
695                            );\r
696       if (Status == EFI_BUFFER_TOO_SMALL) {\r
697         ImageBuffer = AllocatePool (ImageBufferSize);\r
698         if (ImageBuffer == NULL) {\r
699           Status = EFI_OUT_OF_RESOURCES;\r
700         } else {\r
701           Status = LoadFile->LoadFile (\r
702                                LoadFile,\r
703                                DevicePathNode,\r
704                                BootPolicy,\r
705                                &ImageBufferSize,\r
706                                ImageBuffer\r
707                                );\r
708         }\r
709       }\r
710     }\r
711   }\r
712 \r
713 Finish:\r
714 \r
715   if (EFI_ERROR (Status)) {\r
716     if (ImageBuffer != NULL) {\r
717       FreePool (ImageBuffer);\r
718       ImageBuffer = NULL;\r
719     }\r
720     *FileSize = 0;\r
721   } else {\r
722     *FileSize = ImageBufferSize;\r
723   }\r
724 \r
725   FreePool (OrigDevicePathNode);\r
726 \r
727   return ImageBuffer;\r
728 }\r