]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/DxeServicesLib/DxeServicesLib.c
MdePkg: Check input Ptrs in GetSectionFromAnyFvByFileType
[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 - 2018, 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 ASSERT (Buffer != NULL);
257 ASSERT (Size != NULL);
258
259 //
260 // Locate all available FVs.
261 //
262 HandleBuffer = NULL;
263 Status = gBS->LocateHandleBuffer (
264 ByProtocol,
265 &gEfiFirmwareVolume2ProtocolGuid,
266 NULL,
267 &HandleCount,
268 &HandleBuffer
269 );
270 if (EFI_ERROR (Status)) {
271 return Status;
272 }
273
274 //
275 // Go through FVs one by one to find the required section data.
276 //
277 for (IndexFv = 0; IndexFv < HandleCount; IndexFv++) {
278 Status = gBS->HandleProtocol (
279 HandleBuffer[IndexFv],
280 &gEfiFirmwareVolume2ProtocolGuid,
281 (VOID **)&Fv
282 );
283 if (EFI_ERROR (Status)) {
284 continue;
285 }
286
287 //
288 // Use Firmware Volume 2 Protocol to search for a file of type FileType in all FVs.
289 //
290 IndexFile = FileInstance + 1;
291 Key = 0;
292 do {
293 Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, Size);
294 if (EFI_ERROR (Status)) {
295 break;
296 }
297 IndexFile --;
298 } while (IndexFile > 0);
299
300 //
301 // Fv File with the required FV file type is found.
302 // Search the section file in the found FV file.
303 //
304 if (IndexFile == 0) {
305 Status = InternalGetSectionFromFv (
306 HandleBuffer[IndexFv],
307 &NameGuid,
308 SectionType,
309 SectionInstance,
310 Buffer,
311 Size
312 );
313
314 if (!EFI_ERROR (Status)) {
315 goto Done;
316 }
317 }
318 }
319
320 //
321 // The required FFS section file is not found.
322 //
323 if (IndexFv == HandleCount) {
324 Status = EFI_NOT_FOUND;
325 }
326
327 Done:
328 if (HandleBuffer != NULL) {
329 FreePool(HandleBuffer);
330 }
331
332 return Status;
333 }
334
335 /**
336 Searches all the availables firmware volumes and returns the first matching FFS section.
337
338 This function searches all the firmware volumes for FFS files with an FFS filename specified by NameGuid.
339 The order that the firmware volumes is searched is not deterministic. For each FFS file found a search
340 is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances
341 of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
342 Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
343 It is the caller's responsibility to use FreePool() to free the allocated buffer.
344 See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections
345 are retrieved from an FFS file based on SectionType and SectionInstance.
346
347 If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
348 the search will be retried with a section type of EFI_SECTION_PE32.
349 This function must be called with a TPL <= TPL_NOTIFY.
350
351 If NameGuid is NULL, then ASSERT().
352 If Buffer is NULL, then ASSERT().
353 If Size is NULL, then ASSERT().
354
355
356 @param NameGuid A pointer to to the FFS filename GUID to search for
357 within any of the firmware volumes in the platform.
358 @param SectionType Indicates the FFS section type to search for within
359 the FFS file specified by NameGuid.
360 @param SectionInstance Indicates which section instance within the FFS file
361 specified by NameGuid to retrieve.
362 @param Buffer On output, a pointer to a callee allocated buffer
363 containing the FFS file section that was found.
364 Is it the caller's responsibility to free this buffer
365 using FreePool().
366 @param Size On output, a pointer to the size, in bytes, of Buffer.
367
368 @retval EFI_SUCCESS The specified FFS section was returned.
369 @retval EFI_NOT_FOUND The specified FFS section could not be found.
370 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
371 retrieve the matching FFS section.
372 @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
373 device error.
374 @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
375 firmware volume that
376 contains the matching FFS section does not allow reads.
377 **/
378 EFI_STATUS
379 EFIAPI
380 GetSectionFromAnyFv (
381 IN CONST EFI_GUID *NameGuid,
382 IN EFI_SECTION_TYPE SectionType,
383 IN UINTN SectionInstance,
384 OUT VOID **Buffer,
385 OUT UINTN *Size
386 )
387 {
388 EFI_STATUS Status;
389 EFI_HANDLE *HandleBuffer;
390 UINTN HandleCount;
391 UINTN Index;
392 EFI_HANDLE FvHandle;
393
394 //
395 // Search the FV that contain the caller's FFS first.
396 // FV builder can choose to build FFS into the this FV
397 // so that this implementation of GetSectionFromAnyFv
398 // will locate the FFS faster.
399 //
400 FvHandle = InternalImageHandleToFvHandle (gImageHandle);
401 Status = InternalGetSectionFromFv (
402 FvHandle,
403 NameGuid,
404 SectionType,
405 SectionInstance,
406 Buffer,
407 Size
408 );
409 if (!EFI_ERROR (Status)) {
410 return EFI_SUCCESS;
411 }
412
413 HandleBuffer = NULL;
414 Status = gBS->LocateHandleBuffer (
415 ByProtocol,
416 &gEfiFirmwareVolume2ProtocolGuid,
417 NULL,
418 &HandleCount,
419 &HandleBuffer
420 );
421 if (EFI_ERROR (Status)) {
422 goto Done;
423 }
424
425 for (Index = 0; Index < HandleCount; Index++) {
426 //
427 // Skip the FV that contain the caller's FFS
428 //
429 if (HandleBuffer[Index] != FvHandle) {
430 Status = InternalGetSectionFromFv (
431 HandleBuffer[Index],
432 NameGuid,
433 SectionType,
434 SectionInstance,
435 Buffer,
436 Size
437 );
438
439 if (!EFI_ERROR (Status)) {
440 goto Done;
441 }
442 }
443
444 }
445
446 if (Index == HandleCount) {
447 Status = EFI_NOT_FOUND;
448 }
449
450 Done:
451
452 if (HandleBuffer != NULL) {
453 FreePool(HandleBuffer);
454 }
455 return Status;
456
457 }
458
459 /**
460 Searches the firmware volume that the currently executing module was loaded from and returns the first matching FFS section.
461
462 This function searches the firmware volume that the currently executing module was loaded
463 from for an FFS file with an FFS filename specified by NameGuid. If the FFS file is found a search
464 is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance
465 instances of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
466 Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
467 It is the caller's responsibility to use FreePool() to free the allocated buffer.
468 See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections are retrieved from
469 an FFS file based on SectionType and SectionInstance.
470
471 If the currently executing module was not loaded from a firmware volume, then EFI_NOT_FOUND is returned.
472 If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
473 the search will be retried with a section type of EFI_SECTION_PE32.
474
475 This function must be called with a TPL <= TPL_NOTIFY.
476 If NameGuid is NULL, then ASSERT().
477 If Buffer is NULL, then ASSERT().
478 If Size is NULL, then ASSERT().
479
480 @param NameGuid A pointer to to the FFS filename GUID to search for
481 within the firmware volumes that the currently
482 executing module was loaded from.
483 @param SectionType Indicates the FFS section type to search for within
484 the FFS file specified by NameGuid.
485 @param SectionInstance Indicates which section instance within the FFS file
486 specified by NameGuid to retrieve.
487 @param Buffer On output, a pointer to a callee allocated buffer
488 containing the FFS file section that was found.
489 Is it the caller's responsibility to free this buffer
490 using FreePool().
491 @param Size On output, a pointer to the size, in bytes, of Buffer.
492
493
494 @retval EFI_SUCCESS The specified FFS section was returned.
495 @retval EFI_NOT_FOUND The specified FFS section could not be found.
496 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
497 the matching FFS section.
498 @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
499 device error.
500 @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
501 firmware volume that contains the matching FFS
502 section does not allow reads.
503 **/
504 EFI_STATUS
505 EFIAPI
506 GetSectionFromFv (
507 IN CONST EFI_GUID *NameGuid,
508 IN EFI_SECTION_TYPE SectionType,
509 IN UINTN SectionInstance,
510 OUT VOID **Buffer,
511 OUT UINTN *Size
512 )
513 {
514 return InternalGetSectionFromFv (
515 InternalImageHandleToFvHandle(gImageHandle),
516 NameGuid,
517 SectionType,
518 SectionInstance,
519 Buffer,
520 Size
521 );
522 }
523
524
525 /**
526 Searches the FFS file the the currently executing module was loaded from and returns the first matching FFS section.
527
528 This function searches the FFS file that the currently executing module was loaded from for a FFS sections of type SectionType.
529 If the FFS file contains at least SectionInstance instances of the FFS section specified by SectionType,
530 then the SectionInstance instance is returned in Buffer. Buffer is allocated using AllocatePool(),
531 and the size of the allocated buffer is returned in Size. It is the caller's responsibility
532 to use FreePool() to free the allocated buffer. See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for
533 details on how sections are retrieved from an FFS file based on SectionType and SectionInstance.
534
535 If the currently executing module was not loaded from an FFS file, then EFI_NOT_FOUND is returned.
536 If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
537 the search will be retried with a section type of EFI_SECTION_PE32.
538 This function must be called with a TPL <= TPL_NOTIFY.
539
540 If Buffer is NULL, then ASSERT().
541 If Size is NULL, then ASSERT().
542
543
544 @param SectionType Indicates the FFS section type to search for within
545 the FFS file that the currently executing module
546 was loaded from.
547 @param SectionInstance Indicates which section instance to retrieve within
548 the FFS file that the currently executing module
549 was loaded from.
550 @param Buffer On output, a pointer to a callee allocated buffer
551 containing the FFS file section that was found.
552 Is it the caller's responsibility to free this buffer
553 using FreePool().
554 @param Size On output, a pointer to the size, in bytes, of Buffer.
555
556 @retval EFI_SUCCESS The specified FFS section was returned.
557 @retval EFI_NOT_FOUND The specified FFS section could not be found.
558 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
559 the matching FFS section.
560 @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
561 device error.
562 @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
563 firmware volume that contains the matching FFS
564 section does not allow reads.
565
566 **/
567 EFI_STATUS
568 EFIAPI
569 GetSectionFromFfs (
570 IN EFI_SECTION_TYPE SectionType,
571 IN UINTN SectionInstance,
572 OUT VOID **Buffer,
573 OUT UINTN *Size
574 )
575 {
576 return InternalGetSectionFromFv(
577 InternalImageHandleToFvHandle(gImageHandle),
578 &gEfiCallerIdGuid,
579 SectionType,
580 SectionInstance,
581 Buffer,
582 Size
583 );
584 }
585
586
587 /**
588 Get the image file buffer data and buffer size by its device path.
589
590 Access the file either from a firmware volume, from a file system interface,
591 or from the load file interface.
592
593 Allocate memory to store the found image. The caller is responsible to free memory.
594
595 If FilePath is NULL, then NULL is returned.
596 If FileSize is NULL, then NULL is returned.
597 If AuthenticationStatus is NULL, then NULL is returned.
598
599 @param[in] BootPolicy Policy for Open Image File.If TRUE, indicates
600 that the request originates from the boot
601 manager, and that the boot manager is
602 attempting to load FilePath as a boot
603 selection. If FALSE, then FilePath must
604 match an exact file to be loaded.
605 @param[in] FilePath The pointer to the device path of the file
606 that is absracted to the file buffer.
607 @param[out] FileSize The pointer to the size of the abstracted
608 file buffer.
609 @param[out] AuthenticationStatus Pointer to the authentication status.
610
611 @retval NULL FilePath is NULL, or FileSize is NULL, or AuthenticationStatus is NULL, or the file can't be found.
612 @retval other The abstracted file buffer. The caller is responsible to free memory.
613 **/
614 VOID *
615 EFIAPI
616 GetFileBufferByFilePath (
617 IN BOOLEAN BootPolicy,
618 IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath,
619 OUT UINTN *FileSize,
620 OUT UINT32 *AuthenticationStatus
621 )
622 {
623 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
624 EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
625 EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
626 EFI_HANDLE Handle;
627 EFI_GUID *FvNameGuid;
628 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
629 EFI_SECTION_TYPE SectionType;
630 UINT8 *ImageBuffer;
631 UINTN ImageBufferSize;
632 EFI_FV_FILETYPE Type;
633 EFI_FV_FILE_ATTRIBUTES Attrib;
634 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
635 EFI_FILE_HANDLE FileHandle;
636 EFI_FILE_HANDLE LastHandle;
637 EFI_FILE_INFO *FileInfo;
638 UINTN FileInfoSize;
639 EFI_LOAD_FILE_PROTOCOL *LoadFile;
640 EFI_LOAD_FILE2_PROTOCOL *LoadFile2;
641 EFI_STATUS Status;
642
643 //
644 // Check input File device path.
645 //
646 if (FilePath == NULL || FileSize == NULL || AuthenticationStatus == NULL) {
647 return NULL;
648 }
649
650 //
651 // Init local variable
652 //
653 TempDevicePathNode = NULL;
654 FvNameGuid = NULL;
655 FileInfo = NULL;
656 FileHandle = NULL;
657 ImageBuffer = NULL;
658 ImageBufferSize = 0;
659 *AuthenticationStatus = 0;
660
661 //
662 // Copy File Device Path
663 //
664 OrigDevicePathNode = DuplicateDevicePath (FilePath);
665 if (OrigDevicePathNode == NULL) {
666 return NULL;
667 }
668
669 //
670 // Check whether this device path support FV2 protocol.
671 // Is so, this device path may contain a Image.
672 //
673 DevicePathNode = OrigDevicePathNode;
674 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);
675 if (!EFI_ERROR (Status)) {
676 //
677 // For FwVol File system there is only a single file name that is a GUID.
678 //
679 FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePathNode);
680 if (FvNameGuid == NULL) {
681 Status = EFI_INVALID_PARAMETER;
682 } else {
683 //
684 // Read image from the firmware file
685 //
686 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol);
687 if (!EFI_ERROR (Status)) {
688 SectionType = EFI_SECTION_PE32;
689 ImageBuffer = NULL;
690 Status = FwVol->ReadSection (
691 FwVol,
692 FvNameGuid,
693 SectionType,
694 0,
695 (VOID **)&ImageBuffer,
696 &ImageBufferSize,
697 AuthenticationStatus
698 );
699 if (EFI_ERROR (Status)) {
700 //
701 // Try a raw file, since a PE32 SECTION does not exist
702 //
703 if (ImageBuffer != NULL) {
704 FreePool (ImageBuffer);
705 *AuthenticationStatus = 0;
706 }
707 ImageBuffer = NULL;
708 Status = FwVol->ReadFile (
709 FwVol,
710 FvNameGuid,
711 (VOID **)&ImageBuffer,
712 &ImageBufferSize,
713 &Type,
714 &Attrib,
715 AuthenticationStatus
716 );
717 }
718 }
719 }
720 if (!EFI_ERROR (Status)) {
721 goto Finish;
722 }
723 }
724
725 //
726 // Attempt to access the file via a file system interface
727 //
728 DevicePathNode = OrigDevicePathNode;
729 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
730 if (!EFI_ERROR (Status)) {
731 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
732 if (!EFI_ERROR (Status)) {
733 //
734 // Open the Volume to get the File System handle
735 //
736 Status = Volume->OpenVolume (Volume, &FileHandle);
737 if (!EFI_ERROR (Status)) {
738 //
739 // Duplicate the device path to avoid the access to unaligned device path node.
740 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
741 // nodes, It assures the fields in device path nodes are 2 byte aligned.
742 //
743 TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
744 if (TempDevicePathNode == NULL) {
745 FileHandle->Close (FileHandle);
746 //
747 // Setting Status to an EFI_ERROR value will cause the rest of
748 // the file system support below to be skipped.
749 //
750 Status = EFI_OUT_OF_RESOURCES;
751 }
752 //
753 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
754 // directory information and filename can be seperate. The goal is to inch
755 // our way down each device path node and close the previous node
756 //
757 DevicePathNode = TempDevicePathNode;
758 while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
759 if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
760 DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
761 Status = EFI_UNSUPPORTED;
762 break;
763 }
764
765 LastHandle = FileHandle;
766 FileHandle = NULL;
767
768 Status = LastHandle->Open (
769 LastHandle,
770 &FileHandle,
771 ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
772 EFI_FILE_MODE_READ,
773 0
774 );
775
776 //
777 // Close the previous node
778 //
779 LastHandle->Close (LastHandle);
780
781 DevicePathNode = NextDevicePathNode (DevicePathNode);
782 }
783
784 if (!EFI_ERROR (Status)) {
785 //
786 // We have found the file. Now we need to read it. Before we can read the file we need to
787 // figure out how big the file is.
788 //
789 FileInfo = NULL;
790 FileInfoSize = 0;
791 Status = FileHandle->GetInfo (
792 FileHandle,
793 &gEfiFileInfoGuid,
794 &FileInfoSize,
795 FileInfo
796 );
797
798 if (Status == EFI_BUFFER_TOO_SMALL) {
799 FileInfo = AllocatePool (FileInfoSize);
800 if (FileInfo == NULL) {
801 Status = EFI_OUT_OF_RESOURCES;
802 } else {
803 Status = FileHandle->GetInfo (
804 FileHandle,
805 &gEfiFileInfoGuid,
806 &FileInfoSize,
807 FileInfo
808 );
809 }
810 }
811
812 if (!EFI_ERROR (Status) && (FileInfo != NULL)) {
813 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
814 //
815 // Allocate space for the file
816 //
817 ImageBuffer = AllocatePool ((UINTN)FileInfo->FileSize);
818 if (ImageBuffer == NULL) {
819 Status = EFI_OUT_OF_RESOURCES;
820 } else {
821 //
822 // Read the file into the buffer we allocated
823 //
824 ImageBufferSize = (UINTN)FileInfo->FileSize;
825 Status = FileHandle->Read (FileHandle, &ImageBufferSize, ImageBuffer);
826 }
827 }
828 }
829 }
830 //
831 // Close the file and Free FileInfo and TempDevicePathNode since we are done
832 //
833 if (FileInfo != NULL) {
834 FreePool (FileInfo);
835 }
836 if (FileHandle != NULL) {
837 FileHandle->Close (FileHandle);
838 }
839 if (TempDevicePathNode != NULL) {
840 FreePool (TempDevicePathNode);
841 }
842 }
843 }
844 if (!EFI_ERROR (Status)) {
845 goto Finish;
846 }
847 }
848
849 //
850 // Attempt to access the file via LoadFile2 interface
851 //
852 if (!BootPolicy) {
853 DevicePathNode = OrigDevicePathNode;
854 Status = gBS->LocateDevicePath (&gEfiLoadFile2ProtocolGuid, &DevicePathNode, &Handle);
855 if (!EFI_ERROR (Status)) {
856 Status = gBS->HandleProtocol (Handle, &gEfiLoadFile2ProtocolGuid, (VOID**)&LoadFile2);
857 if (!EFI_ERROR (Status)) {
858 //
859 // Call LoadFile2 with the correct buffer size
860 //
861 ImageBufferSize = 0;
862 ImageBuffer = NULL;
863 Status = LoadFile2->LoadFile (
864 LoadFile2,
865 DevicePathNode,
866 FALSE,
867 &ImageBufferSize,
868 ImageBuffer
869 );
870 if (Status == EFI_BUFFER_TOO_SMALL) {
871 ImageBuffer = AllocatePool (ImageBufferSize);
872 if (ImageBuffer == NULL) {
873 Status = EFI_OUT_OF_RESOURCES;
874 } else {
875 Status = LoadFile2->LoadFile (
876 LoadFile2,
877 DevicePathNode,
878 FALSE,
879 &ImageBufferSize,
880 ImageBuffer
881 );
882 }
883 }
884 }
885 if (!EFI_ERROR (Status)) {
886 goto Finish;
887 }
888 }
889 }
890
891 //
892 // Attempt to access the file via LoadFile interface
893 //
894 DevicePathNode = OrigDevicePathNode;
895 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &DevicePathNode, &Handle);
896 if (!EFI_ERROR (Status)) {
897 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID**)&LoadFile);
898 if (!EFI_ERROR (Status)) {
899 //
900 // Call LoadFile with the correct buffer size
901 //
902 ImageBufferSize = 0;
903 ImageBuffer = NULL;
904 Status = LoadFile->LoadFile (
905 LoadFile,
906 DevicePathNode,
907 BootPolicy,
908 &ImageBufferSize,
909 ImageBuffer
910 );
911 if (Status == EFI_BUFFER_TOO_SMALL) {
912 ImageBuffer = AllocatePool (ImageBufferSize);
913 if (ImageBuffer == NULL) {
914 Status = EFI_OUT_OF_RESOURCES;
915 } else {
916 Status = LoadFile->LoadFile (
917 LoadFile,
918 DevicePathNode,
919 BootPolicy,
920 &ImageBufferSize,
921 ImageBuffer
922 );
923 }
924 }
925 }
926 }
927
928 Finish:
929
930 if (EFI_ERROR (Status)) {
931 if (ImageBuffer != NULL) {
932 FreePool (ImageBuffer);
933 ImageBuffer = NULL;
934 }
935 *FileSize = 0;
936 } else {
937 *FileSize = ImageBufferSize;
938 }
939
940 FreePool (OrigDevicePathNode);
941
942 return ImageBuffer;
943 }
944
945 /**
946 Searches all the available firmware volumes and returns the file device path of first matching
947 FFS section.
948
949 This function searches all the firmware volumes for FFS files with an FFS filename specified by NameGuid.
950 The order that the firmware volumes is searched is not deterministic. For each FFS file found a search
951 is made for FFS sections of type SectionType.
952
953 If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
954 the search will be retried with a section type of EFI_SECTION_PE32.
955 This function must be called with a TPL <= TPL_NOTIFY.
956
957 If NameGuid is NULL, then ASSERT().
958
959 @param NameGuid A pointer to to the FFS filename GUID to search for
960 within any of the firmware volumes in the platform.
961 @param SectionType Indicates the FFS section type to search for within
962 the FFS file specified by NameGuid.
963 @param SectionInstance Indicates which section instance within the FFS file
964 specified by NameGuid to retrieve.
965 @param FvFileDevicePath Device path for the target FFS
966 file.
967
968 @retval EFI_SUCCESS The specified file device path of FFS section was returned.
969 @retval EFI_NOT_FOUND The specified file device path of FFS section could not be found.
970 @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
971 device error.
972 @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
973 firmware volume that contains the matching FFS section does not
974 allow reads.
975 @retval EFI_INVALID_PARAMETER FvFileDevicePath is NULL.
976
977 **/
978 EFI_STATUS
979 EFIAPI
980 GetFileDevicePathFromAnyFv (
981 IN CONST EFI_GUID *NameGuid,
982 IN EFI_SECTION_TYPE SectionType,
983 IN UINTN SectionInstance,
984 OUT EFI_DEVICE_PATH_PROTOCOL **FvFileDevicePath
985 )
986 {
987 EFI_STATUS Status;
988 EFI_HANDLE *HandleBuffer;
989 UINTN HandleCount;
990 UINTN Index;
991 EFI_HANDLE FvHandle;
992 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
993 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *TempFvFileDevicePath;
994 VOID *Buffer;
995 UINTN Size;
996
997 if (FvFileDevicePath == NULL) {
998 return EFI_INVALID_PARAMETER;
999 }
1000
1001 HandleBuffer = NULL;
1002 FvDevicePath = NULL;
1003 TempFvFileDevicePath = NULL;
1004 Buffer = NULL;
1005 Size = 0;
1006
1007 //
1008 // Search the FV that contain the caller's FFS first.
1009 // FV builder can choose to build FFS into the this FV
1010 // so that this implementation of GetSectionFromAnyFv
1011 // will locate the FFS faster.
1012 //
1013 FvHandle = InternalImageHandleToFvHandle (gImageHandle);
1014 Status = InternalGetSectionFromFv (
1015 FvHandle,
1016 NameGuid,
1017 SectionType,
1018 SectionInstance,
1019 &Buffer,
1020 &Size
1021 );
1022 if (!EFI_ERROR (Status)) {
1023 goto Done;
1024 }
1025
1026 Status = gBS->LocateHandleBuffer (
1027 ByProtocol,
1028 &gEfiFirmwareVolume2ProtocolGuid,
1029 NULL,
1030 &HandleCount,
1031 &HandleBuffer
1032 );
1033 if (EFI_ERROR (Status)) {
1034 goto Done;
1035 }
1036
1037 for (Index = 0; Index < HandleCount; Index++) {
1038 //
1039 // Skip the FV that contain the caller's FFS
1040 //
1041 if (HandleBuffer[Index] != FvHandle) {
1042 Status = InternalGetSectionFromFv (
1043 HandleBuffer[Index],
1044 NameGuid,
1045 SectionType,
1046 SectionInstance,
1047 &Buffer,
1048 &Size
1049 );
1050
1051 if (!EFI_ERROR (Status)) {
1052 //
1053 // Update FvHandle to the current handle.
1054 //
1055 FvHandle = HandleBuffer[Index];
1056 goto Done;
1057 }
1058 }
1059 }
1060
1061 if (Index == HandleCount) {
1062 Status = EFI_NOT_FOUND;
1063 }
1064
1065 Done:
1066 if (Status == EFI_SUCCESS) {
1067 //
1068 // Build a device path to the file in the FV to pass into gBS->LoadImage
1069 //
1070 Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
1071 if (EFI_ERROR (Status)) {
1072 *FvFileDevicePath = NULL;
1073 } else {
1074 TempFvFileDevicePath = AllocateZeroPool (sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);
1075 if (TempFvFileDevicePath == NULL) {
1076 *FvFileDevicePath = NULL;
1077 return EFI_OUT_OF_RESOURCES;
1078 }
1079 EfiInitializeFwVolDevicepathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH*)TempFvFileDevicePath, NameGuid);
1080 SetDevicePathEndNode (NextDevicePathNode (TempFvFileDevicePath));
1081 *FvFileDevicePath = AppendDevicePath (
1082 FvDevicePath,
1083 (EFI_DEVICE_PATH_PROTOCOL *)TempFvFileDevicePath
1084 );
1085 FreePool (TempFvFileDevicePath);
1086 }
1087 }
1088
1089 if (Buffer != NULL) {
1090 FreePool (Buffer);
1091 }
1092
1093 if (HandleBuffer != NULL) {
1094 FreePool (HandleBuffer);
1095 }
1096
1097 return Status;
1098 }