efildr.c
来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 2,225 行 · 第 1/4 页
C
2,225 行
*ImageSize = PeHdr.OptionalHeader.SizeOfImage;
return EFI_SUCCESS;
}
EFI_STATUS
Ia32EmbLoadPeImage (
IN VOID *FHand,
IN EFILDR_LOADED_IMAGE *Image,
IN UINT32 *NumberOfMemoryMapEntries,
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
)
{
IMAGE_DOS_HEADER DosHdr;
IMAGE_NT_HEADERS PeHdr;
IMAGE_SECTION_HEADER *FirstSection;
IMAGE_SECTION_HEADER *Section;
UINTN Index;
EFI_STATUS Status;
CHAR8 *Base, *End;
EFI_PHYSICAL_ADDRESS MaxPhysicalStart;
UINT64 MaxNoPages;
IMAGE_DATA_DIRECTORY *DirectoryEntry;
UINTN DirCount;
IMAGE_DEBUG_DIRECTORY_ENTRY TempDebugEntry;
IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
UINTN CodeViewSize;
UINTN CodeViewOffset;
UINTN CodeViewFileOffset;
EFILDRZeroMem (&DosHdr, sizeof(DosHdr));
EFILDRZeroMem (&PeHdr, sizeof(PeHdr));
//
// Read image headers
//
Ia32EmbImageRead (FHand, 0, sizeof(IMAGE_DOS_HEADER), &DosHdr);
if (DosHdr.e_magic != IMAGE_DOS_SIGNATURE) {
// DEBUG ((D_LOAD, "Ia32EmbLoadPeImage: Dos header signature not found\n"));
*(UINT8 *)(0x000b8000+20) = 'F';
return EFI_UNSUPPORTED;
}
Ia32EmbImageRead (FHand, DosHdr.e_lfanew, sizeof(IMAGE_NT_HEADERS), &PeHdr);
if (PeHdr.Signature != IMAGE_NT_SIGNATURE) {
// DEBUG ((D_LOAD, "Ia32EmbLoadPeImage: PE image header signature not found\n"));
*(UINT8 *)(0x000b8000+22) = 'G';
return EFI_UNSUPPORTED;
}
//
// Set the image subsystem type
//
Status = Ia32EmbSetImageType (Image, PeHdr.OptionalHeader.Subsystem);
if (EFI_ERROR(Status)) {
// DEBUG ((D_LOAD, "Ia32EmbLoadPeImage: Subsystem type not known\n"));
*(UINT8 *)(0x000b8000+24) = 'H';
return Status;
}
//
// Verify machine type
//
Status = Ia32EmbCheckImageMachineType (PeHdr.FileHeader.Machine);
if (EFI_ERROR(Status)) {
// DEBUG ((D_LOAD, "Ia32EmbLoadPeImage: Incorrect machine type\n"));
*(UINT8 *)(0x000b8000+26) = '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;
DirectoryEntry = (IMAGE_DATA_DIRECTORY *)&(PeHdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]);
for (DirCount = 0;
(DirCount < DirectoryEntry->Size / sizeof (IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewSize == 0;
DirCount++) {
Status = Ia32EmbImageRead (FHand,
DirectoryEntry->VirtualAddress + DirCount * sizeof (IMAGE_DEBUG_DIRECTORY_ENTRY),
sizeof (IMAGE_DEBUG_DIRECTORY_ENTRY),
&TempDebugEntry);
if (!EFI_ERROR (Status)) {
if (TempDebugEntry.Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
CodeViewSize = TempDebugEntry.SizeOfData;
CodeViewFileOffset = TempDebugEntry.FileOffset;
}
}
}
CodeViewOffset = PeHdr.OptionalHeader.SizeOfImage + PeHdr.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
//
MaxPhysicalStart = 0;
for (Index = 0;Index < *NumberOfMemoryMapEntries; Index++) {
if (EfiMemoryDescriptor[Index].Type == EfiConventionalMemory &&
EfiMemoryDescriptor[Index].NumberOfPages >= (Image->NoPages + EFI_MAX_STACK_SIZE/EFI_PAGE_SIZE + 1)) {
if (EfiMemoryDescriptor[Index].PhysicalStart > MaxPhysicalStart) {
MaxPhysicalStart = EfiMemoryDescriptor[Index].PhysicalStart;
MaxNoPages = EfiMemoryDescriptor[Index].NumberOfPages;
}
}
}
if (MaxPhysicalStart == 0) {
return EFI_OUT_OF_RESOURCES;
}
Image->ImageBasePage = MaxPhysicalStart + (((UINT32)MaxNoPages - (Image->NoPages + 1)) << EFI_PAGE_SHIFT);
//
// Add a memory descriptor for the EFI Core Firmware
//
EfiAddMemoryDescriptor(
NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiRuntimeServicesCode,
(EFI_PHYSICAL_ADDRESS)(Image->ImageBasePage),
Image->NoPages,
EFI_MEMORY_WB
);
//
// Add a memory descriptor for the EFI Firmware Stack
//
EfiAddMemoryDescriptor(
NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiBootServicesData,
(EFI_PHYSICAL_ADDRESS)(Image->ImageBasePage-EFI_MAX_STACK_SIZE),
EFI_MAX_STACK_SIZE/EFI_PAGE_SIZE,
EFI_MEMORY_WB
);
if (EFI_ERROR(Status)) {
*(UINT8 *)(0x000b8000+28) = 'J';
return Status;
}
// DEBUG((D_LOAD, "LoadPe: new image base %lx\n", Image->ImageBasePage));
Image->Info.ImageBase = (VOID *) Image->ImageBasePage;
Image->Info.ImageSize = (Image->NoPages << EFI_PAGE_SHIFT) - 1;
Image->ImageBase = (CHAR8 *) Image->ImageBasePage;
Image->ImageEof = Image->ImageBase + Image->Info.ImageSize;
Image->ImageAdjust = Image->ImageBase;
//
// Copy the Image header to the base location
//
Status = Ia32EmbImageRead (
FHand,
0,
PeHdr.OptionalHeader.SizeOfHeaders,
Image->ImageBase
);
if (EFI_ERROR(Status)) {
*(UINT8 *)(0x000b8000+30) = 'K';
return Status;
}
//
// Load each directory of the image into memory...
// Save the address of the Debug directory for later
//
DebugEntry = NULL;
for (Index = 0; Index < PeHdr.OptionalHeader.NumberOfRvaAndSizes; Index++) {
if (PeHdr.OptionalHeader.DataDirectory[Index].VirtualAddress != 0 &&
PeHdr.OptionalHeader.DataDirectory[Index].Size != 0 ) {
Status = Ia32EmbImageRead (
FHand,
PeHdr.OptionalHeader.DataDirectory[Index].VirtualAddress,
PeHdr.OptionalHeader.DataDirectory[Index].Size,
Image->ImageBase + PeHdr.OptionalHeader.DataDirectory[Index].VirtualAddress
);
if (EFI_ERROR(Status)) {
return Status;
}
if (Index == IMAGE_DIRECTORY_ENTRY_DEBUG) {
DebugEntry = (IMAGE_DEBUG_DIRECTORY_ENTRY *) (Image->ImageBase + PeHdr.OptionalHeader.DataDirectory[Index].VirtualAddress);
}
}
}
//
// Load each section of the image
//
// BUGBUG: change this to use the in memory copy
FirstSection = (IMAGE_SECTION_HEADER *) (
Image->ImageBase +
DosHdr.e_lfanew +
sizeof(PeHdr) +
PeHdr.FileHeader.SizeOfOptionalHeader -
sizeof (IMAGE_OPTIONAL_HEADER)
);
Section = FirstSection;
for (Index=0; Index < PeHdr.FileHeader.NumberOfSections; Index += 1) {
//
// Compute sections address
//
Base = Ia32EmbImageAddress(Image, Section->VirtualAddress);
End = Ia32EmbImageAddress(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));
*(UINT8 *)(0x000b8000+32) = 'L';
return EFI_LOAD_ERROR;
}
// DEBUG((D_LOAD, "LoadPe: Section %d, loaded at %x\n", Index, Base));
//
// Read the section
//
if (Section->SizeOfRawData) {
Status = Ia32EmbImageRead (FHand, Section->PointerToRawData, Section->SizeOfRawData, Base);
if (EFI_ERROR(Status)) {
*(UINT8 *)(0x000b8000+34) = 'M';
return Status;
}
}
//
// If raw size is less then virt size, zero fill the remaining
//
if (Section->SizeOfRawData < Section->Misc.VirtualSize) {
EFILDRZeroMem (
Base + Section->SizeOfRawData,
Section->Misc.VirtualSize - Section->SizeOfRawData
);
}
//
// Next Section
//
Section += 1;
}
//
// Copy in CodeView information if it exists
//
if (CodeViewSize != 0) {
Status = Ia32EmbImageRead (FHand, CodeViewFileOffset, CodeViewSize, Image->ImageBase + CodeViewOffset);
DebugEntry->RVA = (UINT32) (CodeViewOffset);
}
//
// Apply relocations only if needed
//
if((UINTN)(Image->ImageBase) != (UINTN) (PeHdr.OptionalHeader.ImageBase)) {
Status = Ia32EmbLoadPeRelocate (
Image,
&PeHdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC],
(UINTN) Image->ImageBase - PeHdr.OptionalHeader.ImageBase,
NumberOfMemoryMapEntries,
EfiMemoryDescriptor
);
if (EFI_ERROR(Status)) {
*(UINT8 *)(0x000b8000+36) = 'N';
return Status;
}
}
//
// Use exported EFI specific interface if present, else use the image's entry point
//
Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)
(Ia32EmbImageAddress(
Image,
PeHdr.OptionalHeader.AddressOfEntryPoint
));
return Status;
}
#define ALIGN_POINTER(p,s) ((VOID *) (p + ((s - ((UINTN)p)) & (s-1))))
STATIC
EFI_STATUS
Ia32EmbLoadPeRelocate (
IN EFILDR_LOADED_IMAGE *Image,
IN IMAGE_DATA_DIRECTORY *RelocDir,
IN UINTN Adjust,
IN UINT32 *NumberOfMemoryMapEntries,
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
)
{
IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
UINT16 *Reloc, *RelocEnd;
CHAR8 *Fixup, *FixupBase;
UINT16 *F16;
UINT32 *F32;
CHAR8 *FixupData;
UINTN NoFixupPages;
//
// Find the relocation block
//
RelocBase = Ia32EmbImageAddress(Image, RelocDir->VirtualAddress);
RelocBaseEnd = Ia32EmbImageAddress(Image, RelocDir->VirtualAddress + RelocDir->Size);
if (!RelocBase || !RelocBaseEnd) {
*(UINT8 *)(0x000b8000+22) = 'O';
return EFI_LOAD_ERROR;
}
NoFixupPages = (RelocDir->Size / sizeof(UINT16) * sizeof(UINTN) + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT;
Image->FixupData = (CHAR8*) FindSpace (NoFixupPages, NumberOfMemoryMapEntries, EfiMemoryDescriptor);
if (!Image->FixupData) {
return EFI_OUT_OF_RESOURCES;
}
EfiAddMemoryDescriptor(NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiBootServicesData,
(UINTN)Image->FixupData,
NoFixupPages,
EFI_MEMORY_WB);
//
// Run the whole relocation block
//
FixupData = Image->FixupData;
while (RelocBase < RelocBaseEnd) {
Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof(IMAGE_BASE_RELOCATION));
RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
FixupBase = Ia32EmbImageAddress (Image, RelocBase->VirtualAddress);
if ((CHAR8 *) RelocEnd < Image->ImageBase || (CHAR8 *) RelocEnd > Image->ImageEof) {
*(UINT8 *)(0x000b8000+22) = 'P';
return EFI_LOAD_ERROR;
}
//
// Run this relocation record
//
while (Reloc < RelocEnd) {
Fixup = FixupBase + (*Reloc & 0xFFF);
switch ((*Reloc) >> 12) {
case IMAGE_REL_BASED_ABSOLUTE:
break;
case IMAGE_REL_BASED_HIGH:
F16 = (UINT16 *) Fixup;
*F16 = (*F16 << 16) + (UINT16) Adjust;
*(UINT16 *) FixupData = *F16;
FixupData = FixupData + sizeof(UINT16);
break;
case IMAGE_REL_BASED_LOW:
F16 = (UINT16 *) Fixup;
*F16 = *F16 + (UINT16) Adjust;
*(UINT16 *) FixupData = *F16;
FixupData = FixupData + sizeof(UINT16);
break;
case IMAGE_REL_BASED_HIGHLOW:
F32 = (UINT32 *) Fixup;
*F32 = *F32 + (UINT32) Adjust;
FixupData = ALIGN_POINTER(FixupData, sizeof(UINT32));
*(UINT32 *) FixupData = *F32;
FixupData = FixupData + sizeof(UINT32);
break;
case IMAGE_REL_BASED_HIGHADJ:
BREAKPOINT(); // BUGBUG: not done
break;
default:
// DEBUG((D_LOAD|D_ERROR, "PeRelocate: unknown fixed type\n"));
*(UINT8 *)(0x000b8000+22) = 'Q';
return EFI_LOAD_ERROR;
}
// Next reloc record
Reloc += 1;
}
// next reloc block
RelocBase = (IMAGE_BASE_RELOCATION *) RelocEnd;
}
return EFI_SUCCESS;
}
STATIC
VOID
Ia32EmbConvertPeImage (
IN EFILDR_LOADED_IMAGE *Image,
IN UINT32 DescriptorCount,
IN UINT32 DescriptorSize,
IN CHAR8 *MemoryMap
)
/* Reapply fixups to move an image to a new address */
{
IMAGE_DOS_HEADER *DosHdr;
IMAGE_NT_HEADERS *PeHdr;
IMAGE_DATA_DIRECTORY *RelocDir;
IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
UINT16 *Reloc, *RelocEnd;
CHAR8 *Fixup, *FixupBase;
UINT16 *F16;
UINT32 *F32;
CHAR8 *FixupData;
UINTN Adjust;
EFI_MEMORY_DESCRIPTOR *Descriptor;
for (Adjust = 0; Adjust < DescriptorCount; ++Adjust) {
Descriptor = (VOID*)(MemoryMap + Adjust * DescriptorSize);
if (Descriptor->PhysicalStart < Image->ImageBasePage + (Image->NoPages << EFI_PAGE_SHIFT)
&& Descriptor->PhysicalStart + EFILDRLShiftU64(Descriptor->NumberOfPages, EFI_PAGE_SHIFT) > Image->ImageBasePage
&& (Descriptor->Attribute & EFI_MEMORY_RUNTIME))
break;
}
if (Adjust >= DescriptorCount) {
BREAKPOINT();
return;
}
Adjust = (UINTN) (Descriptor->VirtualStart - Descriptor->PhysicalStart);
/*
* Find the image's relocate dir info
*/
DosHdr = (IMAGE_DOS_HEADER *) Image->ImageBase;
PeHdr = (IMAGE_NT_HEADERS *) (((CHAR8 *) DosHdr) + DosHdr->e_lfanew);
RelocDir = &PeHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
RelocBase = Ia32EmbImageAddress(Image, RelocDir->VirtualAddress);
RelocBaseEnd = Ia32EmbImageAddress(Image, RelocDir->VirtualAddress + RelocDir->Size);
/*
* Run the whole relocation block
*/
FixupData = Image->FixupData;
while (RelocBase < RelocBaseEnd) {
Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof(IMAGE_BASE_RELOCATION));
RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
FixupBase = Ia32EmbImageAddress (Image, RelocBase->VirtualAddress);
/*
* Run this relocation record
*/
while (Reloc < RelocEnd) {
Fixup = FixupBase + (*Reloc & 0xFFF);
switch ((*Reloc) >> 12) {
case IMAGE_REL_BASED_ABSOLUTE:
break;
case IMAGE_REL_BASED_HIGH:
F16 = (UINT16 *) Fixup;
if (*(UINT16 *) FixupData == *F16) {
*F16 = (*F16 << 16) + (UINT16) Adjust;
}
FixupData = FixupData + sizeof(UINT16);
break;
case IMAGE_REL_BASED_LOW:
F16 = (UINT16 *) Fixup;
if (*(UINT16 *) FixupData == *F16) {
*F16 = *F16 + (UINT16) Adjust;
}
FixupData = FixupData + sizeof(UINT16);
break;
case 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 IMAGE_REL_BASED_HIGHADJ:
BREAKPOINT(); /* BUGBUG: not done */
break;
default:
BREAKPOINT(); /* BUGBUG: not done */
return;
}
/* Next reloc record */
Reloc += 1;
}
/* next reloc block */
RelocBase = (IMAGE_BASE_RELOCATION *) RelocEnd;
}
}
STATIC
EFI_STATUS
Ia32EmbImageRead (
IN VOID *FHand,
IN UINTN Offset,
IN OUT UINTN ReadSize,
OUT VOID *Buffer
)
// Load some data from the image
{
EFILDRCopyMem(Buffer,(VOID *)((UINT32)FHand + Offset),ReadSize);
return EFI_SUCCESS;
}
STATIC
VOID *
Ia32EmbImageAddress (
IN EFILDR_LOADED_IMAGE *Image,
IN UINTN Address
)
// Convert an image address to the loaded address
{
CHAR8 *p;
p = Image->ImageAdjust + Address;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?