diff --git a/.gitignore b/.gitignore index 4ea88da..fe26926 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ .vscode build build-* + +# TODO: Don't forget to remove this ;) +bootdata/xtldr/kernel.elf \ No newline at end of file diff --git a/bootdata/xtldr/CMakeLists.txt b/bootdata/xtldr/CMakeLists.txt index 9dcfcfb..5212662 100644 --- a/bootdata/xtldr/CMakeLists.txt +++ b/bootdata/xtldr/CMakeLists.txt @@ -1 +1,2 @@ set_install_file(xtldr.ini efi/boot/xtldr) +set_install_file(kernel.elf exectos/boot) diff --git a/bootdata/xtldr/xtldr.ini b/bootdata/xtldr/xtldr.ini index 31dfdfd..a21027c 100644 --- a/bootdata/xtldr/xtldr.ini +++ b/bootdata/xtldr/xtldr.ini @@ -37,6 +37,14 @@ SystemPath=multi(0)disk(0)rdisk(0)partition(1)/ExectOS KernelFile=xtoskrnl.exe Parameters=DEBUG=COM1,115200 +[ELFTest] +SystemName="ELF Test" +SystemType=MULTIBOOT2 +BootModules=multiboot2 +SystemPath=multi(0)disk(0)rdisk(0)partition(1)/ExectOS +KernelFile=kernel.elf +Parameters= + [Windows] SystemName="Microsoft Windows 2000" SystemType=NT50 diff --git a/sdk/xtdk/xtimage.h b/sdk/xtdk/xtimage.h index 047c352..146930c 100644 --- a/sdk/xtdk/xtimage.h +++ b/sdk/xtdk/xtimage.h @@ -606,4 +606,115 @@ typedef struct _PECOFF_IMAGE_RESOURCE_DATA_ENTRY ULONG Reserved; } PECOFF_IMAGE_RESOURCE_DATA_ENTRY, *PPECOFF_IMAGE_RESOURCE_DATA_ENTRY; +/* ELF identities */ +typedef enum _ELF_IMAGE_IDENTITY +{ + 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_IMAGE_IDENTITY, *PELF_IMAGE_IDENTITY; + +/* ELF Program header types */ +typedef enum _ELF_IMAGE_PROGRAM_HEADER_TYPE +{ + 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_IMAGE_PROGRAM_HEADER_TYPE, *PELF_IMAGE_PROGRAM_HEADER_TYPE; + +/* ELF image representation structure */ +typedef struct _ELF_IMAGE_CONTEXT +{ + union + { + PELF_IMAGE_HEADER32 Header32; + PELF_IMAGE_HEADER64 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 _ELF_IMAGE_HEADER32 +{ + /* 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; +} ELF_IMAGE_HEADER32, *PELF_IMAGE_HEADER32; + +/* 64-bit ELF image header structure */ +typedef struct _ELF_IMAGE_HEADER64 +{ + /* 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; +} ELF_IMAGE_HEADER64, *PELF_IMAGE_HEADER64; + +/* 32-bit ELF program header structure */ +typedef struct _ELF_IMAGE_PROGRAM_HEADER32 +{ + UINT32 p_type; + UINT32 p_offset; + UINT32 p_vaddr; + UINT32 p_paddr; + UINT32 p_filesz; + UINT32 p_memsz; + UINT32 p_flags; + UINT32 p_align; +} ELF_IMAGE_PROGRAM_HEADER32, *PELF_IMAGE_PROGRAM_HEADER32; + +/* 64-bit ELF program header structure */ +typedef struct _ELF_IMAGE_PROGRAM_HEADER64 +{ + UINT32 p_type; + UINT32 p_flags; + ULONG p_offset; + ULONG p_vaddr; + ULONG p_paddr; + ULONG p_filesz; + ULONG p_memsz; + ULONG p_align; +} ELF_IMAGE_PROGRAM_HEADER64, *PELF_IMAGE_PROGRAM_HEADER64; + #endif /* __XTDK_XTIMAGE_H */ diff --git a/sdk/xtdk/xtstruct.h b/sdk/xtdk/xtstruct.h index dcc19ab..66cfc27 100644 --- a/sdk/xtdk/xtstruct.h +++ b/sdk/xtdk/xtstruct.h @@ -39,6 +39,8 @@ typedef enum _EFI_TIMER_DELAY EFI_TIMER_DELAY, *PEFI_TIMER_DELAY; typedef enum _EFI_UART_PARITY_TYPE EFI_UART_PARITY_TYPE, *PEFI_UART_PARITY_TYPE; typedef enum _EFI_UART_STOP_BITS_TYPE EFI_UART_STOP_BITS_TYPE, *PEFI_UART_STOP_BITS_TYPE; typedef enum _EFI_UNIVERSA_GRAPHICS_BLT_OPERATION EFI_UNIVERSA_GRAPHICS_BLT_OPERATION, *PEFI_UNIVERSA_GRAPHICS_BLT_OPERATION; +typedef enum _ELF_IMAGE_IDENTITY ELF_IMAGE_IDENTITY, *PELF_IMAGE_IDENTITY; +typedef enum _ELF_IMAGE_PROGRAM_HEADER_TYPE ELF_IMAGE_PROGRAM_HEADER_TYPE, *PELF_IMAGE_PROGRAM_HEADER_TYPE; typedef enum _KAPC_ENVIRONMENT KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; typedef enum _KDPC_IMPORTANCE KDPC_IMPORTANCE, *PKDPC_IMPORTANCE; typedef enum _KEVENT_TYPE KEVENT_TYPE, *PKEVENT_TYPE; @@ -199,6 +201,11 @@ typedef struct _EFI_USB_DEVICE_PATH EFI_USB_DEVICE_PATH, *PEFI_USB_DEVICE_PATH; typedef struct _EFI_USB_WWID_DEVICE_PATH EFI_USB_WWID_DEVICE_PATH, *PEFI_USB_WWID_DEVICE_PATH; typedef struct _EFI_VENDOR_DEVICE_PATH EFI_VENDOR_DEVICE_PATH, *PEFI_VENDOR_DEVICE_PATH; typedef struct _EFI_VLAN_DEVICE_PATH EFI_VLAN_DEVICE_PATH, *PEFI_VLAN_DEVICE_PATH; +typedef struct _ELF_IMAGE_CONTEXT ELF_IMAGE_CONTEXT, *PELF_IMAGE_CONTEXT; +typedef struct _ELF_IMAGE_HEADER32 ELF_IMAGE_HEADER32, *PELF_IMAGE_HEADER32; +typedef struct _ELF_IMAGE_HEADER64 ELF_IMAGE_HEADER64, *PELF_IMAGE_HEADER64; +typedef struct _ELF_IMAGE_PROGRAM_HEADER32 ELF_IMAGE_PROGRAM_HEADER32, *PELF_IMAGE_PROGRAM_HEADER32; +typedef struct _ELF_IMAGE_PROGRAM_HEADER64 ELF_IMAGE_PROGRAM_HEADER64, *PELF_IMAGE_PROGRAM_HEADER64; typedef struct _EPROCESS EPROCESS, *PEPROCESS; typedef struct _ETHREAD ETHREAD, *PETHREAD; typedef struct _EX_RUNDOWN_REFERENCE EX_RUNDOWN_REFERENCE, *PEX_RUNDOWN_REFERENCE; diff --git a/xtldr/modules/CMakeLists.txt b/xtldr/modules/CMakeLists.txt index 375c1d7..900fff2 100644 --- a/xtldr/modules/CMakeLists.txt +++ b/xtldr/modules/CMakeLists.txt @@ -1,5 +1,7 @@ add_subdirectory(beep) add_subdirectory(dummy) +add_subdirectory(elf) +add_subdirectory(multiboot2) add_subdirectory(fb_o) add_subdirectory(pecoff_o) add_subdirectory(xtos_o) diff --git a/xtldr/modules/elf/CMakeLists.txt b/xtldr/modules/elf/CMakeLists.txt new file mode 100644 index 0000000..b705b69 --- /dev/null +++ b/xtldr/modules/elf/CMakeLists.txt @@ -0,0 +1,26 @@ +# XT Boot Loader +PROJECT(XTLDR_ELF) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_ELF_SOURCE_DIR}/includes) + +# Specify list of source code files +list(APPEND XTLDR_ELF_SOURCE + ${XTLDR_ELF_SOURCE_DIR}/elf.c) + +# Link bootloader executable +add_executable(elf ${XTLDR_ELF_SOURCE}) + +# Add linker libraries +target_link_libraries(elf libxtos libxtldr) + +# Set proper binary name and install target +set_target_properties(elf PROPERTIES SUFFIX .efi) +set_install_target(elf efi/boot/xtldr/modules) + +# Set module entrypoint and subsystem +set_entrypoint(elf "XtLdrModuleMain") +set_linker_map(elf TRUE) +set_subsystem(elf efi_boot_service_driver) diff --git a/xtldr/modules/elf/elf.c b/xtldr/modules/elf/elf.c new file mode 100644 index 0000000..94035fe --- /dev/null +++ b/xtldr/modules/elf/elf.c @@ -0,0 +1,379 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/elf/elf.c + * DESCRIPTION: ELF executable file format support module + * DEVELOPERS: Jozef Nagy + */ + +#include + +/* ELF 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(ELF_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 = (PELF_IMAGE_HEADER32)Data; + ImageData->Header64 = (PELF_IMAGE_HEADER64)Data; + + /* Set physical and virtual addresses */ + ImageData->PhysicalAddress = (PVOID)(UINT_PTR)Address; + if(VirtualAddress) + { + ImageData->VirtualAddress = VirtualAddress; + } + else + { + ImageData->VirtualAddress = (PVOID)(UINT_PTR)Address; + } + + /* 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 */ + XtLdrProtocol->Debug.Print(L"Kernel is a 32-bit executable\n"); + + /* Set entry point */ + ImageData->EntryPoint = (PVOID)(UINT_PTR)ImageData->Header32->e_entry; + + /* Load individual segments according to program headers */ + PELF_IMAGE_PROGRAM_HEADER32 ProgramHeaders = (PELF_IMAGE_PROGRAM_HEADER32)(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 */ + XtLdrProtocol->Debug.Print(L"Kernel is a 64-bit executable\n"); + + /* Set entry point */ + ImageData->EntryPoint = (PVOID)(UINT_PTR)ImageData->Header64->e_entry; + XtLdrProtocol->Debug.Print(L"Entry point: 0x%lx (0x%lx)\n", ImageData->EntryPoint, ImageData->Header64->e_entry); + + /* Load individual segments according to program headers */ + XtLdrProtocol->Debug.Print(L"Program header count: %d\n", ImageData->Header64->e_phnum); + PELF_IMAGE_PROGRAM_HEADER64 ProgramHeaders = (PELF_IMAGE_PROGRAM_HEADER64)(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) + { + /* 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, ProgramHeaders[Count].p_offset); + Status = FileHandle->Read(FileHandle, (PUINT_PTR)&ProgramHeaders[Count].p_filesz, (PVOID)(UINT_PTR)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); + } + + XtLdrProtocol->Debug.Print(L"Read %d pages (%d bytes) to %lx\n", PageCount, ZeroCount, (UINT64)ProgramHeaders[Count].p_offset); + } + } + } + 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/includes/elf.h b/xtldr/modules/elf/includes/elf.h new file mode 100644 index 0000000..fcbe3a9 --- /dev/null +++ b/xtldr/modules/elf/includes/elf.h @@ -0,0 +1,47 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/elf/includes/elf.h + * DESCRIPTION: ELF executable file format support header + * DEVELOPERS: Jozef Nagy + */ + +#ifndef __XTLDR_MODULES_ELF_H +#define __XTLDR_MODULES_ELF_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_H */ diff --git a/xtldr/modules/multiboot2/CMakeLists.txt b/xtldr/modules/multiboot2/CMakeLists.txt new file mode 100644 index 0000000..1ae62b0 --- /dev/null +++ b/xtldr/modules/multiboot2/CMakeLists.txt @@ -0,0 +1,26 @@ +# XT Boot Loader +PROJECT(XTLDR_MULTIBOOT2) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_MULTIBOOT2_SOURCE_DIR}/includes) + +# Specify list of source code files +list(APPEND XTLDR_MULTIBOOT2_SOURCE + ${XTLDR_MULTIBOOT2_SOURCE_DIR}/multiboot2.c) + +# Link bootloader executable +add_executable(multiboot2 ${XTLDR_MULTIBOOT2_SOURCE}) + +# Add linker libraries +target_link_libraries(multiboot2 libxtos libxtldr) + +# Set proper binary name and install target +set_target_properties(multiboot2 PROPERTIES SUFFIX .efi) +set_install_target(multiboot2 efi/boot/xtldr/modules) + +# Set module entrypoint and subsystem +set_entrypoint(multiboot2 "XtLdrModuleMain") +set_linker_map(multiboot2 TRUE) +set_subsystem(multiboot2 efi_boot_service_driver) diff --git a/xtldr/modules/multiboot2/includes/multiboot2.h b/xtldr/modules/multiboot2/includes/multiboot2.h new file mode 100644 index 0000000..e9e74c3 --- /dev/null +++ b/xtldr/modules/multiboot2/includes/multiboot2.h @@ -0,0 +1,63 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/xtos/includes/xtos.h + * DESCRIPTION: XTOS boot protocol support header + * DEVELOPERS: Rafal Kupiec + */ + +#ifndef __XTLDR_MODULES_XTOS_H +#define __XTLDR_MODULES_XTOS_H + +#include + +typedef VOID (*PXT_FRAMEBUFFER_GET_DISPLAY_DRIVER)(OUT PWCHAR DriverName); +typedef VOID (*PXT_FRAMEBUFFER_GET_DISPLAY_INFORMATION)(OUT PLOADER_GRAPHICS_INFORMATION_BLOCK InformationBlock); +typedef EFI_STATUS (*PXT_FRAMEBUFFER_INITIALIZE)(); +typedef VOID (*PXT_FRAMEBUFFER_PRINT_DISPLAY_INFORMATION)(); + +/* XT framebuffer support protocol */ +typedef struct _XT_FRAMEBUFFER_PROTOCOL +{ + PXT_FRAMEBUFFER_GET_DISPLAY_DRIVER GetDisplayDriver; + PXT_FRAMEBUFFER_GET_DISPLAY_INFORMATION GetDisplayInformation; + PXT_FRAMEBUFFER_INITIALIZE Initialize; + PXT_FRAMEBUFFER_PRINT_DISPLAY_INFORMATION PrintDisplayInformation; +} XT_FRAMEBUFFER_PROTOCOL, *PXT_FRAMEBUFFER_PROTOCOL; + +/* EFI XT Loader Protocol */ +EXTERN PXTBL_LOADER_PROTOCOL XtLdrProtocol; + +/* XTOS kernel entry point */ +typedef VOID (XTAPI *PXT_ENTRY_POINT)(IN PKERNEL_INITIALIZATION_BLOCK BootParameters); + +/* XTOS boot protocol related routines forward references */ +XTCDECL +EFI_STATUS +Multiboot2BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters); + +XTCDECL +EFI_STATUS +XtpBootSequence(IN PEFI_FILE_HANDLE BootDir, + IN PXTBL_BOOT_PARAMETERS Parameters); + +XTCDECL +EFI_STATUS +XtpInitializeLoaderBlock(IN PLIST_ENTRY MemoryMappings, + IN PVOID *VirtualAddress, + IN PXTBL_BOOT_PARAMETERS Parameters); + +XTCDECL +EFI_STATUS +XtpLoadModule(IN PEFI_FILE_HANDLE BootDir, + IN PWCHAR FileName, + IN PVOID VirtualAddress, + IN LOADER_MEMORY_TYPE MemoryType, + OUT PELF_IMAGE_CONTEXT *ImageContext); + +XTCDECL +EFI_STATUS +BlXtLdrModuleMain(IN EFI_HANDLE ImageHandle, + IN PEFI_SYSTEM_TABLE SystemTable); + +#endif /* __XTLDR_MODULES_XTOS_H */ diff --git a/xtldr/modules/multiboot2/multiboot2.c b/xtldr/modules/multiboot2/multiboot2.c new file mode 100644 index 0000000..2da40b5 --- /dev/null +++ b/xtldr/modules/multiboot2/multiboot2.c @@ -0,0 +1,331 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/multiboot2/multiboot2.c + * DESCRIPTION: Multiboot2 boot protocol support + * DEVELOPERS: Jozef Nagy + */ + +#include + +/* XTOS module information */ +XTBL_MODINFO = L"Multiboot2 boot protocol support"; +XTBL_MODDEPS = {L"elf"}; + +/* EFI XT Loader Protocol */ +PXTBL_LOADER_PROTOCOL XtLdrProtocol; + +/* XTOS ELF Image Protocol */ +PXTBL_EXECUTABLE_IMAGE_PROTOCOL XtElfProtocol; + +/* XTOS Boot Protocol */ +XTBL_BOOT_PROTOCOL Multiboot2BootProtocol; + +/* XTOS Page Map */ +PVOID XtPageMap; + +/** + * Starts the operating system according to the provided parameters using XTOS boot protocol. + * + * @param Parameters + * Input parameters with detailed system configuration like boot device or kernel path. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +Multiboot2BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters) +{ + EFI_GUID ElfProtocolGuid = XT_ELF_IMAGE_PROTOCOL_GUID; + EFI_HANDLE DiskHandle, ProtocolHandle; + PEFI_FILE_HANDLE FsHandle, BootDir; + PWCHAR SystemPath; + EFI_STATUS Status; + + /* Print debug message */ + XtLdrProtocol->Debug.Print(L"Multiboot2 boot protocol activated\n"); + + /* Open the XT ELF protocol */ + Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID *)&XtElfProtocol, &ElfProtocolGuid); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to open loader protocol */ + XtLdrProtocol->Debug.Print(L"ERROR: Unable to load ELF image protocol\n"); + return STATUS_EFI_PROTOCOL_ERROR; + } + + /* Check device path */ + if(Parameters->DevicePath == NULL) + { + /* No device path set */ + XtLdrProtocol->Debug.Print(L"ERROR: No device path provided, unable to boot system\n"); + return STATUS_EFI_INVALID_PARAMETER; + } + + /* Check if system path is set */ + if(Parameters->SystemPath != NULL) + { + /* Make sure system path begins with backslash, the only separator supported by EFI */ + if(Parameters->SystemPath[0] == '/') + { + /* Replace directory separator if needed */ + Parameters->SystemPath[0] = '\\'; + } + + /* Validate system path */ + SystemPath = &Parameters->SystemPath[1]; + while(*SystemPath) + { + /* Make sure it does not point to any subdirectory and not contains special characters */ + if(((*SystemPath | 32) - 'a' >= 26) && ((*SystemPath - '0') >= 10)) + { + /* Invalid path specified */ + XtLdrProtocol->Debug.Print(L"ERROR: System path does not point to the valid XTOS installation\n"); + return STATUS_EFI_INVALID_PARAMETER; + } + /* Check next character in the path */ + SystemPath++; + } + } + else + { + /* Fallback to '/ExectOS' by default */ + XtLdrProtocol->Debug.Print(L"WARNING: No system path set, falling back to defaults\n"); + Parameters->SystemPath = L"\\ExectOS"; + } + + /* Check if kernel file is set */ + if(Parameters->KernelFile == NULL) + { + /* No kernel filename set, fallback to default */ + XtLdrProtocol->Debug.Print(L"WARNING: No kernel file specified, falling back to defaults\n"); + Parameters->KernelFile = L"kernel.elf"; + } + + /* Check if provided any kernel boot arguments */ + if(Parameters->Parameters == NULL) + { + /* No argument supplied */ + Parameters->Parameters = L""; + } + + /* Print a debug message */ + XtLdrProtocol->Debug.Print(L"[XTOS] ARC Path: %S\n" + L"[XTOS] System Path: %S\n" + L"[XTOS] Kernel File: %S\n" + L"[XTOS] Boot Arguments: %S\n", + Parameters->ArcName, Parameters->SystemPath, + Parameters->KernelFile, Parameters->Parameters); + + /* Open EFI volume */ + Status = XtLdrProtocol->Disk.OpenVolume(NULL, &DiskHandle, &FsHandle); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to open a volume */ + XtLdrProtocol->Debug.Print(L"ERROR: Unable to open boot volume\n"); + return Status; + } + + /* System path has to point to the boot directory */ + RtlConcatenateWideString(Parameters->SystemPath, L"\\Boot", 0); + + /* Open XTOS system boot directory */ + Status = FsHandle->Open(FsHandle, &BootDir, Parameters->SystemPath, EFI_FILE_MODE_READ, 0); + FsHandle->Close(FsHandle); + + /* Check if system path directory opened successfully */ + if(Status == STATUS_EFI_NOT_FOUND) + { + /* Directory not found, nothing to load */ + XtLdrProtocol->Debug.Print(L"ERROR: System boot directory not found\n"); + + /* Close volume */ + XtLdrProtocol->Disk.CloseVolume(DiskHandle); + return Status; + } + else if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to open directory */ + XtLdrProtocol->Debug.Print(L"ERROR: Unable to open system boot directory\n"); + XtLdrProtocol->Disk.CloseVolume(DiskHandle); + return Status; + } + + /* Start boot sequence */ + return XtpBootSequence(BootDir, Parameters); +} + +/** + * This routine initiates an XTOS boot sequence. + * + * @param BootDir + * An EFI handle to the XTOS boot directory. + * + * @param Parameters + * Input parameters with detailed system configuration like boot device or kernel path. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtpBootSequence(IN PEFI_FILE_HANDLE BootDir, + IN PXTBL_BOOT_PARAMETERS Parameters) +{ + EFI_GUID LoadedImageGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + PKERNEL_INITIALIZATION_BLOCK KernelParameters; + PELF_IMAGE_CONTEXT ImageContext = NULL; + PEFI_LOADED_IMAGE_PROTOCOL ImageProtocol; + PVOID VirtualAddress, VirtualMemoryArea; + PXT_ENTRY_POINT KernelEntryPoint; + LIST_ENTRY MemoryMappings; + EFI_HANDLE ProtocolHandle; + EFI_STATUS Status; + + /* Initialize XTOS startup sequence */ + XtLdrProtocol->Debug.Print(L"Initializing XTOS startup sequence\n"); + + /* Set base virtual memory area for the kernel mappings */ + VirtualMemoryArea = (PVOID)KSEG0_BASE; + VirtualAddress = (PVOID)(KSEG0_BASE + KSEG0_KERNEL_BASE); + + /* Load the kernel */ + Status = XtpLoadModule(BootDir, Parameters->KernelFile, VirtualAddress, LoaderSystemCode, &ImageContext); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to load the kernel */ + return Status; + } + + /* Get kernel entry point */ + XtElfProtocol->GetEntryPoint(ImageContext, (PVOID)&KernelEntryPoint); + + /* Close boot directory handle */ + BootDir->Close(BootDir); + + /* Call XTOS kernel */ + XtLdrProtocol->Debug.Print(L"Booting the ELF Multiboot2 kernel\n"); + KernelEntryPoint(KernelParameters); + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * Loads XTOS ELF module. + * + * @param SystemDir + * An EFI handle to the opened system directory containing a module that will be loaded. + * + * @param FileName + * An on disk filename of the module that will be loaded. + * + * @param VirtualAddress + * Optional virtual address pointing to the memory area where ELF file will be loaded. + * + * @param MemoryType + * Supplies the type of memory to be assigned to the memory descriptor. + * + * @param ImageContext + * Supplies pointer to the memory area where loaded ELF image context will be stored. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtpLoadModule(IN PEFI_FILE_HANDLE SystemDir, + IN PWCHAR FileName, + IN PVOID VirtualAddress, + IN LOADER_MEMORY_TYPE MemoryType, + OUT PELF_IMAGE_CONTEXT *ImageContext) +{ + PEFI_FILE_HANDLE ModuleHandle; + USHORT MachineType, SubSystem; + EFI_STATUS Status; + + /* Print debug message */ + XtLdrProtocol->Debug.Print(L"Loading %S... \n", FileName); + + /* Open module file */ + Status = SystemDir->Open(SystemDir, &ModuleHandle, FileName, EFI_FILE_MODE_READ, 0); + if(Status != STATUS_EFI_SUCCESS) + { + /* Unable to open the file */ + XtLdrProtocol->Debug.Print(L"ERROR: Failed to open '%S'\n", FileName); + return Status; + } + + /* Load the ELF image file */ + Status = XtElfProtocol->LoadImage(ModuleHandle, MemoryType, VirtualAddress, (PVOID)ImageContext); + if(Status != STATUS_EFI_SUCCESS) + { + /* Unable to load the file */ + XtLdrProtocol->Debug.Print(L"ERROR: Failed to load '%S'\n", FileName); + return Status; + } + + /* Close image file */ + ModuleHandle->Close(ModuleHandle); + + /* Check ELF image machine type compatibility */ + XtElfProtocol->GetMachineType(*ImageContext, &MachineType); + if(MachineType != 0x03 && + MachineType != 0x32 && + MachineType != 0x3E) + { + /* Machine type mismatch */ + XtLdrProtocol->Debug.Print(L"ERROR: Loaded incompatible ELF image (machine type mismatch)\n"); + return STATUS_EFI_INCOMPATIBLE_VERSION; + } + + /* Print debug message */ + XtLdrProtocol->Debug.Print(L"Loaded %S at PA: 0x%lx, VA: 0x%lx\n", FileName, + (*ImageContext)->PhysicalAddress, (*ImageContext)->VirtualAddress); + + /* 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_XTOS_BOOT_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 Multiboot2 boot protocol */ + Multiboot2BootProtocol.BootSystem = Multiboot2BootSystem; + + /* Register XTOS boot protocol */ + XtLdrProtocol->Boot.RegisterProtocol(L"MULTIBOOT2", &Guid); + + /* Install XTOS protocol */ + return XtLdrProtocol->Protocol.Install(&Multiboot2BootProtocol, &Guid); +}