pecoffloader.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,408 行 · 第 1/4 页

C
1,408
字号
/*++

Copyright (c) 2005 - 2006, Intel Corporation                                                         
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.             

Module Name:

  PeCoffLoader.c

Abstract:

  Tiano PE/COFF loader 

Revision History

--*/

#include "Tiano.h"
#include "Pei.h"
#include "PeiLib.h"
#include "PeCoffLoaderEx.h"

#ifdef EFI_NT_EMULATOR
#include "peilib.h"
#include "EfiHobLib.h"
#include EFI_PPI_DEFINITION (NtLoadAsDll)
#endif

STATIC
EFI_STATUS
PeCoffLoaderGetPeHeader (
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT   *ImageContext,
  OUT    EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION    Hdr
  );

STATIC
VOID*
PeCoffLoaderImageAddress (
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
  IN     UINTN                                 Address
  );

EFI_STATUS
EFIAPI
PeCoffLoaderGetImageInfo (
  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  );

EFI_STATUS
EFIAPI
PeCoffLoaderRelocateImage (
  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  );

EFI_STATUS
EFIAPI
PeCoffLoaderLoadImage (
  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  );

EFI_STATUS
EFIAPI
PeCoffLoaderUnloadImage (
  IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT   *ImageContext
  );

#if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)
VOID
AsmEfiSetBreakSupport (
  IN UINTN  LoadAddr
  );
#endif

EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader = {
  PeCoffLoaderGetImageInfo,
  PeCoffLoaderLoadImage,
  PeCoffLoaderRelocateImage,
  PeCoffLoaderUnloadImage
};

#ifdef EFI_NT_EMULATOR
EFI_NT_LOAD_AS_DLL_PPI          *mPeCoffLoaderWinNtLoadAsDll = NULL;
#endif

EFI_STATUS
InstallEfiPeiPeCoffLoader (
  IN EFI_PEI_SERVICES                          **PeiServices,
  IN OUT  EFI_PEI_PE_COFF_LOADER_PROTOCOL      **This,
  IN EFI_PEI_PPI_DESCRIPTOR                    *ThisPpi
  )
/*++

Routine Description:

  Install PE/COFF loader PPI
  
Arguments:

  PeiServices - General purpose services available to every PEIM

  This        - Pointer to get Pei PE coff loader protocol as output
  
  ThisPpi     - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform

Returns:

  EFI_SUCCESS

--*/
{
  EFI_STATUS  Status;

  Status = EFI_SUCCESS;

#ifdef EFI_NT_EMULATOR
  //
  // For use by PEI Core and Modules
  //
  if (NULL != PeiServices) {
    Status = (**PeiServices).LocatePpi (
                              PeiServices,
                              &gEfiNtLoadAsDllPpiGuid,
                              0,
                              NULL,
                              &mPeCoffLoaderWinNtLoadAsDll
                              );
  } else {
    //
    // Now in SecMain or ERM usage, bind appropriately
    //
    PEI_ASSERT (PeiServices, (NULL != ThisPpi));

    mPeCoffLoaderWinNtLoadAsDll = (EFI_NT_LOAD_AS_DLL_PPI *) ThisPpi;
    PEI_ASSERT (PeiServices, (NULL != mPeCoffLoaderWinNtLoadAsDll));
  }
#endif

  if (NULL != This) {
    *This = &mPeCoffLoader;
  }

  return Status;
}

STATIC
EFI_STATUS
PeCoffLoaderGetPeHeader (
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT   *ImageContext,
  OUT    EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION    Hdr
  )
/*++

Routine Description:

  Retrieves the PE or TE Header from a PE/COFF or TE image

Arguments:

  ImageContext  - The context of the image being loaded

  PeHdr         - The buffer in which to return the PE32, PE32+, or TE header

Returns:

  EFI_SUCCESS if the PE or TE Header is read, 
  Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.

--*/
{
  EFI_STATUS            Status;
  EFI_IMAGE_DOS_HEADER  DosHdr;
  UINTN                 Size;
  UINT16                Magic;

  //
  // Read the DOS image header to check for it's existance
  //
  Size = sizeof (EFI_IMAGE_DOS_HEADER);
  Status = ImageContext->ImageRead (
                           ImageContext->Handle,
                           0,
                           &Size,
                           &DosHdr
                           );
  if (EFI_ERROR (Status)) {
    ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
    return Status;
  }

  ImageContext->PeCoffHeaderOffset = 0;
  if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    //
    // DOS image header is present, so read the PE header after the DOS image 
    // header
    //
    ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
  }

  //
  // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much 
  // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic
  // determins if this is a PE32 or PE32+ image. The magic is in the same 
  // location in both images.
  //
  Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
  Status = ImageContext->ImageRead (
                           ImageContext->Handle,
                           ImageContext->PeCoffHeaderOffset,
                           &Size,
                           Hdr.Pe32
                           );
  if (EFI_ERROR (Status)) {
    ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
    return Status;
  }

  //
  // Use Signature to figure out if we understand the image format
  //
  if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    ImageContext->IsTeImage         = TRUE;
    ImageContext->Machine           = Hdr.Te->Machine;
    ImageContext->ImageType         = (UINT16)(Hdr.Te->Subsystem);
    ImageContext->ImageSize         = 0;
    ImageContext->SectionAlignment  = 4096;
    ImageContext->SizeOfHeaders     = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;

  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
    ImageContext->IsTeImage         = FALSE;
    ImageContext->Machine           = Hdr.Pe32->FileHeader.Machine;
    
    //
    // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
    //       It is for backward-compatibility consideration, because
    //       some system will generate PE32+ image with PE32 Magic.
    //
    if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {
      Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
    } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {
      Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {
      Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    } else {
      Magic = Hdr.Pe32->OptionalHeader.Magic;
    }

    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
      //
      // Use PE32 offset
      //
      ImageContext->ImageType         = Hdr.Pe32->OptionalHeader.Subsystem;
      ImageContext->ImageSize         = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
      ImageContext->SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;
      ImageContext->SizeOfHeaders     = Hdr.Pe32->OptionalHeader.SizeOfHeaders;

    } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
      //
      // Use PE32+ offset
      //
      ImageContext->ImageType         = Hdr.Pe32Plus->OptionalHeader.Subsystem;
      ImageContext->ImageSize         = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
      ImageContext->SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
      ImageContext->SizeOfHeaders     = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
    } else {
      ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;
      return EFI_UNSUPPORTED;    
    }
  } else {
    ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;
    return EFI_UNSUPPORTED;
  }

  if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
    //
    // If the PE/COFF loader does not support the image type return
    // unsupported. This library can suport lots of types of images
    // this does not mean the user of this library can call the entry
    // point of the image. 
    //
    return EFI_UNSUPPORTED;
  }

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
PeCoffLoaderCheckImageType (
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  )
/*++

Routine Description:

  Checks the PE or TE header of a PE/COFF or TE image to determine if it supported

Arguments:

  ImageContext  - The context of the image being loaded

Returns:

  EFI_SUCCESS if the PE/COFF or TE image is supported
  EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.

--*/
{
  switch (ImageContext->ImageType) {

  case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
    ImageContext->ImageCodeMemoryType = EfiLoaderCode;
    ImageContext->ImageDataMemoryType = EfiLoaderData;
    break;

  case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
    ImageContext->ImageCodeMemoryType = EfiBootServicesCode;
    ImageContext->ImageDataMemoryType = EfiBootServicesData;
    break;

  case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
  case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
    ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;
    ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;
    break;

  default:
    ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;
    return EFI_UNSUPPORTED;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
PeCoffLoaderGetImageInfo (
  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
  IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  )
/*++

Routine Description:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?