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