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 + -
显示快捷键?