forked from xt-sys/exectos
		
	Rewrite core of the XTLDR boot loader
Reviewed-on: xt-sys/exectos#7 Reviewed-by: Piotr Likoski <likoski@noreply.codingworkshop.git> Co-authored-by: Rafal Kupiec <belliash@codingworkshop.eu.org> Co-committed-by: Rafal Kupiec <belliash@codingworkshop.eu.org>
This commit is contained in:
		
				
					committed by
					
						
						CodingWorkshop Signing Team
					
				
			
			
				
	
				
						parent
						
							44905bb71d
						
					
				
				
					commit
					4412d4fc98
				
			
							
								
								
									
										26
									
								
								xtldr/modules/pecoff_o/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								xtldr/modules/pecoff_o/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
# XT Boot Loader
 | 
			
		||||
PROJECT(XTLDR_PECOFF_O)
 | 
			
		||||
 | 
			
		||||
# Specify include directories
 | 
			
		||||
include_directories(
 | 
			
		||||
    ${EXECTOS_SOURCE_DIR}/sdk/xtdk
 | 
			
		||||
    ${XTLDR_PECOFF_O_SOURCE_DIR}/includes)
 | 
			
		||||
 | 
			
		||||
# Specify list of source code files
 | 
			
		||||
list(APPEND XTLDR_PECOFF_O_SOURCE
 | 
			
		||||
    ${XTLDR_PECOFF_O_SOURCE_DIR}/pecoff.c)
 | 
			
		||||
 | 
			
		||||
# Link bootloader executable
 | 
			
		||||
add_executable(pecoff_o ${XTLDR_PECOFF_O_SOURCE})
 | 
			
		||||
 | 
			
		||||
# Add linker libraries
 | 
			
		||||
target_link_libraries(pecoff_o libxtos libxtldr)
 | 
			
		||||
 | 
			
		||||
# Set proper binary name and install target
 | 
			
		||||
set_target_properties(pecoff_o PROPERTIES SUFFIX .efi)
 | 
			
		||||
set_install_target(pecoff_o efi/boot/xtldr/modules)
 | 
			
		||||
 | 
			
		||||
# Set module entrypoint and subsystem
 | 
			
		||||
set_entrypoint(pecoff_o "XtLdrModuleMain")
 | 
			
		||||
set_linker_map(pecoff_o TRUE)
 | 
			
		||||
set_subsystem(pecoff_o efi_boot_service_driver)
 | 
			
		||||
							
								
								
									
										58
									
								
								xtldr/modules/pecoff_o/includes/pecoff.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								xtldr/modules/pecoff_o/includes/pecoff.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
/**
 | 
			
		||||
 * PROJECT:         ExectOS
 | 
			
		||||
 * COPYRIGHT:       See COPYING.md in the top level directory
 | 
			
		||||
 * FILE:            xtldr/modules/pecoff_o/includes/pecoff.h
 | 
			
		||||
 * DESCRIPTION:     PE/COFF executable file format support header
 | 
			
		||||
 * DEVELOPERS:      Rafal Kupiec <belliash@codingworkshop.eu.org>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __XTLDR_MODULES_PECOFF_O_H
 | 
			
		||||
#define __XTLDR_MODULES_PECOFF_O_H
 | 
			
		||||
 | 
			
		||||
#include <xtblapi.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* PE/COFF image protocol related routines forward references */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeGetEntryPoint(IN PVOID ImagePointer,
 | 
			
		||||
                OUT PVOID *EntryPoint);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeGetMachineType(IN PVOID ImagePointer,
 | 
			
		||||
                 OUT PUSHORT MachineType);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeGetSubSystem(IN PVOID ImagePointer,
 | 
			
		||||
               OUT PUSHORT SubSystem);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeLoadImage(IN PEFI_FILE_HANDLE FileHandle,
 | 
			
		||||
            IN LOADER_MEMORY_TYPE MemoryType,
 | 
			
		||||
            IN PVOID VirtualAddress,
 | 
			
		||||
            OUT PVOID *ImagePointer);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeRelocateImage(IN PVOID ImagePointer,
 | 
			
		||||
                IN EFI_VIRTUAL_ADDRESS Address);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PepRelocateLoadedImage(IN PPECOFF_IMAGE_CONTEXT Image);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PepValidateImageHeaders(IN PPECOFF_IMAGE_DOS_HEADER DosHeader,
 | 
			
		||||
                        IN PPECOFF_IMAGE_PE_HEADER PeHeader,
 | 
			
		||||
                        IN SIZE_T FileSize);
 | 
			
		||||
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
BlXtLdrModuleMain(IN EFI_HANDLE ImageHandle,
 | 
			
		||||
                  IN PEFI_SYSTEM_TABLE SystemTable);
 | 
			
		||||
 | 
			
		||||
#endif /* __XTLDR_MODULES_PECOFF_O_H */
 | 
			
		||||
							
								
								
									
										607
									
								
								xtldr/modules/pecoff_o/pecoff.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								xtldr/modules/pecoff_o/pecoff.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,607 @@
 | 
			
		||||
/**
 | 
			
		||||
 * PROJECT:         ExectOS
 | 
			
		||||
 * COPYRIGHT:       See COPYING.md in the top level directory
 | 
			
		||||
 * FILE:            xtldr/modules/pecoff_o/pecoff.c
 | 
			
		||||
 * DESCRIPTION:     OLD and deprecated PE/COFF executable file format support module
 | 
			
		||||
 * DEVELOPERS:      Rafal Kupiec <belliash@codingworkshop.eu.org>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pecoff.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* PE/COFF_O module information */
 | 
			
		||||
XTBL_MODINFO = L"PE/COFF executable file format support";
 | 
			
		||||
 | 
			
		||||
/* EFI XT Loader Protocol */
 | 
			
		||||
PXTBL_LOADER_PROTOCOL XtLdrProtocol;
 | 
			
		||||
 | 
			
		||||
/* XTOS PE/COFF Image Protocol */
 | 
			
		||||
XTBL_EXECUTABLE_IMAGE_PROTOCOL XtPeCoffProtocol;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the address of the entry point.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Image
 | 
			
		||||
 *        A pointer to the PE/COFF context structure representing the loaded image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param EntryPoint
 | 
			
		||||
 *        A pointer to the memory area where address of the image entry point will be stored.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns a status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeGetEntryPoint(IN PVOID ImagePointer,
 | 
			
		||||
                OUT PVOID *EntryPoint)
 | 
			
		||||
{
 | 
			
		||||
    PPECOFF_IMAGE_CONTEXT Image = ImagePointer;
 | 
			
		||||
 | 
			
		||||
    /* Validate input data */
 | 
			
		||||
    if(!Image || !Image->PeHeader)
 | 
			
		||||
    {
 | 
			
		||||
        /* Invalid parameter passed */
 | 
			
		||||
        return STATUS_EFI_INVALID_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Get entry point and return success */
 | 
			
		||||
    *EntryPoint = (PUINT8)Image->VirtualAddress + Image->PeHeader->OptionalHeader.AddressOfEntryPoint;
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the machine type of the PE/COFF image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Image
 | 
			
		||||
 *        A pointer to the PE/COFF context structure representing the loaded image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param MachineType
 | 
			
		||||
 *        A pointer to the memory area where a value defined for the 'machine' field will be stored.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns a status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeGetMachineType(IN PVOID ImagePointer,
 | 
			
		||||
                 OUT PUSHORT MachineType)
 | 
			
		||||
{
 | 
			
		||||
    PPECOFF_IMAGE_CONTEXT Image = ImagePointer;
 | 
			
		||||
 | 
			
		||||
    /* Validate input data */
 | 
			
		||||
    if(!Image || !Image->PeHeader)
 | 
			
		||||
    {
 | 
			
		||||
        /* Invalid parameter passed */
 | 
			
		||||
        return STATUS_EFI_INVALID_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Get image machine type and return success */
 | 
			
		||||
    *MachineType = Image->PeHeader->FileHeader.Machine;
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns an information about subsystem that is required to run PE/COFF image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Image
 | 
			
		||||
 *        A pointer to the PE/COFF context structure representing the loaded image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param SubSystem
 | 
			
		||||
 *        A pointer to the memory area storing a value defined for the 'subsystem' field of the image.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns a status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeGetSubSystem(IN PVOID ImagePointer,
 | 
			
		||||
               OUT PUSHORT SubSystem)
 | 
			
		||||
{
 | 
			
		||||
    PPECOFF_IMAGE_CONTEXT Image = ImagePointer;
 | 
			
		||||
 | 
			
		||||
    /* Validate input data */
 | 
			
		||||
    if(!Image || !Image->PeHeader)
 | 
			
		||||
    {
 | 
			
		||||
        /* Invalid parameter passed */
 | 
			
		||||
        return STATUS_EFI_INVALID_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Get image subsystem and return success */
 | 
			
		||||
    *SubSystem = Image->PeHeader->OptionalHeader.Subsystem;
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Loads a PE/COFF image file.
 | 
			
		||||
 *
 | 
			
		||||
 * @param FileHandle
 | 
			
		||||
 *        The handle of the opened portable executable (PE) file.
 | 
			
		||||
 *
 | 
			
		||||
 * @param MemoryType
 | 
			
		||||
 *        Supplies the type of memory to be assigned to the memory descriptor.
 | 
			
		||||
 *
 | 
			
		||||
 * @param VirtualAddress
 | 
			
		||||
 *        Optional virtual address pointing to the memory area where PE/COFF file will be loaded.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Image
 | 
			
		||||
 *        Supplies pointer to the memory area where loaded PE/COFF image context will be stored.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeLoadImage(IN PEFI_FILE_HANDLE FileHandle,
 | 
			
		||||
            IN LOADER_MEMORY_TYPE MemoryType,
 | 
			
		||||
            IN PVOID VirtualAddress,
 | 
			
		||||
            OUT PVOID *ImagePointer)
 | 
			
		||||
{
 | 
			
		||||
    EFI_GUID FileInfoGuid = EFI_FILE_INFO_PROTOCOL_GUID;
 | 
			
		||||
    PPECOFF_IMAGE_SECTION_HEADER SectionHeader;
 | 
			
		||||
    PPECOFF_IMAGE_CONTEXT ImageData;
 | 
			
		||||
    EFI_PHYSICAL_ADDRESS Address;
 | 
			
		||||
    PEFI_FILE_INFO FileInfo;
 | 
			
		||||
    UINT_PTR ReadSize;
 | 
			
		||||
    EFI_STATUS Status;
 | 
			
		||||
    UINT SectionSize;
 | 
			
		||||
    SIZE_T Pages;
 | 
			
		||||
    PUCHAR Data;
 | 
			
		||||
    UINT Index;
 | 
			
		||||
 | 
			
		||||
    /* Set required size for getting file information */
 | 
			
		||||
    ReadSize = sizeof(EFI_FILE_INFO) + 32;
 | 
			
		||||
 | 
			
		||||
    /* Allocate necessary amount of memory */
 | 
			
		||||
    Status = XtLdrProtocol->Memory.AllocatePool(ReadSize, (PVOID *)&FileInfo);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Memory allocation failure */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Memory pool allocation failure\n");
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* First attempt to get file information */
 | 
			
		||||
    Status = FileHandle->GetInfo(FileHandle, &FileInfoGuid, &ReadSize, FileInfo);
 | 
			
		||||
    if(Status == STATUS_EFI_BUFFER_TOO_SMALL)
 | 
			
		||||
    {
 | 
			
		||||
        /* Buffer it too small, but EFI tells the required size, let's reallocate */
 | 
			
		||||
        XtLdrProtocol->Memory.FreePool(&FileInfo);
 | 
			
		||||
        Status = XtLdrProtocol->Memory.AllocatePool(ReadSize, (PVOID *)&FileInfo);
 | 
			
		||||
        if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
        {
 | 
			
		||||
            /* Memory allocation failure */
 | 
			
		||||
            XtLdrProtocol->Debug.Print(L"ERROR: Memory pool allocation failure\n");
 | 
			
		||||
            return Status;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Second attempt to get file information */
 | 
			
		||||
        Status = FileHandle->GetInfo(FileHandle, &FileInfoGuid, &ReadSize, FileInfo);
 | 
			
		||||
    }
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Unable to get file information */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Failed to get file information\n");
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Allocate memory for storing image data */
 | 
			
		||||
    Status = XtLdrProtocol->Memory.AllocatePool(sizeof(PECOFF_IMAGE_CONTEXT), (PVOID *)&ImageData);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Memory allocation failure */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Memory pool allocation failure\n");
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Store file size and memory type, nullify data and free up memory */
 | 
			
		||||
    ImageData->Data = NULL;
 | 
			
		||||
    ImageData->FileSize = FileInfo->FileSize;
 | 
			
		||||
    ImageData->MemoryType = MemoryType;
 | 
			
		||||
    XtLdrProtocol->Memory.FreePool(FileInfo);
 | 
			
		||||
 | 
			
		||||
    /* Calculate number of pages */
 | 
			
		||||
    Pages = EFI_SIZE_TO_PAGES(ImageData->FileSize);
 | 
			
		||||
 | 
			
		||||
    /* Allocate pages */
 | 
			
		||||
    Status = XtLdrProtocol->Memory.AllocatePages(Pages, &Address);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Pages allocation failure */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Pages allocation failure\n");
 | 
			
		||||
        XtLdrProtocol->Memory.FreePool(ImageData);
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Read PE/COFF image */
 | 
			
		||||
    ReadSize = Pages * EFI_PAGE_SIZE;
 | 
			
		||||
    Data = (PUCHAR)(UINT_PTR)Address;
 | 
			
		||||
    Status = FileHandle->Read(FileHandle, &ReadSize, Data);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Failed to read data */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Unable to read PE/COFF image file\n");
 | 
			
		||||
        XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
 | 
			
		||||
        XtLdrProtocol->Memory.FreePool(ImageData);
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Extract DOS and PE headers */
 | 
			
		||||
    ImageData->DosHeader = (PPECOFF_IMAGE_DOS_HEADER)Data;
 | 
			
		||||
    ImageData->PeHeader = (PPECOFF_IMAGE_PE_HEADER)((PUINT8)Data + ImageData->DosHeader->e_lfanew);
 | 
			
		||||
 | 
			
		||||
    /* Validate headers */
 | 
			
		||||
    Status = PepValidateImageHeaders(ImageData->DosHeader, ImageData->PeHeader, ImageData->FileSize);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Header validation failed, probably broken or invalid PE/COFF image */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Invalid PE/COFF image headers\n");
 | 
			
		||||
        XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
 | 
			
		||||
        XtLdrProtocol->Memory.FreePool(ImageData);
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Make sure image is executable */
 | 
			
		||||
    if (!(ImageData->PeHeader->FileHeader.Characteristics & PECOFF_IMAGE_FILE_EXECUTABLE_IMAGE))
 | 
			
		||||
    {
 | 
			
		||||
        /* Loaded image is not executable */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Non-executable PE/COFF image loaded\n");
 | 
			
		||||
        XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
 | 
			
		||||
        XtLdrProtocol->Memory.FreePool(ImageData);
 | 
			
		||||
        return STATUS_EFI_LOAD_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Store image size and calculate number of image pages */
 | 
			
		||||
    ImageData->ImageSize = ImageData->PeHeader->OptionalHeader.SizeOfImage;
 | 
			
		||||
    ImageData->ImagePages = EFI_SIZE_TO_PAGES(ImageData->ImageSize);
 | 
			
		||||
 | 
			
		||||
    /* Allocate image pages */
 | 
			
		||||
    Status = XtLdrProtocol->Memory.AllocatePages(ImageData->ImagePages, &Address);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Pages reallocation failure */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: Pages reallocation failure\n");
 | 
			
		||||
        XtLdrProtocol->Memory.FreePool(ImageData);
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Store image data and virtual address */
 | 
			
		||||
    ImageData->Data = (PUINT8)(UINT_PTR)Address;
 | 
			
		||||
    ImageData->PhysicalAddress = (PVOID)(UINT_PTR)Address;
 | 
			
		||||
    if(VirtualAddress)
 | 
			
		||||
    {
 | 
			
		||||
        /* Virtual address passed to this routine */
 | 
			
		||||
        ImageData->VirtualAddress = VirtualAddress;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        /* Virtual address not specified, use physical address */
 | 
			
		||||
        ImageData->VirtualAddress = (PVOID)(UINT_PTR)Address;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Copy all sections */
 | 
			
		||||
    RtlCopyMemory(ImageData->Data, Data, ImageData->PeHeader->OptionalHeader.SizeOfHeaders);
 | 
			
		||||
 | 
			
		||||
    /* Find section header */
 | 
			
		||||
    SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&ImageData->PeHeader->OptionalHeader +
 | 
			
		||||
                                                   ImageData->PeHeader->FileHeader.SizeOfOptionalHeader);
 | 
			
		||||
 | 
			
		||||
    /* Load each section into memory */
 | 
			
		||||
    for(Index = 0; Index < ImageData->PeHeader->FileHeader.NumberOfSections; Index++)
 | 
			
		||||
    {
 | 
			
		||||
        /* Check section raw data size and section virtual size */
 | 
			
		||||
        if(SectionHeader[Index].SizeOfRawData < SectionHeader[Index].Misc.VirtualSize)
 | 
			
		||||
        {
 | 
			
		||||
            /* Use raw data size if it is smaller than virtual size */
 | 
			
		||||
            SectionSize = SectionHeader[Index].SizeOfRawData;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            /* User virtual size otherwise */
 | 
			
		||||
            SectionSize = SectionHeader[Index].Misc.VirtualSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Make sure section is available */
 | 
			
		||||
        if(SectionSize > 0 && SectionHeader[Index].PointerToRawData != 0)
 | 
			
		||||
        {
 | 
			
		||||
            /* Copy section */
 | 
			
		||||
            RtlCopyMemory((PUINT8)ImageData->Data + SectionHeader[Index].VirtualAddress,
 | 
			
		||||
                          Data + SectionHeader[Index].PointerToRawData, SectionSize);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Check if raw size is shorter than virtual size */
 | 
			
		||||
        if(SectionSize < SectionHeader[Index].Misc.VirtualSize)
 | 
			
		||||
        {
 | 
			
		||||
            /* Fill remaining space with zeroes */
 | 
			
		||||
            RtlZeroMemory((PUINT8)ImageData->Data + SectionHeader[Index].VirtualAddress + SectionSize,
 | 
			
		||||
                         SectionHeader[Index].Misc.VirtualSize - SectionSize);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Free pages */
 | 
			
		||||
    XtLdrProtocol->Memory.FreePages((EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data, Pages);
 | 
			
		||||
 | 
			
		||||
    /* Perform relocation fixups */
 | 
			
		||||
    Status = PepRelocateLoadedImage(ImageData);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Failed to relocate image */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"ERROR: PE/COFF image relocation failed\n");
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Store image data */
 | 
			
		||||
    *ImagePointer = ImageData;
 | 
			
		||||
 | 
			
		||||
    /* Return SUCCESS */
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Relocates PE/COFF image to the specified address.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Image
 | 
			
		||||
 *        A pointer to the PE/COFF context structure representing the loaded image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Address
 | 
			
		||||
 *        Destination address of memory region, where image should be relocated.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PeRelocateImage(IN PVOID ImagePointer,
 | 
			
		||||
                IN EFI_VIRTUAL_ADDRESS Address)
 | 
			
		||||
{
 | 
			
		||||
    PPECOFF_IMAGE_CONTEXT Image = ImagePointer;
 | 
			
		||||
 | 
			
		||||
    UINT64 ImageBase, OldVirtualAddress;
 | 
			
		||||
    EFI_STATUS Status;
 | 
			
		||||
 | 
			
		||||
    /* Store original virtual address */
 | 
			
		||||
    OldVirtualAddress = (UINT_PTR)Image->VirtualAddress;
 | 
			
		||||
 | 
			
		||||
    /* Check PE/COFF image type */
 | 
			
		||||
    if(Image->PeHeader->OptionalHeader.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
 | 
			
		||||
    {
 | 
			
		||||
        /* This is 64-bit PE32+, store its image base address */
 | 
			
		||||
        ImageBase = Image->PeHeader->OptionalHeader.ImageBase64;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        /* This is 32-bit PE32, store its image base address */
 | 
			
		||||
        ImageBase = Image->PeHeader->OptionalHeader.ImageBase32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Overwrite virtual address and relocate image once again */
 | 
			
		||||
    Image->VirtualAddress = (PVOID)(Address - OldVirtualAddress + ImageBase);
 | 
			
		||||
    Status = PepRelocateLoadedImage(Image);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Relocation failed */
 | 
			
		||||
        return Status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Store new image virtual address */
 | 
			
		||||
    Image->VirtualAddress = (PVOID)Address;
 | 
			
		||||
 | 
			
		||||
    /* Return success */
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Relocates a loaded PE/COFF image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param Image
 | 
			
		||||
 *        A pointer to the PE/COFF context structure representing the loaded image.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns a status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PepRelocateLoadedImage(IN PPECOFF_IMAGE_CONTEXT Image)
 | 
			
		||||
{
 | 
			
		||||
    PPECOFF_IMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
 | 
			
		||||
    PPECOFF_IMAGE_DATA_DIRECTORY DataDirectory;
 | 
			
		||||
    USHORT Offset, Type, Count;
 | 
			
		||||
    PUSHORT TypeOffset;
 | 
			
		||||
    UINT64 ImageBase;
 | 
			
		||||
    PUINT32 Address;
 | 
			
		||||
    PUINT64 LongPtr;
 | 
			
		||||
    PUINT ShortPtr;
 | 
			
		||||
 | 
			
		||||
    /* Make sure image is not stripped */
 | 
			
		||||
    if(Image->PeHeader->FileHeader.Characteristics & PECOFF_IMAGE_FILE_RELOCS_STRIPPED)
 | 
			
		||||
    {
 | 
			
		||||
        /* No relocation information found */
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"WARNING: PE/COFF image is stripped and contains no information about relocations\n");
 | 
			
		||||
        return STATUS_EFI_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set relocation data directory */
 | 
			
		||||
    DataDirectory = &Image->PeHeader->OptionalHeader.DataDirectory[PECOFF_IMAGE_DIRECTORY_ENTRY_BASERELOC];
 | 
			
		||||
 | 
			
		||||
    /* Check if loaded image should be relocated */
 | 
			
		||||
    if(Image->PeHeader->OptionalHeader.NumberOfRvaAndSizes <= PECOFF_IMAGE_DIRECTORY_ENTRY_BASERELOC ||
 | 
			
		||||
       DataDirectory->VirtualAddress == 0 || DataDirectory->Size < sizeof(PECOFF_IMAGE_BASE_RELOCATION))
 | 
			
		||||
    {
 | 
			
		||||
        /* No need to relocate the image */
 | 
			
		||||
        return STATUS_EFI_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Check PE/COFF image type */
 | 
			
		||||
    if(Image->PeHeader->OptionalHeader.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
 | 
			
		||||
    {
 | 
			
		||||
        /* This is 64-bit PE32+, store its image base address */
 | 
			
		||||
        ImageBase = Image->PeHeader->OptionalHeader.ImageBase64;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        /* This is 32-bit PE32, store its image base address */
 | 
			
		||||
        ImageBase = Image->PeHeader->OptionalHeader.ImageBase32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set relocation pointers */
 | 
			
		||||
    RelocationDir = (PPECOFF_IMAGE_BASE_RELOCATION)((ULONG_PTR)Image->Data + DataDirectory->VirtualAddress);
 | 
			
		||||
    RelocationEnd = (PPECOFF_IMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + DataDirectory->Size);
 | 
			
		||||
 | 
			
		||||
    /* Do relocations */
 | 
			
		||||
    while(RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0)
 | 
			
		||||
    {
 | 
			
		||||
        /* Calculate number of relocations needed, address and type offset */
 | 
			
		||||
        Count = (RelocationDir->SizeOfBlock - sizeof(PECOFF_IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
 | 
			
		||||
        Address = (PUINT)((PUCHAR)Image->Data + RelocationDir->VirtualAddress);
 | 
			
		||||
        TypeOffset = (PUSHORT)((PUCHAR)RelocationDir + sizeof(PECOFF_IMAGE_BASE_RELOCATION));
 | 
			
		||||
 | 
			
		||||
        /* Do relocations */
 | 
			
		||||
        while(Count--)
 | 
			
		||||
        {
 | 
			
		||||
            /* Calculate offset and relocation type */
 | 
			
		||||
            Offset = *TypeOffset & 0xFFF;
 | 
			
		||||
            Type = *TypeOffset >> 12;
 | 
			
		||||
 | 
			
		||||
            /* Check if end of the loaded address reached */
 | 
			
		||||
            if((PVOID)(PUSHORT)(Address + Offset) >= Image->Data + Image->ImageSize)
 | 
			
		||||
            {
 | 
			
		||||
                /* Do not relocate after the end of loaded image */
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Make sure we are not going to relocate into .reloc section */
 | 
			
		||||
            if((ULONG_PTR)(Address + Offset) < (ULONG_PTR)RelocationDir ||
 | 
			
		||||
               (ULONG_PTR)(Address + Offset) >= (ULONG_PTR)RelocationEnd)
 | 
			
		||||
            {
 | 
			
		||||
                /* Apply relocation fixup */
 | 
			
		||||
                switch (Type)
 | 
			
		||||
                {
 | 
			
		||||
                    case PECOFF_IMAGE_REL_BASED_ABSOLUTE:
 | 
			
		||||
                        /* No relocation required */
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PECOFF_IMAGE_REL_BASED_DIR64:
 | 
			
		||||
                        /* 64-bit relocation */
 | 
			
		||||
                        LongPtr = (PULONGLONG)((PUCHAR)Address + Offset);
 | 
			
		||||
                        *LongPtr = *LongPtr - ImageBase + (UINT_PTR)Image->VirtualAddress;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PECOFF_IMAGE_REL_BASED_HIGHLOW:
 | 
			
		||||
                        /* 32-bit relocation of hight and low half of address */
 | 
			
		||||
                        ShortPtr = (PUINT32)((PUCHAR)Address + Offset);
 | 
			
		||||
                        *ShortPtr = *ShortPtr - ImageBase + (UINT_PTR)Image->VirtualAddress;
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                        /* Unknown or unsupported relocation type */
 | 
			
		||||
                        return STATUS_EFI_UNSUPPORTED;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            /* Increment the type offset */
 | 
			
		||||
            TypeOffset++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Next relocation */
 | 
			
		||||
        RelocationDir = (PPECOFF_IMAGE_BASE_RELOCATION)((PUCHAR)RelocationDir + RelocationDir->SizeOfBlock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Return SUCCESS */
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Validates a PE/COFF image headers.
 | 
			
		||||
 *
 | 
			
		||||
 * @param DosHeader
 | 
			
		||||
 *        Pointer to the memory area with DOS header stored.
 | 
			
		||||
 *
 | 
			
		||||
 * @param PeHeader
 | 
			
		||||
 *        Pointer to the memory area with PE header stored.
 | 
			
		||||
 *
 | 
			
		||||
 * @param FileSize
 | 
			
		||||
 *        A PE/COFF image file size.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns a status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
PepValidateImageHeaders(IN PPECOFF_IMAGE_DOS_HEADER DosHeader,
 | 
			
		||||
                        IN PPECOFF_IMAGE_PE_HEADER PeHeader,
 | 
			
		||||
                        IN SIZE_T FileSize)
 | 
			
		||||
{
 | 
			
		||||
    /* Validate file size */
 | 
			
		||||
    if(FileSize < sizeof(PECOFF_IMAGE_DOS_HEADER))
 | 
			
		||||
    {
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"WARNING: PE/COFF image shorter than DOS header\n");
 | 
			
		||||
        return STATUS_EFI_END_OF_FILE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Validate DOS header */
 | 
			
		||||
    if(DosHeader->e_magic != PECOFF_IMAGE_DOS_SIGNATURE)
 | 
			
		||||
    {
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"WARNING: Invalid DOS signature found\n");
 | 
			
		||||
        return STATUS_EFI_INCOMPATIBLE_VERSION;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Validate PE header */
 | 
			
		||||
    if(PeHeader->Signature != PECOFF_IMAGE_NT_SIGNATURE && PeHeader->Signature != PECOFF_IMAGE_XT_SIGNATURE)
 | 
			
		||||
    {
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"WARNING: Invalid NT/XT signature found\n");
 | 
			
		||||
        return STATUS_EFI_INCOMPATIBLE_VERSION;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Validate optional header */
 | 
			
		||||
    if(PeHeader->OptionalHeader.Magic != PECOFF_IMAGE_PE_OPTIONAL_HDR32_MAGIC &&
 | 
			
		||||
       PeHeader->OptionalHeader.Magic != PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
 | 
			
		||||
    {
 | 
			
		||||
        XtLdrProtocol->Debug.Print(L"WARNING: Invalid optional header signature found\n");
 | 
			
		||||
        return STATUS_EFI_INCOMPATIBLE_VERSION;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Return success */
 | 
			
		||||
    return STATUS_EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This routine is the entry point of the XT EFI boot loader module.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ImageHandle
 | 
			
		||||
 *        Firmware-allocated handle that identifies the image.
 | 
			
		||||
 *
 | 
			
		||||
 * @param SystemTable
 | 
			
		||||
 *        Provides the EFI system table.
 | 
			
		||||
 *
 | 
			
		||||
 * @return This routine returns status code.
 | 
			
		||||
 *
 | 
			
		||||
 * @since XT 1.0
 | 
			
		||||
 */
 | 
			
		||||
XTCDECL
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
XtLdrModuleMain(IN EFI_HANDLE ImageHandle,
 | 
			
		||||
                IN PEFI_SYSTEM_TABLE SystemTable)
 | 
			
		||||
{
 | 
			
		||||
    EFI_GUID Guid = XT_PECOFF_IMAGE_PROTOCOL_GUID;
 | 
			
		||||
    EFI_STATUS Status;
 | 
			
		||||
 | 
			
		||||
    /* Open the XTLDR protocol */
 | 
			
		||||
    Status = BlGetXtLdrProtocol(SystemTable, ImageHandle, &XtLdrProtocol);
 | 
			
		||||
    if(Status != STATUS_EFI_SUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        /* Failed to open loader protocol */
 | 
			
		||||
        return STATUS_EFI_PROTOCOL_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set routines available via PE/COFF image protocol */
 | 
			
		||||
    XtPeCoffProtocol.GetEntryPoint = PeGetEntryPoint;
 | 
			
		||||
    XtPeCoffProtocol.GetMachineType = PeGetMachineType;
 | 
			
		||||
    XtPeCoffProtocol.GetSubSystem = PeGetSubSystem;
 | 
			
		||||
    XtPeCoffProtocol.LoadImage = PeLoadImage;
 | 
			
		||||
    XtPeCoffProtocol.RelocateImage = PeRelocateImage;
 | 
			
		||||
 | 
			
		||||
    /* Register PE/COFF protocol */
 | 
			
		||||
    return XtLdrProtocol->Protocol.Install(&XtPeCoffProtocol, &Guid);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user