diff --git a/.gitignore b/.gitignore index d194e52..fe26926 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ build build-* # TODO: Don't forget to remove this ;) -xtldr/modules/multiboot2 \ No newline at end of file +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/xtldr/modules/elf/elf.c b/xtldr/modules/elf/elf.c index 0af7365..94035fe 100644 --- a/xtldr/modules/elf/elf.c +++ b/xtldr/modules/elf/elf.c @@ -275,6 +275,7 @@ ElfLoadImage(IN PEFI_FILE_HANDLE FileHandle, 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++) { @@ -293,7 +294,7 @@ ElfLoadImage(IN PEFI_FILE_HANDLE FileHandle, } /* Read segment into memory */ - Status = FileHandle->SetPosition(FileHandle, (UINT64)&ProgramHeaders[Count].p_offset); + 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) { @@ -310,6 +311,8 @@ ElfLoadImage(IN PEFI_FILE_HANDLE FileHandle, 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); } } } 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); +}