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