efildr.c
来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 2,225 行 · 第 1/4 页
C
2,225 行
/*++
Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
efildr.c
Abstract:
Revision History
--*/
#include "efi.h"
#include "efilib.h"
#include "pe.h"
#include "decompress.h"
#include "EfiLdrHandoff.h"
#define INT15_E820_AddressRangeMemory 1
#define INT15_E820_AddressRangeReserved 2
#define INT15_E820_AddressRangeACPI 3
#define INT15_E820_AddressRangeNVS 4
#define EFILDR_LOAD_ADDRESS (EFILDR_BASE_SEGMENT << 4)
#define EFILDR_HEADER_ADDRESS (EFILDR_LOAD_ADDRESS+0x2000)
#define EFI_FIRMWARE_BASE_ADDRESS 0x00200000
#define EFI_MAX_STACK_SIZE 0x00020000
#define EFI_DECOMPRESSED_BUFFER_ADDRESS 0x00600000
#define EFI_MAX_MEMORY_DESCRIPTORS 64
#define LOADED_IMAGE_SIGNATURE EFI_SIGNATURE_32('l','d','r','i')
typedef struct {
UINTN Signature;
CHAR16 *Name; // Displayable name
UINTN Type;
BOOLEAN Started; // If entrypoint has been called
VOID *StartImageContext;
EFI_IMAGE_ENTRY_POINT EntryPoint; // The image's entry point
EFI_LOADED_IMAGE Info; // loaded image protocol
//
EFI_PHYSICAL_ADDRESS ImageBasePage; // Location in memory
UINTN NoPages; // Number of pages
CHAR8 *ImageBase; // As a char pointer
CHAR8 *ImageEof; // End of memory image
// relocate info
CHAR8 *ImageAdjust; // Bias for reloc calculations
UINTN StackAddress;
CHAR8 *FixupData; // Original fixup data
} EFILDR_LOADED_IMAGE;
typedef struct {
UINT32 CheckSum;
UINT32 Offset;
UINT32 Length;
UINT8 FileName[52];
} EFILDR_IMAGE;
typedef struct {
UINT32 Signature;
UINT32 HeaderCheckSum;
UINT32 FileLength;
UINT32 NumberOfImages;
} EFILDR_HEADER;
typedef struct {
UINT32 BaseAddress;
UINT32 Foo;
UINT32 Length;
UINT32 Bar;
UINT32 Type;
} BIOS_MEMORY_MAP_ENTRY;
typedef struct {
UINT32 MemoryMapSize;
BIOS_MEMORY_MAP_ENTRY MemoryMapEntry[1];
} BIOS_MEMORY_MAP;
//
//
//
EFI_STATUS
EFIAPI
Bios32GetInfo (
IN EFI_DECOMPRESS_PROTOCOL *This,
IN VOID *Source,
IN UINT32 SrcSize,
OUT UINT32 *DstSize,
OUT UINT32 *ScratchSize
);
EFI_STATUS
EFIAPI
Bios32Decompress (
IN EFI_DECOMPRESS_PROTOCOL *This,
IN VOID *Source,
IN UINT32 SrcSize,
IN OUT VOID *Destination,
IN UINT32 DstSize,
IN OUT VOID *Scratch,
IN UINT32 ScratchSize
);
EFI_STATUS
GetPeImageInfo (
IN VOID *FHand,
OUT UINT32 *ImageBase,
OUT UINT32 *ImageSize
);
EFI_STATUS
Bios32LoadPeImage (
IN VOID *FHand,
IN EFILDR_LOADED_IMAGE *Image,
IN UINT32 *NumberOfMemoryMapEntries,
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
);
STATIC
EFI_STATUS
Bios32LoadPeRelocate (
IN EFILDR_LOADED_IMAGE *Image,
IN IMAGE_DATA_DIRECTORY *RelocDir,
IN UINTN Adjust,
IN UINT32 *NumberOfMemoryMapEntries,
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
);
STATIC
VOID
Bios32ConvertPeImage (
IN EFILDR_LOADED_IMAGE *Image,
IN UINT32 DescriptorCount,
IN UINT32 DescriptorSize,
IN CHAR8 *MemoryMap
);
STATIC
EFI_STATUS
Bios32ImageRead (
IN VOID *FHand,
IN UINTN Offset,
IN OUT UINTN ReadSize,
OUT VOID *Buffer
);
STATIC
VOID *
Bios32ImageAddress (
IN EFILDR_LOADED_IMAGE *Image,
IN UINTN Address
);
INTERNAL
EFI_STATUS
Bios32SetImageType (
IN OUT EFILDR_LOADED_IMAGE *Image,
IN UINTN ImageType
);
INTERNAL
EFI_STATUS
Bios32CheckImageMachineType (
IN UINTN MachineType
);
EFI_STATUS
EfiAddMemoryDescriptor(
UINTN *NoDesc,
EFI_MEMORY_DESCRIPTOR *Desc,
EFI_MEMORY_TYPE Type,
EFI_PHYSICAL_ADDRESS BaseAddress,
UINTN NoPages,
UINT64 Attribute
);
UINTN
FindSpace(
UINTN NoPages,
IN UINT32 *NumberOfMemoryMapEntries,
IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor
);
UINT64
EFILDRLShiftU64 (
IN UINT64 Operand,
IN UINTN Count
);
VOID
EFILDRZeroMem (
IN VOID *Buffer,
IN UINTN Size
);
VOID
EFILDRCopyMem (
IN VOID *Dest,
IN VOID *Src,
IN UINTN len
);
UINTN
EFILDRstrcmpa (
IN CHAR8 *s1,
IN CHAR8 *s2
);
VOID
PrintValue(UINT32 Value);
VOID
PrintString(UINT8 *String);
VOID
ClearScreen();
//
//
//
STATIC EFILDR_CALLBACK EfiLdrCallBack;
EFILDR_LOADED_IMAGE EfiCoreImage;
UINT8 *Cursor;
__declspec (naked)
VOID
EfiLoader (
UINT32 BiosMemoryMapBaseAddress
)
{
BIOS_MEMORY_MAP *BiosMemoryMap;
EFILDR_HEADER *EFILDRHeader;
EFILDR_IMAGE *EFILDRImage;
UINTN i;
EFI_MEMORY_DESCRIPTOR EfiMemoryDescriptor[EFI_MAX_MEMORY_DESCRIPTORS];
EFI_STATUS Status;
UINT32 NumberOfMemoryMapEntries;
UINT32 BaseAddress;
UINT32 Length;
EFI_MEMORY_TYPE Type;
UINT32 DestinationSize;
UINT32 ScratchSize;
UINTN Attr;
UINT32 EfiLoaderImageBase;
UINT32 EfiLoaderImageSize;
// This function is a 'naked' function, meaning the compiler does not set
// up the call frame. Furthermore, we must set up the call frame as if the
// function was called with a 'near' call, even though it was a 'far' call.
// The compiler thinks it is a 'NEAR' function and expects only EIP on the
// stack after the parameters. Since we made a 'FAR' call to this function,
// the parameters are 8 bytes into the stack rather than 4. To fix this,
// we pop the stack once before setting up the call frame, which leaves the
// parameters 4 bytes into the stack as expected. Since we'll never return,
// there's no worry about what was popped off
// set up call frame since this is a 'naked' function
__asm pop eax // initial pop to make it look like a 'near' call
__asm push ebp
__asm mov ebp, esp
__asm sub esp, __LOCAL_SIZE
*(UINT8 *)(0x000b8000+10) = 'A';
ClearScreen();
PrintString("EFI Loader 0.2\n");
// PrintString("&BiosMemoryMapBaseAddress = ");
// PrintValue((UINT32)(&BiosMemoryMapBaseAddress));
// PrintString(" BiosMemoryMapBaseAddress = ");
// PrintValue(BiosMemoryMapBaseAddress);
// PrintString("\n");
//
// Add all EfiConventionalMemory descriptors to the table. If there are partial pages, then
// round the start address up to the next page, and round the length down to a page boundry.
//
BiosMemoryMap = (BIOS_MEMORY_MAP *)(BiosMemoryMapBaseAddress);
NumberOfMemoryMapEntries = 0;
for(i=0;i<BiosMemoryMap->MemoryMapSize / sizeof(BIOS_MEMORY_MAP_ENTRY);i++) {
switch(BiosMemoryMap->MemoryMapEntry[i].Type) {
case (INT15_E820_AddressRangeMemory):
Type = EfiConventionalMemory;
Attr = EFI_MEMORY_WB;
break;
case (INT15_E820_AddressRangeReserved):
Type = EfiReservedMemoryType;
Attr = EFI_MEMORY_UC;
break;
case (INT15_E820_AddressRangeACPI):
Type = EfiACPIReclaimMemory;
Attr = EFI_MEMORY_WB;
break;
case (INT15_E820_AddressRangeNVS):
Type = EfiACPIMemoryNVS;
Attr = EFI_MEMORY_UC;
break;
default:
// We should not get here, according to ACPI 2.0 Spec.
// BIOS behaviour of the Int15h, E820h
Type = EfiReservedMemoryType;
Attr = EFI_MEMORY_UC;
break;
}
if (Type == EfiConventionalMemory) {
BaseAddress = BiosMemoryMap->MemoryMapEntry[i].BaseAddress;
Length = BiosMemoryMap->MemoryMapEntry[i].Length;
if (BaseAddress & EFI_PAGE_MASK) {
Length = Length + (BaseAddress & EFI_PAGE_MASK) - EFI_PAGE_SIZE;
BaseAddress = ((BaseAddress >> EFI_PAGE_SHIFT) + 1) << EFI_PAGE_SHIFT;
}
} else {
BaseAddress = BiosMemoryMap->MemoryMapEntry[i].BaseAddress;
Length = BiosMemoryMap->MemoryMapEntry[i].Length + (BaseAddress & EFI_PAGE_MASK);
BaseAddress = (BaseAddress >> EFI_PAGE_SHIFT) << EFI_PAGE_SHIFT;
if (Length & EFI_PAGE_MASK) {
Length = ((Length >> EFI_PAGE_SHIFT) + 1) << EFI_PAGE_SHIFT;
}
}
EfiAddMemoryDescriptor(&NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
Type,
(EFI_PHYSICAL_ADDRESS)BaseAddress,
Length>>EFI_PAGE_SHIFT,
Attr);
}
//
// Add a memory descriptor for the Real Mode Interrupt Descriptor Table
//
EfiAddMemoryDescriptor(&NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiBootServicesData,
(EFI_PHYSICAL_ADDRESS)0x00000000,
1,
EFI_MEMORY_WB);
//
// Add a memory descriptor for the GDT and IDT used by EFI
//
EfiAddMemoryDescriptor(&NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiBootServicesData,
(EFI_PHYSICAL_ADDRESS)EFILDR_LOAD_ADDRESS,
(EFILDR_HEADER_ADDRESS - EFILDR_LOAD_ADDRESS + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT,
EFI_MEMORY_WB);
//
// Get information on where the image is in memory
//
EFILDRHeader = (EFILDR_HEADER *)(EFILDR_HEADER_ADDRESS);
EFILDRImage = (EFILDR_IMAGE *)(EFILDR_HEADER_ADDRESS + sizeof(EFILDR_HEADER));
//
// Add a memory descriptor for this image so we can do the runtime transition latter
//
Status = GetPeImageInfo (
(VOID *)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
&EfiLoaderImageBase,
&EfiLoaderImageSize
);
if (!EFI_ERROR (Status)) {
EfiAddMemoryDescriptor(&NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiRuntimeServicesCode,
(EFI_PHYSICAL_ADDRESS)EfiLoaderImageBase,
(EfiLoaderImageSize + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT,
EFI_MEMORY_WB);
}
//
// Point to the 2nd image
//
EFILDRImage++;
//
// Add a memory descriptor for the remaining portion of the EFILDR file
//
EfiAddMemoryDescriptor(&NumberOfMemoryMapEntries,
EfiMemoryDescriptor,
EfiReservedMemoryType,
(EFI_PHYSICAL_ADDRESS)EFILDR_HEADER_ADDRESS,
(EFILDRHeader->FileLength + EFI_PAGE_SIZE -1) >> EFI_PAGE_SHIFT,
EFI_MEMORY_WB);
*(UINT8 *)(0x000b8000+12) = 'B';
//
// Decompress the image
//
Status = Bios32GetInfo(
NULL,
(VOID *)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
EFILDRImage->Length,
&DestinationSize,
&ScratchSize
);
if (EFI_ERROR (Status)) {
for(;;);
}
Status = Bios32Decompress(
NULL,
(VOID *)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
EFILDRImage->Length,
(VOID *)EFI_DECOMPRESSED_BUFFER_ADDRESS,
DestinationSize,
(VOID *)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000),
ScratchSize
);
if (EFI_ERROR (Status)) {
for(;;);
}
//
// Load and relocate the EFI PE/COFF Firmware Image
//
Status = Bios32LoadPeImage ((VOID *)(EFI_DECOMPRESSED_BUFFER_ADDRESS),
&EfiCoreImage,
&NumberOfMemoryMapEntries,
EfiMemoryDescriptor);
// PrintString("Image.NoPages = ");
// PrintValue(Image.NoPages);
// PrintString("\n");
*(UINT8 *)(0x000b8000+14) = 'C';
//
// Display the table of memory descriptors.
//
// PrintString("\nEFI Memory Descriptors\n");
for(i=0;i<NumberOfMemoryMapEntries;i++) {
PrintString("Type = ");
PrintValue(EfiMemoryDescriptor[i].Type);
PrintString(" Start = ");
PrintValue((UINT32)(EfiMemoryDescriptor[i].PhysicalStart));
PrintString(" NumberOfPages = ");
PrintValue((UINT32)(EfiMemoryDescriptor[i].NumberOfPages));
PrintString("\n");
}
*(UINT8 *)(0x000b8000+16) = 'D';
//
// Jump to EFI Firmware
//
if (!EFI_ERROR(Status) && EfiCoreImage.EntryPoint!=NULL) {
static EFILDRHANDOFF Handoff;
Handoff.MemDescCount = NumberOfMemoryMapEntries;
Handoff.MemDesc = EfiMemoryDescriptor;
Handoff.EfiLdrCallBack = EfiLdrCallBack;
Handoff.ImageBase = (VOID *)(UINTN)EfiCoreImage.ImageBasePage;
Handoff.ImageSize = EfiCoreImage.NoPages * EFI_PAGE_SIZE;
__asm lea eax, Handoff
__asm mov ebx, EfiCoreImage.EntryPoint
__asm mov esp, Handoff.ImageBase
__asm push eax
//
// seed the stack with a zero for the return from MainEntry()
// so a debugger knows where to stop unwinding
//
__asm push 0
__asm jmp ebx
/* EfiCoreImage.EntryPoint (&Handoff); */
}
*(UINT8 *)(0x000b8000+18) = 'E';
//
// There was a problem loading the image, so HALT the system.
//
for(;;);
}
EFI_STATUS
GetPeImageInfo (
IN VOID *FHand,
OUT UINT32 *ImageBase,
OUT UINT32 *ImageSize
)
{
EFI_STATUS Status;
IMAGE_DOS_HEADER DosHdr;
IMAGE_NT_HEADERS PeHdr;
EFILDRZeroMem (&DosHdr, sizeof(DosHdr));
EFILDRZeroMem (&PeHdr, sizeof(PeHdr));
//
// Read image headers
//
Bios32ImageRead (FHand, 0, sizeof(IMAGE_DOS_HEADER), &DosHdr);
if (DosHdr.e_magic != IMAGE_DOS_SIGNATURE) {
return EFI_UNSUPPORTED;
}
Bios32ImageRead (FHand, DosHdr.e_lfanew, sizeof(IMAGE_NT_HEADERS), &PeHdr);
if (PeHdr.Signature != IMAGE_NT_SIGNATURE) {
return EFI_UNSUPPORTED;
}
//
// Verify machine type
//
Status = Bios32CheckImageMachineType (PeHdr.FileHeader.Machine);
if (EFI_ERROR(Status)) {
return Status;
}
*ImageBase = PeHdr.OptionalHeader.ImageBase;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?