Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
216
EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c
Normal file
216
EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*++
|
||||
|
||||
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:
|
||||
|
||||
PeHotRelocate.c
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "Runtime.h"
|
||||
|
||||
STATIC
|
||||
VOID *
|
||||
RuntimePeImageAddress (
|
||||
IN RUNTIME_IMAGE_RELOCATION_DATA *Image,
|
||||
IN UINTN Address
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Converts an image address to the loaded address
|
||||
|
||||
Arguments:
|
||||
|
||||
Image - The relocation data of the image being loaded
|
||||
|
||||
Address - The address to be converted to the loaded address
|
||||
|
||||
Returns:
|
||||
|
||||
NULL if the address can not be converted, otherwise, the converted address
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Address >= (Image->ImageSize) << EFI_PAGE_SHIFT) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (CHAR8 *) ((UINTN) Image->ImageBase + Address);
|
||||
}
|
||||
|
||||
VOID
|
||||
RelocatePeImageForRuntime (
|
||||
RUNTIME_IMAGE_RELOCATION_DATA *Image
|
||||
)
|
||||
{
|
||||
CHAR8 *OldBase;
|
||||
CHAR8 *NewBase;
|
||||
EFI_IMAGE_DOS_HEADER *DosHdr;
|
||||
EFI_IMAGE_NT_HEADERS *PeHdr;
|
||||
UINT32 NumberOfRvaAndSizes;
|
||||
EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
|
||||
EFI_IMAGE_DATA_DIRECTORY *RelocDir;
|
||||
EFI_IMAGE_BASE_RELOCATION *RelocBase;
|
||||
EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
|
||||
UINT16 *Reloc;
|
||||
UINT16 *RelocEnd;
|
||||
CHAR8 *Fixup;
|
||||
CHAR8 *FixupBase;
|
||||
UINT16 *F16;
|
||||
UINT32 *F32;
|
||||
CHAR8 *FixupData;
|
||||
UINTN Adjust;
|
||||
EFI_STATUS Status;
|
||||
|
||||
OldBase = (CHAR8 *) ((UINTN) Image->ImageBase);
|
||||
NewBase = (CHAR8 *) ((UINTN) Image->ImageBase);
|
||||
|
||||
Status = RuntimeDriverConvertPointer (0, (VOID **) &NewBase);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Adjust = (UINTN) NewBase - (UINTN) OldBase;
|
||||
|
||||
//
|
||||
// Find the image's relocate dir info
|
||||
//
|
||||
DosHdr = (EFI_IMAGE_DOS_HEADER *) OldBase;
|
||||
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
|
||||
//
|
||||
// Valid DOS header so get address of PE header
|
||||
//
|
||||
PeHdr = (EFI_IMAGE_NT_HEADERS *) (((CHAR8 *) DosHdr) + DosHdr->e_lfanew);
|
||||
} else {
|
||||
//
|
||||
// No Dos header so assume image starts with PE header.
|
||||
//
|
||||
PeHdr = (EFI_IMAGE_NT_HEADERS *) OldBase;
|
||||
}
|
||||
|
||||
if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
|
||||
//
|
||||
// Not a valid PE image so Exit
|
||||
//
|
||||
return ;
|
||||
}
|
||||
//
|
||||
// Get some data from the PE type dependent data
|
||||
//
|
||||
NumberOfRvaAndSizes = PeHdr->OptionalHeader.NumberOfRvaAndSizes;
|
||||
DataDirectory = &PeHdr->OptionalHeader.DataDirectory[0];
|
||||
|
||||
//
|
||||
// Find the relocation block
|
||||
//
|
||||
// Per the PE/COFF spec, you can't assume that a given data directory
|
||||
// is present in the image. You have to check the NumberOfRvaAndSizes in
|
||||
// the optional header to verify a desired directory entry is there.
|
||||
//
|
||||
if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
|
||||
RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
|
||||
RelocBase = RuntimePeImageAddress (Image, RelocDir->VirtualAddress);
|
||||
RelocBaseEnd = RuntimePeImageAddress (Image, RelocDir->VirtualAddress + RelocDir->Size);
|
||||
} else {
|
||||
//
|
||||
// Cannot find relocations, cannot continue
|
||||
//
|
||||
ASSERT (FALSE);
|
||||
return ;
|
||||
}
|
||||
|
||||
ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
|
||||
|
||||
//
|
||||
// Run the whole relocation block. And re-fixup data that has not been
|
||||
// modified. The FixupData is used to see if the image has been modified
|
||||
// since it was relocated. This is so data sections that have been updated
|
||||
// by code will not be fixed up, since that would set them back to
|
||||
// defaults.
|
||||
//
|
||||
FixupData = Image->RelocationData;
|
||||
while (RelocBase < RelocBaseEnd) {
|
||||
|
||||
Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
|
||||
RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
|
||||
FixupBase = (CHAR8 *) ((UINTN) Image->ImageBase) + RelocBase->VirtualAddress;
|
||||
|
||||
//
|
||||
// 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;
|
||||
if (*(UINT16 *) FixupData == *F16) {
|
||||
*F16 = (UINT16) ((*F16 << 16) + ((UINT16) Adjust & 0xffff));
|
||||
}
|
||||
|
||||
FixupData = FixupData + sizeof (UINT16);
|
||||
break;
|
||||
|
||||
case EFI_IMAGE_REL_BASED_LOW:
|
||||
F16 = (UINT16 *) Fixup;
|
||||
if (*(UINT16 *) FixupData == *F16) {
|
||||
*F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));
|
||||
}
|
||||
|
||||
FixupData = FixupData + sizeof (UINT16);
|
||||
break;
|
||||
|
||||
case EFI_IMAGE_REL_BASED_HIGHLOW:
|
||||
F32 = (UINT32 *) Fixup;
|
||||
FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
|
||||
if (*(UINT32 *) FixupData == *F32) {
|
||||
*F32 = *F32 + (UINT32) Adjust;
|
||||
}
|
||||
|
||||
FixupData = FixupData + sizeof (UINT32);
|
||||
break;
|
||||
|
||||
case EFI_IMAGE_REL_BASED_HIGHADJ:
|
||||
//
|
||||
// Not implemented, but not used in EFI 1.0
|
||||
//
|
||||
ASSERT (FALSE);
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// Only Itanium requires ConvertPeImage_Ex
|
||||
//
|
||||
Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Next relocation record
|
||||
//
|
||||
Reloc += 1;
|
||||
}
|
||||
//
|
||||
// next reloc block
|
||||
//
|
||||
RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
|
||||
}
|
||||
|
||||
FlushCpuCache (Image->ImageBase, (UINT64) Image->ImageSize);
|
||||
}
|
Reference in New Issue
Block a user