peloader.c

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

C
594
字号
/*++

Copyright (c) 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:
  PeLoader.c

Abstract:

Revision History:

--*/

EFI_STATUS
EfiLdrGetPeImageInfo (
  IN  VOID                    *FHand,
  OUT UINT64                  *ImageBase,
  OUT UINT32                  *ImageSize
  )
{
  EFI_STATUS                        Status;
  EFI_IMAGE_DOS_HEADER              DosHdr;
  EFI_IMAGE_OPTIONAL_HEADER_UNION   PeHdr;

  EfiCommonLibZeroMem (&DosHdr, sizeof(DosHdr));
  EfiCommonLibZeroMem (&PeHdr, sizeof(PeHdr));

  //
  // Read image headers
  //

  EfiLdrPeCoffImageRead (FHand, 0, sizeof(DosHdr), &DosHdr);
  if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
    return EFI_UNSUPPORTED;
  }

  EfiLdrPeCoffImageRead (FHand, DosHdr.e_lfanew, sizeof(PeHdr), &PeHdr);

  if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
    return EFI_UNSUPPORTED;
  }
    
  //
  // Verify machine type
  //

  Status = EfiLdrPeCoffCheckImageMachineType (PeHdr.Pe32.FileHeader.Machine);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    *ImageBase = (UINT32)PeHdr.Pe32.OptionalHeader.ImageBase;
  } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    *ImageBase = PeHdr.Pe32Plus.OptionalHeader.ImageBase;
  } else {
    return EFI_UNSUPPORTED;
  }
  
  *ImageSize = PeHdr.Pe32.OptionalHeader.SizeOfImage;

  return EFI_SUCCESS;
}

EFI_STATUS
EfiLdrPeCoffLoadPeImage (
  IN VOID                     *FHand,
  IN EFILDR_LOADED_IMAGE      *Image,
  IN UINTN                    *NumberOfMemoryMapEntries,
  IN EFI_MEMORY_DESCRIPTOR    *EfiMemoryDescriptor
  )
{
  EFI_IMAGE_DOS_HEADER            DosHdr;
  EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
  EFI_IMAGE_SECTION_HEADER        *FirstSection;
  EFI_IMAGE_SECTION_HEADER        *Section;
  UINTN                           Index;
  EFI_STATUS                      Status;
  UINT8                           *Base;
  UINT8                           *End;
  EFI_IMAGE_DATA_DIRECTORY        *DirectoryEntry;
  UINTN                           DirCount;
  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY TempDebugEntry;
  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
  UINTN                           CodeViewSize;
  UINTN                           CodeViewOffset;
  UINTN                           CodeViewFileOffset;
  UINTN                           OptionalHeaderSize;
  UINTN                           PeHeaderSize;
  UINT32                          NumberOfRvaAndSizes;
  EFI_IMAGE_DATA_DIRECTORY        *DataDirectory;
  UINT64                          ImageBase;

  EfiCommonLibZeroMem (&DosHdr, sizeof(DosHdr));
  EfiCommonLibZeroMem (&PeHdr, sizeof(PeHdr));

  //
  // Read image headers
  //

  EfiLdrPeCoffImageRead (FHand, 0, sizeof(DosHdr), &DosHdr);
  if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
//    DEBUG ((D_LOAD, "PeCoffLoadPeImage: Dos header signature not found\n"));
PrintHeader ('F');
    return EFI_UNSUPPORTED;
  }

  EfiLdrPeCoffImageRead (FHand, DosHdr.e_lfanew, sizeof(PeHdr), &PeHdr);

  if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
//    DEBUG ((D_LOAD, "PeCoffLoadPeImage: PE image header signature not found\n"));
PrintHeader ('G');
    return EFI_UNSUPPORTED;
  }
    
  //
  // Set the image subsystem type
  //

  Status = EfiLdrPeCoffSetImageType (Image, PeHdr.Pe32.OptionalHeader.Subsystem);
  if (EFI_ERROR(Status)) {
//    DEBUG ((D_LOAD, "PeCoffLoadPeImage: Subsystem type not known\n"));
PrintHeader ('H');
    return Status;
  }

  //
  // Verify machine type
  //

  Status = EfiLdrPeCoffCheckImageMachineType (PeHdr.Pe32.FileHeader.Machine);
  if (EFI_ERROR(Status)) {
//    DEBUG ((D_LOAD, "PeCoffLoadPeImage: Incorrect machine type\n"));
PrintHeader ('I');
    return Status;
  }

  //
  // Compute the amount of memory needed to load the image and 
  // allocate it.  This will include all sections plus the codeview debug info.
  // Since the codeview info is actually outside of the image, we calculate
  // its size seperately and add it to the total.
  //
  // Memory starts off as data
  //

  CodeViewSize       = 0;
  CodeViewFileOffset = 0;
  if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(PeHdr.Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
  } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(PeHdr.Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
  } else {
    return EFI_UNSUPPORTED;
  }
  for (DirCount = 0; 
       (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && (CodeViewSize == 0);
       DirCount++) {
    Status = EfiLdrPeCoffImageRead (
               FHand, 
               DirectoryEntry->VirtualAddress + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY),
               sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY),
               &TempDebugEntry
               );
    if (!EFI_ERROR (Status)) {
      if (TempDebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
        CodeViewSize = TempDebugEntry.SizeOfData;
        CodeViewFileOffset = TempDebugEntry.FileOffset;
      }
    }
  }
    
  CodeViewOffset = PeHdr.Pe32.OptionalHeader.SizeOfImage + PeHdr.Pe32.OptionalHeader.SectionAlignment;
  Image->NoPages = EFI_SIZE_TO_PAGES (CodeViewOffset + CodeViewSize);

  //
  // Compute the amount of memory needed to load the image and 
  // allocate it.  Memory starts off as data
  //

  Image->ImageBasePage = (EFI_PHYSICAL_ADDRESS)FindSpace (Image->NoPages, NumberOfMemoryMapEntries, EfiMemoryDescriptor, EfiRuntimeServicesCode, EFI_MEMORY_WB);
  if (Image->ImageBasePage == 0) {
    return EFI_OUT_OF_RESOURCES;
  }

  if (EFI_ERROR(Status)) {
PrintHeader ('J');
    return Status;
  }

//  DEBUG((D_LOAD, "LoadPe: new image base %lx\n", Image->ImageBasePage));
  Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageBasePage;
  Image->Info.ImageSize = (Image->NoPages << EFI_PAGE_SHIFT) - 1;
  Image->ImageBase      = (UINT8 *)(UINTN)Image->ImageBasePage;
  Image->ImageEof       = Image->ImageBase + Image->Info.ImageSize;
  Image->ImageAdjust    = Image->ImageBase;

  //
  // Copy the Image header to the base location
  //
  Status = EfiLdrPeCoffImageRead (
             FHand, 
             0, 
             PeHdr.Pe32.OptionalHeader.SizeOfHeaders, 
             Image->ImageBase
             );

  if (EFI_ERROR(Status)) {
PrintHeader ('K');
    return Status;
  }

  //
  // Load each directory of the image into memory... 
  //  Save the address of the Debug directory for later
  //
  if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    NumberOfRvaAndSizes = PeHdr.Pe32.OptionalHeader.NumberOfRvaAndSizes;
    DataDirectory = PeHdr.Pe32.OptionalHeader.DataDirectory;
  } else {
    NumberOfRvaAndSizes = PeHdr.Pe32Plus.OptionalHeader.NumberOfRvaAndSizes;
    DataDirectory = PeHdr.Pe32Plus.OptionalHeader.DataDirectory;
  }
  DebugEntry = NULL;
  for (Index = 0; Index < NumberOfRvaAndSizes; Index++) {
    if ((DataDirectory[Index].VirtualAddress != 0) && (DataDirectory[Index].Size != 0)) {
      Status = EfiLdrPeCoffImageRead (
                 FHand,
                 DataDirectory[Index].VirtualAddress,
                 DataDirectory[Index].Size,
                 Image->ImageBase + DataDirectory[Index].VirtualAddress
                 );
      if (EFI_ERROR(Status)) {
        return Status;
      }
      if (Index == EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
        DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (Image->ImageBase + DataDirectory[Index].VirtualAddress);
      }
    }
  }

  //
  // Load each section of the image
  //

  // BUGBUG: change this to use the in memory copy
  if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    OptionalHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32);
    PeHeaderSize       = sizeof(EFI_IMAGE_NT_HEADERS32);
  } else {
    OptionalHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64);
    PeHeaderSize       = sizeof(EFI_IMAGE_NT_HEADERS64);
  }
  FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
                   Image->ImageBase +
                   DosHdr.e_lfanew + 
                   PeHeaderSize + 
                   PeHdr.Pe32.FileHeader.SizeOfOptionalHeader - 
                   OptionalHeaderSize
                   );

  Section = FirstSection;
  for (Index=0; Index < PeHdr.Pe32.FileHeader.NumberOfSections; Index += 1) {

    //
    // Compute sections address
    //

    Base = EfiLdrPeCoffImageAddress (Image, Section->VirtualAddress);
    End = EfiLdrPeCoffImageAddress (Image, Section->VirtualAddress + Section->Misc.VirtualSize);
        
    if (EFI_ERROR(Status) || !Base || !End) {
//      DEBUG((D_LOAD|D_ERROR, "LoadPe: Section %d was not loaded\n", Index));
PrintHeader ('L');
      return EFI_LOAD_ERROR;
    }

//    DEBUG((D_LOAD, "LoadPe: Section %d, loaded at %x\n", Index, Base));

    //
    // Read the section
    //
 
    if (Section->SizeOfRawData) {
      Status = EfiLdrPeCoffImageRead (FHand, Section->PointerToRawData, Section->SizeOfRawData, Base);
      if (EFI_ERROR(Status)) {
PrintHeader ('M');
        return Status;
      }
    }

⌨️ 快捷键说明

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