diff --git a/sdk/xtdk/xtblapi.h b/sdk/xtdk/xtblapi.h index 5da87e8..78b3e7b 100644 --- a/sdk/xtdk/xtblapi.h +++ b/sdk/xtdk/xtblapi.h @@ -32,15 +32,17 @@ #include /* Architecture dependent XT kernel data types */ -// #include ARCH_HEADER(artypes.h) -// #include ARCH_HEADER(hltypes.h) +#include ARCH_HEADER(artypes.h) +#include ARCH_HEADER(hltypes.h) +#include ARCH_HEADER(ketypes.h) +#include ARCH_HEADER(mmtypes.h) /* XT Kernel runtime routines */ #include #include /* Architecture specific XT kernel routines */ -// #include ARCH_HEADER(arfuncs.h) +#include ARCH_HEADER(arfuncs.h) // #include ARCH_HEADER(hlfuncs.h) /* Boot Manager specific structures */ diff --git a/xtldr2/modules/CMakeLists.txt b/xtldr2/modules/CMakeLists.txt index ffdddb3..136fbbb 100644 --- a/xtldr2/modules/CMakeLists.txt +++ b/xtldr2/modules/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(dummy) add_subdirectory(fb_o) add_subdirectory(pecoff_o) +add_subdirectory(xtos_o) diff --git a/xtldr2/modules/xtos_o/CMakeLists.txt b/xtldr2/modules/xtos_o/CMakeLists.txt new file mode 100644 index 0000000..f157240 --- /dev/null +++ b/xtldr2/modules/xtos_o/CMakeLists.txt @@ -0,0 +1,28 @@ +# XT Boot Loader +PROJECT(XTLDR_XTOS_O) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_XTOS_O_SOURCE_DIR}/includes) + +# Specify list of source code files +list(APPEND XTLDR_XTOS_O_SOURCE + ${XTLDR_XTOS_O_SOURCE_DIR}/${ARCH}/memory.c + ${XTLDR_XTOS_O_SOURCE_DIR}/memory.c + ${XTLDR_XTOS_O_SOURCE_DIR}/xtos.c) + +# Link bootloader executable +add_executable(xtos_o ${XTLDR_XTOS_O_SOURCE}) + +# Add linker libraries +target_link_libraries(xtos_o libxtos libxtldr) + +# Set proper binary name and install target +set_target_properties(xtos_o PROPERTIES SUFFIX .efi) +set_install_target(xtos_o efi/boot/xtldr/modules) + +# Set module entrypoint and subsystem +set_entrypoint(xtos_o "XtLdrModuleMain") +set_linker_map(xtos_o TRUE) +set_subsystem(xtos_o efi_boot_service_driver) diff --git a/xtldr2/modules/xtos_o/amd64/memory.c b/xtldr2/modules/xtos_o/amd64/memory.c new file mode 100644 index 0000000..3a21055 --- /dev/null +++ b/xtldr2/modules/xtos_o/amd64/memory.c @@ -0,0 +1,305 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/amd64/memory.c + * DESCRIPTION: EFI memory management for AMD64 target + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Builds the actual memory mapping page table and enables paging. This routine exits EFI boot services as well. + * + * @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. + * + * @param ImageProtocol + * A pointer to the EFI loaded image protocol with information about where in memory the loader code was placed. + * + * @param PtePointer + * Supplies a pointer to memory area containing a Page Table Entries (PTE). + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtEnablePaging(IN PLIST_ENTRY MemoryMappings, + IN PVOID VirtualAddress, + IN PEFI_LOADED_IMAGE_PROTOCOL ImageProtocol, + IN PVOID *PtePointer) +{ + PLOADER_MEMORY_MAPPING Mapping; + EFI_PHYSICAL_ADDRESS Address; + PEFI_MEMORY_MAP MemoryMap; + PLIST_ENTRY ListEntry; + EFI_STATUS Status; + + /* Allocate pages for PML4 */ + Status = XtLdrProtocol->Memory.AllocatePages(1, &Address); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure */ + return Status; + } + + /* Assign and zero-fill memory used by page mappings */ + *PtePointer = (PVOID)(UINT_PTR)Address; + RtlZeroMemory(*PtePointer, EFI_PAGE_SIZE); + + /* Map XTLDR code */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, ImageProtocol->ImageBase, ImageProtocol->ImageBase, + EFI_SIZE_TO_PAGES(ImageProtocol->ImageSize), LoaderFirmwareTemporary); + if(Status != STATUS_EFI_SUCCESS) + { + /* Mapping the boot loader code failed */ + return Status; + } + + /* Add page mapping itself to memory mapping */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, NULL, *PtePointer, 1, LoaderMemoryData); + if(Status != STATUS_EFI_SUCCESS) + { + /* Mapping PML4 failed */ + return Status; + } + + /* Iterate through and map all the mappings*/ + XtLdrProtocol->Debug.Print(L"Mapping and dumping EFI memory:\n"); + ListEntry = MemoryMappings->Flink; + while(ListEntry != MemoryMappings) + { + /* Take mapping from the list */ + Mapping = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_MAPPING, ListEntry); + + /* Check if virtual address is set */ + if(Mapping->VirtualAddress) + { + /* Dump memory mapping */ + XtLdrProtocol->Debug.Print(L" Type=%02lu, PhysicalBase=0x%016lx, VirtualBase=0x%016lx, Pages=%lu\n", Mapping->MemoryType, + Mapping->PhysicalAddress, Mapping->VirtualAddress, Mapping->NumberOfPages); + + /* Map memory */ + Status = XtMapVirtualMemory(MemoryMappings, (UINT_PTR)Mapping->VirtualAddress, + (UINT_PTR)Mapping->PhysicalAddress, Mapping->NumberOfPages, PtePointer); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory mapping failed */ + return Status; + } + } + + /* Take next element */ + ListEntry = ListEntry->Flink; + } + + /* Map zero page as well */ + XtMapVirtualMemory(MemoryMappings, 0, 0, 1, PtePointer); + + /* Allocate and zero-fill buffer for EFI memory map */ + XtLdrProtocol->Memory.AllocatePool(sizeof(EFI_MEMORY_MAP), (PVOID*)&MemoryMap); + RtlZeroMemory(MemoryMap, sizeof(EFI_MEMORY_MAP)); + + /* Get EFI memory map and prepare for exiting boot services */ + XtLdrProtocol->Debug.Print(L"Exiting EFI boot services\n"); + Status = XtLdrProtocol->Memory.GetMemoryMap(MemoryMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Unable to get memory map */ + return Status; + } + + /* Exit EFI Boot Services */ + Status = XtLdrProtocol->Util.ExitBootServices(MemoryMap->MapKey); + + /* Check if exitted boot services successfully */ + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to exit boot services */ + XtLdrProtocol->Debug.Print(L"Failed to exit boot services (Status code: %lx)\n", Status); + return STATUS_EFI_ABORTED; + } + + /* Write PML4 to CR3 */ + ArWriteControlRegister(3, (UINT_PTR)*PtePointer); + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * This routine does the actual virtual memory mapping. + * + * @param MemoryMappings + * Supplies a pointer to linked list containing all memory mappings. + * + * @param VirtualAddress + * Supplies a virtual address of the mapping. + * + * @param PhysicalAddress + * Supplies a physical address of the mapping. + * + * @param NumberOfPages + * Supplies a number of the pages of the mapping. + * + * @param PaeExtension + * Specifies whether Physical Address Extension (PAE) is supported by the hardware. Not used on AMD64. + * + * @param PtePointer + * Supplies a pointer to an array of pointers to page table entries. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtMapVirtualMemory(IN PLIST_ENTRY MemoryMappings, + IN UINT_PTR VirtualAddress, + IN UINT_PTR PhysicalAddress, + IN UINT NumberOfPages, + IN OUT PVOID *PtePointer) +{ + PHARDWARE_PTE PageDirectoryPointTable, PageDirectory, PageTable; + UINT Pml4Index, PdpIndex, PdIndex, PtIndex; + EFI_PHYSICAL_ADDRESS Address; + UINT_PTR PageFrameNumber; + EFI_STATUS Status; + UINT64 Pointer; + + /* Set the PFN */ + PageFrameNumber = PhysicalAddress >> EFI_PAGE_SHIFT; + + /* Do the recursive mapping */ + while(NumberOfPages > 0) + { + /* Calculate indices from a virtual address */ + Pml4Index = (VirtualAddress >> 39) & 0x1FF; + PdpIndex = (VirtualAddress >> 30) & 0x1FF; + PdIndex = (VirtualAddress >> 21) & 0x1FF; + PtIndex = (VirtualAddress >> 12) & 0x1FF; + + /* Validate Page Map Level 4 (PML4) */ + if(!((PHARDWARE_PTE)(*PtePointer))[Pml4Index].Valid) + { + /* Allocate pages for the PDPT */ + Status = XtLdrProtocol->Memory.AllocatePages(1, &Address); + if (Status != STATUS_EFI_SUCCESS) { + /* Memory allocation failure */ + return Status; + } + + /* Add new memory mapping */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, NULL, (PVOID)(UINT_PTR)Address, 1, LoaderMemoryData); + if(Status != STATUS_EFI_SUCCESS) { + /* Memory mapping failed */ + return Status; + } + + /* Fill allocated memory with zeros */ + RtlZeroMemory((PVOID)(UINT_PTR)Address, EFI_PAGE_SIZE); + + /* Set paging entry settings */ + ((PHARDWARE_PTE)(*PtePointer))[Pml4Index].PageFrameNumber = Address / EFI_PAGE_SIZE; + ((PHARDWARE_PTE)(*PtePointer))[Pml4Index].Valid = 1; + ((PHARDWARE_PTE)(*PtePointer))[Pml4Index].Write = 1; + PageDirectoryPointTable = (PHARDWARE_PTE)(UINT_PTR)Address; + } + else + { + /* Find Page Directory Point Table (PDPT) */ + Pointer = ((PHARDWARE_PTE)(*PtePointer))[Pml4Index].PageFrameNumber; + Pointer <<= EFI_PAGE_SHIFT; + PageDirectoryPointTable = (PHARDWARE_PTE)(UINT_PTR)Pointer; + } + + /* Validate Page Directory Point Table (PDPT)*/ + if(!PageDirectoryPointTable[PdpIndex].Valid) + { + /* Allocate pages for the PD */ + Status = XtLdrProtocol->Memory.AllocatePages(1, &Address); + if (Status != STATUS_EFI_SUCCESS) { + /* Memory allocation failure */ + return Status; + } + + /* Add new memory mapping */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, NULL, (PVOID)(UINT_PTR)Address, 1, LoaderMemoryData); + if (Status != STATUS_EFI_SUCCESS) { + /* Memory mapping failed */ + return Status; + } + + /* Fill allocated memory with zeros */ + RtlZeroMemory((PVOID)(UINT_PTR)Address, EFI_PAGE_SIZE); + + /* Set paging entry settings */ + PageDirectoryPointTable[PdpIndex].PageFrameNumber = Address / EFI_PAGE_SIZE; + PageDirectoryPointTable[PdpIndex].Valid = 1; + PageDirectoryPointTable[PdpIndex].Write = 1; + PageDirectory = (PHARDWARE_PTE)(UINT_PTR)Address; + } + else + { + /* Find Page Directory (PD) */ + Pointer = PageDirectoryPointTable[PdpIndex].PageFrameNumber; + Pointer <<= EFI_PAGE_SHIFT; + PageDirectory = (PHARDWARE_PTE)(UINT_PTR)Pointer; + } + + /* Validate Page Directory (PD)*/ + if(!PageDirectory[PdIndex].Valid) + { + /* Allocate pages for the PT */ + Status = XtLdrProtocol->Memory.AllocatePages(1, &Address); + if (Status != STATUS_EFI_SUCCESS) { + /* Memory allocation failure */ + return Status; + } + + /* Add new memory mapping */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, NULL, (PVOID)(UINT_PTR)Address, 1, LoaderMemoryData); + if (Status != STATUS_EFI_SUCCESS) { + /* Memory mapping failed */ + return Status; + } + + /* Fill allocated memory with zeros */ + RtlZeroMemory((PVOID)(UINT_PTR)Address, EFI_PAGE_SIZE); + + /* Set paging entry settings */ + PageDirectory[PdIndex].PageFrameNumber = Address / EFI_PAGE_SIZE; + PageDirectory[PdIndex].Valid = 1; + PageDirectory[PdIndex].Write = 1; + PageTable = (PHARDWARE_PTE)(UINT_PTR)Address; + } + else + { + /* Find Page Table (PT) */ + Pointer = PageDirectory[PdIndex].PageFrameNumber; + Pointer <<= EFI_PAGE_SHIFT; + PageTable = (PHARDWARE_PTE)(UINT_PTR)Pointer; + } + + /* Set paging entry settings */ + PageTable[PtIndex].PageFrameNumber = PageFrameNumber; + PageTable[PtIndex].Valid = 1; + PageTable[PtIndex].Write = 1; + + /* Take next virtual address and PFN */ + VirtualAddress += EFI_PAGE_SIZE; + PageFrameNumber++; + + /* Decrease number of pages left */ + NumberOfPages--; + } + + /* Return success */ + return STATUS_EFI_SUCCESS; +} diff --git a/xtldr2/modules/xtos_o/i686/memory.c b/xtldr2/modules/xtos_o/i686/memory.c new file mode 100644 index 0000000..f0d1354 --- /dev/null +++ b/xtldr2/modules/xtos_o/i686/memory.c @@ -0,0 +1,329 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/i686/memory.c + * DESCRIPTION: EFI memory management for i686 target + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Builds the actual memory mapping page table and enables paging. This routine exits EFI boot services as well. + * + * @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. + * + * @param ImageProtocol + * A pointer to the EFI loaded image protocol with information about where in memory the loader code was placed. + * + * @param PtePointer + * Supplies a pointer to memory area containing a Page Table Entries (PTE). + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtEnablePaging(IN PLIST_ENTRY MemoryMappings, + IN PVOID VirtualAddress, + IN PEFI_LOADED_IMAGE_PROTOCOL ImageProtocol, + IN PVOID *PtePointer) +{ + UINT_PTR PhysicalAddress, DescriptorCount; + EFI_PHYSICAL_ADDRESS Address, PDPTAddress = 0; + PCPUID_REGISTERS CpuRegisters = NULL; + PEFI_MEMORY_DESCRIPTOR Descriptor; + PLOADER_MEMORY_MAPPING Mapping; + PEFI_MEMORY_MAP MemoryMap; + PLIST_ENTRY ListEntry; + EFI_STATUS Status; + UINT Index; + + /* Prepare CPUID registers */ + CpuRegisters->Leaf = CPUID_GET_CPU_FEATURES; + CpuRegisters->SubLeaf = 0; + CpuRegisters->Eax = 0; + CpuRegisters->Ebx = 0; + CpuRegisters->Ecx = 0; + CpuRegisters->Edx = 0; + + /* Get CPUID */ + ArCpuId(CpuRegisters); + + /* Store PAE status from the CPUID results */ + if(!(CpuRegisters->Edx & CPUID_FEATURES_EDX_PAE)) + { + /* No PAE support */ + XtLdrProtocol->Debug.Print(L"ERROR: PAE extension not supported by the CPU\n"); + return STATUS_EFI_UNSUPPORTED; + } + + /* Allocate and zero-fill buffer for EFI memory map */ + XtLdrProtocol->Memory.AllocatePool(sizeof(EFI_MEMORY_MAP), (PVOID*)&MemoryMap); + RtlZeroMemory(MemoryMap, sizeof(EFI_MEMORY_MAP)); + + /* Get EFI memory map */ + Status = XtLdrProtocol->Memory.GetMemoryMap(MemoryMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Unable to get memory map */ + return Status; + } + + /* Calculate descriptors count and get first one */ + Descriptor = MemoryMap->Map; + DescriptorCount = MemoryMap->MapSize / MemoryMap->DescriptorSize; + + /* Calculate physical address based on KSEG0 base */ + PhysicalAddress = (UINT_PTR)VirtualAddress - KSEG0_BASE; + + /* Iterate over all descriptors from memory map to find satisfying address for PDPT */ + for(Index = 0; Index < DescriptorCount; Index++) + { + /* Check descriptor if it can be used to store PDPT */ + if((Descriptor->PhysicalStart + ((Descriptor->NumberOfPages - 1) * EFI_PAGE_SIZE) >= PhysicalAddress) && + (Descriptor->Type == EfiConventionalMemory)) + { + /* Use highest address possible */ + if(PhysicalAddress >= Descriptor->PhysicalStart) + { + /* Use physical address */ + PDPTAddress = PhysicalAddress; + } + else + { + /* Use descriptor physical start as PDPT address */ + PDPTAddress = Descriptor->PhysicalStart; + } + + /* Allocate pages for the PDPT address */ + Status = XtLdrProtocol->Memory.AllocatePages(1, &PDPTAddress); + if(Status != STATUS_EFI_SUCCESS) { + return Status; + } + break; + } + + /* Get next descriptor */ + Descriptor = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Descriptor + MemoryMap->DescriptorSize); + } + + /* Make sure PDPT address found */ + if(PDPTAddress == 0) + { + /* No suitable area for PDPT found in EFI memory map */ + return STATUS_EFI_NOT_FOUND; + } + + /* Set virtual address based on new PDPT address mapped to KSEG0 base */ + VirtualAddress = (PVOID)(UINT_PTR)(PDPTAddress + EFI_PAGE_SIZE + KSEG0_BASE); + + /* Set base page frame number */ + Address = 0x100000; + + /* Allocate pages for the PFN */ + Status = XtLdrProtocol->Memory.AllocatePages(4, &Address); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure */ + return Status; + } + + /* Set and zero memory used by page mappings and CR3 */ + *PtePointer = (PVOID)(UINT_PTR)PDPTAddress; + RtlZeroMemory(*PtePointer, EFI_PAGE_SIZE); + RtlZeroMemory((PVOID)Address, EFI_PAGE_SIZE * 4); + + /* Set the page directory into the PDPT and mark it present */ + for(Index = 0; Index < 4; Index++) + { + /* Set paging entry settings */ + ((PHARDWARE_PTE)*PtePointer)[Index].PageFrameNumber = Address / EFI_PAGE_SIZE; + ((PHARDWARE_PTE)*PtePointer)[Index].Valid = 1; + + /* Next valid PFN address */ + Address += EFI_PAGE_SIZE; + } + + /* Map XTLDR code */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, ImageProtocol->ImageBase, ImageProtocol->ImageBase, + EFI_SIZE_TO_PAGES(ImageProtocol->ImageSize), LoaderFirmwareTemporary); + if(Status != STATUS_EFI_SUCCESS) + { + /* Mapping the boot loader code failed */ + return Status; + } + + /* Add page mapping itself to memory mapping */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, NULL, *PtePointer, 1, LoaderMemoryData); + if(Status != STATUS_EFI_SUCCESS) + { + /* Mapping PD failed */ + return Status; + } + + /* Iterate through and map all the mappings */ + XtLdrProtocol->Debug.Print(L"Mapping and dumping EFI memory:\n"); + ListEntry = MemoryMappings->Flink; + while(ListEntry != MemoryMappings) + { + /* Take mapping from the list */ + Mapping = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_MAPPING, ListEntry); + + /* Check if virtual address is set */ + if(Mapping->VirtualAddress) + { + /* Dump memory mapping */ + XtLdrProtocol->Debug.Print(L" Type=%02lu, PhysicalBase=0x%08lx, VirtualBase=0x%08lx, Pages=%lu\n", Mapping->MemoryType, + Mapping->PhysicalAddress, Mapping->VirtualAddress, Mapping->NumberOfPages); + + /* Map memory */ + Status = XtMapVirtualMemory(MemoryMappings, (UINT_PTR)Mapping->VirtualAddress, + (UINT_PTR)Mapping->PhysicalAddress, Mapping->NumberOfPages, PtePointer); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory mapping failed */ + return Status; + } + } + + /* Take next element */ + ListEntry = ListEntry->Flink; + } + + /* Map zero page as well */ + XtMapVirtualMemory(MemoryMappings, 0, 0, 1, PtePointer); + + /* Zero-fill buffer for EFI memory map */ + RtlZeroMemory(MemoryMap, sizeof(EFI_MEMORY_MAP)); + + /* Get EFI memory map and prepare for exiting boot services */ + XtLdrProtocol->Debug.Print(L"Exiting EFI boot services\n"); + Status = XtLdrProtocol->Memory.GetMemoryMap(MemoryMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Unable to get memory map */ + return Status; + } + + /* Exit EFI Boot Services */ + Status = XtLdrProtocol->Util.ExitBootServices(MemoryMap->MapKey); + + /* Check if exitted boot services successfully */ + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to exit boot services */ + XtLdrProtocol->Debug.Print(L"Failed to exit boot services (Status code: %lx)\n", Status); + return STATUS_EFI_ABORTED; + } + + /* Enable Physical Address Extension (PAE) */ + ArWriteControlRegister(4, ArReadControlRegister(4) | CR4_PAE); + + /* Write page mappings to CR3 */ + ArWriteControlRegister(3, (UINT_PTR)*PtePointer); + + /* Enable paging */ + ArWriteControlRegister(0, ArReadControlRegister(0) | CR0_PG); + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * This routine does the actual virtual memory mapping. + * + * @param MemoryMappings + * Supplies a pointer to linked list containing all memory mappings. + * + * @param VirtualAddress + * Supplies a virtual address of the mapping. + * + * @param PhysicalAddress + * Supplies a physical address of the mapping. + * + * @param NumberOfPages + * Supplies a number of the pages of the mapping. + * + * @param PaeExtension + * Specifies whether Physical Address Extension (PAE) is supported by the hardware. + * + * @param PtePointer + * Supplies a pointer to an array of pointers to page table entries. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtMapVirtualMemory(IN PLIST_ENTRY MemoryMappings, + IN UINT_PTR VirtualAddress, + IN UINT_PTR PhysicalAddress, + IN UINT NumberOfPages, + IN OUT PVOID *PtePointer) +{ + EFI_PHYSICAL_ADDRESS Address; + UINT_PTR PageFrameNumber; + PHARDWARE_PTE PageTable, PageDirectory; + EFI_STATUS Status; + unsigned int PdIndex, PtIndex; + + /* Set the PFN */ + PageFrameNumber = PhysicalAddress >> EFI_PAGE_SHIFT; + + /* Do the recursive mapping */ + while(NumberOfPages > 0) + { + /* Find Page Directory and calculate indices from a virtual address */ + PageDirectory = (PHARDWARE_PTE)(UINT_PTR)(((PHARDWARE_PTE)(*PtePointer))[VirtualAddress >> 30].PageFrameNumber * EFI_PAGE_SIZE); + PdIndex = (VirtualAddress >> 21) & 0x1FF; + PtIndex = (VirtualAddress & 0x1FF000) >> 12; + + /* Validate Page Directory */ + if(!PageDirectory[PdIndex].Valid) { + /* Allocate pages for new page table */ + Status = XtLdrProtocol->Memory.AllocatePages(1, &Address); + if(Status != STATUS_EFI_SUCCESS) { + /* Memory allocation failure */ + return Status; + } + + /* Fill allocated memory with zeros */ + RtlZeroMemory((PVOID)(UINT_PTR)Address, EFI_PAGE_SIZE); + + /* Set paging entry settings */ + PageDirectory[PdIndex].PageFrameNumber = Address / EFI_PAGE_SIZE; + PageDirectory[PdIndex].Valid = 1; + PageDirectory[PdIndex].Write = 1; + + /* Set page table */ + PageTable = (PHARDWARE_PTE)(UINT_PTR)Address; + } + else + { + /* Set page table */ + PageTable = (PHARDWARE_PTE)(UINT_PTR)(PageDirectory[PdIndex].PageFrameNumber * EFI_PAGE_SIZE); + } + /* Set page table settings */ + PageTable[PtIndex].PageFrameNumber = PageFrameNumber; + PageTable[PtIndex].Valid = 1; + PageTable[PtIndex].Write = 1; + + /* Take next virtual address and PFN */ + VirtualAddress += EFI_PAGE_SIZE; + PageFrameNumber++; + + /* Decrease number of pages left */ + NumberOfPages--; + } + + /* Return success */ + return STATUS_EFI_SUCCESS; +} diff --git a/xtldr2/modules/xtos_o/includes/xtos.h b/xtldr2/modules/xtos_o/includes/xtos.h new file mode 100644 index 0000000..34695c5 --- /dev/null +++ b/xtldr2/modules/xtos_o/includes/xtos.h @@ -0,0 +1,107 @@ +/** + * 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 +XtAddVirtualMemoryMapping(IN PLIST_ENTRY MemoryMappings, + IN PVOID VirtualAddress, + IN PVOID PhysicalAddress, + IN UINT NumberOfPages, + IN LOADER_MEMORY_TYPE MemoryType); + +XTCDECL +EFI_STATUS +XtBootSystem(IN PXTBL_BOOT_PARAMETERS Parameters); + +XTCDECL +LOADER_MEMORY_TYPE +XtConvertEfiMemoryType(IN EFI_MEMORY_TYPE EfiMemoryType); + +XTCDECL +EFI_STATUS +XtEnablePaging(IN PLIST_ENTRY MemoryMappings, + IN PVOID VirtualAddress, + IN PEFI_LOADED_IMAGE_PROTOCOL ImageProtocol, + IN PVOID *PtePointer); + +XTCDECL +EFI_STATUS +XtGetVirtualAddress(IN PLIST_ENTRY MemoryMappings, + IN PVOID PhysicalAddress, + OUT PVOID *VirtualAddress); + +XTCDECL +EFI_STATUS +XtInitializeVirtualMemory(IN OUT PLIST_ENTRY MemoryMappings, + IN OUT PVOID *MemoryMapAddress); + +XTCDECL +EFI_STATUS +XtMapVirtualMemory(IN PLIST_ENTRY MemoryMappings, + IN UINT_PTR VirtualAddress, + IN UINT_PTR PhysicalAddress, + IN UINT NumberOfPages, + IN OUT PVOID *PtePointer); + +XTCDECL +EFI_STATUS +XtpBootSequence(IN PEFI_FILE_HANDLE BootDir, + IN PXTBL_BOOT_PARAMETERS Parameters); + + +XTCDECL +EFI_STATUS +XtpInitializeApicBase(IN PLIST_ENTRY MemoryMappings); + +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 PPECOFF_IMAGE_CONTEXT *ImageContext); + +XTCDECL +EFI_STATUS +BlXtLdrModuleMain(IN EFI_HANDLE ImageHandle, + IN PEFI_SYSTEM_TABLE SystemTable); + +#endif /* __XTLDR_MODULES_XTOS_H */ diff --git a/xtldr2/modules/xtos_o/memory.c b/xtldr2/modules/xtos_o/memory.c new file mode 100644 index 0000000..c64a9cc --- /dev/null +++ b/xtldr2/modules/xtos_o/memory.c @@ -0,0 +1,385 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/memory.c + * DESCRIPTION: EFI memory management + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Adds a physical to virtual address mapping to the linked list for future processing. + * + * @param MemoryMapping + * Supplies the head of the memory mapping list. + * + * @param VirtualAddress + * Supplies a virtual address where the physical address should be mapped. + * + * @param PhysicalAddress + * Supplies a physical address which will be mapped. + * + * @param NumberOfPages + * Supplies a number of pages which will be mapped. + * + * @param MemoryType + * Supplies the type of memory that will be assigned to the memory descriptor. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtAddVirtualMemoryMapping(IN PLIST_ENTRY MemoryMappings, + IN PVOID VirtualAddress, + IN PVOID PhysicalAddress, + IN UINT NumberOfPages, + IN LOADER_MEMORY_TYPE MemoryType) +{ + PLOADER_MEMORY_MAPPING Mapping1, Mapping2, Mapping3; + PVOID PhysicalAddressEnd, PhysicalAddress2End; + PLIST_ENTRY ListEntry, MappingListEntry; + SIZE_T NumberOfMappedPages; + EFI_STATUS Status; + + /* Allocate memory for new mapping */ + Status = XtLdrProtocol->Memory.AllocatePool(sizeof(LOADER_MEMORY_MAPPING), (PVOID *)&Mapping1); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure */ + return Status; + } + + /* Set mapping fields */ + Mapping1->PhysicalAddress = PhysicalAddress; + Mapping1->VirtualAddress = VirtualAddress; + Mapping1->NumberOfPages = NumberOfPages; + Mapping1->MemoryType = MemoryType; + + /* Calculate the end of the physical address */ + PhysicalAddressEnd = (PUINT8)PhysicalAddress + (NumberOfPages * EFI_PAGE_SIZE) - 1; + + /* Iterate through all the mappings already set to insert new mapping at the correct place */ + ListEntry = MemoryMappings->Flink; + while(ListEntry != MemoryMappings) + { + /* Take a mapping from the list and calculate its end of physical address */ + Mapping2 = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_MAPPING, ListEntry); + PhysicalAddress2End = (PUINT8)Mapping2->PhysicalAddress + (Mapping2->NumberOfPages * EFI_PAGE_SIZE) - 1 ; + + /* Check if they overlap */ + if(PhysicalAddressEnd > Mapping2->PhysicalAddress && PhysicalAddressEnd <= PhysicalAddress2End) + { + /* Make sure it's memory type is LoaderFree */ + if(Mapping2->MemoryType != LoaderFree) + { + /* LoaderFree memory type is strictly expected */ + return STATUS_EFI_INVALID_PARAMETER; + } + + /* Calculate number of pages for this mapping */ + NumberOfMappedPages = ((PUINT8)PhysicalAddress2End - (PUINT8)PhysicalAddressEnd) / EFI_PAGE_SIZE; + if(NumberOfMappedPages > 0) + { + /* Pages associated to the mapping, allocate memory for it */ + Status = XtLdrProtocol->Memory.AllocatePool(sizeof(LOADER_MEMORY_MAPPING), (PVOID*)&Mapping3); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure */ + return Status; + } + + /* Set mapping fields and insert it on the top */ + Mapping3->PhysicalAddress = (PUINT8)PhysicalAddressEnd + 1; + Mapping3->VirtualAddress = NULL; + Mapping3->NumberOfPages = NumberOfMappedPages; + Mapping3->MemoryType = Mapping2->MemoryType; + RtlInsertHeadList(&Mapping2->ListEntry, &Mapping3->ListEntry); + } + + /* Calculate number of pages and the end of the physical address */ + Mapping2->NumberOfPages = ((PUINT8)PhysicalAddressEnd + 1 - + (PUINT8)Mapping2->PhysicalAddress) / EFI_PAGE_SIZE; + PhysicalAddress2End = (PUINT8)Mapping2->PhysicalAddress + (Mapping2->NumberOfPages * EFI_PAGE_SIZE) - 1; + } + + /* Check if they overlap */ + if(Mapping1->PhysicalAddress > Mapping2->PhysicalAddress && Mapping1->PhysicalAddress < PhysicalAddress2End) + { + /* Make sure it's memory type is LoaderFree */ + if(Mapping2->MemoryType != LoaderFree) + { + /* LoaderFree memory type is strictly expected */ + return STATUS_EFI_INVALID_PARAMETER; + } + + /* Calculate number of pages for this mapping */ + NumberOfMappedPages = ((PUINT8)PhysicalAddress2End + 1 - (PUINT8)Mapping1->PhysicalAddress) / EFI_PAGE_SIZE; + if(NumberOfMappedPages > 0) + { + /* Pages associated to the mapping, allocate memory for it */ + Status = XtLdrProtocol->Memory.AllocatePool(sizeof(LOADER_MEMORY_MAPPING), (PVOID*)&Mapping3); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure */ + return Status; + } + + /* Set mapping fields and insert it on the top */ + Mapping3->PhysicalAddress = Mapping1->PhysicalAddress; + Mapping3->VirtualAddress = NULL; + Mapping3->NumberOfPages = NumberOfMappedPages; + Mapping3->MemoryType = Mapping2->MemoryType; + RtlInsertHeadList(&Mapping2->ListEntry, &Mapping3->ListEntry); + } + + /* Calculate number of pages and the end of the physical address */ + Mapping2->NumberOfPages = ((PUINT8)Mapping1->PhysicalAddress - + (PUINT8)Mapping2->PhysicalAddress) / EFI_PAGE_SIZE; + PhysicalAddress2End = (PUINT8)Mapping2->PhysicalAddress + (Mapping2->NumberOfPages * EFI_PAGE_SIZE) - 1; + } + + /* Check if mapping is really needed */ + if((Mapping2->PhysicalAddress >= Mapping1->PhysicalAddress && PhysicalAddress2End <= PhysicalAddressEnd) || + (Mapping2->NumberOfPages == 0)) + { + /* Make sure it's memory type is LoaderFree */ + if(Mapping2->MemoryType != LoaderFree) + { + /* LoaderFree memory type is strictly expected */ + return STATUS_EFI_INVALID_PARAMETER; + } + + /* Store address of the next mapping */ + MappingListEntry = ListEntry->Flink; + + /* Remove mapping from the list and free up it's memory */ + RtlRemoveEntryList(&Mapping2->ListEntry); + Status = XtLdrProtocol->Memory.FreePool(Mapping2); + ListEntry = MappingListEntry; + + /* Go to the next mapping */ + continue; + } + + /* Determine phsical address order */ + if(Mapping2->PhysicalAddress > Mapping1->PhysicalAddress) + { + /* Insert new mapping in front */ + RtlInsertHeadList(Mapping2->ListEntry.Blink, &Mapping1->ListEntry); + return STATUS_EFI_SUCCESS; + } + + /* Get next mapping from the list */ + ListEntry = ListEntry->Flink; + } + + /* Insert new mapping to the end of the list and return success */ + RtlInsertTailList(MemoryMappings, &Mapping1->ListEntry); + return STATUS_EFI_SUCCESS; +} + +/** + * Converts an EFI memory type into an XTOS memory type. + * + * @param EfiMemoryType + * Supplies the EFI memory type. + * + * @return Returns a conversion of the memory type. + * + * @since XT 1.0 + */ +XTCDECL +LOADER_MEMORY_TYPE +XtConvertEfiMemoryType(IN EFI_MEMORY_TYPE EfiMemoryType) +{ + LOADER_MEMORY_TYPE MemoryType; + + /* Check EFI memory type and convert to XTOS memory type */ + switch(EfiMemoryType) + { + case EfiACPIMemoryNVS: + case EfiACPIReclaimMemory: + case EfiPalCode: + MemoryType = LoaderSpecialMemory; + break; + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + MemoryType = LoaderFirmwarePermanent; + break; + case EfiBootServicesData: + case EfiLoaderCode: + case EfiLoaderData: + MemoryType = LoaderFirmwareTemporary; + break; + case EfiUnusableMemory: + MemoryType = LoaderBad; + break; + default: + MemoryType = LoaderFree; + break; + } + + /* Return XTOS memory type */ + return MemoryType; +} + +/** + * Attempts to find a virtual address of the specified physical address in memory mappings. + * + * @param MemoryMappings + * Supplies a pointer to linked list containing all memory mappings. + * + * @param PhysicalAddress + * Supplies a physical address to search for in the mappings. + * + * @param VirtualAddress + * Supplies a buffer, where mapped virtual address of the found mapping will be stored. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtGetVirtualAddress(IN PLIST_ENTRY MemoryMappings, + IN PVOID PhysicalAddress, + OUT PVOID *VirtualAddress) +{ + PLOADER_MEMORY_MAPPING Mapping; + PLIST_ENTRY ListEntry; + + /* NULLify virtual address */ + *VirtualAddress = NULL; + + /* Iterate over memory mappings in order to find descriptor containing a physical address */ + ListEntry = MemoryMappings->Flink; + while(ListEntry != MemoryMappings) + { + /* Get mapping from linked list */ + Mapping = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_MAPPING, ListEntry); + + /* Make sure any virtual address is set */ + if(Mapping->VirtualAddress) + { + /* Check if provided physical address is in range of this mapping */ + if((PhysicalAddress >= Mapping->PhysicalAddress) && + (PhysicalAddress < Mapping->PhysicalAddress + (Mapping->NumberOfPages * EFI_PAGE_SIZE))) + { + /* Calculate virtual address based on the mapping */ + *VirtualAddress = PhysicalAddress - Mapping->PhysicalAddress + Mapping->VirtualAddress; + } + } + + /* Get next element from the list */ + ListEntry = ListEntry->Flink; + } + + /* If virtual address is still NULL, then mapping was not found */ + if(*VirtualAddress == NULL) + { + /* Mapping not found */ + return STATUS_EFI_NOT_FOUND; + } + + /* Mapping found, return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * Initializes virtual memory by adding known and general mappings. + * + * @param MemoryMappings + * Supplies a pointer to linked list containing all memory mappings. + * + * @param MemoryMapAddress + * Supplies an address of the mapped virtual memory area. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtInitializeVirtualMemory(IN OUT PLIST_ENTRY MemoryMappings, + IN OUT PVOID *MemoryMapAddress) +{ + PEFI_MEMORY_DESCRIPTOR Descriptor; + LOADER_MEMORY_TYPE MemoryType; + PEFI_MEMORY_MAP MemoryMap; + SIZE_T DescriptorCount; + PUCHAR VirtualAddress; + EFI_STATUS Status; + SIZE_T Index; + + /* Set initial virtual address */ + VirtualAddress = *MemoryMapAddress; + + /* Allocate and zero-fill buffer for EFI memory map */ + XtLdrProtocol->Memory.AllocatePool(sizeof(EFI_MEMORY_MAP), (PVOID*)&MemoryMap); + RtlZeroMemory(MemoryMap, sizeof(EFI_MEMORY_MAP)); + + /* Get EFI memory map */ + Status = XtLdrProtocol->Memory.GetMemoryMap(MemoryMap); + if(Status != STATUS_EFI_SUCCESS) + { + return Status; + } + + /* Calculate descriptors count and get first one */ + Descriptor = MemoryMap->Map; + DescriptorCount = MemoryMap->MapSize / MemoryMap->DescriptorSize; + + /* Iterate through all descriptors from the memory map */ + for(Index = 0; Index < DescriptorCount; Index++) + { + /* Make sure descriptor does not go beyond lowest physical page */ + if((Descriptor->PhysicalStart + (Descriptor->NumberOfPages * EFI_PAGE_SIZE)) <= (UINT_PTR)-1) + { + /* Convert EFI memory type into XTOS memory type */ + MemoryType = XtConvertEfiMemoryType(Descriptor->Type); + + /* Do memory mappings depending on memory type */ + if(MemoryType == LoaderFirmwareTemporary) + { + /* Map EFI firmware code */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, (PVOID)Descriptor->PhysicalStart, + (PVOID)Descriptor->PhysicalStart, Descriptor->NumberOfPages, MemoryType); + } + else if(MemoryType != LoaderFree) + { + /* Add any non-free memory mapping */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, VirtualAddress, (PVOID)Descriptor->PhysicalStart, + Descriptor->NumberOfPages, MemoryType); + + /* Calculate next valid virtual address */ + VirtualAddress += Descriptor->NumberOfPages * EFI_PAGE_SIZE; + } + else + { + /* Map all other memory as loader free */ + Status = XtAddVirtualMemoryMapping(MemoryMappings, NULL, (PVOID)Descriptor->PhysicalStart, + Descriptor->NumberOfPages, LoaderFree); + } + + /* Make sure memory mapping succeeded */ + if(Status != STATUS_EFI_SUCCESS) + { + /* Mapping failed */ + return Status; + } + + /* Grab next descriptor */ + Descriptor = (PEFI_MEMORY_DESCRIPTOR)((PUCHAR)Descriptor + MemoryMap->DescriptorSize); + } + } + + /* Store next valid virtual address and return success */ + *MemoryMapAddress = VirtualAddress; + return STATUS_EFI_SUCCESS; +} diff --git a/xtldr2/modules/xtos_o/xtos.c b/xtldr2/modules/xtos_o/xtos.c new file mode 100644 index 0000000..b8aec1f --- /dev/null +++ b/xtldr2/modules/xtos_o/xtos.c @@ -0,0 +1,548 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/xtos/xtos.c + * DESCRIPTION: XTOS boot protocol support + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/* XTOS module information */ +XTBL_MODINFO = L"XTOS boot protocol support"; +XTBL_MODDEPS = {L"fb_o", L"pecoff_o"}; + +/* EFI XT Loader Protocol */ +PXTBL_LOADER_PROTOCOL XtLdrProtocol; + +/* XTOS PE/COFF Image Protocol */ +PXTBL_EXECUTABLE_IMAGE_PROTOCOL XtPeCoffProtocol; + +/* XTOS Boot Protocol */ +XTBL_BOOT_PROTOCOL XtBootProtocol; + +/* 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 +XtBootSystem(IN PXTBL_BOOT_PARAMETERS Parameters) +{ + EFI_GUID PeCoffProtocolGuid = XT_PECOFF_IMAGE_PROTOCOL_GUID; + EFI_HANDLE DiskHandle; + 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((PVOID *)&XtPeCoffProtocol, &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 == 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"xtoskrnl.exe"; + } + + /* 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; + PPECOFF_IMAGE_CONTEXT ImageContext = NULL; + PEFI_LOADED_IMAGE_PROTOCOL ImageProtocol; + PVOID VirtualAddress, VirtualMemoryArea; + PXT_ENTRY_POINT KernelEntryPoint; + LIST_ENTRY MemoryMappings; + 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); + + /* Initialize memory mapping linked list */ + RtlInitializeListHead(&MemoryMappings); + + /* Initialize virtual memory mappings */ + Status = XtInitializeVirtualMemory(&MemoryMappings, &VirtualMemoryArea); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to initialize virtual memory */ + return Status; + } + + /* Load the kernel */ + Status = XtpLoadModule(BootDir, Parameters->KernelFile, VirtualAddress, LoaderSystemCode, &ImageContext); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to load the kernel */ + return Status; + } + + /* Add kernel image memory mapping */ + Status = XtAddVirtualMemoryMapping(&MemoryMappings, ImageContext->VirtualAddress, + ImageContext->PhysicalAddress, ImageContext->ImagePages, 0); + if(Status != STATUS_EFI_SUCCESS) + { + return Status; + } + + /* Set next valid virtual address right after the kernel */ + VirtualAddress += ImageContext->ImagePages * EFI_PAGE_SIZE; + + /* Store virtual address of kernel initialization block for future kernel call */ + KernelParameters = (PKERNEL_INITIALIZATION_BLOCK)VirtualAddress; + + /* Setup and map kernel initialization block */ + Status = XtpInitializeLoaderBlock(&MemoryMappings, &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: %lx)\n", Status); + return Status; + } + + /* Find and map APIC base address */ + Status = XtpInitializeApicBase(&MemoryMappings); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to setup kernel initialization block */ + XtLdrProtocol->Debug.Print(L"Failed to initialize APIC (Status Code: %lx)\n", Status); + return Status; + } + + /* Get kernel entry point */ + XtPeCoffProtocol->GetEntryPoint(ImageContext, (PVOID)&KernelEntryPoint); + + /* Close boot directory handle */ + BootDir->Close(BootDir); + + /* Enable paging */ + XtLdrProtocol->Protocol.Open((PVOID*)&ImageProtocol, &LoadedImageGuid); + Status = XtEnablePaging(&MemoryMappings, VirtualAddress, ImageProtocol, &XtPageMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to enable paging */ + XtLdrProtocol->Debug.Print(L"Failed to enable paging (Status Code: %lx)\n", Status); + return Status; + } + + /* Call XTOS kernel */ + XtLdrProtocol->Debug.Print(L"Booting the XTOS kernel\n"); + KernelEntryPoint(KernelParameters); + + /* 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 +XtpInitializeApicBase(IN PLIST_ENTRY MemoryMappings) +{ + PCPUID_REGISTERS CpuRegisters = NULL; + PVOID ApicBaseAddress; + + /* Get CPU features list */ + CpuRegisters->Leaf = CPUID_GET_CPU_FEATURES; + CpuRegisters->SubLeaf = 0; + CpuRegisters->Eax = 0; + CpuRegisters->Ebx = 0; + CpuRegisters->Ecx = 0; + CpuRegisters->Edx = 0; + ArCpuId(CpuRegisters); + + /* Check if APIC is present */ + if((CpuRegisters->Edx & CPUID_FEATURES_EDX_APIC) == 0) + { + /* APIC is not supported by the CPU */ + return STATUS_EFI_UNSUPPORTED; + } + + /* Get APIC base address */ + ApicBaseAddress = (PVOID)((UINT_PTR)ArReadModelSpecificRegister(0x1B) & 0xFFFFF000); + + /* Map APIC base address */ + XtAddVirtualMemoryMapping(MemoryMappings, (PVOID)APIC_BASE, 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 +XtpInitializeLoaderBlock(IN PLIST_ENTRY MemoryMappings, + IN PVOID *VirtualAddress, + IN PXTBL_BOOT_PARAMETERS Parameters) +{ + EFI_GUID FrameBufGuid = XT_FRAMEBUFFER_PROTOCOL_GUID; + PXT_FRAMEBUFFER_PROTOCOL FrameBufProtocol; + PKERNEL_INITIALIZATION_BLOCK LoaderBlock; + EFI_PHYSICAL_ADDRESS Address; + // PVOID RuntimeServices; + EFI_STATUS Status; + UINT BlockPages, FrameBufferPages; + + /* Calculate number of pages needed for initialization block */ + BlockPages = EFI_SIZE_TO_PAGES(sizeof(KERNEL_INITIALIZATION_BLOCK)); + + /* Allocate memory for kernel initialization block */ + Status = XtLdrProtocol->Memory.AllocatePages(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; + RtlZeroMemory(LoaderBlock, sizeof(KERNEL_INITIALIZATION_BLOCK)); + + /* 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 = XtLdrProtocol->Debug.Print; + + /* Load FrameBuffer protocol */ + Status = XtLdrProtocol->Protocol.Open((PVOID*)&FrameBufProtocol, &FrameBufGuid); + if(Status == STATUS_EFI_SUCCESS) + { + /* Make sure FrameBuffer is initialized */ + FrameBufProtocol->Initialize(); + FrameBufProtocol->PrintDisplayInformation(); + + /* Store information about FrameBuffer device */ + FrameBufProtocol->GetDisplayInformation(&LoaderBlock->LoaderInformation.FrameBuffer); + } + else + { + /* No FrameBuffer available */ + LoaderBlock->LoaderInformation.FrameBuffer.Initialized = FALSE; + LoaderBlock->LoaderInformation.FrameBuffer.Protocol = NONE; + } + + /* Attempt to find virtual address of the EFI Runtime Services */ + // Status = XtLdrProtocol->GetVirtualAddress(MemoryMappings, &EfiSystemTable->RuntimeServices->Hdr, &RuntimeServices); + // if(Status == STATUS_EFI_SUCCESS) + // { + /* Set FirmwareInformation block properties */ + LoaderBlock->FirmwareInformation.FirmwareType = SystemFirmwareEfi; + LoaderBlock->FirmwareInformation.EfiFirmware.EfiVersion = 0; //EfiSystemTable->Hdr.Revision; + LoaderBlock->FirmwareInformation.EfiFirmware.EfiRuntimeServices = NULL; + // } + // else + // { + // /* Set invalid firmware type to indicate that kernel cannot rely on FirmwareInformation block */ + // LoaderBlock->FirmwareInformation.FirmwareType = SystemFirmwareInvalid; + // } + + /* Copy parameters to kernel initialization block */ + RtlCopyMemory(&LoaderBlock->KernelParameters, Parameters->Parameters, RtlWideStringLength(Parameters->Parameters, 0)); + + /* Map kernel initialization block */ + XtAddVirtualMemoryMapping(MemoryMappings, *VirtualAddress, (PVOID)LoaderBlock, + BlockPages, LoaderSystemBlock); + + /* Calculate next valid virtual address */ + *VirtualAddress += (UINT_PTR)(BlockPages * EFI_PAGE_SIZE); + + /* Check if framebuffer initialized */ + if(LoaderBlock->LoaderInformation.FrameBuffer.Initialized) + { + /* Calculate pages needed to map framebuffer */ + FrameBufferPages = EFI_SIZE_TO_PAGES(LoaderBlock->LoaderInformation.FrameBuffer.BufferSize); + + /* Map frame buffer memory */ + XtAddVirtualMemoryMapping(MemoryMappings, *VirtualAddress, + LoaderBlock->LoaderInformation.FrameBuffer.Address, + FrameBufferPages, LoaderFirmwarePermanent); + + /* Rewrite framebuffer address by using virtual address */ + LoaderBlock->LoaderInformation.FrameBuffer.Address = *VirtualAddress; + + /* Calcualate next valid virtual address */ + *VirtualAddress += (UINT_PTR)(FrameBufferPages * EFI_PAGE_SIZE); + } + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * 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 +XtpLoadModule(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 = XtPeCoffProtocol->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 */ + XtPeCoffProtocol->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 */ + XtPeCoffProtocol->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: 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; + + // /* Set the system table and image handle */ + // EfiImageHandle = ImageHandle; + // EfiSystemTable = SystemTable; + + /* 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 */ + XtBootProtocol.BootSystem = XtBootSystem; + + /* Register XTOS boot protocol */ + return XtLdrProtocol->Protocol.Register(&Guid, &XtBootProtocol); +}