git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10704 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			918 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			918 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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 - 2010, 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 File 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 The pointer to a caller-allocated UINT32 
 | 
						|
                                        in which the authentication status is returned.
 | 
						|
 | 
						|
  @retval NULL   File is NULL, or FileSize 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
 | 
						|
                            );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    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);
 | 
						|
          Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          goto Finish;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // 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 (!IsDevicePathEnd (DevicePathNode) && !EFI_ERROR (Status)) {
 | 
						|
          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)) {
 | 
						|
            //
 | 
						|
            // 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);
 | 
						|
        }
 | 
						|
        FreePool (TempDevicePathNode);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    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
 | 
						|
                                 );
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
      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;
 | 
						|
}
 |