summaryrefslogtreecommitdiff
path: root/Core/MdePkg/Library/DxeServicesLib/DxeServicesLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/MdePkg/Library/DxeServicesLib/DxeServicesLib.c')
-rw-r--r--Core/MdePkg/Library/DxeServicesLib/DxeServicesLib.c929
1 files changed, 929 insertions, 0 deletions
diff --git a/Core/MdePkg/Library/DxeServicesLib/DxeServicesLib.c b/Core/MdePkg/Library/DxeServicesLib/DxeServicesLib.c
new file mode 100644
index 0000000000..c8f0014d7a
--- /dev/null
+++ b/Core/MdePkg/Library/DxeServicesLib/DxeServicesLib.c
@@ -0,0 +1,929 @@
+/** @file
+ MDE DXE Services Library provides functions that simplify the development of DXE Drivers.
+ These functions help access data from sections of FFS files or from file path.
+
+ Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/LoadFile2.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Guid/FileInfo.h>
+
+/**
+ Identify the device handle from which the Image is loaded from. As this device handle is passed to
+ GetSectionFromFv as the identifier for a Firmware Volume, an EFI_FIRMWARE_VOLUME2_PROTOCOL
+ protocol instance should be located succesfully by calling gBS->HandleProtocol ().
+
+ This function locates the EFI_LOADED_IMAGE_PROTOCOL instance installed
+ on ImageHandle. It then returns EFI_LOADED_IMAGE_PROTOCOL.DeviceHandle.
+
+ If ImageHandle is NULL, then ASSERT ();
+ If failed to locate a EFI_LOADED_IMAGE_PROTOCOL on ImageHandle, then ASSERT ();
+
+ @param ImageHandle The firmware allocated handle for UEFI image.
+
+ @retval EFI_HANDLE The device handle from which the Image is loaded from.
+
+**/
+EFI_HANDLE
+InternalImageHandleToFvHandle (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+
+ ASSERT (ImageHandle != NULL);
+
+ Status = gBS->HandleProtocol (
+ (EFI_HANDLE *) ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return LoadedImage->DeviceHandle;
+
+}
+
+/**
+ Allocate and fill a buffer from a Firmware Section identified by a Firmware File GUID name, a Firmware
+ Section type and instance number from the specified Firmware Volume.
+
+ This functions first locate the EFI_FIRMWARE_VOLUME2_PROTOCOL protocol instance on FvHandle in order to
+ carry out the Firmware Volume read operation. The function then reads the Firmware Section found sepcifed
+ by NameGuid, SectionType and SectionInstance.
+
+ The details of this search order is defined in description of EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection ()
+ found in PI Specification.
+
+ If SectionType is EFI_SECTION_TE, EFI_SECTION_TE is used as section type to start the search. If EFI_SECTION_TE section
+ 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
+ is returned.
+
+ The data and size is returned by Buffer and Size. The caller is responsible to free the Buffer allocated
+ by this function. This function can be only called at TPL_NOTIFY and below.
+
+ If FvHandle is NULL, then ASSERT ();
+ If NameGuid is NULL, then ASSERT();
+ If Buffer is NULL, then ASSERT();
+ If Size is NULL, then ASSERT().
+
+ @param FvHandle The device handle that contains a instance of
+ EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
+ @param NameGuid The GUID name of a Firmware File.
+ @param SectionType The Firmware Section type.
+ @param SectionInstance The instance number of Firmware Section to
+ read from starting from 0.
+ @param Buffer On output, Buffer contains the the data read
+ from the section in the Firmware File found.
+ @param Size On output, the size of Buffer.
+
+ @retval EFI_SUCCESS The image is found and data and size is returned.
+ @retval EFI_NOT_FOUND The image specified by NameGuid and SectionType
+ can't be found.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ output data buffer or complete the operations.
+ @retval EFI_DEVICE_ERROR A hardware error occurs during reading from the
+ Firmware Volume.
+ @retval EFI_ACCESS_DENIED The firmware volume containing the searched
+ Firmware File is configured to disallow reads.
+
+**/
+EFI_STATUS
+InternalGetSectionFromFv (
+ IN EFI_HANDLE FvHandle,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ OUT VOID **Buffer,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINT32 AuthenticationStatus;
+
+ ASSERT (NameGuid != NULL);
+ ASSERT (Buffer != NULL);
+ ASSERT (Size != NULL);
+
+ ASSERT (FvHandle != NULL);
+
+ Status = gBS->HandleProtocol (
+ FvHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Read desired section content in NameGuid file
+ //
+ *Buffer = NULL;
+ *Size = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ NameGuid,
+ SectionType,
+ SectionInstance,
+ Buffer,
+ Size,
+ &AuthenticationStatus
+ );
+
+ if (EFI_ERROR (Status) && (SectionType == EFI_SECTION_TE)) {
+ //
+ // Try reading PE32 section, if the required section is TE type
+ //
+ *Buffer = NULL;
+ *Size = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ NameGuid,
+ EFI_SECTION_PE32,
+ SectionInstance,
+ Buffer,
+ Size,
+ &AuthenticationStatus
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Searches all the available firmware volumes and returns the first matching FFS section.
+
+ This function searches all the firmware volumes for FFS files with FV file type specified by FileType
+ The order that the firmware volumes is searched is not deterministic. For each available FV a search
+ is made for FFS file of type FileType. If the FV contains more than one FFS file with the same FileType,
+ the FileInstance instance will be the matched FFS file. For each FFS file found a search
+ is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances
+ of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
+ Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
+ It is the caller's responsibility to use FreePool() to free the allocated buffer.
+ See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections
+ are retrieved from an FFS file based on SectionType and SectionInstance.
+
+ If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
+ the search will be retried with a section type of EFI_SECTION_PE32.
+ This function must be called with a TPL <= TPL_NOTIFY.
+
+ If Buffer is NULL, then ASSERT().
+ If Size is NULL, then ASSERT().
+
+ @param FileType Indicates the FV file type to search for within all
+ available FVs.
+ @param FileInstance Indicates which file instance within all available
+ FVs specified by FileType.
+ FileInstance starts from zero.
+ @param SectionType Indicates the FFS section type to search for
+ within the FFS file
+ specified by FileType with FileInstance.
+ @param SectionInstance Indicates which section instance within the FFS file
+ specified by FileType with FileInstance to retrieve.
+ SectionInstance starts from zero.
+ @param Buffer On output, a pointer to a callee allocated buffer
+ containing the FFS file section that was found.
+ Is it the caller's responsibility to free this
+ buffer using FreePool().
+ @param Size On output, a pointer to the size, in bytes, of Buffer.
+
+ @retval EFI_SUCCESS The specified FFS section was returned.
+ @retval EFI_NOT_FOUND The specified FFS section could not be found.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
+ the matching FFS section.
+ @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
+ device error.
+ @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because
+ the firmware volume that
+ contains the matching FFS section does not allow reads.
+**/
+EFI_STATUS
+EFIAPI
+GetSectionFromAnyFvByFileType (
+ IN EFI_FV_FILETYPE FileType,
+ IN UINTN FileInstance,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ OUT VOID **Buffer,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN IndexFv;
+ UINTN IndexFile;
+ UINTN Key;
+ EFI_GUID NameGuid;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ //
+ // Locate all available FVs.
+ //
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Go through FVs one by one to find the required section data.
+ //
+ for (IndexFv = 0; IndexFv < HandleCount; IndexFv++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[IndexFv],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&Fv
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Use Firmware Volume 2 Protocol to search for a file of type FileType in all FVs.
+ //
+ IndexFile = FileInstance + 1;
+ Key = 0;
+ do {
+ Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, Size);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ IndexFile --;
+ } while (IndexFile > 0);
+
+ //
+ // Fv File with the required FV file type is found.
+ // Search the section file in the found FV file.
+ //
+ if (IndexFile == 0) {
+ Status = InternalGetSectionFromFv (
+ HandleBuffer[IndexFv],
+ &NameGuid,
+ SectionType,
+ SectionInstance,
+ Buffer,
+ Size
+ );
+
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // The required FFS section file is not found.
+ //
+ if (IndexFv == HandleCount) {
+ Status = EFI_NOT_FOUND;
+ }
+
+Done:
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Searches all the availables firmware volumes and returns the first matching FFS section.
+
+ This function searches all the firmware volumes for FFS files with an FFS filename specified by NameGuid.
+ The order that the firmware volumes is searched is not deterministic. For each FFS file found a search
+ is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances
+ of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
+ Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
+ It is the caller's responsibility to use FreePool() to free the allocated buffer.
+ See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections
+ are retrieved from an FFS file based on SectionType and SectionInstance.
+
+ If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
+ the search will be retried with a section type of EFI_SECTION_PE32.
+ This function must be called with a TPL <= TPL_NOTIFY.
+
+ If NameGuid is NULL, then ASSERT().
+ If Buffer is NULL, then ASSERT().
+ If Size is NULL, then ASSERT().
+
+
+ @param NameGuid A pointer to to the FFS filename GUID to search for
+ within any of the firmware volumes in the platform.
+ @param SectionType Indicates the FFS section type to search for within
+ the FFS file specified by NameGuid.
+ @param SectionInstance Indicates which section instance within the FFS file
+ specified by NameGuid to retrieve.
+ @param Buffer On output, a pointer to a callee allocated buffer
+ containing the FFS file section that was found.
+ Is it the caller's responsibility to free this buffer
+ using FreePool().
+ @param Size On output, a pointer to the size, in bytes, of Buffer.
+
+ @retval EFI_SUCCESS The specified FFS section was returned.
+ @retval EFI_NOT_FOUND The specified FFS section could not be found.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ retrieve the matching FFS section.
+ @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
+ device error.
+ @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
+ firmware volume that
+ contains the matching FFS section does not allow reads.
+**/
+EFI_STATUS
+EFIAPI
+GetSectionFromAnyFv (
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ OUT VOID **Buffer,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_HANDLE FvHandle;
+
+ //
+ // Search the FV that contain the caller's FFS first.
+ // FV builder can choose to build FFS into the this FV
+ // so that this implementation of GetSectionFromAnyFv
+ // will locate the FFS faster.
+ //
+ FvHandle = InternalImageHandleToFvHandle (gImageHandle);
+ Status = InternalGetSectionFromFv (
+ FvHandle,
+ NameGuid,
+ SectionType,
+ SectionInstance,
+ Buffer,
+ Size
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Skip the FV that contain the caller's FFS
+ //
+ if (HandleBuffer[Index] != FvHandle) {
+ Status = InternalGetSectionFromFv (
+ HandleBuffer[Index],
+ NameGuid,
+ SectionType,
+ SectionInstance,
+ Buffer,
+ Size
+ );
+
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ }
+
+ if (Index == HandleCount) {
+ Status = EFI_NOT_FOUND;
+ }
+
+Done:
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+ return Status;
+
+}
+
+/**
+ Searches the firmware volume that the currently executing module was loaded from and returns the first matching FFS section.
+
+ This function searches the firmware volume that the currently executing module was loaded
+ from for an FFS file with an FFS filename specified by NameGuid. If the FFS file is found a search
+ is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance
+ instances of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
+ Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
+ It is the caller's responsibility to use FreePool() to free the allocated buffer.
+ See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for details on how sections are retrieved from
+ an FFS file based on SectionType and SectionInstance.
+
+ If the currently executing module was not loaded from a firmware volume, then EFI_NOT_FOUND is returned.
+ If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
+ the search will be retried with a section type of EFI_SECTION_PE32.
+
+ This function must be called with a TPL <= TPL_NOTIFY.
+ If NameGuid is NULL, then ASSERT().
+ If Buffer is NULL, then ASSERT().
+ If Size is NULL, then ASSERT().
+
+ @param NameGuid A pointer to to the FFS filename GUID to search for
+ within the firmware volumes that the currently
+ executing module was loaded from.
+ @param SectionType Indicates the FFS section type to search for within
+ the FFS file specified by NameGuid.
+ @param SectionInstance Indicates which section instance within the FFS file
+ specified by NameGuid to retrieve.
+ @param Buffer On output, a pointer to a callee allocated buffer
+ containing the FFS file section that was found.
+ Is it the caller's responsibility to free this buffer
+ using FreePool().
+ @param Size On output, a pointer to the size, in bytes, of Buffer.
+
+
+ @retval EFI_SUCCESS The specified FFS section was returned.
+ @retval EFI_NOT_FOUND The specified FFS section could not be found.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
+ the matching FFS section.
+ @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
+ device error.
+ @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
+ firmware volume that contains the matching FFS
+ section does not allow reads.
+**/
+EFI_STATUS
+EFIAPI
+GetSectionFromFv (
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ OUT VOID **Buffer,
+ OUT UINTN *Size
+ )
+{
+ return InternalGetSectionFromFv (
+ InternalImageHandleToFvHandle(gImageHandle),
+ NameGuid,
+ SectionType,
+ SectionInstance,
+ Buffer,
+ Size
+ );
+}
+
+
+/**
+ Searches the FFS file the the currently executing module was loaded from and returns the first matching FFS section.
+
+ This function searches the FFS file that the currently executing module was loaded from for a FFS sections of type SectionType.
+ If the FFS file contains at least SectionInstance instances of the FFS section specified by SectionType,
+ then the SectionInstance instance is returned in Buffer. Buffer is allocated using AllocatePool(),
+ and the size of the allocated buffer is returned in Size. It is the caller's responsibility
+ to use FreePool() to free the allocated buffer. See EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() for
+ details on how sections are retrieved from an FFS file based on SectionType and SectionInstance.
+
+ If the currently executing module was not loaded from an FFS file, then EFI_NOT_FOUND is returned.
+ If SectionType is EFI_SECTION_TE, and the search with an FFS file fails,
+ the search will be retried with a section type of EFI_SECTION_PE32.
+ This function must be called with a TPL <= TPL_NOTIFY.
+
+ If Buffer is NULL, then ASSERT().
+ If Size is NULL, then ASSERT().
+
+
+ @param SectionType Indicates the FFS section type to search for within
+ the FFS file that the currently executing module
+ was loaded from.
+ @param SectionInstance Indicates which section instance to retrieve within
+ the FFS file that the currently executing module
+ was loaded from.
+ @param Buffer On output, a pointer to a callee allocated buffer
+ containing the FFS file section that was found.
+ Is it the caller's responsibility to free this buffer
+ using FreePool().
+ @param Size On output, a pointer to the size, in bytes, of Buffer.
+
+ @retval EFI_SUCCESS The specified FFS section was returned.
+ @retval EFI_NOT_FOUND The specified FFS section could not be found.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve
+ the matching FFS section.
+ @retval EFI_DEVICE_ERROR The FFS section could not be retrieves due to a
+ device error.
+ @retval EFI_ACCESS_DENIED The FFS section could not be retrieves because the
+ firmware volume that contains the matching FFS
+ section does not allow reads.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSectionFromFfs (
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ OUT VOID **Buffer,
+ OUT UINTN *Size
+ )
+{
+ return InternalGetSectionFromFv(
+ InternalImageHandleToFvHandle(gImageHandle),
+ &gEfiCallerIdGuid,
+ SectionType,
+ SectionInstance,
+ Buffer,
+ Size
+ );
+}
+
+
+/**
+ Get the image file buffer data and buffer size by its device path.
+
+ Access the file either from a firmware volume, from a file system interface,
+ or from the load file interface.
+
+ Allocate memory to store the found image. The caller is responsible to free memory.
+
+ If FilePath is NULL, then NULL is returned.
+ If FileSize is NULL, then NULL is returned.
+ If AuthenticationStatus is NULL, then NULL is returned.
+
+ @param[in] BootPolicy Policy for Open Image File.If TRUE, indicates
+ that the request originates from the boot
+ manager, and that the boot manager is
+ attempting to load FilePath as a boot
+ selection. If FALSE, then FilePath must
+ match an exact file to be loaded.
+ @param[in] FilePath The pointer to the device path of the file
+ that is absracted to the file buffer.
+ @param[out] FileSize The pointer to the size of the abstracted
+ file buffer.
+ @param[out] AuthenticationStatus Pointer to the authentication status.
+
+ @retval NULL FilePath is NULL, or FileSize is NULL, or AuthenticationStatus is NULL, or the file can't be found.
+ @retval other The abstracted file buffer. The caller is responsible to free memory.
+**/
+VOID *
+EFIAPI
+GetFileBufferByFilePath (
+ IN BOOLEAN BootPolicy,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT UINTN *FileSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
+ EFI_HANDLE Handle;
+ EFI_GUID *FvNameGuid;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
+ EFI_SECTION_TYPE SectionType;
+ UINT8 *ImageBuffer;
+ UINTN ImageBufferSize;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attrib;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE FileHandle;
+ EFI_FILE_HANDLE LastHandle;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileInfoSize;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+ EFI_LOAD_FILE2_PROTOCOL *LoadFile2;
+ EFI_STATUS Status;
+
+ //
+ // Check input File device path.
+ //
+ if (FilePath == NULL || FileSize == NULL || AuthenticationStatus == NULL) {
+ return NULL;
+ }
+
+ //
+ // Init local variable
+ //
+ TempDevicePathNode = NULL;
+ FvNameGuid = NULL;
+ FileInfo = NULL;
+ FileHandle = NULL;
+ ImageBuffer = NULL;
+ ImageBufferSize = 0;
+ *AuthenticationStatus = 0;
+
+ //
+ // Copy File Device Path
+ //
+ OrigDevicePathNode = DuplicateDevicePath (FilePath);
+ if (OrigDevicePathNode == NULL) {
+ return NULL;
+ }
+
+ //
+ // Check whether this device path support FV2 protocol.
+ // Is so, this device path may contain a Image.
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For FwVol File system there is only a single file name that is a GUID.
+ //
+ FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePathNode);
+ if (FvNameGuid == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // Read image from the firmware file
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol);
+ if (!EFI_ERROR (Status)) {
+ SectionType = EFI_SECTION_PE32;
+ ImageBuffer = NULL;
+ Status = FwVol->ReadSection (
+ FwVol,
+ FvNameGuid,
+ SectionType,
+ 0,
+ (VOID **)&ImageBuffer,
+ &ImageBufferSize,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Try a raw file, since a PE32 SECTION does not exist
+ //
+ if (ImageBuffer != NULL) {
+ FreePool (ImageBuffer);
+ *AuthenticationStatus = 0;
+ }
+ ImageBuffer = NULL;
+ Status = FwVol->ReadFile (
+ FwVol,
+ FvNameGuid,
+ (VOID **)&ImageBuffer,
+ &ImageBufferSize,
+ &Type,
+ &Attrib,
+ AuthenticationStatus
+ );
+ }
+ }
+ }
+ if (!EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+
+ //
+ // Attempt to access the file via a file system interface
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open the Volume to get the File System handle
+ //
+ Status = Volume->OpenVolume (Volume, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Duplicate the device path to avoid the access to unaligned device path node.
+ // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
+ // nodes, It assures the fields in device path nodes are 2 byte aligned.
+ //
+ TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
+ if (TempDevicePathNode == NULL) {
+ FileHandle->Close (FileHandle);
+ //
+ // Setting Status to an EFI_ERROR value will cause the rest of
+ // the file system support below to be skipped.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
+ // directory information and filename can be seperate. The goal is to inch
+ // our way down each device path node and close the previous node
+ //
+ DevicePathNode = TempDevicePathNode;
+ while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
+ if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ LastHandle = FileHandle;
+ FileHandle = NULL;
+
+ Status = LastHandle->Open (
+ LastHandle,
+ &FileHandle,
+ ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+
+ //
+ // Close the previous node
+ //
+ LastHandle->Close (LastHandle);
+
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // We have found the file. Now we need to read it. Before we can read the file we need to
+ // figure out how big the file is.
+ //
+ FileInfo = NULL;
+ FileInfoSize = 0;
+ Status = FileHandle->GetInfo (
+ FileHandle,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FileInfo = AllocatePool (FileInfoSize);
+ if (FileInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = FileHandle->GetInfo (
+ FileHandle,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+ }
+ }
+
+ if (!EFI_ERROR (Status) && (FileInfo != NULL)) {
+ if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ //
+ // Allocate space for the file
+ //
+ ImageBuffer = AllocatePool ((UINTN)FileInfo->FileSize);
+ if (ImageBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Read the file into the buffer we allocated
+ //
+ ImageBufferSize = (UINTN)FileInfo->FileSize;
+ Status = FileHandle->Read (FileHandle, &ImageBufferSize, ImageBuffer);
+ }
+ }
+ }
+ }
+ //
+ // Close the file and Free FileInfo and TempDevicePathNode since we are done
+ //
+ if (FileInfo != NULL) {
+ FreePool (FileInfo);
+ }
+ if (FileHandle != NULL) {
+ FileHandle->Close (FileHandle);
+ }
+ if (TempDevicePathNode != NULL) {
+ FreePool (TempDevicePathNode);
+ }
+ }
+ }
+ if (!EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+
+ //
+ // Attempt to access the file via LoadFile2 interface
+ //
+ if (!BootPolicy) {
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiLoadFile2ProtocolGuid, &DevicePathNode, &Handle);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFile2ProtocolGuid, (VOID**)&LoadFile2);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Call LoadFile2 with the correct buffer size
+ //
+ ImageBufferSize = 0;
+ ImageBuffer = NULL;
+ Status = LoadFile2->LoadFile (
+ LoadFile2,
+ DevicePathNode,
+ FALSE,
+ &ImageBufferSize,
+ ImageBuffer
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ ImageBuffer = AllocatePool (ImageBufferSize);
+ if (ImageBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = LoadFile2->LoadFile (
+ LoadFile2,
+ DevicePathNode,
+ FALSE,
+ &ImageBufferSize,
+ ImageBuffer
+ );
+ }
+ }
+ }
+ if (!EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+ }
+
+ //
+ // Attempt to access the file via LoadFile interface
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &DevicePathNode, &Handle);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID**)&LoadFile);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Call LoadFile with the correct buffer size
+ //
+ ImageBufferSize = 0;
+ ImageBuffer = NULL;
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ DevicePathNode,
+ BootPolicy,
+ &ImageBufferSize,
+ ImageBuffer
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ ImageBuffer = AllocatePool (ImageBufferSize);
+ if (ImageBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ DevicePathNode,
+ BootPolicy,
+ &ImageBufferSize,
+ ImageBuffer
+ );
+ }
+ }
+ }
+ }
+
+Finish:
+
+ if (EFI_ERROR (Status)) {
+ if (ImageBuffer != NULL) {
+ FreePool (ImageBuffer);
+ ImageBuffer = NULL;
+ }
+ *FileSize = 0;
+ } else {
+ *FileSize = ImageBufferSize;
+ }
+
+ FreePool (OrigDevicePathNode);
+
+ return ImageBuffer;
+}