From 5dfa8aeac4c7e36fdaeee73c6900c4ae21361983 Mon Sep 17 00:00:00 2001 From: Jozef Nagy Date: Wed, 10 Jan 2024 17:40:59 +0100 Subject: [PATCH] Added elf_o module --- sdk/xtdk/xtimage.h | 110 +++++++++ sdk/xtdk/xtstruct.h | 5 + xtldr/modules/elf_o/CMakeLists.txt | 26 ++ xtldr/modules/elf_o/elf.c | 371 +++++++++++++++++++++++++++++ xtldr/modules/elf_o/includes/elf.h | 47 ++++ 5 files changed, 559 insertions(+) create mode 100644 xtldr/modules/elf_o/CMakeLists.txt create mode 100644 xtldr/modules/elf_o/elf.c create mode 100644 xtldr/modules/elf_o/includes/elf.h diff --git a/sdk/xtdk/xtimage.h b/sdk/xtdk/xtimage.h index 047c352..451ec33 100644 --- a/sdk/xtdk/xtimage.h +++ b/sdk/xtdk/xtimage.h @@ -606,4 +606,114 @@ typedef struct _PECOFF_IMAGE_RESOURCE_DATA_ENTRY ULONG Reserved; } PECOFF_IMAGE_RESOURCE_DATA_ENTRY, *PPECOFF_IMAGE_RESOURCE_DATA_ENTRY; +/* TODO: Name these enumerations */ +typedef enum _ELF_IDENT +{ + EI_MAG0 = 0, + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, + EI_DATA = 5, + EI_VERSION = 6, + EI_OSABI = 7, + EI_ABIVERSION = 8 +} ELF_IDENT; + +typedef enum _ELF_PT +{ + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7 +} ELF_PT; + +/* ELF image representation structure */ +typedef struct _ELF_IMAGE_CONTEXT +{ + union + { + PELF32_HEADER Header32; + PELF64_HEADER Header64; + }; + PVOID Data; + PVOID EntryPoint; + UINT64 FileSize; + UINT ImagePages; + UINT ImageSize; + LOADER_MEMORY_TYPE MemoryType; + PVOID PhysicalAddress; + PVOID VirtualAddress; +} ELF_IMAGE_CONTEXT, *PELF_IMAGE_CONTEXT; + +/* 32-bit ELF image header structure */ +typedef struct _ELF32_HEADER +{ + /* NOTE: EI_NIDENT seems to always be defined as 16. */ + UCHAR e_ident[16]; + UINT16 e_type; + UINT16 e_machine; + UINT32 e_version; + UINT32 e_entry; + UINT32 e_phoff; + UINT32 e_shoff; + UINT32 e_flags; + UINT16 e_ehsize; + UINT16 e_phentsize; + UINT16 e_phnum; + UINT16 e_shentsize; + UINT16 e_shnum; + UINT16 e_shstrndx; +} ELF32_HEADER, *PELF32_HEADER; + +/* 64-bit ELF image header structure */ +typedef struct _ELF64_HEADER +{ + /* NOTE: EI_NIDENT seems to always be defined as 16. */ + UCHAR e_ident[16]; + UINT16 e_type; + UINT16 e_machine; + UINT32 e_version; + ULONG e_entry; + ULONG e_phoff; + ULONG e_shoff; + UINT32 e_flags; + UINT16 e_ehsize; + UINT16 e_phentsize; + UINT16 e_phnum; + UINT16 e_shentsize; + UINT16 e_shnum; + UINT16 e_shstrndx; +} ELF64_HEADER, *PELF64_HEADER; + +/* 32-bit ELF program header structure */ +typedef struct _ELF32_PROGRAM_HEADER +{ + UINT32 p_type; + UINT32 p_offset; + UINT32 p_vaddr; + UINT32 p_paddr; + UINT32 p_filesz; + UINT32 p_memsz; + UINT32 p_flags; + UINT32 p_align; +} ELF32_PROGRAM_HEADER, *PELF32_PROGRAM_HEADER; + +/* 64-bit ELF program header structure */ +typedef struct _ELF64_PROGRAM_HEADER +{ + UINT32 p_type; + UINT32 p_flags; + ULONG p_offset; + ULONG p_vaddr; + ULONG p_paddr; + ULONG p_filesz; + ULONG p_memsz; + ULONG p_align; +} ELF64_PROGRAM_HEADER, *PELF64_PROGRAM_HEADER; + #endif /* __XTDK_XTIMAGE_H */ diff --git a/sdk/xtdk/xtstruct.h b/sdk/xtdk/xtstruct.h index dcc19ab..c9ed7a8 100644 --- a/sdk/xtdk/xtstruct.h +++ b/sdk/xtdk/xtstruct.h @@ -254,6 +254,11 @@ typedef struct _PECOFF_IMAGE_ROM_HEADER PECOFF_IMAGE_ROM_HEADER, *PPECOFF_IMAGE_ typedef struct _PECOFF_IMAGE_ROM_OPTIONAL_HEADER PECOFF_IMAGE_ROM_OPTIONAL_HEADER, *PPECOFF_IMAGE_ROM_OPTIONAL_HEADER; typedef struct _PECOFF_IMAGE_SECTION_HEADER PECOFF_IMAGE_SECTION_HEADER, *PPECOFF_IMAGE_SECTION_HEADER; typedef struct _PECOFF_IMAGE_VXD_HEADER PECOFF_IMAGE_VXD_HEADER, *PPECOFF_IMAGE_VXD_HEADER; +typedef struct _ELF_IMAGE_CONTEXT ELF_IMAGE_CONTEXT, *PELF_IMAGE_CONTEXT; +typedef struct _ELF32_HEADER ELF32_HEADER, *PELF32_HEADER; +typedef struct _ELF64_HEADER ELF64_HEADER, *PELF64_HEADER; +typedef struct _ELF32_PROGRAM_HEADER ELF32_PROGRAM_HEADER, *PELF32_PROGRAM_HEADER; +typedef struct _ELF64_PROGRAM_HEADER ELF64_PROGRAM_HEADER, *PELF64_PROGRAM_HEADER; typedef struct _PROCESSOR_POWER_STATE PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE; typedef struct _SINGLE_LIST_ENTRY SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; typedef struct _STRING STRING, *PSTRING; diff --git a/xtldr/modules/elf_o/CMakeLists.txt b/xtldr/modules/elf_o/CMakeLists.txt new file mode 100644 index 0000000..2cf25fb --- /dev/null +++ b/xtldr/modules/elf_o/CMakeLists.txt @@ -0,0 +1,26 @@ +# XT Boot Loader +PROJECT(XTLDR_ELF_O) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_ELF_O_SOURCE_DIR}/includes) + +# Specify list of source code files +list(APPEND XTLDR_ELF_O_SOURCE + ${XTLDR_ELF_O_SOURCE_DIR}/elf.c) + +# Link bootloader executable +add_executable(elf_o ${XTLDR_ELF_O_SOURCE}) + +# Add linker libraries +target_link_libraries(elf_o libxtos libxtldr) + +# Set proper binary name and install target +set_target_properties(elf_o PROPERTIES SUFFIX .efi) +set_install_target(elf_o efi/boot/xtldr/modules) + +# Set module entrypoint and subsystem +set_entrypoint(elf_o "XtLdrModuleMain") +set_linker_map(elf_o TRUE) +set_subsystem(elf_o efi_boot_service_driver) diff --git a/xtldr/modules/elf_o/elf.c b/xtldr/modules/elf_o/elf.c new file mode 100644 index 0000000..bf5282e --- /dev/null +++ b/xtldr/modules/elf_o/elf.c @@ -0,0 +1,371 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/elf_o/elf.c + * DESCRIPTION: ELF executable file format support module + * DEVELOPERS: Jozef Nagy + */ + +#include + +/* ELF_O module information */ +XTBL_MODINFO = L"ELF executable file format support"; + +/* EFI XT Loader Protocol */ +PXTBL_LOADER_PROTOCOL XtLdrProtocol; + +/* XTOS ELF Image Protocol */ +XTBL_EXECUTABLE_IMAGE_PROTOCOL XtElfProtocol; + +/** + * Returns the address of the entry point. + * + * @param Image + * A pointer to the ELF 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 +ElfGetEntryPoint(IN PVOID ImagePointer, + OUT PVOID *EntryPoint) +{ + PELF_IMAGE_CONTEXT Image = ImagePointer; + + /* Validate input data */ + if(!Image) + { + /* Invalid parameter passed */ + return STATUS_EFI_INVALID_PARAMETER; + } + + /* Save entry point and return success */ + *EntryPoint = Image->EntryPoint; + return STATUS_EFI_SUCCESS; +} + +XTCDECL +EFI_STATUS +ElfGetMachineType(IN PVOID ImagePointer, + OUT PUSHORT MachineType) +{ + PELF_IMAGE_CONTEXT Image = ImagePointer; + + *MachineType = Image->Header32->e_machine; + return STATUS_EFI_SUCCESS; +} + +XTCDECL +EFI_STATUS +ElfGetSubSystem(IN PVOID ImagePointer, + OUT PUSHORT SubSystem) +{ + PELF_IMAGE_CONTEXT Image = ImagePointer; + + *SubSystem = Image->Header32->e_ident[EI_OSABI]; + return STATUS_EFI_SUCCESS; +} + +XTCDECL +EFI_STATUS +ElfRelocateImage(IN PVOID ImagePointer, + IN EFI_VIRTUAL_ADDRESS Address) +{ + /* No relocation yet */ + return STATUS_EFI_SUCCESS; +} + +/** + * Loads an ELF image file. + * + * @param FileHandle + * The handle of the opened ELF 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 ELF file will be loaded. + * + * @param Image + * Supplies pointer to the memory area where loaded ELF image context will be stored. + * + * @return This routine returns status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +ElfLoadImage(IN PEFI_FILE_HANDLE FileHandle, + IN LOADER_MEMORY_TYPE MemoryType, + IN PVOID VirtualAddress, + OUT PVOID *ImagePointer) +{ + EFI_GUID FileInfoGuid = EFI_FILE_INFO_PROTOCOL_GUID; + PELF_IMAGE_CONTEXT ImageData; + EFI_PHYSICAL_ADDRESS Address; + PEFI_FILE_INFO FileInfo; + UINT_PTR ReadSize; + EFI_STATUS Status; + // UINT SectionSize; + SIZE_T Pages; + PUCHAR Data; + + /* 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 ELF 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 ELF image file\n"); + XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data); + XtLdrProtocol->Memory.FreePool(ImageData); + return Status; + } + + /* Extract header */ + ImageData->Header32 = (PELF32_HEADER)Data; + ImageData->Header64 = (PELF64_HEADER)Data; + + /* Validate ELF file */ + if(ImageData->Header32->e_ident[EI_MAG0] != 0x7F || + ImageData->Header32->e_ident[EI_MAG1] != 0x45 || + ImageData->Header32->e_ident[EI_MAG2] != 0x4C || + ImageData->Header32->e_ident[EI_MAG3] != 0x46) + { + /* ELF file header is invalid */ + return STATUS_EFI_INVALID_PARAMETER; + } + + /* Check architecture */ + if(ImageData->Header32->e_ident[EI_CLASS] == 1) + { + /* 32-bit executable */ + + /* Set entry point */ + ImageData->EntryPoint = (PVOID)(UINT_PTR)ImageData->Header32->e_entry; + + /* Load individual segments according to program headers */ + PELF32_PROGRAM_HEADER ProgramHeaders = (PELF32_PROGRAM_HEADER)(Data + ImageData->Header32->e_phoff); + for (UINT Count = 0; Count < ImageData->Header32->e_phnum; Count++) + { + /* PT_DYNAMIC will be used for relocations */ + if(ProgramHeaders[Count].p_type == PT_LOAD) + { + UINT32 PageCount = EFI_SIZE_TO_PAGES((UINT32)ProgramHeaders[Count].p_memsz); + + Status = XtLdrProtocol->Memory.AllocatePages(PageCount, (PEFI_PHYSICAL_ADDRESS)&PageCount); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to allocate memory */ + XtLdrProtocol->Debug.Print(L"ERROR: Page allocation failure\n"); + return STATUS_EFI_PROTOCOL_ERROR; + } + + /* Read segment into memory */ + Status = FileHandle->SetPosition(FileHandle, (UINT64)&ProgramHeaders[Count].p_offset); + Status = FileHandle->Read(FileHandle, (PUINT_PTR)&ProgramHeaders[Count].p_filesz, &ProgramHeaders[Count].p_paddr); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to read data */ + XtLdrProtocol->Debug.Print(L"ERROR: Unable to load ELF segment into memory!\n"); + XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)&ProgramHeaders[Count].p_paddr); + return Status; + } + + /* If memory size is larger than file size, zero the memory out */ + UINT32 ZeroCount = ProgramHeaders[Count].p_memsz - ProgramHeaders[Count].p_filesz; + if(ZeroCount > 0) + { + UINT_PTR ZeroedMemoryStart = (UINT_PTR)ProgramHeaders[Count].p_paddr + (UINT_PTR)ProgramHeaders[Count].p_filesz; + RtlZeroMemory((PVOID)ZeroedMemoryStart, ZeroCount); + } + } + } + } + else if(ImageData->Header32->e_ident[EI_CLASS] == 2) + { + /* 64-bit executable */ + + /* Set entry point */ + ImageData->EntryPoint = (PVOID)(UINT_PTR)ImageData->Header64->e_entry; + + /* Load individual segments according to program headers */ + PELF64_PROGRAM_HEADER ProgramHeaders = (PELF64_PROGRAM_HEADER)(Data + ImageData->Header64->e_phoff); + for (UINT Count = 0; Count < ImageData->Header64->e_phnum; Count++) + { + /* PT_DYNAMIC will be used for relocations */ + if(ProgramHeaders[Count].p_type == PT_LOAD) + { + /* Set PhysicalAddress and VirtualAddress to the lowest address present */ + ImageData->PhysicalAddress = (UINT_PTR)ImageData->PhysicalAddress < ProgramHeaders[Count].p_paddr ? + ImageData->PhysicalAddress : + (PVOID)(UINT_PTR)(UINT64)ProgramHeaders[Count].p_paddr; + + ImageData->VirtualAddress = (UINT_PTR)ImageData->VirtualAddress < ProgramHeaders[Count].p_vaddr ? + ImageData->VirtualAddress : + (PVOID)(UINT_PTR)(UINT64)ProgramHeaders[Count].p_vaddr; + + /* Allocate memory for the program headers */ + UINT32 PageCount = EFI_SIZE_TO_PAGES((UINT32)ProgramHeaders[Count].p_memsz); + + Status = XtLdrProtocol->Memory.AllocatePages(PageCount, (PEFI_PHYSICAL_ADDRESS)&PageCount); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to allocate memory */ + XtLdrProtocol->Debug.Print(L"ERROR: Page allocation failure\n"); + return STATUS_EFI_PROTOCOL_ERROR; + } + + /* Read segment into memory */ + Status = FileHandle->SetPosition(FileHandle, (UINT64)&ProgramHeaders[Count].p_offset); + Status = FileHandle->Read(FileHandle, (PUINT_PTR)&ProgramHeaders[Count].p_filesz, &ProgramHeaders[Count].p_paddr); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to read data */ + XtLdrProtocol->Debug.Print(L"ERROR: Unable to load ELF segment into memory!\n"); + XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)&ProgramHeaders[Count].p_paddr); + return Status; + } + + /* If memory size is larger than file size, zero the memory out */ + UINT32 ZeroCount = ProgramHeaders[Count].p_memsz - ProgramHeaders[Count].p_filesz; + if(ZeroCount > 0) + { + UINT_PTR ZeroedMemoryStart = (UINT_PTR)ProgramHeaders[Count].p_paddr + (UINT_PTR)ProgramHeaders[Count].p_filesz; + RtlZeroMemory((PVOID)ZeroedMemoryStart, ZeroCount); + } + } + } + } + else + { + /* Invalid executable */ + XtLdrProtocol->Debug.Print(L"ERROR: ELF executable has invalid architecture\n"); + return STATUS_EFI_UNSUPPORTED; + } + + /* Check endianness */ + if(ImageData->Header32->e_ident[EI_DATA] != 1) + { + /* Big-endian */ + XtLdrProtocol->Debug.Print(L"ERROR: XTLDR only supports LSB (little-endian) ELF executables\n"); + return STATUS_EFI_UNSUPPORTED; + } + + /* Store image data */ + *ImagePointer = ImageData; + + /* 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_ELF_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 ELF image protocol */ + XtElfProtocol.GetEntryPoint = ElfGetEntryPoint; + XtElfProtocol.GetMachineType = ElfGetMachineType; + XtElfProtocol.GetSubSystem = ElfGetSubSystem; + XtElfProtocol.LoadImage = ElfLoadImage; + XtElfProtocol.RelocateImage = ElfRelocateImage; + + /* Register ELF protocol */ + return XtLdrProtocol->Protocol.Install(&XtElfProtocol, &Guid); +} diff --git a/xtldr/modules/elf_o/includes/elf.h b/xtldr/modules/elf_o/includes/elf.h new file mode 100644 index 0000000..c234f0e --- /dev/null +++ b/xtldr/modules/elf_o/includes/elf.h @@ -0,0 +1,47 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/elf_o/includes/elf.h + * DESCRIPTION: ELF executable file format support header + * DEVELOPERS: Jozef Nagy + */ + +#ifndef __XTLDR_MODULES_ELF_O_H +#define __XTLDR_MODULES_ELF_O_H + +#include + +/* ELF image protocol related routines forward references */ +XTCDECL +EFI_STATUS +ElfGetEntryPoint(IN PVOID ImagePointer, + OUT PVOID *EntryPoint); + +XTCDECL +EFI_STATUS +ElfGetMachineType(IN PVOID ImagePointer, + OUT PUSHORT MachineType); + +XTCDECL +EFI_STATUS +ElfGetSubSystem(IN PVOID ImagePointer, + OUT PUSHORT SubSystem); + +XTCDECL +EFI_STATUS +ElfLoadImage(IN PEFI_FILE_HANDLE FileHandle, + IN LOADER_MEMORY_TYPE MemoryType, + IN PVOID VirtualAddress, + OUT PVOID *ImagePointer); + +XTCDECL +EFI_STATUS +ElfRelocateImage(IN PVOID ImagePointer, + IN EFI_VIRTUAL_ADDRESS Address); + +XTCDECL +EFI_STATUS +BlXtLdrModuleMain(IN EFI_HANDLE ImageHandle, + IN PEFI_SYSTEM_TABLE SystemTable); + +#endif /* __XTLDR_MODULES_ELF_O_H */