/** * 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); }