Files
exectos/boot/xtldr/modules/xtos_o/xtos.cc
Aiken Harris 032cab7f2f
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in 35s
Builds / ExectOS (i686, release) (push) Successful in 31s
Builds / ExectOS (i686, debug) (push) Successful in 55s
Builds / ExectOS (amd64, debug) (push) Successful in 57s
Update function documentation and remove debug prints
2026-01-12 19:26:07 +01:00

843 lines
28 KiB
C++

/**
* 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 <belliash@codingworkshop.eu.org>
*/
#include <xtos.hh>
/* XTOS module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
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,
OUT PLIST_ENTRY MemoryDescriptorList)
{
EFI_PHYSICAL_ADDRESS Address;
EFI_STATUS Status;
ULONGLONG Pages;
Pages = (ULONGLONG)EFI_SIZE_TO_PAGES((PageMap->MapSize + 1) * sizeof(LOADER_MEMORY_DESCRIPTOR));
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, Pages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
return Status;
}
Status = MapMemory(PageMap, Address, Pages, LoaderMemoryData, TRUE);
if(Status != STATUS_EFI_SUCCESS)
{
XtLdrProtocol->Memory.FreePages(Address, Pages);
return Status;
}
PVOID PhysicalBase = (PVOID)Address;
PVOID CurrentDescriptor = PhysicalBase;
PLIST_ENTRY ListEntry;
ListEntry = PageMap->MemoryMap.Flink;
while(ListEntry != &PageMap->MemoryMap)
{
PXTBL_MEMORY_MAPPING MemoryMapping = CONTAIN_RECORD(ListEntry, XTBL_MEMORY_MAPPING, ListEntry);
PLOADER_MEMORY_DESCRIPTOR MemoryDescriptor = (PLOADER_MEMORY_DESCRIPTOR)CurrentDescriptor;
MemoryDescriptor->MemoryType = MemoryMapping->MemoryType;
MemoryDescriptor->BasePage = (UINT_PTR)MemoryMapping->PhysicalAddress / EFI_PAGE_SIZE;
MemoryDescriptor->PageCount = MemoryMapping->NumberOfPages;
XtLdrProtocol->LinkedList.InsertTail(MemoryDescriptorList, &MemoryDescriptor->ListEntry);
CurrentDescriptor = (PUINT8)CurrentDescriptor + sizeof(LOADER_MEMORY_DESCRIPTOR);
ListEntry = ListEntry->Flink;
}
PhysicalListToVirtual(MemoryDescriptorList);
return STATUS_EFI_SUCCESS;
}
XTCDECL
EFI_STATUS
Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap,
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;
ULONG_PTR FbSize;
UINT FrameBufferPages;
PSYSTEM_RESOURCE_FRAMEBUFFER FrameBufferResource;
PSYSTEM_RESOURCE_ACPI AcpiResource;
ULONGLONG Pages;
EFI_PHYSICAL_ADDRESS Address;
Pages = (ULONGLONG)EFI_SIZE_TO_PAGES(sizeof(SYSTEM_RESOURCE_ACPI) + sizeof(SYSTEM_RESOURCE_FRAMEBUFFER));
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, Pages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
return Status;
}
Status = MapMemory(PageMap, Address, Pages, LoaderFirmwarePermanent, TRUE);
if(Status != STATUS_EFI_SUCCESS)
{
XtLdrProtocol->Memory.FreePages(Address, Pages);
return Status;
}
AcpiResource = (PSYSTEM_RESOURCE_ACPI)Address;
XtLdrProtocol->Memory.ZeroMemory(AcpiResource, sizeof(SYSTEM_RESOURCE_ACPI));
/* Load FrameBuffer 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((PVOID *)&AcpiResource->ApicBase);
AcpiProtocol->GetAcpiDescriptionPointer(&AcpiResource->Header.PhysicalAddress);
/* No need to map ACPI */
AcpiResource->Header.VirtualAddress = 0;
XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &AcpiResource->Header.ListEntry);
/* Close FrameBuffer protocol */
XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid);
Address = Address + sizeof(SYSTEM_RESOURCE_ACPI);
FrameBufferResource = (PSYSTEM_RESOURCE_FRAMEBUFFER)Address;
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;
}
/* Calculate pages needed to map framebuffer */
FrameBufferPages = EFI_SIZE_TO_PAGES(FbSize);
/* Rewrite framebuffer address by using virtual address */
FrameBufferResource->Header.VirtualAddress = PhysicalAddressToVirtual(FrameBufferResource->Header.PhysicalAddress);
/* Map frame buffer memory */
XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)FrameBufferResource->Header.VirtualAddress,
(ULONGLONG)FrameBufferResource->Header.PhysicalAddress,
FrameBufferPages, LoaderHardwareCachedMemory);
/* Close FrameBuffer protocol */
XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid);
XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &FrameBufferResource->Header.ListEntry);
PhysicalListToVirtual(SystemResourcesList);
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;
EFI_PHYSICAL_ADDRESS 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((PVOID *)&ApicBaseAddress);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get APIC base address */
return Status;
}
/* Map APIC base address */
XtLdrProtocol->Memory.MapVirtualMemory(PageMap, APIC_BASE, ApicBaseAddress, 1, LoaderFirmwarePermanent);
return STATUS_EFI_SUCCESS;
}
/**
* Initializes and maps the kernel initialization block.
*
* @param PageMap
* Supplies a pointer to the page map.
*
* @param KernelParameters
* Returns a pointer to the kernel initialization block.
*
* @param Parameters
* Supplies a list of input parameters passed to the kernel.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::InitializeLoaderBlock(IN PXTBL_PAGE_MAPPING PageMap,
OUT PKERNEL_INITIALIZATION_BLOCK *KernelParameters,
IN PXTBL_BOOT_PARAMETERS Parameters)
{
PKERNEL_INITIALIZATION_BLOCK LoaderBlock;
EFI_PHYSICAL_ADDRESS Address;
EFI_STATUS Status;
UINT BlockPages;
UINT ParametersSize;
ULONGLONG LoaderBlockVa;
/* 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);
/* Allocate memory for kernel initialization block */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, BlockPages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Initialize and zero-fill kernel initialization block */
LoaderBlock = (PKERNEL_INITIALIZATION_BLOCK)(UINT_PTR)Address;
XtLdrProtocol->Memory.ZeroMemory(LoaderBlock, sizeof(KERNEL_INITIALIZATION_BLOCK) + ParametersSize);
/* Set basic loader block properties */
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;
/* Get the KSEG0-based virtual address for the loader block */
LoaderBlockVa = (ULONGLONG)PhysicalAddressToVirtual(LoaderBlock);
*KernelParameters = (PKERNEL_INITIALIZATION_BLOCK)LoaderBlockVa;
/* Copy parameters to kernel initialization block */
LoaderBlock->KernelParameters = (PWCHAR)(LoaderBlockVa + sizeof(KERNEL_INITIALIZATION_BLOCK));
XtLdrProtocol->Memory.CopyMemory((PVOID)((UINT_PTR)LoaderBlock + sizeof(KERNEL_INITIALIZATION_BLOCK)),
Parameters->Parameters,
ParametersSize);
/* Map kernel initialization block */
Status = MapMemory(PageMap, (ULONGLONG)LoaderBlock, BlockPages, LoaderSystemBlock, TRUE);
if(Status != STATUS_EFI_SUCCESS)
{
return Status;
}
XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->SystemResourcesListHead);
GetSystemResourcesList(PageMap, &LoaderBlock->SystemResourcesListHead);
/* Initialize memory descriptor list */
XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->MemoryDescriptorListHead);
GetMemoryDescriptorList(PageMap, &LoaderBlock->MemoryDescriptorListHead);
/* 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 MemoryType
* Supplies the type of memory to be assigned to the memory descriptor.
*
* @param PageMap
* Supplies pointer to the memory area where memory mappings will be stored.
*
* @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 LOADER_MEMORY_TYPE MemoryType,
IN OUT PXTBL_PAGE_MAPPING PageMap,
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 into memory */
Status = PeCoffProtocol->LoadImage(ModuleHandle, MemoryType, NULLPTR, (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;
}
/* Relocate the PE/COFF image file */
Status = PeCoffProtocol->RelocateImage(*ImageContext, KSEG0_BASE + (ULONGLONG)(*ImageContext)->PhysicalAddress);
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to relocate the file */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to relocate '%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");
}
/* Ensure that page map is provided */
if(PageMap != NULLPTR)
{
/* Add kernel image memory mapping */
Status = MapMemory(PageMap, (ULONGLONG)(*ImageContext)->PhysicalAddress,
(*ImageContext)->ImagePages, LoaderSystemCode, TRUE);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to map kernel image memory */
return Status;
}
}
/* Print debug message */
XtLdrProtocol->Debug.Print(L"Loaded '%S' at PA: %P, VA: %P\n", FileName, (*ImageContext)->PhysicalAddress,
PhysicalAddressToVirtual((*ImageContext)->VirtualAddress));
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Adds a physical to virtual address mapping.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param PhysicalAddress
* Supplies a physical address which will be mapped.
*
* @param NumberOfPages
* Supplies a number of pages that will be mapped.
*
* @param MemoryType
* Supplies the type of mapped memory that will be assigned to the memory descriptor.
*
* @param KernelMapping
* Supplies a flag that indicates if mapping should be done in kernel mode or if identity mapping should be used.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::MapMemory(IN OUT PXTBL_PAGE_MAPPING PageMap,
IN ULONGLONG Address,
IN ULONG NumberOfPages,
IN LOADER_MEMORY_TYPE MemoryType,
IN BOOLEAN KernelMapping)
{
ULONGLONG BaseAddress;
/* Check if kernel mode mapping */
if(KernelMapping)
{
/* Map memory based on kernel base address */
BaseAddress = KSEG0_BASE;
}
else
{
/* Use identity mapping */
BaseAddress = (ULONGLONG)NULLPTR;
}
/* Map memory and return status code */
return XtLdrProtocol->Memory.MapVirtualMemory(PageMap, BaseAddress + Address, Address, NumberOfPages, MemoryType);
}
/**
* Converts physical address to virtual address.
*
* @param PhysicalAddress
* Specifies physical address that will be converted to virtual address.
*
* @return This routine returns a mapped virtual address.
*
* @since XT 1.0
*/
XTCDECL
PVOID
Xtos::PhysicalAddressToVirtual(PVOID PhysicalAddress)
{
return (PVOID)((ULONG_PTR)PhysicalAddress | KSEG0_BASE);
}
/**
* Converts whole linked list addressing from physical to virtual for future use after enabling paging.
*
* @param ListHead
* Supplies a pointer to a structure that serves as the list header.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::PhysicalListToVirtual(IN OUT PLIST_ENTRY ListHead)
{
PLIST_ENTRY ListEntry, NextEntry;
/* Make sure list is properly initialized */
if(ListHead->Flink == 0 || ListHead->Blink == 0)
{
/* List not initialized, return error code */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Iterate through the list */
ListEntry = ListHead->Flink;
while(ListEntry != ListHead)
{
/* Store the next entry */
NextEntry = ListEntry->Flink;
/* Convert the list entry */
ListEntry->Flink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListEntry->Flink);
ListEntry->Blink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListEntry->Blink);
/* Get the next element */
ListEntry = NextEntry;
}
/* Convert the list head */
ListHead->Flink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListHead->Flink);
ListHead->Blink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListHead->Blink);
/* 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;
PXT_ENTRY_POINT KernelEntryPoint;
EFI_HANDLE ProtocolHandle;
EFI_STATUS Status;
XTBL_PAGE_MAPPING PageMap;
/* 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);
/* Initialize virtual memory mappings */
XtLdrProtocol->Memory.InitializePageMap(&PageMap, DeterminePagingLevel(Parameters->Parameters), Size4K);
PVOID VirtualMemoryArea = (PVOID)KSEG0_BASE;
Status = XtLdrProtocol->Memory.MapEfiMemory(&PageMap, &VirtualMemoryArea, NULLPTR);
if(Status != STATUS_EFI_SUCCESS)
{
return Status;
}
/* Load the kernel */
Status = LoadModule(BootDir, Parameters->KernelFile, LoaderSystemCode, &PageMap, &ImageContext);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load the kernel */
return Status;
}
/* 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;
}
/* Setup and map kernel initialization block */
Status = InitializeLoaderBlock(&PageMap, &KernelParameters, 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;
}
/* 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);
}