/** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory * FILE: xtldr/modules/xtos/xtos.cc * DESCRIPTION: XTOS boot protocol support * DEVELOPERS: Rafal Kupiec */ #include /* XTOS module information */ MODULE_AUTHOR(L"Rafal Kupiec "); MODULE_DESCRIPTION(L"XTOS boot protocol support"); MODULE_DEPENDENCY(L"acpi framebuf pecoff"); MODULE_LICENSE(L"GPLv3"); MODULE_VERSION(L"0.1"); /** * 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 Xtos::BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters) { EFI_GUID PeCoffProtocolGuid = XT_PECOFF_IMAGE_PROTOCOL_GUID; EFI_HANDLE DiskHandle, ProtocolHandle; PEFI_FILE_HANDLE FsHandle, BootDir; PWCHAR SystemPath; EFI_STATUS Status; /* Print debug message */ XtLdrProtocol->Debug.Print(L"XTOS boot protocol activated\n"); /* Open the XT PE/COFF protocol */ Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID *)&PeCoffProtocol, &PeCoffProtocolGuid); if(Status != STATUS_EFI_SUCCESS) { /* Failed to open loader protocol */ XtLdrProtocol->Debug.Print(L"ERROR: Unable to load PE/COFF image protocol\n"); return STATUS_EFI_PROTOCOL_ERROR; } /* Check device path */ if(Parameters->DevicePath == NULLPTR) { /* 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 != NULLPTR) { /* 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 = (PWCHAR)L"\\ExectOS"; } /* Check if kernel file is set */ if(Parameters->KernelFile == NULLPTR) { /* No kernel filename set, fallback to default */ XtLdrProtocol->Debug.Print(L"WARNING: No kernel file specified, falling back to defaults\n"); Parameters->KernelFile = (PWCHAR)L"xtoskrnl.exe"; } /* Check if provided any kernel boot arguments */ if(Parameters->Parameters == NULLPTR) { /* No argument supplied */ Parameters->Parameters = (PWCHAR)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(Parameters->DevicePath, &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 */ XtLdrProtocol->WideString.Concatenate(Parameters->SystemPath, (PWCHAR)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 RunBootSequence(BootDir, Parameters); } /** * Returns information about frame buffer in XTOS compatible format. * * @param InformationBlock * A pointer to memory area containing XT structure where all the information will be stored. * * @return This routine does not return any value. * * @since XT 1.0 */ XTCDECL VOID Xtos::GetDisplayInformation(OUT PSYSTEM_RESOURCE_FRAMEBUFFER FrameBufferResource, IN PEFI_PHYSICAL_ADDRESS FrameBufferBase, IN PULONG_PTR FrameBufferSize, IN PXTBL_FRAMEBUFFER_MODE_INFORMATION FrameBufferModeInfo) { /* Fill in frame buffer resource */ FrameBufferResource->Header.PhysicalAddress = (PVOID)*FrameBufferBase; FrameBufferResource->Header.ResourceType = SystemResourceFrameBuffer; FrameBufferResource->Header.ResourceSize = sizeof(SYSTEM_RESOURCE_FRAMEBUFFER); FrameBufferResource->BufferSize = *FrameBufferSize; FrameBufferResource->Width = FrameBufferModeInfo->Width; FrameBufferResource->Height = FrameBufferModeInfo->Height; FrameBufferResource->Depth = FrameBufferModeInfo->Depth; FrameBufferResource->BitsPerPixel = FrameBufferModeInfo->BitsPerPixel; FrameBufferResource->PixelsPerScanLine = FrameBufferModeInfo->PixelsPerScanLine; FrameBufferResource->Pitch = FrameBufferModeInfo->Pitch; FrameBufferResource->Pixels.BlueShift = FrameBufferModeInfo->PixelInformation.BlueShift; FrameBufferResource->Pixels.BlueSize = FrameBufferModeInfo->PixelInformation.BlueSize; FrameBufferResource->Pixels.GreenShift = FrameBufferModeInfo->PixelInformation.GreenShift; FrameBufferResource->Pixels.GreenSize = FrameBufferModeInfo->PixelInformation.GreenSize; FrameBufferResource->Pixels.RedShift = FrameBufferModeInfo->PixelInformation.RedShift; FrameBufferResource->Pixels.RedSize = FrameBufferModeInfo->PixelInformation.RedSize; FrameBufferResource->Pixels.ReservedShift = FrameBufferModeInfo->PixelInformation.ReservedShift; FrameBufferResource->Pixels.ReservedSize = FrameBufferModeInfo->PixelInformation.ReservedSize; } XTCDECL EFI_STATUS Xtos::GetMemoryDescriptorList(IN PXTBL_PAGE_MAPPING PageMap, IN EFI_PHYSICAL_ADDRESS PhysicalBase, IN PVOID VirtualBase, OUT PLIST_ENTRY MemoryDescriptorList) { PLOADER_MEMORY_DESCRIPTOR Descriptor; PXTBL_MEMORY_MAPPING MemoryMapping; PLIST_ENTRY ListEntry; /* Initialize the descriptor pointer to the start of the allocated physical buffer */ Descriptor = (PLOADER_MEMORY_DESCRIPTOR)PhysicalBase; /* Get the first entry from the internal boot loader memory map */ ListEntry = PageMap->MemoryMap.Flink; /* Iterate through the internal memory map and populate the loader descriptor list */ while(ListEntry != &PageMap->MemoryMap) { /* Retrieve the internal memory mapping record from the current list entry */ MemoryMapping = CONTAIN_RECORD(ListEntry, XTBL_MEMORY_MAPPING, ListEntry); /* Transfer memory type and address information to the kernel descriptor */ Descriptor->MemoryType = MemoryMapping->MemoryType; Descriptor->BasePage = (UINT_PTR)(MemoryMapping->PhysicalAddress / EFI_PAGE_SIZE); Descriptor->PageCount = (ULONG)MemoryMapping->NumberOfPages; /* Link the entry */ XtLdrProtocol->LinkedList.InsertTail(MemoryDescriptorList, &Descriptor->ListEntry); /* Move to the next slot in the allocated buffer */ Descriptor++; ListEntry = ListEntry->Flink; } /* Convert all physical link pointers in the list to their corresponding virtual addresses */ XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, MemoryDescriptorList, (PVOID)PhysicalBase, VirtualBase); /* Return success */ return STATUS_EFI_SUCCESS; } XTCDECL EFI_STATUS Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap, IN EFI_PHYSICAL_ADDRESS PhysicalBase, IN PVOID VirtualBase, IN PVOID FrameBufferVirtualBase, OUT PLIST_ENTRY SystemResourcesList) { XTSTATUS Status; EFI_HANDLE ProtocolHandle; EFI_GUID AcpiGuid = XT_ACPI_PROTOCOL_GUID; EFI_GUID FrameBufGuid = XT_FRAMEBUFFER_PROTOCOL_GUID; PXTBL_ACPI_PROTOCOL AcpiProtocol; PXTBL_FRAMEBUFFER_PROTOCOL FrameBufProtocol; XTBL_FRAMEBUFFER_MODE_INFORMATION FbModeInfo; EFI_PHYSICAL_ADDRESS FbAddress; EFI_PHYSICAL_ADDRESS OriginalPhysicalBase; ULONG_PTR FbSize; PSYSTEM_RESOURCE_FRAMEBUFFER FrameBufferResource; PSYSTEM_RESOURCE_ACPI AcpiResource; /* Save original physical base */ OriginalPhysicalBase = PhysicalBase; AcpiResource = (PSYSTEM_RESOURCE_ACPI)PhysicalBase; XtLdrProtocol->Memory.ZeroMemory(AcpiResource, sizeof(SYSTEM_RESOURCE_ACPI)); /* Load ACPI protocol */ Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&AcpiProtocol, &AcpiGuid); if(Status != STATUS_EFI_SUCCESS) { return Status; } AcpiResource->Header.ResourceType = SystemResourceAcpi; AcpiResource->Header.ResourceSize = sizeof(SYSTEM_RESOURCE_ACPI); /* Get APIC and XSDP/RSDP addresses */ AcpiProtocol->GetApicBase(&AcpiResource->ApicBase); AcpiProtocol->GetAcpiDescriptionPointer(&AcpiResource->Header.PhysicalAddress); /* No need to map ACPI */ AcpiResource->Header.VirtualAddress = 0; XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &AcpiResource->Header.ListEntry); /* Close ACPI protocol */ XtLdrProtocol->Protocol.Close(&ProtocolHandle, &AcpiGuid); PhysicalBase = PhysicalBase + sizeof(SYSTEM_RESOURCE_ACPI); FrameBufferResource = (PSYSTEM_RESOURCE_FRAMEBUFFER)PhysicalBase; XtLdrProtocol->Memory.ZeroMemory(FrameBufferResource, sizeof(SYSTEM_RESOURCE_FRAMEBUFFER)); /* Load FrameBuffer protocol */ Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&FrameBufProtocol, &FrameBufGuid); if(Status == STATUS_EFI_SUCCESS) { /* Get FrameBuffer information */ Status = FrameBufProtocol->GetDisplayInformation(&FbAddress, &FbSize, &FbModeInfo); if(Status == STATUS_EFI_SUCCESS) { /* Store information about FrameBuffer device */ GetDisplayInformation(FrameBufferResource, &FbAddress, &FbSize, &FbModeInfo); } } if(Status != STATUS_EFI_SUCCESS) { return Status; } /* Assign the pre-mapped virtual address to the resource block */ FrameBufferResource->Header.VirtualAddress = FrameBufferVirtualBase; XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid); XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &FrameBufferResource->Header.ListEntry); /* Convert list pointers to virtual */ XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, SystemResourcesList, (PVOID)OriginalPhysicalBase, VirtualBase); /* Return success */ return STATUS_EFI_SUCCESS; } /** * Checks if APIC is present in the system and finds its base address. * * @param MemoryMappings * Supplies a pointer to linked list containing all memory mappings. * * @return This routine returns an EFI status code. * * @since XT 1.0 */ XTCDECL EFI_STATUS Xtos::InitializeApicBase(IN PXTBL_PAGE_MAPPING PageMap) { EFI_GUID AcpiGuid = XT_ACPI_PROTOCOL_GUID; PXTBL_ACPI_PROTOCOL AcpiProtocol; EFI_HANDLE ProtocolHandle; PVOID ApicBaseAddress; EFI_STATUS Status; /* Open ACPI protocol */ Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&AcpiProtocol, &AcpiGuid); if(Status != STATUS_EFI_SUCCESS) { /* ACPI protocol not found */ return Status; } /* Get APIC base address */ Status = AcpiProtocol->GetApicBase(&ApicBaseAddress); if(Status != STATUS_EFI_SUCCESS) { /* Failed to get APIC base address */ return Status; } /* Map APIC base address */ XtLdrProtocol->Memory.MapVirtualMemory(PageMap, APIC_BASE, (ULONGLONG)ApicBaseAddress, 1, LoaderFirmwarePermanent); return STATUS_EFI_SUCCESS; } /** * Initializes and maps the kernel initialization block. * * @param MemoryMappings * Supplies a pointer to linked list containing all memory mappings. * * @param VirtualAddress * Supplies a pointer to the next valid, free and available virtual address. * * @return This routine returns a status code. * * @since XT 1.0 */ XTCDECL EFI_STATUS Xtos::InitializeLoaderBlock(IN PXTBL_PAGE_MAPPING PageMap, IN OUT PVOID *VirtualAddress, IN PXTBL_BOOT_PARAMETERS Parameters) { EFI_PHYSICAL_ADDRESS FbPhysicalAddress, PhysicalBlock, PhysicalDescriptor, PhysicalResources; PVOID FbVirtualAddress, VirtualBlock, VirtualResources, VirtualDescriptor; UINT BlockPages, DescriptorPages, FbPages, ParametersSize, ResourcesPages; XTBL_FRAMEBUFFER_MODE_INFORMATION FbModeInfo; PXTBL_FRAMEBUFFER_PROTOCOL FrameBufProtocol; PKERNEL_INITIALIZATION_BLOCK LoaderBlock; EFI_HANDLE ProtocolHandle; EFI_STATUS Status; ULONG_PTR FbSize; EFI_GUID FrameBufGuid = XT_FRAMEBUFFER_PROTOCOL_GUID; /* Initialize Framebuffer information */ FbPhysicalAddress = 0; FbSize = 0; FbVirtualAddress = NULLPTR; FbPages = 0; /* Calculate size of parameters */ ParametersSize = (XtLdrProtocol->WideString.Length(Parameters->Parameters, 0) + 1) * sizeof(WCHAR); /* Calculate number of pages needed for initialization block */ BlockPages = EFI_SIZE_TO_PAGES(sizeof(KERNEL_INITIALIZATION_BLOCK) + ParametersSize); ResourcesPages = EFI_SIZE_TO_PAGES(sizeof(SYSTEM_RESOURCE_ACPI) + sizeof(SYSTEM_RESOURCE_FRAMEBUFFER)); /* Query Framebuffer size for allocation */ if(XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&FrameBufProtocol, &FrameBufGuid) == STATUS_EFI_SUCCESS) { /* Get FrameBuffer information */ FrameBufProtocol->GetDisplayInformation(&FbPhysicalAddress, &FbSize, &FbModeInfo); XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid); } FbPages = EFI_SIZE_TO_PAGES(FbSize); /* Add padding to MapSize to account for the ledger mappings */ DescriptorPages = EFI_SIZE_TO_PAGES((PageMap->MapSize + 16) * sizeof(LOADER_MEMORY_DESCRIPTOR)); /* Allocate memory for the kernel initialization block and boot parameters */ Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, BlockPages, &PhysicalBlock); if(Status != STATUS_EFI_SUCCESS) { /* Memory allocation failure, return status code */ return Status; } /* Allocate memory for the system resources data structures */ Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, ResourcesPages, &PhysicalResources); if(Status != STATUS_EFI_SUCCESS) { /* Memory allocation failure, return status code */ return Status; } /* Allocate memory for the memory descriptor list */ Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, DescriptorPages, &PhysicalDescriptor); if(Status != STATUS_EFI_SUCCESS) { /* Memory allocation failure, return status code */ return Status; } /* Map the Kernel Initialization Block into virtual memory and advance the virtual address pointer */ VirtualBlock = *VirtualAddress; XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)VirtualBlock, PhysicalBlock, BlockPages, LoaderSystemBlock); *VirtualAddress = (PUINT8)*VirtualAddress + (BlockPages * EFI_PAGE_SIZE); /* Map the system resources physical memory into virtual address space and update the allocation pointer */ VirtualResources = *VirtualAddress; XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)VirtualResources, PhysicalResources, ResourcesPages, LoaderFirmwarePermanent); *VirtualAddress = (PUINT8)*VirtualAddress + (ResourcesPages * EFI_PAGE_SIZE); /* Check if a framebuffer was detected and requires memory mapping */ if(FbPages > 0) { /* Map the framebuffer physical memory range into virtual address space */ FbVirtualAddress = *VirtualAddress; XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)FbVirtualAddress, FbPhysicalAddress, FbPages, LoaderFirmwarePermanent); *VirtualAddress = (PUINT8)*VirtualAddress + (FbPages * EFI_PAGE_SIZE); } /* Map the allocated physical memory for memory descriptors into the virtual address space */ VirtualDescriptor = *VirtualAddress; XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)VirtualDescriptor, PhysicalDescriptor, DescriptorPages, LoaderMemoryData); *VirtualAddress = (PUINT8)*VirtualAddress + (DescriptorPages * EFI_PAGE_SIZE); /* Set basic loader block properties */ XtLdrProtocol->Memory.ZeroMemory((PVOID)PhysicalBlock, sizeof(KERNEL_INITIALIZATION_BLOCK) + ParametersSize); LoaderBlock = (PKERNEL_INITIALIZATION_BLOCK)PhysicalBlock; LoaderBlock->BlockSize = sizeof(KERNEL_INITIALIZATION_BLOCK); LoaderBlock->BlockVersion = INITIALIZATION_BLOCK_VERSION; LoaderBlock->ProtocolVersion = BOOT_PROTOCOL_VERSION; /* Set LoaderInformation block properties */ LoaderBlock->LoaderInformation.DbgPrint = (PVOID)XtLdrProtocol->Debug.Print; /* Set FirmwareInformation block properties */ LoaderBlock->FirmwareInformation.FirmwareType = SystemFirmwareEfi; // LoaderBlock->FirmwareInformation.EfiFirmware.EfiVersion = EfiSystemTable->Hdr.Revision; LoaderBlock->FirmwareInformation.EfiFirmware.EfiRuntimeServices = NULLPTR; /* Copy parameters to kernel initialization block */ LoaderBlock->KernelParameters = (PWCHAR)((UINT_PTR)VirtualBlock + sizeof(KERNEL_INITIALIZATION_BLOCK)); XtLdrProtocol->Memory.CopyMemory((PVOID)((UINT_PTR)LoaderBlock + sizeof(KERNEL_INITIALIZATION_BLOCK)), Parameters->Parameters, ParametersSize); /* HACK: Commit page map to avoid memory leaks (AGAIN!) */ XtLdrProtocol->Memory.CommitPageMap(PageMap); /* Initialize system resources list */ XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->SystemResourcesListHead); Status = GetSystemResourcesList(PageMap, PhysicalResources, VirtualResources, FbVirtualAddress, &LoaderBlock->SystemResourcesListHead); if(Status != STATUS_EFI_SUCCESS) { /* Failed to initialize system resources list, return status code */ return Status; } /* Initialize memory descriptor list */ XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->MemoryDescriptorListHead); Status = GetMemoryDescriptorList(PageMap, PhysicalDescriptor, VirtualDescriptor, &LoaderBlock->MemoryDescriptorListHead); if(Status != STATUS_EFI_SUCCESS) { /* Failed to initialize memory descriptor list, return status code */ return Status; } /* Set boot image size */ LoaderBlock->BootImageSize = (PFN_NUMBER)(((ULONGLONG)*VirtualAddress - KSEG0_BASE) / EFI_PAGE_SIZE); /* Return success */ return STATUS_EFI_SUCCESS; } XTCDECL EFI_STATUS Xtos::InitializeModule(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 XTOS boot protocol */ BootProtocol.BootSystem = Xtos::BootSystem; /* Register XTOS boot protocol */ XtLdrProtocol->Boot.RegisterProtocol(L"XTOS", &Guid); /* Install XTOS protocol */ return XtLdrProtocol->Protocol.Install(&BootProtocol, &Guid); } /** * Loads XTOS PE/COFF 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 PE/COFF 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 PE/COFF image context will be stored. * * @return This routine returns a status code. * * @since XT 1.0 */ XTCDECL EFI_STATUS Xtos::LoadModule(IN PEFI_FILE_HANDLE SystemDir, IN PWCHAR FileName, IN PVOID VirtualAddress, IN LOADER_MEMORY_TYPE MemoryType, OUT PPECOFF_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 PE/COFF image file */ Status = PeCoffProtocol->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 PE/COFF image machine type compatibility */ PeCoffProtocol->GetMachineType(*ImageContext, &MachineType); if(MachineType != _ARCH_IMAGE_MACHINE_TYPE) { /* Machine type mismatch */ XtLdrProtocol->Debug.Print(L"ERROR: Loaded incompatible PE/COFF image (machine type mismatch)\n"); return STATUS_EFI_INCOMPATIBLE_VERSION; } /* Check PE/COFF image subsystem */ PeCoffProtocol->GetSubSystem(*ImageContext, &SubSystem); if(SubSystem != PECOFF_IMAGE_SUBSYSTEM_XT_NATIVE_KERNEL && SubSystem != PECOFF_IMAGE_SUBSYSTEM_XT_NATIVE_APPLICATION && SubSystem != PECOFF_IMAGE_SUBSYSTEM_XT_NATIVE_DRIVER) { XtLdrProtocol->Debug.Print(L"WARNING: Loaded PE/COFF image with non-XT subsystem set\n"); } /* Print debug message */ XtLdrProtocol->Debug.Print(L"Loaded %S at PA: %P, VA: %P\n", FileName, (*ImageContext)->PhysicalAddress, (*ImageContext)->VirtualAddress); /* Return success */ return STATUS_EFI_SUCCESS; } /** * 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 Xtos::RunBootSequence(IN PEFI_FILE_HANDLE BootDir, IN PXTBL_BOOT_PARAMETERS Parameters) { EFI_GUID LoadedImageGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; EFI_GUID FrameBufGuid = XT_FRAMEBUFFER_PROTOCOL_GUID; PKERNEL_INITIALIZATION_BLOCK KernelParameters; PXTBL_FRAMEBUFFER_PROTOCOL FrameBufProtocol; PPECOFF_IMAGE_CONTEXT ImageContext = NULLPTR; PEFI_LOADED_IMAGE_PROTOCOL ImageProtocol; PVOID VirtualAddress; PXT_ENTRY_POINT KernelEntryPoint; EFI_HANDLE ProtocolHandle; EFI_STATUS Status; XTBL_PAGE_MAPPING PageMap; BOOLEAN IdentityMapping; /* Initialize XTOS startup sequence */ XtLdrProtocol->Debug.Print(L"Initializing XTOS startup sequence\n"); /* Load FrameBuffer protocol */ Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&FrameBufProtocol, &FrameBufGuid); if(Status == STATUS_EFI_SUCCESS) { /* Make sure FrameBuffer is initialized */ FrameBufProtocol->Initialize(); FrameBufProtocol->SetScreenResolution(0, 0); } /* Close FrameBuffer protocol */ XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid); /* Determine whether to use a sequential or an identity mapping strategy */ IdentityMapping = DetermineMappingStrategy(); /* Set base virtual memory area for the kernel mappings */ VirtualAddress = (PVOID)(KSEG0_BASE); /* Initialize virtual memory mappings */ XtLdrProtocol->Memory.InitializePageMap(&PageMap, DeterminePagingLevel(Parameters->Parameters), Size4K); /* Map all EFI memory regions */ Status = XtLdrProtocol->Memory.MapEfiMemory(&PageMap, &VirtualAddress, IdentityMapping, NULLPTR); if(Status != STATUS_EFI_SUCCESS) { /* Mapping failed */ return Status; } /* Check mapping strategy */ if(IdentityMapping) { /* Adjust virtual address to skip the identity-mapped physical range */ VirtualAddress = (PVOID)((ULONGLONG)VirtualAddress + 0x800000000); } /* Load the kernel */ Status = LoadModule(BootDir, Parameters->KernelFile, VirtualAddress, LoaderSystemCode, &ImageContext); if(Status != STATUS_EFI_SUCCESS) { /* Failed to load the kernel */ return Status; } /* Add kernel image memory mapping */ Status = XtLdrProtocol->Memory.MapVirtualMemory(&PageMap, (ULONGLONG)ImageContext->VirtualAddress, (ULONGLONG)ImageContext->PhysicalAddress, ImageContext->ImagePages, LoaderSystemCode); if(Status != STATUS_EFI_SUCCESS) { return Status; } /* Set next valid virtual address right after the kernel */ VirtualAddress = (PUINT8)VirtualAddress + (ImageContext->ImagePages * EFI_PAGE_SIZE); /* Find and map APIC base address */ Status = InitializeApicBase(&PageMap); if(Status != STATUS_EFI_SUCCESS) { /* Failed to setup kernel initialization block */ XtLdrProtocol->Debug.Print(L"Failed to initialize APIC (Status Code: 0x%zX)\n", Status); return Status; } /* Build page map */ Status = BuildPageMap(&PageMap); if(Status != STATUS_EFI_SUCCESS) { XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); return Status; } /* Commit mappings */ Status = XtLdrProtocol->Memory.CommitPageMap(&PageMap); if(Status != STATUS_EFI_SUCCESS) { XtLdrProtocol->Debug.Print(L"Failed to commit hardware mappings (Pass 1)\n"); return Status; } /* Store virtual address of kernel initialization block for future kernel call */ KernelParameters = (PKERNEL_INITIALIZATION_BLOCK)VirtualAddress; /* Setup and map kernel initialization block */ Status = InitializeLoaderBlock(&PageMap, &VirtualAddress, Parameters); if(Status != STATUS_EFI_SUCCESS) { /* Failed to setup kernel initialization block */ XtLdrProtocol->Debug.Print(L"Failed to setup kernel initialization block (Status Code: 0x%zX)\n", Status); return Status; } /* HACK: Commit mappings again to include the kernel initialization block */ Status = XtLdrProtocol->Memory.CommitPageMap(&PageMap); if(Status != STATUS_EFI_SUCCESS) { /* Failed to build page map */ XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); return Status; } /* Get kernel entry point */ PeCoffProtocol->GetEntryPoint(ImageContext, (PVOID*)&KernelEntryPoint); /* Close boot directory handle */ BootDir->Close(BootDir); /* Enable paging */ XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&ImageProtocol, &LoadedImageGuid); Status = EnablePaging(&PageMap); if(Status != STATUS_EFI_SUCCESS) { /* Failed to enable paging */ XtLdrProtocol->Debug.Print(L"Failed to enable paging (Status Code: 0x%zX)\n", Status); return Status; } /* Call XTOS kernel */ XtLdrProtocol->Debug.Print(L"Booting the XTOS kernel\n"); KernelEntryPoint(KernelParameters); /* 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) { /* Initialize XTOS module */ return Xtos::InitializeModule(ImageHandle, SystemTable); }