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