2008-04-18 05:09:54 +02:00
|
|
|
/*++
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#include "EfiLdr.h"
|
|
|
|
#include "Debug.h"
|
|
|
|
#include "Support.h"
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffLoadPeRelocate (
|
|
|
|
IN EFILDR_LOADED_IMAGE *Image,
|
|
|
|
IN EFI_IMAGE_DATA_DIRECTORY *RelocDir,
|
|
|
|
IN UINTN Adjust,
|
|
|
|
IN UINTN *NumberOfMemoryMapEntries,
|
|
|
|
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffImageRead (
|
|
|
|
IN VOID *FHand,
|
|
|
|
IN UINTN Offset,
|
|
|
|
IN OUT UINTN ReadSize,
|
|
|
|
OUT VOID *Buffer
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID *
|
|
|
|
EfiLdrPeCoffImageAddress (
|
|
|
|
IN EFILDR_LOADED_IMAGE *Image,
|
|
|
|
IN UINTN Address
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffSetImageType (
|
|
|
|
IN OUT EFILDR_LOADED_IMAGE *Image,
|
|
|
|
IN UINTN ImageType
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffCheckImageMachineType (
|
|
|
|
IN UINT16 MachineType
|
|
|
|
);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
ZeroMem (&DosHdr, sizeof(DosHdr));
|
|
|
|
ZeroMem (&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;
|
2008-04-25 11:30:24 +02:00
|
|
|
CHAR8 PrintBuffer[256];
|
2008-04-18 05:09:54 +02:00
|
|
|
|
|
|
|
ZeroMem (&DosHdr, sizeof(DosHdr));
|
|
|
|
ZeroMem (&PeHdr, sizeof(PeHdr));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Read image headers
|
|
|
|
//
|
|
|
|
|
|
|
|
EfiLdrPeCoffImageRead (FHand, 0, sizeof(DosHdr), &DosHdr);
|
|
|
|
if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
2008-04-25 11:30:24 +02:00
|
|
|
AsciiSPrint (PrintBuffer, 256, "PeCoffLoadPeImage: Dos header signature not found\n");
|
|
|
|
PrintString (PrintBuffer);
|
|
|
|
PrintHeader ('F');
|
2008-04-18 05:09:54 +02:00
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
EfiLdrPeCoffImageRead (FHand, DosHdr.e_lfanew, sizeof(PeHdr), &PeHdr);
|
|
|
|
|
|
|
|
if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
|
2008-04-25 11:30:24 +02:00
|
|
|
AsciiSPrint (PrintBuffer, 256, "PeCoffLoadPeImage: PE image header signature not found\n");
|
|
|
|
PrintString (PrintBuffer);
|
|
|
|
PrintHeader ('G');
|
2008-04-18 05:09:54 +02:00
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set the image subsystem type
|
|
|
|
//
|
|
|
|
|
|
|
|
Status = EfiLdrPeCoffSetImageType (Image, PeHdr.Pe32.OptionalHeader.Subsystem);
|
|
|
|
if (EFI_ERROR(Status)) {
|
2008-04-25 11:30:24 +02:00
|
|
|
AsciiSPrint (PrintBuffer, 256, "PeCoffLoadPeImage: Subsystem type not known\n");
|
|
|
|
PrintString (PrintBuffer);
|
|
|
|
PrintHeader ('H');
|
2008-04-18 05:09:54 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Verify machine type
|
|
|
|
//
|
|
|
|
|
|
|
|
Status = EfiLdrPeCoffCheckImageMachineType (PeHdr.Pe32.FileHeader.Machine);
|
|
|
|
if (EFI_ERROR(Status)) {
|
2008-04-25 11:30:24 +02:00
|
|
|
AsciiSPrint (PrintBuffer, 256, "PeCoffLoadPeImage: Incorrect machine type\n");
|
|
|
|
PrintString (PrintBuffer);
|
|
|
|
PrintHeader ('I');
|
2008-04-18 05:09:54 +02:00
|
|
|
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)) {
|
2008-04-25 11:30:24 +02:00
|
|
|
PrintHeader ('J');
|
2008-04-18 05:09:54 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2008-04-25 11:30:24 +02:00
|
|
|
AsciiSPrint (PrintBuffer, 256, "LoadPe: new image base %lx\n", Image->ImageBasePage);
|
|
|
|
PrintString (PrintBuffer);
|
2008-04-18 05:09:54 +02:00
|
|
|
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)) {
|
2008-04-25 11:30:24 +02:00
|
|
|
PrintHeader ('K');
|
2008-04-18 05:09:54 +02:00
|
|
|
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, (UINTN)Section->VirtualAddress);
|
|
|
|
End = EfiLdrPeCoffImageAddress (Image, (UINTN)(Section->VirtualAddress + Section->Misc.VirtualSize));
|
|
|
|
|
|
|
|
if (EFI_ERROR(Status) || !Base || !End) {
|
|
|
|
// DEBUG((D_LOAD|D_ERROR, "LoadPe: Section %d was not loaded\n", Index));
|
2008-04-25 11:30:24 +02:00
|
|
|
PrintHeader ('L');
|
2008-04-18 05:09:54 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If raw size is less then virt size, zero fill the remaining
|
|
|
|
//
|
|
|
|
|
|
|
|
if (Section->SizeOfRawData < Section->Misc.VirtualSize) {
|
|
|
|
ZeroMem (
|
|
|
|
Base + Section->SizeOfRawData,
|
|
|
|
Section->Misc.VirtualSize - Section->SizeOfRawData
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Next Section
|
|
|
|
//
|
|
|
|
|
|
|
|
Section += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Copy in CodeView information if it exists
|
|
|
|
//
|
|
|
|
if (CodeViewSize != 0) {
|
|
|
|
Status = EfiLdrPeCoffImageRead (FHand, CodeViewFileOffset, CodeViewSize, Image->ImageBase + CodeViewOffset);
|
|
|
|
DebugEntry->RVA = (UINT32) (CodeViewOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Apply relocations only if needed
|
|
|
|
//
|
|
|
|
if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
|
|
ImageBase = (UINT64)PeHdr.Pe32.OptionalHeader.ImageBase;
|
|
|
|
} else {
|
|
|
|
ImageBase = PeHdr.Pe32Plus.OptionalHeader.ImageBase;
|
|
|
|
}
|
|
|
|
if ((UINTN)(Image->ImageBase) != (UINTN) (ImageBase)) {
|
|
|
|
Status = EfiLdrPeCoffLoadPeRelocate (
|
|
|
|
Image,
|
|
|
|
&DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC],
|
|
|
|
(UINTN) Image->ImageBase - (UINTN)ImageBase,
|
|
|
|
NumberOfMemoryMapEntries,
|
|
|
|
EfiMemoryDescriptor
|
|
|
|
);
|
|
|
|
|
|
|
|
if (EFI_ERROR(Status)) {
|
2008-04-25 11:30:24 +02:00
|
|
|
PrintHeader ('N');
|
2008-04-18 05:09:54 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Use exported EFI specific interface if present, else use the image's entry point
|
|
|
|
//
|
|
|
|
Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)
|
|
|
|
(EfiLdrPeCoffImageAddress(
|
|
|
|
Image,
|
|
|
|
PeHdr.Pe32.OptionalHeader.AddressOfEntryPoint
|
|
|
|
));
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffLoadPeRelocate (
|
|
|
|
IN EFILDR_LOADED_IMAGE *Image,
|
|
|
|
IN EFI_IMAGE_DATA_DIRECTORY *RelocDir,
|
|
|
|
IN UINTN Adjust,
|
|
|
|
IN UINTN *NumberOfMemoryMapEntries,
|
|
|
|
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_IMAGE_BASE_RELOCATION *RelocBase;
|
|
|
|
EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
|
|
|
|
UINT16 *Reloc;
|
|
|
|
UINT16 *RelocEnd;
|
|
|
|
UINT8 *Fixup;
|
|
|
|
UINT8 *FixupBase;
|
|
|
|
UINT16 *F16;
|
|
|
|
UINT32 *F32;
|
|
|
|
UINT64 *F64;
|
|
|
|
UINT8 *FixupData;
|
|
|
|
UINTN NoFixupPages;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Find the relocation block
|
|
|
|
//
|
|
|
|
|
|
|
|
RelocBase = EfiLdrPeCoffImageAddress (Image, RelocDir->VirtualAddress);
|
|
|
|
RelocBaseEnd = EfiLdrPeCoffImageAddress (Image, RelocDir->VirtualAddress + RelocDir->Size);
|
|
|
|
if (!RelocBase || !RelocBaseEnd) {
|
|
|
|
PrintHeader ('O');
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
NoFixupPages = EFI_SIZE_TO_PAGES(RelocDir->Size / sizeof(UINT16) * sizeof(UINTN));
|
|
|
|
Image->FixupData = (UINT8*) FindSpace (NoFixupPages, NumberOfMemoryMapEntries, EfiMemoryDescriptor, EfiRuntimeServicesData, EFI_MEMORY_WB);
|
|
|
|
if (Image->FixupData == 0) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Run the whole relocation block
|
|
|
|
//
|
|
|
|
|
|
|
|
FixupData = Image->FixupData;
|
|
|
|
while (RelocBase < RelocBaseEnd) {
|
|
|
|
|
|
|
|
Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof(EFI_IMAGE_BASE_RELOCATION));
|
|
|
|
RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
|
|
|
|
FixupBase = EfiLdrPeCoffImageAddress (Image, RelocBase->VirtualAddress);
|
|
|
|
if ((UINT8 *) RelocEnd < Image->ImageBase || (UINT8 *) RelocEnd > Image->ImageEof) {
|
|
|
|
PrintHeader ('P');
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Run this relocation record
|
|
|
|
//
|
|
|
|
|
|
|
|
while (Reloc < RelocEnd) {
|
|
|
|
|
|
|
|
Fixup = FixupBase + (*Reloc & 0xFFF);
|
|
|
|
switch ((*Reloc) >> 12) {
|
|
|
|
|
|
|
|
case EFI_IMAGE_REL_BASED_ABSOLUTE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_REL_BASED_HIGH:
|
|
|
|
F16 = (UINT16 *) Fixup;
|
|
|
|
*F16 = (UINT16) (*F16 + (UINT16)(((UINT32)Adjust) >> 16));
|
|
|
|
if (FixupData != NULL) {
|
|
|
|
*(UINT16 *) FixupData = *F16;
|
|
|
|
FixupData = FixupData + sizeof(UINT16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_REL_BASED_LOW:
|
|
|
|
F16 = (UINT16 *) Fixup;
|
|
|
|
*F16 = *F16 + (UINT16) Adjust;
|
|
|
|
if (FixupData != NULL) {
|
|
|
|
*(UINT16 *) FixupData = *F16;
|
|
|
|
FixupData = FixupData + sizeof(UINT16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_REL_BASED_HIGHLOW:
|
|
|
|
F32 = (UINT32 *) Fixup;
|
|
|
|
*F32 = *F32 + (UINT32) Adjust;
|
|
|
|
if (FixupData != NULL) {
|
|
|
|
FixupData = ALIGN_POINTER(FixupData, sizeof(UINT32));
|
|
|
|
*(UINT32 *) FixupData = *F32;
|
|
|
|
FixupData = FixupData + sizeof(UINT32);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_REL_BASED_DIR64:
|
|
|
|
F64 = (UINT64 *) Fixup;
|
|
|
|
*F64 = *F64 + (UINT64) Adjust;
|
|
|
|
if (FixupData != NULL) {
|
|
|
|
FixupData = ALIGN_POINTER(FixupData, sizeof(UINT64));
|
|
|
|
*(UINT64 *) FixupData = *F64;
|
|
|
|
FixupData = FixupData + sizeof(UINT64);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_REL_BASED_HIGHADJ:
|
|
|
|
CpuDeadLoop(); // BUGBUG: not done
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// DEBUG((D_LOAD|D_ERROR, "PeRelocate: unknown fixed type\n"));
|
|
|
|
PrintHeader ('Q');
|
|
|
|
CpuDeadLoop();
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next reloc record
|
|
|
|
Reloc += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// next reloc block
|
|
|
|
RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Add Fixup data to whole Image (assume Fixup data just below the image), so that there is no hole in the descriptor.
|
|
|
|
// Because only NoPages or ImageBasePage will be used in EfiLoader(), we update these 2 fields.
|
|
|
|
//
|
|
|
|
Image->NoPages += NoFixupPages;
|
|
|
|
Image->ImageBasePage -= (NoFixupPages << EFI_PAGE_SHIFT);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffImageRead (
|
|
|
|
IN VOID *FHand,
|
|
|
|
IN UINTN Offset,
|
|
|
|
IN OUT UINTN ReadSize,
|
|
|
|
OUT VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CopyMem (Buffer, (VOID *)((UINTN)FHand + Offset), ReadSize);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID *
|
|
|
|
EfiLdrPeCoffImageAddress (
|
|
|
|
IN EFILDR_LOADED_IMAGE *Image,
|
|
|
|
IN UINTN Address
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT8 *FixedAddress;
|
|
|
|
|
|
|
|
FixedAddress = Image->ImageAdjust + Address;
|
|
|
|
|
|
|
|
if ((FixedAddress < Image->ImageBase) || (FixedAddress > Image->ImageEof)) {
|
|
|
|
// DEBUG((D_LOAD|D_ERROR, "PeCoffImageAddress: pointer is outside of image\n"));
|
|
|
|
FixedAddress = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DEBUG((
|
|
|
|
// D_LOAD,
|
|
|
|
// "PeCoffImageAddress: ImageBase %x, ImageEof %x, Address %x, FixedAddress %x\n",
|
|
|
|
// Image->ImageBase,
|
|
|
|
// Image->ImageEof,
|
|
|
|
// Address,
|
|
|
|
// FixedAddress
|
|
|
|
// ));
|
|
|
|
return FixedAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffSetImageType (
|
|
|
|
IN OUT EFILDR_LOADED_IMAGE *Image,
|
|
|
|
IN UINTN ImageType
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_MEMORY_TYPE CodeType;
|
|
|
|
EFI_MEMORY_TYPE DataType;
|
|
|
|
|
|
|
|
switch (ImageType) {
|
|
|
|
case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
|
|
|
|
CodeType = EfiLoaderCode;
|
|
|
|
DataType = EfiLoaderData;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
|
|
|
|
CodeType = EfiBootServicesCode;
|
|
|
|
DataType = EfiBootServicesData;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
|
|
|
|
CodeType = EfiRuntimeServicesCode;
|
|
|
|
DataType = EfiRuntimeServicesData;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
Image->Type = ImageType;
|
|
|
|
Image->Info.ImageCodeType = CodeType;
|
|
|
|
Image->Info.ImageDataType = DataType;
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLdrPeCoffCheckImageMachineType (
|
|
|
|
IN UINT16 MachineType
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
|
|
|
|
#if EFI32
|
|
|
|
if (MachineType == EFI_IMAGE_MACHINE_IA32) {
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if EFIX64
|
|
|
|
if (MachineType == EFI_IMAGE_MACHINE_X64) {
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if EFI64
|
|
|
|
if (MachineType == EFI_IMAGE_MACHINE_IA64) {
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|