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