diff --git a/sdk/xtdk/bltypes.h b/sdk/xtdk/bltypes.h index e910672..199520b 100644 --- a/sdk/xtdk/bltypes.h +++ b/sdk/xtdk/bltypes.h @@ -64,6 +64,11 @@ typedef VOID (*PBL_CONSOLE_SET_ATTRIBUTES)(IN ULONGLONG Attributes); typedef VOID (*PBL_CONSOLE_SET_CURSOR_POSITION)(IN ULONGLONG PosX, IN ULONGLONG PosY); typedef VOID (*PBL_CONSOLE_WRITE)(IN PUSHORT String); typedef VOID (*PBL_DEBUG_PRINT)(IN PUINT16 Format, IN ...); +typedef EFI_STATUS (*PBL_EXECIMAGE_GET_ENTRY_POINT)(IN PVOID ImagePointer, OUT PVOID *EntryPoint); +typedef EFI_STATUS (*PBL_EXECIMAGE_GET_MACHINE_TYPE)(IN PVOID ImagePointer, OUT PUSHORT MachineType); +typedef EFI_STATUS (*PBL_EXECIMAGE_GET_SUBSYSTEM)(IN PVOID ImagePointer, OUT PUSHORT SubSystem); +typedef EFI_STATUS (*PBL_EXECIMAGE_LOAD_IMAGE)(IN PEFI_FILE_HANDLE FileHandle, IN LOADER_MEMORY_TYPE MemoryType, IN PVOID VirtualAddress, OUT PVOID *ImagePointer); +typedef EFI_STATUS (*PBL_EXECIMAGE_RELOCATE_IMAGE)(IN PVOID ImagePointer, IN EFI_VIRTUAL_ADDRESS Address); typedef EFI_STATUS (*PBL_EXIT_BOOT_SERVICES)(IN UINT_PTR MapKey); typedef EFI_STATUS (*PBL_FIND_BOOT_PROTOCOL)(IN PWCHAR SystemType, OUT PEFI_GUID BootProtocolGuid); typedef EFI_STATUS (*PBL_FREE_PAGES)(IN UINT64 Size, IN EFI_PHYSICAL_ADDRESS Memory); @@ -84,26 +89,6 @@ typedef VOID (*PBL_TUI_UPDATE_PROGRESS_BAR)(IN PXTBL_DIALOG_HANDLE Handle, IN PW typedef EFI_STATUS (*PBL_WAIT_FOR_EFI_EVENT)(IN UINT_PTR NumberOfEvents, IN PEFI_EVENT Event, OUT PUINT_PTR Index); typedef VOID (*PBL_XT_BOOT_MENU)(); -/* XTLDR Boot protocol structure */ -typedef struct _XTBL_BOOT_PROTOCOL -{ - PBL_BOOTPROTO_BOOT_SYSTEM BootSystem; -} XTBL_BOOT_PROTOCOL, *PXTBL_BOOT_PROTOCOL; - -/* XTLDR Executable image protocol structure */ -typedef struct _XTBL_EXECUTABLE_IMAGE_PROTOCOL -{ - // PBL_EXECIMAGE_GET_ENTRY_POINT GetEntryPoint; - // PBL_EXECIMAGE_GET_MACHINE_TYPE GetMachineType; - // PBL_EXECIMAGE_GET_SECTION GetSection; - // PBL_EXECIMAGE_GET_SUBSYSTEM GetSubSystem; - // PBL_EXECIMAGE_GET_VERSION GetVersion; - // PBL_EXECIMAGE_LOAD_IMAGE LoadImage; - // PBL_EXECIMAGE_PRINT_INFO PrintDebugInfo; - // PBL_EXECIMAGE_RELOCATE_IMAGE RelocateImage; - // PBL_EXECUTABLE_VERIFY_IMAGE VerifyImage; -} XTBL_EXECUTABLE_IMAGE_PROTOCOL, *PXTBL_EXECUTABLE_IMAGE_PROTOCOL; - /* Boot parameters structure */ typedef struct _XTBL_BOOT_PARAMETERS { @@ -162,6 +147,52 @@ typedef struct _XTBL_KNOWN_BOOT_PROTOCOL EFI_GUID Guid; } XTBL_KNOWN_BOOT_PROTOCOL, *PXTBL_KNOWN_BOOT_PROTOCOL; +/* XTLDR Module dependencies data */ +typedef struct _XTBL_MODULE_DEPS +{ + LIST_ENTRY Flink; + PWCHAR ModuleName; +} XTBL_MODULE_DEPS, *PXTBL_MODULE_DEPS; + +/* XTLDR Module information data */ +typedef struct _XTBL_MODULE_INFO +{ + LIST_ENTRY Flink; + PWCHAR ModuleName; + PWCHAR ModuleDescription; + LIST_ENTRY Dependencies; +} XTBL_MODULE_INFO, *PXTBL_MODULE_INFO; + +/* XTLDR Status data */ +typedef struct _XTBL_STATUS +{ + PBL_XT_BOOT_MENU BootMenu; + BOOLEAN BootServices; + ULONG DebugPort; + INT_PTR SecureBoot; + CPPORT SerialPort; +} XTBL_STATUS, *PXTBL_STATUS; + +/* XTLDR Boot protocol structure */ +typedef struct _XTBL_BOOT_PROTOCOL +{ + PBL_BOOTPROTO_BOOT_SYSTEM BootSystem; +} XTBL_BOOT_PROTOCOL, *PXTBL_BOOT_PROTOCOL; + +/* XTLDR Executable image protocol structure */ +typedef struct _XTBL_EXECUTABLE_IMAGE_PROTOCOL +{ + PBL_EXECIMAGE_GET_ENTRY_POINT GetEntryPoint; + PBL_EXECIMAGE_GET_MACHINE_TYPE GetMachineType; + // PBL_EXECIMAGE_GET_SECTION GetSection; + PBL_EXECIMAGE_GET_SUBSYSTEM GetSubSystem; + // PBL_EXECIMAGE_GET_VERSION GetVersion; + PBL_EXECIMAGE_LOAD_IMAGE LoadImage; + // PBL_EXECIMAGE_PRINT_INFO PrintDebugInfo; + PBL_EXECIMAGE_RELOCATE_IMAGE RelocateImage; + // PBL_EXECUTABLE_VERIFY_IMAGE VerifyImage; +} XTBL_EXECUTABLE_IMAGE_PROTOCOL, *PXTBL_EXECUTABLE_IMAGE_PROTOCOL; + /* XTLDR Loader protocol */ typedef struct _XTBL_LOADER_PROTOCOL { @@ -225,30 +256,4 @@ typedef struct _XTBL_LOADER_PROTOCOL } Util; } XTBL_LOADER_PROTOCOL, *PXTBL_LOADER_PROTOCOL; -/* XTLDR Module dependencies data */ -typedef struct _XTBL_MODULE_DEPS -{ - LIST_ENTRY Flink; - PWCHAR ModuleName; -} XTBL_MODULE_DEPS, *PXTBL_MODULE_DEPS; - -/* XTLDR Module information data */ -typedef struct _XTBL_MODULE_INFO -{ - LIST_ENTRY Flink; - PWCHAR ModuleName; - PWCHAR ModuleDescription; - LIST_ENTRY Dependencies; -} XTBL_MODULE_INFO, *PXTBL_MODULE_INFO; - -/* XTLDR Status data */ -typedef struct _XTBL_STATUS -{ - PBL_XT_BOOT_MENU BootMenu; - BOOLEAN BootServices; - ULONG DebugPort; - INT_PTR SecureBoot; - CPPORT SerialPort; -} XTBL_STATUS, *PXTBL_STATUS; - #endif /* __XTDK_BLTYPES_H */ diff --git a/xtldr2/modules/CMakeLists.txt b/xtldr2/modules/CMakeLists.txt index c65186e..cde0c5e 100644 --- a/xtldr2/modules/CMakeLists.txt +++ b/xtldr2/modules/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(dummy) +add_subdirectory(pecoff_o) diff --git a/xtldr2/modules/pecoff_o/CMakeLists.txt b/xtldr2/modules/pecoff_o/CMakeLists.txt new file mode 100644 index 0000000..427597e --- /dev/null +++ b/xtldr2/modules/pecoff_o/CMakeLists.txt @@ -0,0 +1,27 @@ +# XT Boot Loader +PROJECT(XTLDR_PECOFF_O) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_SOURCE_DIR}/includes + ${XTLDR_PECOFF_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) + +# Set module entrypoint and subsystem +set_entrypoint(pecoff_o "XtLdrModuleMain") +set_linker_map(pecoff_o TRUE) +set_subsystem(pecoff_o efi_boot_service_driver) diff --git a/xtldr2/modules/pecoff_o/includes/pecoff.h b/xtldr2/modules/pecoff_o/includes/pecoff.h new file mode 100644 index 0000000..af30bf9 --- /dev/null +++ b/xtldr2/modules/pecoff_o/includes/pecoff.h @@ -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 + */ + +#ifndef __XTLDR_MODULES_PECOFF_O_H +#define __XTLDR_MODULES_PECOFF_O_H + +#include + + +/* 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 */ diff --git a/xtldr2/modules/pecoff_o/pecoff.c b/xtldr2/modules/pecoff_o/pecoff.c new file mode 100644 index 0000000..d9c87d2 --- /dev/null +++ b/xtldr2/modules/pecoff_o/pecoff.c @@ -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 + */ + +#include + + +/* 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.Register(&Guid, &XtPeCoffProtocol); +}