Initial PE/COFF support for loading image files
All checks were successful
ci/woodpecker/push/build Pipeline was successful

This commit is contained in:
Rafal Kupiec 2022-11-06 19:59:38 +01:00
parent 4a364212de
commit c8f99ad6ed
Signed by: belliash
GPG Key ID: 4E829243E0CFE6B4
8 changed files with 328 additions and 16 deletions

View File

@ -96,8 +96,8 @@
#define PECOFF_IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
/* PE/COFF image HDR magic */
#define PECOFF_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10B
#define PECOFF_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20B
#define PECOFF_IMAGE_PE_OPTIONAL_HDR32_MAGIC 0x10B
#define PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC 0x20B
#define PECOFF_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
/* PE/COFF directory entries */
@ -137,8 +137,8 @@
#define PECOFF_IMAGE_SIZEOF_SECTION_HEADER 40
#define PECOFF_IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56
#define PECOFF_IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28
#define PECOFF_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
#define PECOFF_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
#define PECOFF_IMAGE_SIZEOF_PE_OPTIONAL32_HEADER 224
#define PECOFF_IMAGE_SIZEOF_PE_OPTIONAL64_HEADER 240
/* PE/COFF image section characteristics */
#define PECOFF_IMAGE_SCN_TYPE_REG 0x00000000
@ -190,11 +190,10 @@
typedef struct _PECOFF_IMAGE_CONTEXT
{
PVOID Data;
PVOID BaseAddress;
ULONG NtSignature;
UINT64 FileSize;
UINT ImagePages;
UINT ImageSize;
UINT Pages;
PVOID VirtualAddress;
} PECOFF_IMAGE_CONTEXT, *PPECOFF_IMAGE_CONTEXT;
/* PE/COFF directory format */
@ -411,13 +410,13 @@ typedef struct _PECOFF_IMAGE_ROM_OPTIONAL_HEADER
ULONG GpValue;
} PECOFF_IMAGE_ROM_OPTIONAL_HEADER, *PPECOFF_IMAGE_ROM_OPTIONAL_HEADER;
/* PE/COFF NT image header */
typedef struct _PECOFF_IMAGE_NT_HEADER
/* PE/COFF PE image header */
typedef struct _PECOFF_IMAGE_PE_HEADER
{
ULONG Signature;
PECOFF_IMAGE_FILE_HEADER FileHeader;
PECOFF_IMAGE_OPTIONAL_HEADER OptionalHeader;
} PECOFF_IMAGE_NT_HEADER, *PPECOFF_IMAGE_NT_HEADER;
} PECOFF_IMAGE_PE_HEADER, *PPECOFF_IMAGE_PE_HEADER;
/* PE/COFF ROM image header */
typedef struct _PECOFF_IMAGE_ROM_HEADER {

View File

@ -156,9 +156,9 @@ typedef struct _PECOFF_IMAGE_IMPORT_DESCRIPTOR PECOFF_IMAGE_IMPORT_DESCRIPTOR, *
typedef struct _PECOFF_IMAGE_LOAD_CONFIG_CODE_INTEGRITY PECOFF_IMAGE_LOAD_CONFIG_CODE_INTEGRITY, *PPECOFF_IMAGE_LOAD_CONFIG_CODE_INTEGRITY;
typedef struct _PECOFF_IMAGE_LOAD_CONFIG_DIRECTORY32 PECOFF_IMAGE_LOAD_CONFIG_DIRECTORY32, *PPECOFF_IMAGE_LOAD_CONFIG_DIRECTORY32;
typedef struct _PECOFF_IMAGE_LOAD_CONFIG_DIRECTORY64 PECOFF_IMAGE_LOAD_CONFIG_DIRECTORY64, *PPECOFF_IMAGE_LOAD_CONFIG_DIRECTORY64;
typedef struct _PECOFF_IMAGE_NT_HEADER PECOFF_IMAGE_NT_HEADER, *PPECOFF_IMAGE_NT_HEADER;
typedef struct _PECOFF_IMAGE_OPTIONAL_HEADER PECOFF_IMAGE_OPTIONAL_HEADER, *PPECOFF_IMAGE_OPTIONAL_HEADER;
typedef struct _PECOFF_IMAGE_OS2_HEADER PECOFF_IMAGE_OS2_HEADER, *PPECOFF_IMAGE_OS2_HEADER;
typedef struct _PECOFF_IMAGE_PE_HEADER PECOFF_IMAGE_PE_HEADER, *PPECOFF_IMAGE_PE_HEADER;
typedef struct _PECOFF_IMAGE_RESOURCE_DATA_ENTRY PECOFF_IMAGE_RESOURCE_DATA_ENTRY, *PPECOFF_IMAGE_RESOURCE_DATA_ENTRY;
typedef struct _PECOFF_IMAGE_RESOURCE_DIRECTORY PECOFF_IMAGE_RESOURCE_DIRECTORY, *PPECOFF_IMAGE_RESOURCE_DIRECTORY;
typedef struct _PECOFF_IMAGE_RESOURCE_DIRECTORY_ENTRY PECOFF_IMAGE_RESOURCE_DIRECTORY_ENTRY, *PPECOFF_IMAGE_RESOURCE_DIRECTORY_ENTRY;

View File

@ -2,7 +2,7 @@
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/includes/blmod.h
* DESCRIPTION: Top level header for XTLDR modules
* DESCRIPTION: Top level header for XTLDR modules support
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
@ -14,4 +14,16 @@
#include <blproto.h>
/* Structures forward declarations */
typedef struct _XT_PECOFFF_IMAGE_PROTOCOL XT_PECOFF_IMAGE_PROTOCOL, *PXT_PECOFF_IMAGE_PROTOCOL;
/* Pointers to the routines provided by the modules */
typedef EFI_STATUS (*PXT_PECOFF_PROTOCOL_LOAD)(IN PEFI_FILE_HANDLE FileHandle, IN PVOID VirtualAddress, OUT PPECOFF_IMAGE_CONTEXT *Image);
/* EFI XT PE/COFF Image Protocol */
typedef struct _XT_PECOFFF_IMAGE_PROTOCOL
{
PXT_PECOFF_PROTOCOL_LOAD Load;
} XT_PECOFF_IMAGE_PROTOCOL, *PXT_PECOFF_IMAGE_PROTOCOL;
#endif /* __XTLDR_BLMOD_H */

View File

@ -14,6 +14,10 @@
/* Loader protocol routine pointers */
typedef EFI_STATUS (*PBL_ALLOCATE_PAGES)(IN UINT64 Size, OUT PEFI_PHYSICAL_ADDRESS Memory);
typedef EFI_STATUS (*PBL_ALLOCATE_POOL)(IN UINT_PTR Size, OUT PVOID *Memory);
typedef EFI_STATUS (*PBL_FREE_PAGES)(IN UINT64 Size, IN EFI_PHYSICAL_ADDRESS Memory);
typedef EFI_STATUS (*PBL_FREE_POOL)(IN PVOID Memory);
typedef VOID (*PBL_DBG_PRINT)(IN PUINT16 Format, IN ...);
typedef VOID (*PBL_EFI_PRINT)(IN PUINT16 Format, IN ...);
typedef EFI_STATUS (*PBL_CLOSE_VOLUME)(IN PEFI_HANDLE VolumeHandle);
@ -22,6 +26,10 @@ typedef EFI_STATUS (*PBL_OPEN_VOLUME)(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath, O
/* EFI XT Boot Loader Protocol */
typedef struct _XT_BOOT_LOADER_PROTOCOL
{
PBL_ALLOCATE_PAGES AllocatePages;
PBL_ALLOCATE_POOL AllocatePool;
PBL_FREE_PAGES FreePages;
PBL_FREE_POOL FreePool;
PBL_DBG_PRINT DbgPrint;
PBL_EFI_PRINT EfiPrint;
PBL_CLOSE_VOLUME CloseVolume;

View File

@ -4,7 +4,8 @@ PROJECT(XTLDR_PECOFF)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_SOURCE_DIR}/includes)
${XTLDR_SOURCE_DIR}/includes
${XTLDR_PECOFF_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_PECOFF_SOURCE

View File

@ -0,0 +1,28 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/pecoff/includes/pecoff.h
* DESCRIPTION: PE/COFF executable file format support header
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_MODULES_PECOFF_H
#define __XTLDR_MODULES_PECOFF_H
#include <blmod.h>
EFI_STATUS PeLoadImage(IN PEFI_FILE_HANDLE FileHandle,
IN PVOID VirtualAddress,
OUT PPECOFF_IMAGE_CONTEXT *Image);
EFI_STATUS
PepReadImageHeader(IN PUCHAR ImageData,
IN SIZE_T FileSize,
OUT PPECOFF_IMAGE_PE_HEADER *PeHeader);
EFI_STATUS
BlXtLdrModuleMain(EFI_HANDLE ImageHandle,
PEFI_SYSTEM_TABLE SystemTable);
#endif /* __XTLDR_MODULES_PECOFF_H */

View File

@ -6,7 +6,7 @@
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <blmod.h>
#include <pecoff.h>
/* EFI Image Handle */
@ -18,6 +18,260 @@ PEFI_SYSTEM_TABLE EfiSystemTable;
/* EFI XT Loader Protocol */
PXT_BOOT_LOADER_PROTOCOL EfiXtLdrProtocol;
/* XTOS PE/COFF Image Protocol */
XT_PECOFF_IMAGE_PROTOCOL XtPeCoffProtocol;
/**
* Loads a PE/COFF image file.
*
* @param FileHandle
* The handle of the opened portable executable (PE) file.
*
* @param VirtualAddress
* Optional virtual address pointing to the memory area where PE/COFF file will be loaded.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
EFI_STATUS PeLoadImage(IN PEFI_FILE_HANDLE FileHandle,
IN PVOID VirtualAddress,
OUT PPECOFF_IMAGE_CONTEXT *Image)
{
EFI_GUID FileInfoGuid = EFI_FILE_INFO_PROTOCOL_GUID;
PPECOFF_IMAGE_SECTION_HEADER SectionHeader;
PPECOFF_IMAGE_PE_HEADER PeHeader;
PPECOFF_IMAGE_CONTEXT ImageData;
EFI_PHYSICAL_ADDRESS Address;
PEFI_FILE_INFO FileInfo;
SIZE_T Size, Pages;
EFI_STATUS Status;
UINT_PTR ReadSize;
UINT SectionSize;
PUCHAR Data;
UINT Index;
/* Set required size for getting file information */
Size = sizeof(EFI_FILE_INFO) + 32;
/* Allocate necessary amount of memory */
Status = EfiXtLdrProtocol->AllocatePool(Size, (PVOID *)&FileInfo);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Memory pool allocation failure\n");
return Status;
}
/* First attempt to get file information */
Status = FileHandle->GetInfo(FileHandle, &FileInfoGuid, &Size, FileInfo);
if(Status == STATUS_EFI_BUFFER_TOO_SMALL)
{
/* Buffer it too small, but EFI tells the required size, let's reallocate */
EfiXtLdrProtocol->FreePool(&FileInfo);
Status = EfiXtLdrProtocol->AllocatePool(Size, (PVOID *)&FileInfo);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Memory pool allocation failure\n");
return Status;
}
/* Second attempt to get file information */
Status = FileHandle->GetInfo(FileHandle, &FileInfoGuid, &Size, FileInfo);
}
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to get file information */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Failed to get file information\n");
return Status;
}
/* Allocate memory for storing image data */
Status = EfiXtLdrProtocol->AllocatePool(sizeof(PECOFF_IMAGE_CONTEXT), (PVOID *)&ImageData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Memory pool allocation failure\n");
return Status;
}
/* Store file size and free memory */
ImageData->FileSize = FileInfo->FileSize;
EfiXtLdrProtocol->FreePool(FileInfo);
/* Calculate number of pages */
Pages = EFI_SIZE_TO_PAGES(ImageData->FileSize);
/* Allocate pages */
Status = EfiXtLdrProtocol->AllocatePages(Pages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Pages allocation failure */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Pages allocation failure\n");
EfiXtLdrProtocol->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 */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Unable to read PE/COFF image file\n");
EfiXtLdrProtocol->FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
EfiXtLdrProtocol->FreePool(ImageData);
return Status;
}
/* Read and validate headers */
Status = PepReadImageHeader(Data, ImageData->FileSize, &PeHeader);
if(Status != STATUS_EFI_SUCCESS)
{
/* Header validation failed, probably broken or invalid PE/COFF image */
EfiXtLdrProtocol->DbgPrint(L"ERROR: PE/COFF image validation failed\n");
EfiXtLdrProtocol->FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
EfiXtLdrProtocol->FreePool(ImageData);
return Status;
}
/* Store image size and calculate number of image pages */
ImageData->ImageSize = PeHeader->OptionalHeader.SizeOfImage;
ImageData->ImagePages = EFI_SIZE_TO_PAGES(ImageData->ImageSize);
/* Allocate image pages */
Status = EfiXtLdrProtocol->AllocatePages(ImageData->ImagePages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Pages reallocation failure */
EfiXtLdrProtocol->DbgPrint(L"ERROR: Pages reallocation failure\n");
EfiXtLdrProtocol->FreePool(ImageData);
return Status;
}
/* Store image data and base address */
ImageData->Data = (PUINT8)(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, PeHeader->OptionalHeader.SizeOfHeaders);
/* Find section header */
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&PeHeader->OptionalHeader +
PeHeader->FileHeader.SizeOfOptionalHeader);
/* Load each section into memory */
for(Index = 0; Index < PeHeader->FileHeader.NumberOfSections; Index++)
{
EfiXtLdrProtocol->EfiPrint(L"TEST: %lx\n", SectionHeader[Index].Misc.VirtualSize);
/* 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 */
EfiXtLdrProtocol->FreePages((EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data, Pages);
/* Store image data */
*Image = ImageData;
/* Return SUCCESS */
return STATUS_EFI_SUCCESS;
}
/**
* Reads and validate a PE/COFF image headers
*
* @param ImageData
* A pointer to the buffer containing PE/COFF image contents.
*
* @param FileSize
* An input PE/COFF image file size.
*
* @param PeHeader
* Pointer to the memory area where PE header will be saved.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
EFI_STATUS
PepReadImageHeader(IN PUCHAR ImageData,
IN SIZE_T FileSize,
OUT PPECOFF_IMAGE_PE_HEADER *PeHeader)
{
PPECOFF_IMAGE_DOS_HEADER DosHeader;
/* Validate file size */
if(FileSize < sizeof(PECOFF_IMAGE_DOS_HEADER))
{
EfiXtLdrProtocol->DbgPrint(L"WARNING: PE/COFF image shorter than DOS header\n");
return STATUS_EFI_END_OF_FILE;
}
/* Validate DOS header */
DosHeader = (PPECOFF_IMAGE_DOS_HEADER)ImageData;
if(DosHeader->e_magic != PECOFF_IMAGE_DOS_SIGNATURE)
{
EfiXtLdrProtocol->DbgPrint(L"WARNING: Invalid DOS signature found\n");
return STATUS_EFI_INCOMPATIBLE_VERSION;
}
/* Validate NT/XT header */
*PeHeader = (PPECOFF_IMAGE_PE_HEADER)(ImageData + DosHeader->e_lfanew);
if((*PeHeader)->Signature != PECOFF_IMAGE_NT_SIGNATURE && (*PeHeader)->Signature != PECOFF_IMAGE_XT_SIGNATURE)
{
EfiXtLdrProtocol->DbgPrint(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)
{
EfiXtLdrProtocol->DbgPrint(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.
*
@ -35,6 +289,8 @@ EFI_STATUS
BlXtLdrModuleMain(EFI_HANDLE ImageHandle,
PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID Guid = XT_PECOFF_IMAGE_PROTOCOL_GUID;
EFI_HANDLE Handle = NULL;
EFI_STATUS Status;
/* Set the system table and image handle */
@ -49,6 +305,9 @@ BlXtLdrModuleMain(EFI_HANDLE ImageHandle,
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Return success */
return STATUS_EFI_SUCCESS;
/* Set routines available via PE/COFF image protocol */
XtPeCoffProtocol.Load = PeLoadImage;
/* Register PE/COFF protocol */
return EfiSystemTable->BootServices->InstallProtocolInterface(&Handle, &Guid, EFI_NATIVE_INTERFACE, &XtPeCoffProtocol);
}

View File

@ -260,6 +260,10 @@ BlRegisterXtLoaderProtocol()
EFI_HANDLE Handle = NULL;
/* Set all routines available via loader protocol */
EfiLdrProtocol.AllocatePages = BlEfiMemoryAllocatePages;
EfiLdrProtocol.AllocatePool = BlEfiMemoryAllocatePool;
EfiLdrProtocol.FreePages = BlEfiMemoryFreePages;
EfiLdrProtocol.FreePool = BlEfiMemoryFreePool;
EfiLdrProtocol.DbgPrint = BlDbgPrint;
EfiLdrProtocol.EfiPrint = BlEfiPrint;
@ -327,6 +331,7 @@ BlStartXtLoader(IN EFI_HANDLE ImageHandle,
BlDbgPrint(L"ERROR: Failed to register XTLDR loader protocol\n");
}
/* Load XTLDR modules */
Status = BlLoadEfiModules();
if(Status != STATUS_EFI_SUCCESS)
{