git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8022 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			479 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			16 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_LOAD_FILE2_PROTOCOL           *LoadFile2;
 | |
|   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 LoadFile2 style
 | |
|   //
 | |
|   if (!BootPolicy) {
 | |
|     TempFilePath = *FilePath;
 | |
|     Status = CoreDevicePathToInterface (
 | |
|                &gEfiLoadFile2ProtocolGuid,
 | |
|                &TempFilePath,
 | |
|                (VOID*)&LoadFile2,
 | |
|                DeviceHandle
 | |
|                );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Call LoadFile2 with the correct buffer size
 | |
|       //    
 | |
|       ASSERT (ImageFileHandle->SourceSize == 0);
 | |
|       ASSERT (ImageFileHandle->Source == NULL);
 | |
|       
 | |
|       Status = LoadFile2->LoadFile (
 | |
|                            LoadFile2,
 | |
|                            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 = LoadFile2->LoadFile (
 | |
|                                LoadFile2,
 | |
|                                TempFilePath,
 | |
|                                BootPolicy,
 | |
|                                &ImageFileHandle->SourceSize,
 | |
|                                ImageFileHandle->Source
 | |
|                                );
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         ImageFileHandle->FreeBuffer = TRUE;
 | |
|         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;
 | |
| }
 | |
| 
 |