git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7528 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			432 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			432 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Handle services to image file.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2008, Intel Corporation. <BR>
 | 
						|
All rights reserved. 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 "DxeMain.h"
 | 
						|
#include "Image.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Search a handle to a device on a specified device path that supports a specified protocol,
 | 
						|
  interface of that protocol on that handle is another output.
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  @param  Protocol               The protocol to search for
 | 
						|
  @param  FilePath               The specified device path
 | 
						|
  @param  Interface              Interface of the protocol on the handle
 | 
						|
  @param  Handle                 The handle to the device on the specified device
 | 
						|
                                 path that supports the protocol.
 | 
						|
 | 
						|
  @return Status code.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CoreDevicePathToInterface (
 | 
						|
  IN EFI_GUID                     *Protocol,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     **FilePath,
 | 
						|
  OUT VOID                        **Interface,
 | 
						|
  OUT EFI_HANDLE                  *Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
 | 
						|
  Status = CoreLocateDevicePath (Protocol, FilePath, Handle);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = CoreHandleProtocol (*Handle, Protocol, Interface);
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Opens a file for (simple) reading.  The simple read abstraction
 | 
						|
  will access the file either from a memory copy, from a file
 | 
						|
  system interface, or from the load file interface.
 | 
						|
 | 
						|
  @param  BootPolicy             Policy for Open Image File.
 | 
						|
  @param  SourceBuffer           Pointer to the memory location containing copy
 | 
						|
                                 of the image to be loaded.
 | 
						|
  @param  SourceSize             The size in bytes of SourceBuffer.
 | 
						|
  @param  FilePath               The specific file path from which the image is
 | 
						|
                                 loaded
 | 
						|
  @param  DeviceHandle           Pointer to the return device handle.
 | 
						|
  @param  ImageFileHandle        Pointer to the image file handle.
 | 
						|
  @param  AuthenticationStatus   Pointer to a caller-allocated UINT32 in which
 | 
						|
                                 the authentication status is returned.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Image file successfully opened.
 | 
						|
  @retval EFI_LOAD_ERROR         If the caller passed a copy of the file, and
 | 
						|
                                 SourceSize is 0.
 | 
						|
  @retval EFI_INVALID_PARAMETER  File path is not valid.
 | 
						|
  @retval EFI_NOT_FOUND          File not found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CoreOpenImageFile (
 | 
						|
  IN BOOLEAN                        BootPolicy,
 | 
						|
  IN VOID                           *SourceBuffer   OPTIONAL,
 | 
						|
  IN UINTN                          SourceSize,
 | 
						|
  IN OUT EFI_DEVICE_PATH_PROTOCOL   **FilePath,
 | 
						|
  OUT EFI_HANDLE                    *DeviceHandle,
 | 
						|
  IN IMAGE_FILE_HANDLE              *ImageFileHandle,
 | 
						|
  OUT UINT32                        *AuthenticationStatus
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL          *TempFilePath;
 | 
						|
  FILEPATH_DEVICE_PATH              *FilePathNode;
 | 
						|
  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Volume;
 | 
						|
  EFI_FILE_HANDLE                   FileHandle;
 | 
						|
  EFI_FILE_HANDLE                   LastHandle;
 | 
						|
  EFI_LOAD_FILE_PROTOCOL            *LoadFile;
 | 
						|
  EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;
 | 
						|
  EFI_SECTION_TYPE                  SectionType;
 | 
						|
  UINT8                             *Pe32Buffer;
 | 
						|
  UINTN                             Pe32BufferSize;
 | 
						|
  EFI_FV_FILETYPE                   Type;
 | 
						|
  EFI_FV_FILE_ATTRIBUTES            Attrib;
 | 
						|
  EFI_FILE_INFO                     *FileInfo;
 | 
						|
  UINTN                             FileInfoSize;
 | 
						|
  EFI_GUID                          *NameGuid;
 | 
						|
  FILEPATH_DEVICE_PATH              *OriginalFilePathNode;
 | 
						|
 | 
						|
  OriginalFilePathNode = NULL;
 | 
						|
  *AuthenticationStatus = 0;
 | 
						|
  ZeroMem (ImageFileHandle, sizeof (IMAGE_FILE_HANDLE));
 | 
						|
  ImageFileHandle->Signature = IMAGE_FILE_HANDLE_SIGNATURE;
 | 
						|
 | 
						|
  //
 | 
						|
  // If the caller passed a copy of the file, then just use it
 | 
						|
  //
 | 
						|
  if (SourceBuffer != NULL) {
 | 
						|
    ImageFileHandle->Source     = SourceBuffer;
 | 
						|
    ImageFileHandle->SourceSize = SourceSize;
 | 
						|
    *DeviceHandle               = NULL;
 | 
						|
    CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, FilePath, DeviceHandle);
 | 
						|
    if (SourceSize > 0) {
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    } else {
 | 
						|
      Status = EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure FilePath is valid
 | 
						|
  //
 | 
						|
  if (*FilePath == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check to see if it's in a Firmware Volume
 | 
						|
  //
 | 
						|
  FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) *FilePath;
 | 
						|
  Status = CoreDevicePathToInterface (
 | 
						|
            &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
            (EFI_DEVICE_PATH_PROTOCOL **)&FwVolFilePathNode,
 | 
						|
            (VOID*)&FwVol,
 | 
						|
            DeviceHandle
 | 
						|
            );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // For FwVol File system there is only a single file name that is a GUID.
 | 
						|
    //
 | 
						|
    NameGuid = EfiGetNameGuidFromFwVolDevicePathNode (FwVolFilePathNode);
 | 
						|
    if (NameGuid != NULL) {
 | 
						|
 | 
						|
      SectionType = EFI_SECTION_PE32;
 | 
						|
      Pe32Buffer  = NULL;
 | 
						|
      Status = FwVol->ReadSection (
 | 
						|
                        FwVol,
 | 
						|
                        NameGuid,
 | 
						|
                        SectionType,
 | 
						|
                        0,
 | 
						|
                        (VOID **)&Pe32Buffer,
 | 
						|
                        &Pe32BufferSize,
 | 
						|
                        AuthenticationStatus
 | 
						|
                        );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Try a raw file, since a PE32 SECTION does not exist
 | 
						|
        //
 | 
						|
        if (Pe32Buffer != NULL) {
 | 
						|
          CoreFreePool (Pe32Buffer);
 | 
						|
          *AuthenticationStatus = 0;
 | 
						|
        }
 | 
						|
        Pe32Buffer = NULL;
 | 
						|
        Status = FwVol->ReadFile (
 | 
						|
                          FwVol,
 | 
						|
                          NameGuid,
 | 
						|
                          (VOID **)&Pe32Buffer,
 | 
						|
                          &Pe32BufferSize,
 | 
						|
                          &Type,
 | 
						|
                          &Attrib,
 | 
						|
                          AuthenticationStatus
 | 
						|
                          );
 | 
						|
      }
 | 
						|
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // One of the reads passed so we are done
 | 
						|
        //
 | 
						|
        ImageFileHandle->Source = Pe32Buffer;
 | 
						|
        ImageFileHandle->SourceSize = Pe32BufferSize;
 | 
						|
        ImageFileHandle->FreeBuffer = TRUE;
 | 
						|
        goto Done;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Attempt to access the file via a file system interface
 | 
						|
  //
 | 
						|
  FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath;
 | 
						|
  Status = CoreDevicePathToInterface (
 | 
						|
            &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
            (EFI_DEVICE_PATH_PROTOCOL **)&FilePathNode,
 | 
						|
            (VOID*)&Volume,
 | 
						|
            DeviceHandle
 | 
						|
            );
 | 
						|
  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.
 | 
						|
      //
 | 
						|
      FilePathNode = (FILEPATH_DEVICE_PATH *)DuplicateDevicePath((EFI_DEVICE_PATH_PROTOCOL *)(UINTN)FilePathNode);
 | 
						|
      if (FilePathNode == NULL) {
 | 
						|
        FileHandle->Close (FileHandle);
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      } else {
 | 
						|
        OriginalFilePathNode = FilePathNode;
 | 
						|
        //
 | 
						|
        // 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
 | 
						|
        //
 | 
						|
        while (!IsDevicePathEnd (&FilePathNode->Header)) {
 | 
						|
          if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
 | 
						|
              DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
 | 
						|
            Status = EFI_UNSUPPORTED;
 | 
						|
          }
 | 
						|
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            //
 | 
						|
            // Exit loop on Error
 | 
						|
            //
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          LastHandle = FileHandle;
 | 
						|
          FileHandle = NULL;
 | 
						|
 | 
						|
          Status = LastHandle->Open (
 | 
						|
                                LastHandle,
 | 
						|
                                &FileHandle,
 | 
						|
                                FilePathNode->PathName,
 | 
						|
                                EFI_FILE_MODE_READ,
 | 
						|
                                0
 | 
						|
                                );
 | 
						|
 | 
						|
          //
 | 
						|
          // Close the previous node
 | 
						|
          //
 | 
						|
          LastHandle->Close (LastHandle);
 | 
						|
 | 
						|
          FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header);
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Free the allocated memory pool
 | 
						|
        //
 | 
						|
        CoreFreePool(OriginalFilePathNode);
 | 
						|
      }
 | 
						|
 | 
						|
      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 = FileHandle->GetInfo (
 | 
						|
                                  FileHandle,
 | 
						|
                                  &gEfiFileInfoGuid,
 | 
						|
                                  &FileInfoSize,
 | 
						|
                                  FileInfo
 | 
						|
                                  );
 | 
						|
          } else {
 | 
						|
            Status = EFI_OUT_OF_RESOURCES;
 | 
						|
            goto Done;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          //
 | 
						|
          // Allocate space for the file
 | 
						|
          //
 | 
						|
          ASSERT (FileInfo != NULL);
 | 
						|
          ImageFileHandle->Source = AllocatePool ((UINTN)FileInfo->FileSize);
 | 
						|
          if (ImageFileHandle->Source != NULL) {
 | 
						|
            //
 | 
						|
            // Read the file into the buffer we allocated
 | 
						|
            //
 | 
						|
            ImageFileHandle->SourceSize = (UINTN) FileInfo->FileSize;
 | 
						|
            ImageFileHandle->FreeBuffer = TRUE;
 | 
						|
            Status = FileHandle->Read (FileHandle, &ImageFileHandle->SourceSize, ImageFileHandle->Source);
 | 
						|
 | 
						|
            //
 | 
						|
            // Close the file since we are done
 | 
						|
            //
 | 
						|
            FileHandle->Close (FileHandle);
 | 
						|
            CoreFreePool (FileInfo);
 | 
						|
          } else {
 | 
						|
            Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          }
 | 
						|
 | 
						|
          goto Done;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  //
 | 
						|
  // Try LoadFile style
 | 
						|
  //
 | 
						|
 | 
						|
  TempFilePath = *FilePath;
 | 
						|
  Status = CoreDevicePathToInterface (
 | 
						|
             &gEfiLoadFileProtocolGuid,
 | 
						|
             &TempFilePath,
 | 
						|
             (VOID*) &LoadFile,
 | 
						|
             DeviceHandle
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Call LoadFile with the correct buffer size
 | 
						|
    //
 | 
						|
    ASSERT (ImageFileHandle->SourceSize == 0);
 | 
						|
    ASSERT (ImageFileHandle->Source == NULL);
 | 
						|
    Status = LoadFile->LoadFile (
 | 
						|
                         LoadFile,
 | 
						|
                         TempFilePath,
 | 
						|
                         BootPolicy,
 | 
						|
                         &ImageFileHandle->SourceSize,
 | 
						|
                         ImageFileHandle->Source
 | 
						|
                         );
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      ImageFileHandle->Source = AllocatePool (ImageFileHandle->SourceSize);
 | 
						|
      if (ImageFileHandle->Source == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      } else {
 | 
						|
        Status = LoadFile->LoadFile (
 | 
						|
                             LoadFile,
 | 
						|
                             TempFilePath,
 | 
						|
                             BootPolicy,
 | 
						|
                             &ImageFileHandle->SourceSize,
 | 
						|
                             ImageFileHandle->Source
 | 
						|
                             );
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      ImageFileHandle->FreeBuffer = TRUE;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Nothing else to try
 | 
						|
  //
 | 
						|
  DEBUG ((DEBUG_LOAD|DEBUG_WARN, "CoreOpenImageFile: Device did not support a known load protocol\n"));
 | 
						|
  Status = EFI_NOT_FOUND;
 | 
						|
 | 
						|
Done:
 | 
						|
  //
 | 
						|
  // If the file was not accessed, clean up
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    if (ImageFileHandle->FreeBuffer) {
 | 
						|
      //
 | 
						|
      // Free the source buffer if we allocated it
 | 
						|
      //
 | 
						|
      CoreFreePool (ImageFileHandle->Source);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Read image file (specified by UserHandle) into user specified buffer with specified offset
 | 
						|
  and length.
 | 
						|
 | 
						|
  @param  UserHandle             Image file handle
 | 
						|
  @param  Offset                 Offset to the source file
 | 
						|
  @param  ReadSize               For input, pointer of size to read; For output,
 | 
						|
                                 pointer of size actually read.
 | 
						|
  @param  Buffer                 Buffer to write into
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Successfully read the specified part of file
 | 
						|
                                 into buffer.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreReadImageFile (
 | 
						|
  IN     VOID    *UserHandle,
 | 
						|
  IN     UINTN   Offset,
 | 
						|
  IN OUT UINTN   *ReadSize,
 | 
						|
  OUT    VOID    *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN               EndPosition;
 | 
						|
  IMAGE_FILE_HANDLE  *FHand;
 | 
						|
 | 
						|
  FHand = (IMAGE_FILE_HANDLE  *)UserHandle;
 | 
						|
  ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
 | 
						|
 | 
						|
  //
 | 
						|
  // Move data from our local copy of the file
 | 
						|
  //
 | 
						|
  EndPosition = Offset + *ReadSize;
 | 
						|
  if (EndPosition > FHand->SourceSize) {
 | 
						|
    *ReadSize = (UINT32)(FHand->SourceSize - Offset);
 | 
						|
  }
 | 
						|
  if (Offset >= FHand->SourceSize) {
 | 
						|
      *ReadSize = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 |