Move XTLDR under boot directory
All checks were successful
Builds / ExectOS (i686, debug) (push) Successful in 27s
Builds / ExectOS (amd64, debug) (push) Successful in 26s
Builds / ExectOS (amd64, release) (push) Successful in 38s
Builds / ExectOS (i686, release) (push) Successful in 36s

This commit is contained in:
2025-10-06 12:08:36 +02:00
parent ce8041754b
commit c5f522be4c
53 changed files with 2 additions and 2 deletions

View File

@@ -1,2 +1,3 @@
add_subdirectory(bootdata)
add_subdirectory(bootsect)
add_subdirectory(xtldr)

53
boot/xtldr/CMakeLists.txt Normal file
View File

@@ -0,0 +1,53 @@
# XT Boot Loader
PROJECT(XTLDR)
# Build XTLDR modules
add_subdirectory(modules)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_SOURCE_DIR}/includes)
# Specify list of library source code files
list(APPEND LIBXTLDR_SOURCE
${XTLDR_SOURCE_DIR}/library/modproto.cc)
# Specify list of source code files
list(APPEND XTLDR_SOURCE
${XTLDR_SOURCE_DIR}/arch/${ARCH}/memory.cc
${XTLDR_SOURCE_DIR}/bootutil.cc
${XTLDR_SOURCE_DIR}/config.cc
${XTLDR_SOURCE_DIR}/console.cc
${XTLDR_SOURCE_DIR}/data.cc
${XTLDR_SOURCE_DIR}/debug.cc
${XTLDR_SOURCE_DIR}/efiutils.cc
${XTLDR_SOURCE_DIR}/memory.cc
${XTLDR_SOURCE_DIR}/protocol.cc
${XTLDR_SOURCE_DIR}/shell.cc
${XTLDR_SOURCE_DIR}/textui.cc
${XTLDR_SOURCE_DIR}/volume.cc
${XTLDR_SOURCE_DIR}/xtldr.cc)
# Link static XTLDR library
add_library(libxtldr ${LIBXTLDR_SOURCE})
# Link bootloader executable
add_executable(xtldr ${XTLDR_SOURCE})
# Add linker libraries
target_link_libraries(xtldr libxtos)
# Set proper binary name and install target
if(ARCH STREQUAL "i686")
set(BINARY_NAME "bootia32")
elseif(ARCH STREQUAL "amd64")
set(BINARY_NAME "bootx64")
endif()
set_target_properties(xtldr PROPERTIES OUTPUT_NAME ${BINARY_NAME} SUFFIX .efi)
set_install_target(xtldr efi/boot)
# Set loader entrypoint and subsystem
set_entrypoint(xtldr "BlStartXtLoader")
set_linker_map(xtldr TRUE)
set_subsystem(xtldr efi_application)

14
boot/xtldr/README.md Normal file
View File

@@ -0,0 +1,14 @@
## XT Boot Loader (XTLDR)
The XTLDR, or XTOS Boot Loader, is an EFI (Extensible Firmware Interface) boot loader specifically designed for XTOS.
As an EFI boot loader, XTLDR operates exclusively with EFI-based hardware and is not compatible with non-EFI systems,
like old and deprecated BIOS.
One of the notable features of XTLDR is its modular design. The boot loader is divided into different modules, with only
the essential core being loaded during the boot process. This modular approach allows for a more efficient and
streamlined boot experience, as only the necessary functionality is loaded, reducing the boot time and system resource
usage.
XTLDR includes various modules that provide specific functionalities required for the boot process. For example, there is
a module dedicated to supporting the XTOS boot protocol, which is the specific protocol used by XTOS for loading and
executing the OS kernel. Additionally, there is a module for handling PE/COFF (Portable Executable) binaries, which is
a commonly used format of executable files used by the XTOS.

View File

@@ -0,0 +1,372 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/arch/amd64/memory.cc
* DESCRIPTION: XT Boot Loader AMD64 specific memory management
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
* Aiken Harris <harraiken91@gmail.com>
*/
#include <xtldr.hh>
/**
* Maps boot loader related code and builds page map.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param SelfMapAddress
* Supplies a virtual address of the page tables.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR SelfMapAddress)
{
PLIST_ENTRY ListEntry, ModulesList, ModulesListEntry;
PXTBL_MEMORY_MAPPING Mapping;
PXTBL_MODULE_INFO ModuleInfo;
EFI_PHYSICAL_ADDRESS Address;
PVOID LoaderBase;
ULONGLONG LoaderSize;
EFI_STATUS Status;
/* Allocate pages for the Page Map */
Status = AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Assign and zero-fill memory used by page mappings */
PageMap->PtePointer = (PVOID)(UINT_PTR)Address;
RTL::Memory::ZeroMemory(PageMap->PtePointer, EFI_PAGE_SIZE);
/* Add page mapping itself to memory mapping */
Status = Memory::SelfMapPml(PageMap, SelfMapAddress);
if(Status != STATUS_EFI_SUCCESS)
{
/* PML mapping failed */
return Status;
}
/* Map the trampoline code area */
Status = MapVirtualMemory(PageMap, (PVOID)MM_TRAMPOLINE_ADDRESS,(PVOID)MM_TRAMPOLINE_ADDRESS,
1, LoaderFirmwareTemporary);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping trampoline code failed */
return Status;
}
/* Get list of XTLDR modules */
ModulesList = Protocol::GetModulesList();
ModulesListEntry = ModulesList->Flink;
while(ModulesListEntry != ModulesList)
{
/* Get module info */
ModuleInfo = CONTAIN_RECORD(ModulesListEntry, XTBL_MODULE_INFO, Flink);
/* Map module code */
Status = MapVirtualMemory(PageMap, ModuleInfo->ModuleBase, ModuleInfo->ModuleBase,
EFI_SIZE_TO_PAGES(ModuleInfo->ModuleSize), LoaderFirmwareTemporary);
/* Check if mapping succeeded */
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping module code failed */
return Status;
}
/* Get next module */
ModulesListEntry = ModulesListEntry->Flink;
}
/* Get boot loader image information */
XtLoader::GetLoaderImageInformation(&LoaderBase, &LoaderSize);
/* Make sure boot loader image base and size are set */
if(LoaderBase && LoaderSize)
{
/* Map boot loader code as well */
Status = MapVirtualMemory(PageMap, LoaderBase, LoaderBase,
EFI_SIZE_TO_PAGES(LoaderSize), LoaderFirmwareTemporary);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping boot loader code failed */
return Status;
}
}
else
{
/* Boot loader image information re not available */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Iterate through and map all the mappings*/
Debug::Print(L"Mapping and dumping EFI memory:\n");
ListEntry = PageMap->MemoryMap.Flink;
while(ListEntry != &PageMap->MemoryMap)
{
/* Take mapping from the list */
Mapping = CONTAIN_RECORD(ListEntry, XTBL_MEMORY_MAPPING, ListEntry);
/* Check if virtual address is set */
if(Mapping->VirtualAddress)
{
/* Dump memory mapping */
Debug::Print(L" Type=%02lu, PhysicalBase=%.16P, VirtualBase=%.16P, Pages=%llu\n", Mapping->MemoryType,
Mapping->PhysicalAddress, Mapping->VirtualAddress, Mapping->NumberOfPages);
/* Map memory */
Status = MapPage(PageMap, (UINT_PTR)Mapping->VirtualAddress,
(UINT_PTR)Mapping->PhysicalAddress, Mapping->NumberOfPages);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failed */
return Status;
}
}
/* Take next element */
ListEntry = ListEntry->Flink;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Returns next level of the Page Table.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param PageTable
* Supplies a pointer to the current Page Table.
*
* @param Entry
* Supplies an index of the current Page Table entry.
*
* @param NextPageTable
* Supplies a pointer to the memory area where the next Page Table level is returned.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::GetNextPageTable(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID PageTable,
IN SIZE_T Entry,
OUT PVOID *NextPageTable)
{
EFI_PHYSICAL_ADDRESS Address;
ULONGLONG PmlPointer = 0;
PHARDWARE_PTE PmlTable;
EFI_STATUS Status;
PmlTable = (PHARDWARE_PTE)PageTable;
/* Check if this is a valid table */
if(PmlTable[Entry].Valid)
{
/* Get PML pointer */
PmlPointer = PmlTable[Entry].PageFrameNumber;
PmlPointer <<= EFI_PAGE_SHIFT;
}
else
{
/* Allocate pages for new PML entry */
Status = AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Add new memory mapping */
Status = MapVirtualMemory(PageMap, NULLPTR, (PVOID)(UINT_PTR)Address, 1, LoaderMemoryData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Fill allocated memory with zeros */
RTL::Memory::ZeroMemory((PVOID)(ULONGLONG)Address, EFI_PAGE_SIZE);
/* Set paging entry settings */
PmlTable[Entry].PageFrameNumber = Address / EFI_PAGE_SIZE;
PmlTable[Entry].Valid = 1;
PmlTable[Entry].Writable = 1;
PmlPointer = (ULONGLONG)Address;
}
/* Set next Page Map Level (PML) */
*NextPageTable = (PVOID)(ULONGLONG)PmlPointer;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Does the actual virtual memory mapping.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @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.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::MapPage(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR VirtualAddress,
IN ULONG_PTR PhysicalAddress,
IN ULONG NumberOfPages)
{
PVOID Pml1, Pml2, Pml3, Pml4, Pml5;
SIZE_T Pml1Entry, Pml2Entry, Pml3Entry, Pml4Entry, Pml5Entry;
PHARDWARE_PTE PmlTable;
SIZE_T PageFrameNumber;
EFI_STATUS Status;
/* Set the Page Frame Number (PFN) */
PageFrameNumber = PhysicalAddress >> EFI_PAGE_SHIFT;
/* Do the recursive mapping */
while(NumberOfPages > 0)
{
/* Calculate the indices in the various Page Tables from the virtual address */
Pml5Entry = (VirtualAddress & ((ULONGLONG)0x1FF << MM_P5I_SHIFT)) >> MM_P5I_SHIFT;
Pml4Entry = (VirtualAddress & ((ULONGLONG)0x1FF << MM_PXI_SHIFT)) >> MM_PXI_SHIFT;
Pml3Entry = (VirtualAddress & ((ULONGLONG)0x1FF << MM_PPI_SHIFT)) >> MM_PPI_SHIFT;
Pml2Entry = (VirtualAddress & ((ULONGLONG)0x1FF << MM_PDI_SHIFT)) >> MM_PDI_SHIFT;
Pml1Entry = (VirtualAddress & ((ULONGLONG)0x1FF << MM_PTI_SHIFT)) >> MM_PTI_SHIFT;
/* Check page map level */
if(PageMap->PageMapLevel == 5)
{
/* Five level Page Map */
Pml5 = PageMap->PtePointer;
/* Get PML4 */
Status = GetNextPageTable(PageMap, Pml5, Pml5Entry, &Pml4);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
}
else
{
/* Four level Page Map */
Pml4 = PageMap->PtePointer;
}
/* Get PML3 */
Status = GetNextPageTable(PageMap, Pml4, Pml4Entry, &Pml3);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Get PML 2 */
Status = GetNextPageTable(PageMap, Pml3, Pml3Entry, &Pml2);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Get PML1 */
Status = GetNextPageTable(PageMap, Pml2, Pml2Entry, &Pml1);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Set paging entry settings */
PmlTable = (PHARDWARE_PTE)Pml1;
RTL::Memory::ZeroMemory(&PmlTable[Pml1Entry], sizeof(HARDWARE_PTE));
PmlTable[Pml1Entry].PageFrameNumber = PageFrameNumber;
PmlTable[Pml1Entry].Valid = 1;
PmlTable[Pml1Entry].Writable = 1;
/* Take next virtual address and PFN */
VirtualAddress += EFI_PAGE_SIZE;
PageFrameNumber++;
/* Decrease number of pages left */
NumberOfPages--;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Creates a recursive self mapping for all PML levels.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param SelfMapAddress
* Supplies a virtual address of the page tables.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::SelfMapPml(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR SelfMapAddress)
{
PHARDWARE_PTE PmlBase;
ULONGLONG PmlIndex;
/* Initialize PML base pointer */
PmlBase = (PHARDWARE_PTE)PageMap->PtePointer;
/* Check page map level */
if(PageMap->PageMapLevel == 5)
{
/* Calculate PML index based on provided self map address for PML5 */
PmlIndex = (SelfMapAddress >> MM_P5I_SHIFT) & 0x1FF;
}
else
{
/* Calculate PML index based on provided self map address for PML4 */
PmlIndex = (SelfMapAddress >> MM_PXI_SHIFT) & 0x1FF;
}
/* Add self-mapping */
RTL::Memory::ZeroMemory(&PmlBase[PmlIndex], sizeof(HARDWARE_PTE));
PmlBase[PmlIndex].PageFrameNumber = (UINT_PTR)PageMap->PtePointer / EFI_PAGE_SIZE;
PmlBase[PmlIndex].Valid = 1;
PmlBase[PmlIndex].Writable = 1;
/* Return success */
return STATUS_EFI_SUCCESS;
}

View File

@@ -0,0 +1,461 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/arch/i686/memory.cc
* DESCRIPTION: XT Boot Loader i686 specific memory management
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
* Aiken Harris <harraiken91@gmail.com>
*/
#include <xtldr.hh>
/**
* Maps boot loader related code and builds page map.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR SelfMapAddress)
{
PLIST_ENTRY ListEntry, ModulesList, ModulesListEntry;
EFI_PHYSICAL_ADDRESS Address, DirectoryAddress;
PXTBL_MODULE_INFO ModuleInfo;
PXTBL_MEMORY_MAPPING Mapping;
PVOID LoaderBase;
ULONGLONG LoaderSize;
EFI_STATUS Status;
ULONG Index;
/* Check the page map level to determine which paging structure to create */
if(PageMap->PageMapLevel == 3)
{
/* Allocate a page for the 3-level page map structure (PAE enabled) */
Status = AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failed, cannot proceed with page map creation */
return Status;
}
/* Assign the allocated page to the page map and zero it out */
PageMap->PtePointer = (PVOID)(UINT_PTR)Address;
RTL::Memory::ZeroMemory(PageMap->PtePointer, EFI_PAGE_SIZE);
/* Allocate 4 pages for the Page Directories (PDs) */
Status = AllocatePages(AllocateAnyPages, 4, &DirectoryAddress);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failed, cannot proceed with page map creation */
return Status;
}
/* Zero-fill the allocated memory for the Page Directories */
RTL::Memory::ZeroMemory((PVOID)DirectoryAddress, EFI_PAGE_SIZE * 4);
/* Fill the PDPT with pointers to the Page Directories */
for(Index = 0; Index < 4; Index++)
{
RTL::Memory::ZeroMemory(&((PHARDWARE_MODERN_PTE)PageMap->PtePointer)[Index], sizeof(HARDWARE_MODERN_PTE));
((PHARDWARE_MODERN_PTE)PageMap->PtePointer)[Index].PageFrameNumber = DirectoryAddress / EFI_PAGE_SIZE;
((PHARDWARE_MODERN_PTE)PageMap->PtePointer)[Index].Valid = 1;
DirectoryAddress += EFI_PAGE_SIZE;
}
}
else
{
/* Allocate a page for the 2-level page map structure (PAE disabled) */
Status = AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failed, cannot proceed with page map creation */
return Status;
}
/* Assign the allocated page to the page map and zero it out */
PageMap->PtePointer = (PVOID)(UINT_PTR)Address;
RTL::Memory::ZeroMemory(PageMap->PtePointer, EFI_PAGE_SIZE);
}
/* Add page mapping itself to memory mapping */
Status = SelfMapPml(PageMap, SelfMapAddress);
if(Status != STATUS_EFI_SUCCESS)
{
/* PML mapping failed */
return Status;
}
/* Map the trampoline code area */
Status = MapVirtualMemory(PageMap, (PVOID)MM_TRAMPOLINE_ADDRESS,(PVOID)MM_TRAMPOLINE_ADDRESS,
1, LoaderFirmwareTemporary);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping trampoline code failed */
return Status;
}
/* Get list of XTLDR modules */
ModulesList = Protocol::GetModulesList();
ModulesListEntry = ModulesList->Flink;
while(ModulesListEntry != ModulesList)
{
/* Get module info */
ModuleInfo = CONTAIN_RECORD(ModulesListEntry, XTBL_MODULE_INFO, Flink);
/* Map module code */
Status = MapVirtualMemory(PageMap, ModuleInfo->ModuleBase, ModuleInfo->ModuleBase,
EFI_SIZE_TO_PAGES(ModuleInfo->ModuleSize), LoaderFirmwareTemporary);
/* Check if mapping succeeded */
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping module code failed */
return Status;
}
/* Get next module */
ModulesListEntry = ModulesListEntry->Flink;
}
/* Get boot loader image information */
XtLoader::GetLoaderImageInformation(&LoaderBase, &LoaderSize);
/* Make sure boot loader image base and size are set */
if(LoaderBase && LoaderSize)
{
/* Map boot loader code as well */
Status = MapVirtualMemory(PageMap, LoaderBase, LoaderBase,
EFI_SIZE_TO_PAGES(LoaderSize), LoaderFirmwareTemporary);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping boot loader code failed */
return Status;
}
}
else
{
/* Boot loader image information re not available */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Iterate through and map all the mappings*/
Debug::Print(L"Mapping and dumping EFI memory:\n");
ListEntry = PageMap->MemoryMap.Flink;
while(ListEntry != &PageMap->MemoryMap)
{
/* Take mapping from the list */
Mapping = CONTAIN_RECORD(ListEntry, XTBL_MEMORY_MAPPING, ListEntry);
/* Check if virtual address is set */
if(Mapping->VirtualAddress)
{
/* Dump memory mapping */
Debug::Print(L" Type=%02lu, PhysicalBase=%.8P, VirtualBase=%.8P, Pages=%llu\n", Mapping->MemoryType,
Mapping->PhysicalAddress, Mapping->VirtualAddress, Mapping->NumberOfPages);
/* Map memory */
Status = MapPage(PageMap, (UINT_PTR)Mapping->VirtualAddress,
(UINT_PTR)Mapping->PhysicalAddress, Mapping->NumberOfPages);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failed */
return Status;
}
}
/* Take next element */
ListEntry = ListEntry->Flink;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Returns next level of the Page Table.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param PageTable
* Supplies a pointer to the current Page Table.
*
* @param Entry
* Supplies an index of the current Page Table entry.
*
* @param NextPageTable
* Supplies a pointer to the memory area where the next Page Table level is returned.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::GetNextPageTable(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID PageTable,
IN SIZE_T Entry,
OUT PVOID *NextPageTable)
{
EFI_PHYSICAL_ADDRESS Address;
ULONGLONG PmlPointer = 0;
EFI_STATUS Status;
PHARDWARE_LEGACY_PTE LegacyPmlTable;
PHARDWARE_MODERN_PTE PmlTable;
BOOLEAN ValidPte = FALSE;
/* Check page map level to determine PTE size */
if(PageMap->PageMapLevel >= 3)
{
/* 64-bit PTE for PML3 (PAE enabled) */
PmlTable = (PHARDWARE_MODERN_PTE)PageTable;
if(PmlTable[Entry].Valid)
{
/* Get page frame number from page table entry */
PmlPointer = PmlTable[Entry].PageFrameNumber;
ValidPte = TRUE;
}
}
else
{
/* 32-bit PTE for PML2 (PAE disabled) */
LegacyPmlTable = (PHARDWARE_LEGACY_PTE)PageTable;
if(LegacyPmlTable[Entry].Valid)
{
/* Get page frame number from page table entry */
PmlPointer = LegacyPmlTable[Entry].PageFrameNumber;
ValidPte = TRUE;
}
}
/* Check if page table entry is valid */
if(ValidPte)
{
/* Calculate the base address of the next page table */
PmlPointer <<= EFI_PAGE_SHIFT;
}
else
{
/* Allocate pages for new PML entry */
Status = AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Add new memory mapping */
Status = MapVirtualMemory(PageMap, NULLPTR, (PVOID)(UINT_PTR)Address, 1, LoaderMemoryData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Fill allocated memory with zeros */
RTL::Memory::ZeroMemory((PVOID)(ULONGLONG)Address, EFI_PAGE_SIZE);
/* Set paging entry settings based on level */
if(PageMap->PageMapLevel >= 3)
{
/* 64-bit PTE for PML3 (PAE enabled) */
PmlTable = (PHARDWARE_MODERN_PTE)PageTable;
PmlTable[Entry].PageFrameNumber = Address / EFI_PAGE_SIZE;
PmlTable[Entry].Valid = 1;
PmlTable[Entry].Writable = 1;
}
else
{
/* 32-bit PTE for PML2 (PAE disabled) */
LegacyPmlTable = (PHARDWARE_LEGACY_PTE)PageTable;
LegacyPmlTable[Entry].PageFrameNumber = (UINT32)(Address / EFI_PAGE_SIZE);
LegacyPmlTable[Entry].Valid = 1;
LegacyPmlTable[Entry].Writable = 1;
}
/* Return the address of the new page table */
PmlPointer = (ULONGLONG)Address;
}
/* Set next Page Map Level (PML) */
*NextPageTable = (PVOID)(ULONGLONG)PmlPointer;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Does the actual virtual memory mapping.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @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.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::MapPage(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR VirtualAddress,
IN ULONG_PTR PhysicalAddress,
IN ULONG NumberOfPages)
{
SIZE_T PageFrameNumber;
PVOID Pml1, Pml2, Pml3;
SIZE_T Pml1Entry, Pml2Entry, Pml3Entry;
PHARDWARE_LEGACY_PTE LegacyPmlTable;
PHARDWARE_MODERN_PTE PmlTable;
EFI_STATUS Status;
/* Set the Page Frame Number (PFN) */
PageFrameNumber = PhysicalAddress >> EFI_PAGE_SHIFT;
/* Map all requested pages */
while(NumberOfPages > 0)
{
/* Check the paging mode to use the correct page table structure */
if(PageMap->PageMapLevel == 3)
{
/* Calculate the indices for PAE page tables */
Pml3Entry = (VirtualAddress >> 30) & 0x3;
Pml2Entry = (VirtualAddress >> 21) & 0x1FF;
Pml1Entry = (VirtualAddress >> 12) & 0x1FF;
/* Get Page Directory Pointer Table (PML3) */
Pml3 = PageMap->PtePointer;
/* Get Page Directory (PML2) */
Status = GetNextPageTable(PageMap, Pml3, Pml3Entry, &Pml2);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get the Page Table, abort mapping */
return Status;
}
/* Get Page Table (PML1) */
Status = GetNextPageTable(PageMap, Pml2, Pml2Entry, &Pml1);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get the Page Table, abort mapping */
return Status;
}
/* Set the 64-bit PTE entry */
PmlTable = (PHARDWARE_MODERN_PTE)Pml1;
RTL::Memory::ZeroMemory(&PmlTable[Pml1Entry], sizeof(HARDWARE_MODERN_PTE));
PmlTable[Pml1Entry].PageFrameNumber = PageFrameNumber;
PmlTable[Pml1Entry].Valid = 1;
PmlTable[Pml1Entry].Writable = 1;
}
else
{
/* Calculate the indices for non-PAE page tables */
Pml2Entry = (VirtualAddress >> 22) & 0x3FF;
Pml1Entry = (VirtualAddress >> 12) & 0x3FF;
/* Get Page Directory (PML2) */
Pml2 = PageMap->PtePointer;
/* Get Page Table (PML1) */
Status = GetNextPageTable(PageMap, Pml2, Pml2Entry, &Pml1);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get the Page Table, abort mapping */
return Status;
}
/* Set the 32-bit PTE entry */
LegacyPmlTable = (PHARDWARE_LEGACY_PTE)Pml1;
RTL::Memory::ZeroMemory(&LegacyPmlTable[Pml1Entry], sizeof(HARDWARE_LEGACY_PTE));
LegacyPmlTable[Pml1Entry].PageFrameNumber = (UINT32)PageFrameNumber;
LegacyPmlTable[Pml1Entry].Valid = 1;
LegacyPmlTable[Pml1Entry].Writable = 1;
}
/* Take next virtual address and PFN */
VirtualAddress += EFI_PAGE_SIZE;
PageFrameNumber++;
/* Decrease number of pages left */
NumberOfPages--;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Creates a recursive self mapping for all PML levels.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param SelfMapAddress
* Supplies a virtual address of the page tables.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::SelfMapPml(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR SelfMapAddress)
{
PHARDWARE_LEGACY_PTE LegacyPml;
PHARDWARE_MODERN_PTE Pml;
ULONGLONG PmlIndex;
ULONG Index;
/* Check page map level */
if(PageMap->PageMapLevel == 3)
{
/* Calculate PML index based on provided self map address */
PmlIndex = (SelfMapAddress >> MM_PDI_SHIFT) & 0x1FF;
/* Get Page Directory */
Pml = (PHARDWARE_MODERN_PTE)(((PHARDWARE_MODERN_PTE)PageMap->PtePointer)[SelfMapAddress >> MM_PPI_SHIFT].PageFrameNumber * EFI_PAGE_SIZE);
/* Add self-mapping for PML3 (PAE enabled) */
for(Index = 0; Index < 4; Index++)
{
RTL::Memory::ZeroMemory(&Pml[PmlIndex + Index], sizeof(HARDWARE_MODERN_PTE));
Pml[PmlIndex + Index].PageFrameNumber = ((PHARDWARE_MODERN_PTE)PageMap->PtePointer)[Index].PageFrameNumber;
Pml[PmlIndex + Index].Valid = 1;
Pml[PmlIndex + Index].Writable = 1;
}
}
else
{
LegacyPml = (PHARDWARE_LEGACY_PTE)PageMap->PtePointer;
/* Calculate PML index based on provided self map address */
PmlIndex = (SelfMapAddress >> MM_PDI_LEGACY_SHIFT);
/* Add self-mapping for PML2 (PAE disabled) */
RTL::Memory::ZeroMemory(&LegacyPml[PmlIndex], sizeof(HARDWARE_LEGACY_PTE));
LegacyPml[PmlIndex].PageFrameNumber = (UINT_PTR)PageMap->PtePointer / EFI_PAGE_SIZE;
LegacyPml[PmlIndex].Valid = 1;
LegacyPml[PmlIndex].Writable = 1;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}

87
boot/xtldr/bootutil.cc Normal file
View File

@@ -0,0 +1,87 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/bootutil.cc
* DESCRIPTION: Helper functions used by the boot protocol during system startup
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#include <xtldr.hh>
/**
* Checks if a specific option exists in the list of provided boot parameters.
*
* @param Parameters
* A pointer to the wide-character string containing the boot parameters, separated by spaces.
*
* @param Needle
* A pointer to the wide-character string representing the kernel option to find.
*
* @return This routine returns TRUE if the option is found, otherwise FALSE.
*
* @since XT 1.0
*/
XTCDECL
BOOLEAN
BootUtils::GetBooleanParameter(IN PCWSTR Parameters,
IN PCWSTR Needle)
{
PCWSTR CurrentPosition, TokenEnd, TokenStart;
SIZE_T NeedleLength, TokenLength;
/* Validate input data and ensure the option is not an empty string */
if(Parameters == NULLPTR || Needle == NULLPTR || *Needle == L'\0')
{
/* One of the parameters was invalid */
return FALSE;
}
CurrentPosition = Parameters;
NeedleLength = RTL::WideString::WideStringLength(Needle, 0);
/* Iterate through the entire parameters string */
while(*CurrentPosition != L'\0')
{
/* Skip any leading whitespace to find the start of the token */
while(*CurrentPosition == L' ')
{
CurrentPosition++;
}
/* Check if end of the string has been reached */
if(*CurrentPosition == L'\0')
{
/* End of string reached, no more tokens */
break;
}
/* Identify the boundaries of the current token */
TokenStart = CurrentPosition;
TokenEnd = TokenStart;
while(*TokenEnd != L'\0' && *TokenEnd != L' ')
{
TokenEnd++;
}
/* Calculate the length of the token found */
TokenLength = TokenEnd - TokenStart;
/* Compare the token length */
if(TokenLength == NeedleLength)
{
/* Length matches, compare the strings */
if(RTL::WideString::CompareWideStringInsensitive(TokenStart, Needle, NeedleLength) == 0)
{
/* A match was found */
return TRUE;
}
}
/* Move the position past the current token to continue the search */
CurrentPosition = TokenEnd;
}
/* No match was found */
return FALSE;
}

1052
boot/xtldr/config.cc Normal file

File diff suppressed because it is too large Load Diff

314
boot/xtldr/console.cc Normal file
View File

@@ -0,0 +1,314 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/console.cc
* DESCRIPTION: EFI console support
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* Clears a specified line on the UEFI text console.
*
* @param LineNo
* Supplies a line number to clear.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::ClearLine(IN ULONGLONG LineNo)
{
UINT_PTR Index, ResX, ResY;
/* Query console mode */
QueryMode(&ResX, &ResY);
/* Set cursor position and clear line */
SetCursorPosition(0, LineNo);
for(Index = 0; Index < ResX; Index++)
{
/* Clear line */
Write(L" ");
}
}
/**
* This routine clears the UEFI console screen.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::ClearScreen()
{
/* Clear screen */
XtLoader::GetEfiSystemTable()->ConOut->ClearScreen(XtLoader::GetEfiSystemTable()->ConOut);
}
/**
* Disables the cursor on the UEFI console.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::DisableCursor()
{
XtLoader::GetEfiSystemTable()->ConOut->EnableCursor(XtLoader::GetEfiSystemTable()->ConOut, FALSE);
}
/**
* Enables the cursor on the UEFI console.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::EnableCursor()
{
XtLoader::GetEfiSystemTable()->ConOut->EnableCursor(XtLoader::GetEfiSystemTable()->ConOut, TRUE);
}
/**
* This routine initializes the EFI console.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::InitializeConsole()
{
/* Clear console buffers */
XtLoader::GetEfiSystemTable()->ConIn->Reset(XtLoader::GetEfiSystemTable()->ConIn, TRUE);
XtLoader::GetEfiSystemTable()->ConOut->Reset(XtLoader::GetEfiSystemTable()->ConOut, TRUE);
XtLoader::GetEfiSystemTable()->StdErr->Reset(XtLoader::GetEfiSystemTable()->StdErr, TRUE);
/* Make sure that current console mode is 80x25 characters, as some broken EFI implementations might
* set different mode that do not fit on the screen, causing a text to be displayed offscreen */
if(XtLoader::GetEfiSystemTable()->ConOut->Mode->Mode != 0)
{
/* Set console mode to 0, which is standard, 80x25 text mode */
SetMode(0);
}
/* Clear screen and enable cursor */
SetAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
ClearScreen();
EnableCursor();
}
/**
* This routine formats the input string and prints it out to the stdout and serial console.
*
* @param Format
* The formatted string that is to be written to the output.
*
* @param ...
* Depending on the format string, this routine might expect a sequence of additional arguments.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::Print(IN PCWSTR Format,
IN ...)
{
RTL_PRINT_CONTEXT ConsolePrintContext, SerialPrintContext;
VA_LIST Arguments;
/* Initialise the print contexts */
ConsolePrintContext.WriteWideCharacter = PutChar;
SerialPrintContext.WriteWideCharacter = Debug::PutChar;
/* Initialise the va_list */
VA_START(Arguments, Format);
/* Format and print the string to the stdout */
RTL::WideString::FormatWideString(&ConsolePrintContext, (PWCHAR)Format, Arguments);
/* Print to serial console only if not running under OVMF */
if(RTL::WideString::CompareWideString(XtLoader::GetEfiSystemTable()->FirmwareVendor, L"EDK II", 6) != 0)
{
/* Check if debugging enabled and if EFI serial port is fully initialized */
if(DEBUG && Debug::SerialPortReady())
{
/* Format and print the string to the serial console */
RTL::WideString::FormatWideString(&SerialPrintContext, (PWCHAR)Format, Arguments);
}
}
/* Clean up the va_list */
VA_END(Arguments);
}
/**
* Writes a character to the default EFI console.
*
* @param Character
* The integer promotion of the character to be written.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
XTSTATUS
Console::PutChar(IN WCHAR Character)
{
WCHAR Buffer[2];
/* Check if character is a newline ('\n') */
if(Character == L'\n')
{
/* Print carriage return ('\r') as well */
PutChar(L'\r');
}
/* Write character to the screen console */
Buffer[0] = Character;
Buffer[1] = 0;
XtLoader::GetEfiSystemTable()->ConOut->OutputString(XtLoader::GetEfiSystemTable()->ConOut, Buffer);
/* Return success */
return STATUS_SUCCESS;
}
/**
* Queries information concerning the output devices supported text mode.
*
* @param ResX
* Supplies a buffer to receive the horizontal resolution.
*
* @param ResY
* Supplies a buffer to receive the vertical resolution.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::QueryMode(OUT PUINT_PTR ResX,
OUT PUINT_PTR ResY)
{
XtLoader::GetEfiSystemTable()->ConOut->QueryMode(XtLoader::GetEfiSystemTable()->ConOut,
XtLoader::GetEfiSystemTable()->ConOut->Mode->Mode, ResX, ResY);
}
/**
* Reads a keystroke from the input device.
*
* @param Key
* Supplies a pointer to the EFI_INPUT_KEY structure that will receive the keystroke.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::ReadKeyStroke(OUT PEFI_INPUT_KEY Key)
{
XtLoader::GetEfiSystemTable()->ConIn->ReadKeyStroke(XtLoader::GetEfiSystemTable()->ConIn, Key);
}
/**
* Resets the console input device and clears its input buffer.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::ResetInputBuffer()
{
XtLoader::GetEfiSystemTable()->ConIn->Reset(XtLoader::GetEfiSystemTable()->ConIn, FALSE);
}
/**
* Sets the foreground and background colors.
*
* @param Attribute
* Specifies the foreground and background colors (bits 0..3 are fg, and bits 4..6 are bg color).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::SetAttributes(IN ULONGLONG Attributes)
{
XtLoader::GetEfiSystemTable()->ConOut->SetAttribute(XtLoader::GetEfiSystemTable()->ConOut, Attributes);
}
/**
* Sets new coordinates of the console cursor position.
*
* @param PosX
* Specifies the new X coordinate of the cursor.
*
* @param PosY
* Specifies the new Y coordinate of the cursor.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::SetCursorPosition(IN ULONGLONG PosX,
IN ULONGLONG PosY)
{
XtLoader::GetEfiSystemTable()->ConOut->SetCursorPosition(XtLoader::GetEfiSystemTable()->ConOut, PosX, PosY);
}
/**
* Sets the output console device to the requested mode.
*
* @param Mode
* Supplies a text mode number to set.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Console::SetMode(IN ULONGLONG Mode)
{
return XtLoader::GetEfiSystemTable()->ConOut->SetMode(XtLoader::GetEfiSystemTable()->ConOut, Mode);
}
/**
* Displays the string on the device at the current cursor location.
*
* @param String
* The string to be displayed.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Console::Write(IN PCWSTR String)
{
XtLoader::GetEfiSystemTable()->ConOut->OutputString(XtLoader::GetEfiSystemTable()->ConOut, (PWSTR)String);
}

60
boot/xtldr/data.cc Normal file
View File

@@ -0,0 +1,60 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/data.cc
* DESCRIPTION: XT Boot Loader global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
* Aiken Harris <harraiken91@gmail.com>
*/
#include <xtldr.hh>
/* XT Boot Loader menu list */
PLIST_ENTRY Configuration::BootMenuList = NULLPTR;
/* XT Boot Loader configuration list */
LIST_ENTRY Configuration::Config;
/* XT Boot Loader loaded configuration */
LIST_ENTRY Configuration::ConfigSections;
/* List of user-editable boot options */
PCWSTR Configuration::EditableConfigOptions[] = {
L"BootModules", L"SystemType", L"SystemPath",
L"KernelFile", L"InitrdFile", L"HalFile",
L"Parameters", NULLPTR
};
/* XT Boot Loader serial ports list */
ULONG Debug::ComPortList[COMPORT_COUNT] = COMPORT_ADDRESS;
/* A list of enabled debug ports */
ULONG Debug::EnabledDebugPorts;
/* XT Boot Loader serial port handle */
CPPORT Debug::SerialPort;
/* XT Boot Loader registered boot protocol list */
LIST_ENTRY Protocol::BootProtocols;
/* XT Boot Loader protocol */
XTBL_LOADER_PROTOCOL Protocol::LoaderProtocol;
/* XT Boot Loader loaded modules list */
LIST_ENTRY Protocol::LoadedModules;
/* List of available block devices */
LIST_ENTRY Volume::EfiBlockDevices;
/* Pointer to the boot menu callback routine */
PBL_XT_BOOT_MENU XtLoader::BootMenu = NULLPTR;
/* EFI Image Handle */
EFI_HANDLE XtLoader::EfiImageHandle;
/* EFI System Table */
PEFI_SYSTEM_TABLE XtLoader::EfiSystemTable;
/* XT Boot Loader status data */
XTBL_STATUS XtLoader::LoaderStatus = {0};

402
boot/xtldr/debug.cc Normal file
View File

@@ -0,0 +1,402 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/debug.cc
* DESCRIPTION: XT Boot Loader debugging support
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* Enables I/O space access to all serial controllers found on the PCI(E) root bridge.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Debug::ActivateSerialIOController()
{
EFI_GUID PciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID;
PEFI_PCI_ROOT_BRIDGE_IO_PROTOCOL PciDev;
USHORT Bus, Device, Function, Command;
UINT_PTR Index, PciHandleSize;
PEFI_HANDLE PciHandle = NULLPTR;
PCI_COMMON_HEADER PciHeader;
EFI_STATUS Status;
ULONGLONG Address;
/* Allocate memory for single EFI_HANDLE, what should be enough in most cases */
PciHandleSize = sizeof(EFI_HANDLE);
Status = Memory::AllocatePool(PciHandleSize, (PVOID*)&PciHandle);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Get all instances of PciRootBridgeIo */
Status = XtLoader::GetEfiSystemTable()->BootServices->LocateHandle(ByProtocol, &PciGuid, NULLPTR,
&PciHandleSize, PciHandle);
if(Status == STATUS_EFI_BUFFER_TOO_SMALL)
{
/* Reallocate more memory as requested by UEFI */
Memory::FreePool(PciHandle);
Status = Memory::AllocatePool(PciHandleSize, (PVOID*)&PciHandle);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory reallocation failure */
return Status;
}
/* Second attempt to get instances of PciRootBridgeIo */
Status = XtLoader::GetEfiSystemTable()->BootServices->LocateHandle(ByProtocol, &PciGuid, NULLPTR,
&PciHandleSize, PciHandle);
}
/* Make sure successfully obtained PciRootBridgeIo instances */
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get PciRootBridgeIo instances */
return Status;
}
/* Enumerate all devices for each handle, which decides a segment and a bus number range */
for(Index = 0; Index < (PciHandleSize / sizeof(EFI_HANDLE)); Index++)
{
/* Get inferface from the protocol */
Status = XtLoader::GetEfiSystemTable()->BootServices->HandleProtocol(PciHandle[Index], &PciGuid, (PVOID*)&PciDev);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get interface */
return Status;
}
/* Enumerate whole PCI bridge */
for(Bus = 0; Bus <= PCI_MAX_BRIDGE_NUMBER; Bus++)
{
/* Enumerate all devices for each bus */
for(Device = 0; Device < PCI_MAX_DEVICES; Device++)
{
/* Enumerate all functions for each devices */
for(Function = 0; Function < PCI_MAX_FUNCTION; Function++)
{
/* Read configuration space */
Address = ((ULONGLONG)((((UINT_PTR) Bus) << 24) + (((UINT_PTR) Device) << 16) +
(((UINT_PTR) Function) << 8) + ((UINT_PTR) 0)));
PciDev->Pci.Read(PciDev, EfiPciIoWidthUint32, Address, sizeof (PciHeader) / sizeof (UINT), &PciHeader);
/* Check if device exists */
if(PciHeader.VendorId == PCI_INVALID_VENDORID)
{
/* Skip non-existen device */
continue;
}
/* Check if device is serial controller or multiport serial controller */
if(PciHeader.BaseClass == 0x07 && (PciHeader.SubClass == 0x00 || PciHeader.SubClass == 0x02))
{
/* Enable I/O space access */
Address |= 0x4;
Command = PCI_ENABLE_IO_SPACE;
Status = PciDev->Pci.Write(PciDev, EfiPciIoWidthUint16, Address, 1, &Command);
}
}
}
}
}
/* Return SUCCESS */
return STATUS_EFI_SUCCESS;
}
/**
* This routine initializes the XTLDR debug console.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Debug::InitializeDebugConsole()
{
ULONG PortAddress, PortNumber, BaudRate;
PWCHAR DebugConfiguration, DebugPort, LastPort;
EFI_STATUS Status;
/* Set default serial port options */
PortAddress = 0;
PortNumber = 0;
BaudRate = 0;
/* Get debug configuration */
Configuration::GetValue(L"DEBUG", &DebugConfiguration);
/* Make sure any debug options are provided and debug console is not initialized yet */
if(DebugConfiguration && EnabledDebugPorts == 0)
{
/* Find all debug ports */
DebugPort = RTL::WideString::TokenizeWideString(DebugConfiguration, L";", &LastPort);
/* Iterate over all debug ports */
while(DebugPort != NULLPTR)
{
/* Check what port is set for debugging */
if(RTL::WideString::CompareWideStringInsensitive(DebugPort, L"COM", 3) == 0)
{
/* Read COM port number */
DebugPort += 3;
while(*DebugPort >= '0' && *DebugPort <= '9')
{
/* Get port number */
PortNumber *= 10;
PortNumber += *DebugPort - '0';
DebugPort++;
}
/* Check if custom COM port address supplied */
if(PortNumber == 0 && RTL::WideString::CompareWideStringInsensitive(DebugPort, L":0x", 3) == 0)
{
/* COM port address provided */
DebugPort += 3;
while((*DebugPort >= '0' && *DebugPort <= '9') ||
(*DebugPort >= 'A' && *DebugPort <= 'F') ||
(*DebugPort >= 'a' && *DebugPort <= 'f'))
{
/* Get port address */
PortAddress *= 16;
if(*DebugPort >= '0' && *DebugPort <= '9')
{
PortAddress += *DebugPort - '0';
}
else if(*DebugPort >= 'A' && *DebugPort <= 'F')
{
PortAddress += *DebugPort - 'A' + 10;
}
else if(*DebugPort >= 'a' && *DebugPort <= 'f')
{
PortAddress += *DebugPort - 'a' + 10;
}
DebugPort++;
}
}
/* Look for additional COM port parameters */
if(*DebugPort == ',')
{
/* Baud rate provided */
DebugPort++;
while(*DebugPort >= '0' && *DebugPort <= '9')
{
/* Get baud rate */
BaudRate *= 10;
BaudRate += *DebugPort - '0';
DebugPort++;
}
}
/* Enable debug port */
EnabledDebugPorts |= XTBL_DEBUGPORT_SERIAL;
}
else if(RTL::WideString::CompareWideStringInsensitive(DebugPort, L"SCREEN", 5) == 0)
{
/* Enable debug port */
EnabledDebugPorts |= XTBL_DEBUGPORT_SCREEN;
}
else
{
/* Unsupported debug port specified */
Console::Print(L"ERROR: Unsupported debug port ('%S') specified\n", DebugPort);
EfiUtils::SleepExecution(3000);
}
/* Take next debug port */
DebugPort = RTL::WideString::TokenizeWideString(NULLPTR, L";", &LastPort);
}
/* Check if serial debug port is enabled */
if(EnabledDebugPorts & XTBL_DEBUGPORT_SERIAL)
{
/* Try to initialize COM port */
Status = InitializeSerialPort(PortNumber, PortAddress, BaudRate);
if(Status != STATUS_EFI_SUCCESS)
{
/* Remove serial debug port, as COM port initialization failed and return */
EnabledDebugPorts &= ~XTBL_DEBUGPORT_SERIAL;
return Status;
}
}
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* This routine initializes the serial debug console.
*
* @param PortNumber
* Supplies a port number.
*
* @param PortAddress
* Supplies an address of the COM port.
*
* @param BaudRate
* Supplies an optional port baud rate.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Debug::InitializeSerialPort(IN ULONG PortNumber,
IN ULONG PortAddress,
IN ULONG BaudRate)
{
EFI_STATUS EfiStatus;
XTSTATUS Status;
/* Check if custom COM port address supplied */
if(!PortAddress)
{
/* We support only a pre-defined number of ports */
if(PortNumber > COMPORT_COUNT)
{
/* Fail if wrong/unsupported port used */
return STATUS_INVALID_PARAMETER;
}
/* Check if serial port is set */
if(PortNumber == 0)
{
/* Use COM1 by default */
PortNumber = 1;
}
/* Set custom port address based on the port number and print debug message */
PortAddress = ComPortList[PortNumber - 1];
Console::Print(L"Initializing serial console at port COM%d\n", PortNumber);
}
else
{
/* Custom port address supplied, print debug message */
Console::Print(L"Initializing serial console at COM port address: 0x%lX\n", PortAddress);
}
/* Initialize COM port */
Status = HL::ComPort::InitializeComPort(&SerialPort, (PUCHAR)UlongToPtr(PortAddress), BaudRate);
/* Port not found under supplied address */
if(Status == STATUS_NOT_FOUND && PortAddress)
{
/* This might be PCI(E) serial controller, try to activate I/O space access first */
EfiStatus = ActivateSerialIOController();
if(EfiStatus == STATUS_EFI_SUCCESS)
{
/* Try to reinitialize COM port */
Console::Print(L"Enabled I/O space access for all PCI(E) serial controllers found\n");
Status = HL::ComPort::InitializeComPort(&SerialPort, (PUCHAR)UlongToPtr(PortAddress), BaudRate);
}
}
/* Check COM port initialization status code */
if(Status != STATUS_SUCCESS)
{
/* Serial port initialization failed, mark as not ready */
return STATUS_EFI_NOT_READY;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* This routine formats the input string and prints it out to the debug ports.
*
* @param Format
* The formatted string that is to be written to the output.
*
* @param ...
* Depending on the format string, this routine might expect a sequence of additional arguments.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Debug::Print(IN PCWSTR Format,
IN ...)
{
RTL_PRINT_CONTEXT ConsolePrintContext, SerialPrintContext;
VA_LIST Arguments;
/* Check if debugging enabled and if EFI serial port is fully initialized */
if(DEBUG)
{
/* Initialize the print contexts */
ConsolePrintContext.WriteWideCharacter = Console::PutChar;
SerialPrintContext.WriteWideCharacter = PutChar;
/* Initialise the va_list */
VA_START(Arguments, Format);
/* Check if serial debug port is enabled */
if((EnabledDebugPorts & XTBL_DEBUGPORT_SERIAL) && (SerialPort.Flags & COMPORT_FLAG_INIT))
{
/* Format and print the string to the serial console */
RTL::WideString::FormatWideString(&SerialPrintContext, (PWCHAR)Format, Arguments);
}
/* Check if screen debug port is enabled and Boot Services are still available */
if((EnabledDebugPorts & XTBL_DEBUGPORT_SCREEN) && (XtLoader::GetBootServicesStatus() == TRUE))
{
/* Format and print the string to the screen */
RTL::WideString::FormatWideString(&ConsolePrintContext, (PWCHAR)Format, Arguments);
}
/* Clean up the va_list */
VA_END(Arguments);
}
}
/**
* Writes a character to the serial console.
*
* @param Character
* The integer promotion of the character to be written.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
XTSTATUS
Debug::PutChar(IN WCHAR Character)
{
WCHAR Buffer[2];
/* Write character to the serial console */
Buffer[0] = Character;
Buffer[1] = 0;
return HL::ComPort::WriteComPort(&SerialPort, Buffer[0]);
}
/**
* Determines if the serial port has been successfully initialized and is ready for communication.
*
* @return This routine returns TRUE if the serial port is initialized and ready, FALSE otherwise.
*
* @since XT 1.0
*/
XTCDECL
BOOLEAN
Debug::SerialPortReady()
{
return (SerialPort.Flags & COMPORT_FLAG_INIT);
}

462
boot/xtldr/efiutils.cc Normal file
View File

@@ -0,0 +1,462 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/efiutils.cc
* DESCRIPTION: EFI related routines for XT Boot Loader
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* Reboots into UEFI firmware setup interface.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::EnterFirmwareSetup()
{
EFI_GUID Guid = EFI_GLOBAL_VARIABLE_GUID;
PULONGLONG SetupSupport = NULLPTR;
ULONGLONG Indications;
EFI_STATUS Status;
/* Check if booting into firmware interface is supported */
Status = GetEfiVariable(&Guid, L"OsIndicationsSupported", (PVOID*)&SetupSupport);
if(Status != STATUS_EFI_SUCCESS || !(*SetupSupport & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
{
/* Reboot into firmware setup is not supported */
Debug::Print(L"WARNING: Reboot into firmware setup interface not supported\n");
if(SetupSupport)
{
Memory::FreePool((PVOID)SetupSupport);
}
return STATUS_EFI_UNSUPPORTED;
}
Memory::FreePool((PVOID)SetupSupport);
/* Get the value of OsIndications variable */
Indications = 0;
Status = GetEfiVariable(&Guid, L"OsIndications", (PVOID*)&Indications);
/* Enable FW setup on next boot */
Indications |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
Status = SetEfiVariable(&Guid, L"OsIndications", (PVOID)&Indications, sizeof(Indications));
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to update OsIndications variable */
return Status;
}
/* Reboot into firmware setup */
RebootSystem();
/* Must not reach this point, just make the compiler happy */
return STATUS_EFI_SUCCESS;
}
/**
* Exits EFI boot services.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::ExitBootServices()
{
PEFI_MEMORY_MAP MemoryMap;
EFI_STATUS Status;
ULONG Counter;
/* Boot Services might be partially shutdown, so mark them as unavailable */
XtLoader::DisableBootServices();
/* Allocate buffer for EFI memory map */
Status = Memory::AllocatePool(sizeof(EFI_MEMORY_MAP), (PVOID*)&MemoryMap);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
Debug::Print(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Zero fill the buffer and initialize counter */
RTL::Memory::ZeroMemory(MemoryMap, sizeof(EFI_MEMORY_MAP));
Counter = 0xFF;
/* Attempt to exit boot services */
while(Counter > 0)
{
/* Get memory map each time as it can change between two calls */
Status = Memory::GetMemoryMap(MemoryMap);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get new memory map */
return Status;
}
/* Exit boot services */
Status = XtLoader::GetEfiSystemTable()->BootServices->ExitBootServices(XtLoader::GetEfiImageHandle(),
MemoryMap->MapKey);
if(Status == STATUS_EFI_SUCCESS)
{
break;
}
/* Decrement counter */
Counter--;
}
/* Return EFI status code */
return Status;
}
/**
* Gets the address of a reqested system configuration table.
*
* @param TableGuid
* Supplies a GUID of the configuration table.
*
* @param Table
* Supplies a pointer to the memory area where the table address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::GetConfigurationTable(IN PEFI_GUID TableGuid,
OUT PVOID *Table)
{
SIZE_T Index;
/* Iterate through all system configuration tables */
for(Index = 0; Index < XtLoader::GetEfiSystemTable()->NumberOfTableEntries; Index++)
{
/* Check if this table matches requested table */
if(RTL::Guid::CompareGuids((PGUID)&(XtLoader::GetEfiSystemTable()->ConfigurationTable[Index].VendorGuid),
(PGUID)TableGuid))
{
/* Found requested table, return success */
*Table = XtLoader::GetEfiSystemTable()->ConfigurationTable[Index].VendorTable;
return STATUS_EFI_SUCCESS;
}
}
/* Table not found */
*Table = NULLPTR;
return STATUS_EFI_NOT_FOUND;
}
/**
* Gets the value of the EFI variable.
*
* @param Vendor
* Supplies a pointer to the unique vendor GUID.
*
* @param VariableName
* Supplies a pointer to tge NULL-terminated string containing the variable name.
*
* @param VariableValue
* Supplies a pointer to the buffer, where the variable value will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::GetEfiVariable(IN PEFI_GUID Vendor,
IN PCWSTR VariableName,
OUT PVOID *VariableValue)
{
EFI_STATUS Status;
PVOID Buffer;
UINT_PTR Size = 0;
/* Allocate a buffer for storing a variable's value */
Size = EFI_MAXIMUM_VARIABLE_SIZE * sizeof(PWCHAR);
Status = Memory::AllocatePool(Size, (PVOID*)&Buffer);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Attempt to get variable value */
Status = XtLoader::GetEfiSystemTable()->RuntimeServices->GetVariable((PWCHAR)VariableName, Vendor, NULLPTR,
&Size, Buffer);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get variable, probably not found such one */
return Status;
}
/* Get variable value and return success */
*VariableValue = Buffer;
return STATUS_EFI_SUCCESS;
}
/**
* Returns a random value based on the initialized RNG buffer.
*
* @param RNGBuffer
* Supplies a pointer to the RNG buffer.
*
* @return This routine returns a random value.
*
* @since XT 1.0
*
* @see https://en.wikipedia.org/wiki/Xorshift
*/
XTCDECL
ULONGLONG
EfiUtils::GetRandomValue(IN OUT PULONGLONG RNGBuffer)
{
/* Recalculate RNG buffer with XORSHIFT */
*RNGBuffer ^= *RNGBuffer >> 12;
*RNGBuffer ^= *RNGBuffer << 25;
*RNGBuffer ^= *RNGBuffer >> 27;
/* Return random value */
return *RNGBuffer * 0x2545F4914F6CDD1D;
}
/**
* Checks whether SecureBoot is enabled or not.
*
* @return Numeric representation of SecureBoot status (0 = Disabled, >0 = Enabled, <0 SetupMode).
*
* @since XT 1.0
*/
XTCDECL
INT_PTR
EfiUtils::GetSecureBootStatus()
{
EFI_GUID VarGuid = EFI_GLOBAL_VARIABLE_GUID;
INT_PTR SecureBootStatus = 0;
INT_PTR VarValue = 0;
UINT_PTR Size;
Size = sizeof(INT_PTR);
if(XtLoader::GetEfiSystemTable()->RuntimeServices->GetVariable((PWCHAR)L"SecureBoot", &VarGuid,
NULLPTR, &Size, &VarValue) == STATUS_EFI_SUCCESS)
{
SecureBootStatus = VarValue;
Size = sizeof(INT_PTR);
if((XtLoader::GetEfiSystemTable()->RuntimeServices->GetVariable((PWCHAR)L"SetupMode", &VarGuid,
NULLPTR, &Size, &VarValue) == STATUS_EFI_SUCCESS) && VarValue != 0)
{
SecureBootStatus = -1;
}
}
/* Return SecureBoot status */
return SecureBootStatus;
}
/**
* Initializes the RNG buffer with random bytes from the default EFI RNG algorithm.
*
* @param RNGBuffer
* Supplies a pointer to the RNG buffer.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::InitializeEntropy(PULONGLONG RNGBuffer)
{
EFI_GUID RngGuid = EFI_RNG_PROTOCOL_GUID;
PEFI_RNG_PROTOCOL Rng;
EFI_STATUS Status;
ULONGLONG Seed;
/* Initialize variables */
Rng = NULLPTR;
Seed = 0;
/* Locate RNG protocol */
Status = XtLoader::GetEfiSystemTable()->BootServices->LocateProtocol(&RngGuid, NULLPTR, (PVOID *)&Rng);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to locate RNG protocol, return status code */
return Status;
}
/* Get RNG value using the default algorithm */
Status = Rng->GetRNG(Rng, NULLPTR, 8, (PUCHAR)&Seed);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get RNG value, return status code */
return Status;
}
/* Initialize RNG state and return success */
*RNGBuffer = Seed ? Seed : 1;
return STATUS_EFI_SUCCESS;
}
/**
* Loads an EFI image into memory.
*
* @param DevicePath
* Specifies a device path from which the image is loaded.
*
* @param ImageData
* Supplies a pointer to the memory are containing a copy of the EFI image.
*
* @param ImageSize
* Supplies the size (in bytes) of the EFI image.
*
* @param ImageHandle
* Supplies a pointer to the memory area, where an EFI_image handle will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::LoadEfiImage(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath,
IN PVOID ImageData,
IN SIZE_T ImageSize,
OUT PEFI_HANDLE ImageHandle)
{
/* Load EFI image */
return XtLoader::GetEfiSystemTable()->BootServices->LoadImage(FALSE, XtLoader::GetEfiImageHandle(), DevicePath,
ImageData, ImageSize, ImageHandle);
}
/**
* Reboots the machine.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::RebootSystem()
{
/* Reboot machine */
return XtLoader::GetEfiSystemTable()->RuntimeServices->ResetSystem(EfiResetCold, STATUS_EFI_SUCCESS, 0, NULLPTR);
}
/**
* Sets a value of an EFI variable.
*
* @param Vendor
* Supplies a pointer to the unique vendor GUID.
*
* @param VariableName
* Supplies a pointer to tge NULL-terminated string containing the variable name.
*
* @param VariableValue
* Supplies the contents of the variable.
*
* @param Size
* Supplies the size of the variable data buffer.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::SetEfiVariable(IN PEFI_GUID Vendor,
IN PCWSTR VariableName,
IN PVOID VariableValue,
IN UINT_PTR Size)
{
ULONG Attributes;
/* Set EFI variable */
Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
return XtLoader::GetEfiSystemTable()->RuntimeServices->SetVariable((PWCHAR)VariableName, Vendor, Attributes,
Size, VariableValue);
}
/**
* Shuts down the machine.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::ShutdownSystem()
{
/* Shutdown machine */
return XtLoader::GetEfiSystemTable()->RuntimeServices->ResetSystem(EfiResetShutdown, STATUS_EFI_SUCCESS, 0, NULLPTR);
}
/**
* Puts the system to sleep for the specified number of milliseconds.
*
* @param Milliseconds
* Supplies the number of milliseconds to sleep.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
EfiUtils::SleepExecution(IN ULONG_PTR Milliseconds)
{
XtLoader::GetEfiSystemTable()->BootServices->Stall(Milliseconds * 1000);
}
/**
* Executes a loaded EFI image entry point.
*
* @param ImageHandle
* Provides a handle of loaded image, that will be started.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::StartEfiImage(IN EFI_HANDLE ImageHandle)
{
return XtLoader::GetEfiSystemTable()->BootServices->StartImage(ImageHandle, NULLPTR, NULLPTR);
}
/**
* Waits for one or more EFI events.
*
* @param NumberOfEvents
* Supplies the number of events to wait for.
*
* @param Event
* Supplies the array of events to wait for.
*
* @param Index
* Receives the index of the event that was signaled.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
EfiUtils::WaitForEfiEvent(IN UINT_PTR NumberOfEvents,
IN PEFI_EVENT Event,
OUT PUINT_PTR Index)
{
return XtLoader::GetEfiSystemTable()->BootServices->WaitForEvent(NumberOfEvents, Event, Index);
}

View File

@@ -0,0 +1,142 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/includes/libxtos.hh
* DESCRIPTION: XT Loader to LIBXTOS interface
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
#ifndef __XTLDR_LIBXTOS_HH
#define __XTLDR_LIBXTOS_HH
#include <xtblapi.h>
/* Minimal forward references for AR classes used by XTLDR */
namespace AR
{
class CpuFunc
{
public:
STATIC XTCDECL BOOLEAN CpuId(IN OUT PCPUID_REGISTERS Registers);
STATIC XTCDECL ULONG_PTR ReadControlRegister(IN USHORT ControlRegister);
STATIC XTCDECL ULONGLONG ReadModelSpecificRegister(IN ULONG Register);
STATIC XTCDECL VOID WriteControlRegister(IN USHORT ControlRegister,
IN UINT_PTR Value);
};
class ProcSup
{
public:
STATIC XTAPI VOID GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType,
OUT PVOID *TrampolineCode,
OUT PULONG_PTR TrampolineSize);
};
}
/* Minimal forward references for HL classes used by XTLDR */
namespace HL
{
class ComPort
{
public:
STATIC XTCDECL XTSTATUS InitializeComPort(IN OUT PCPPORT Port,
IN PUCHAR PortAddress,
IN ULONG BaudRate);
STATIC XTCDECL XTSTATUS WriteComPort(IN PCPPORT Port,
IN UCHAR Byte);
};
class IoPort
{
public:
STATIC XTCDECL UCHAR ReadPort8(IN USHORT Port);
STATIC XTCDECL USHORT ReadPort16(IN USHORT Port);
STATIC XTCDECL ULONG ReadPort32(IN USHORT Port);
STATIC XTCDECL VOID WritePort8(IN USHORT Port,
IN UCHAR Value);
STATIC XTCDECL VOID WritePort16(IN USHORT Port,
IN USHORT Value);
STATIC XTCDECL VOID WritePort32(IN USHORT Port,
IN ULONG Value);
};
}
/* Minimal forward references for RTL classes used by XTLDR */
namespace RTL
{
class Guid
{
public:
STATIC XTAPI BOOLEAN CompareGuids(IN PGUID Guid1,
IN PGUID Guid2);
};
class LinkedList
{
public:
STATIC XTCDECL VOID InitializeListHead(IN PLIST_ENTRY ListHead);
STATIC XTCDECL VOID InsertHeadList(IN OUT PLIST_ENTRY ListHead,
IN PLIST_ENTRY Entry);
STATIC XTCDECL VOID InsertTailList(IN OUT PLIST_ENTRY ListHead,
IN PLIST_ENTRY Entry);
STATIC XTCDECL VOID RemoveEntryList(IN PLIST_ENTRY Entry);
};
class Memory
{
public:
STATIC XTAPI SIZE_T CompareMemory(IN PCVOID LeftBuffer,
IN PCVOID RightBuffer,
IN SIZE_T Length);
STATIC XTAPI VOID CopyMemory(OUT PVOID Destination,
IN PCVOID Source,
IN SIZE_T Length);
STATIC XTAPI VOID MoveMemory(OUT PVOID Destination,
IN PCVOID Source,
IN SIZE_T Length);
STATIC XTAPI VOID SetMemory(OUT PVOID Destination,
IN UCHAR Byte,
IN SIZE_T Length);
STATIC XTAPI VOID ZeroMemory(OUT PVOID Destination,
IN SIZE_T Length);
};
class String
{
public:
STATIC XTAPI SIZE_T CompareString(IN PCSTR String1,
IN PCSTR String2,
IN SIZE_T Length);
STATIC XTAPI SIZE_T StringLength(IN PCSTR String,
IN SIZE_T MaxLength);
STATIC XTAPI SIZE_T StringToWideString(OUT PWCHAR Destination,
IN PCSTR *Source,
IN SIZE_T Length);
STATIC XTAPI PCHAR TrimString(IN PCHAR String);
};
class WideString
{
public:
STATIC XTAPI SIZE_T CompareWideString(IN PCWSTR String1,
IN PCWSTR String2,
IN SIZE_T Length);
STATIC XTAPI SIZE_T CompareWideStringInsensitive(IN PCWSTR String1,
IN PCWSTR String2,
IN SIZE_T Length);
STATIC XTAPI PWCHAR ConcatenateWideString(OUT PWCHAR Destination,
IN PWCHAR Source,
IN SIZE_T Count);
STATIC XTAPI XTSTATUS FormatWideString(IN PRTL_PRINT_CONTEXT Context,
IN PCWSTR Format,
IN VA_LIST ArgumentList);
STATIC XTAPI PWCHAR TokenizeWideString(IN PWCHAR String,
IN PCWSTR Delimiter,
IN OUT PWCHAR *SavePtr);
STATIC XTAPI SIZE_T WideStringLength(IN PCWSTR String,
IN SIZE_T MaxLength);
};
}
#endif /* __XTLDR_LIBXTOS_HH */

View File

@@ -0,0 +1,351 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/includes/xtldr.hh
* DESCRIPTION: Top level header for XTLDR
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_XTLDR_HH
#define __XTLDR_XTLDR_HH
#include <xtblapi.h>
#include <xtver.h>
#include <libxtos.hh>
class BootUtils
{
public:
STATIC XTCDECL BOOLEAN GetBooleanParameter(IN PCWSTR Parameters,
IN PCWSTR Needle);
};
class Configuration
{
private:
STATIC PLIST_ENTRY BootMenuList;
STATIC LIST_ENTRY Config;
STATIC LIST_ENTRY ConfigSections;
STATIC PCWSTR EditableConfigOptions[];
public:
STATIC XTCDECL BOOLEAN GetBooleanValue(IN PCWSTR ConfigName);
STATIC XTCDECL EFI_STATUS GetBootOptionValue(IN PLIST_ENTRY Options,
IN PCWSTR OptionName,
OUT PWCHAR *OptionValue);
STATIC XTCDECL VOID GetEditableOptions(OUT PCWSTR **OptionsArray,
OUT PULONG OptionsCount);
STATIC XTCDECL EFI_STATUS GetValue(IN PCWSTR ConfigName,
OUT PWCHAR *ConfigValue);
STATIC XTCDECL EFI_STATUS InitializeBootMenuList(IN ULONG MaxNameLength,
OUT PXTBL_BOOTMENU_ITEM *MenuEntries,
OUT PULONG EntriesCount,
OUT PULONG DefaultId);
STATIC XTCDECL VOID InitializeConfiguration();
STATIC XTCDECL EFI_STATUS LoadConfiguration();
STATIC XTCDECL EFI_STATUS ParseCommandLine();
STATIC XTCDECL EFI_STATUS SetBootOptionValue(IN PLIST_ENTRY Options,
IN PCWSTR OptionName,
IN PCWSTR OptionValue);
private:
STATIC XTCDECL EFI_STATUS ParseConfigFile(IN CONST PCHAR RawConfig,
OUT PLIST_ENTRY Configuration);
STATIC XTCDECL EFI_STATUS ReadConfigFile(IN PCWSTR ConfigDirectory,
IN PCWSTR ConfigFile,
OUT PCHAR *ConfigData);
STATIC XTCDECL EFI_STATUS SetValue(IN PCWSTR ConfigName,
IN PCWSTR ConfigValue);
STATIC XTCDECL VOID UpdateConfiguration(IN PLIST_ENTRY NewConfig);
};
class Console
{
public:
STATIC XTCDECL VOID ClearLine(IN ULONGLONG LineNo);
STATIC XTCDECL VOID ClearScreen();
STATIC XTCDECL VOID DisableCursor();
STATIC XTCDECL VOID EnableCursor();
STATIC XTCDECL VOID InitializeConsole();
STATIC XTCDECL VOID Print(IN PCWSTR Format,
IN ...);
STATIC XTCDECL XTSTATUS PutChar(IN WCHAR Character);
STATIC XTCDECL VOID QueryMode(OUT PUINT_PTR ResX,
OUT PUINT_PTR ResY);
STATIC XTCDECL VOID ReadKeyStroke(OUT PEFI_INPUT_KEY Key);
STATIC XTCDECL VOID ResetInputBuffer();
STATIC XTCDECL VOID SetAttributes(IN ULONGLONG Attributes);
STATIC XTCDECL VOID SetCursorPosition(IN ULONGLONG PosX,
IN ULONGLONG PosY);
STATIC XTCDECL VOID Write(IN PCWSTR String);
private:
STATIC XTCDECL EFI_STATUS SetMode(IN ULONGLONG Mode);
};
class Debug
{
private:
STATIC ULONG ComPortList[COMPORT_COUNT];
STATIC ULONG EnabledDebugPorts;
STATIC CPPORT SerialPort;
public:
STATIC XTCDECL EFI_STATUS InitializeDebugConsole();
STATIC XTCDECL VOID Print(IN PCWSTR Format,
IN ...);
STATIC XTCDECL XTSTATUS PutChar(IN WCHAR Character);
STATIC XTCDECL BOOLEAN SerialPortReady();
private:
STATIC XTCDECL EFI_STATUS ActivateSerialIOController();
STATIC XTCDECL EFI_STATUS InitializeSerialPort(IN ULONG PortNumber,
IN ULONG PortAddress,
IN ULONG BaudRate);
};
class EfiUtils
{
public:
STATIC XTCDECL EFI_STATUS EnterFirmwareSetup();
STATIC XTCDECL EFI_STATUS ExitBootServices();
STATIC XTCDECL EFI_STATUS GetConfigurationTable(IN PEFI_GUID TableGuid,
OUT PVOID *Table);
STATIC XTCDECL EFI_STATUS GetEfiVariable(IN PEFI_GUID Vendor,
IN PCWSTR VariableName,
OUT PVOID *VariableValue);
STATIC XTCDECL ULONGLONG GetRandomValue(IN OUT PULONGLONG RNGBuffer);
STATIC XTCDECL INT_PTR GetSecureBootStatus();
STATIC XTCDECL EFI_STATUS InitializeEntropy(PULONGLONG RNGBuffer);
STATIC XTCDECL EFI_STATUS LoadEfiImage(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath,
IN PVOID ImageData,
IN SIZE_T ImageSize,
OUT PEFI_HANDLE ImageHandle);
STATIC XTCDECL EFI_STATUS RebootSystem();
STATIC XTCDECL EFI_STATUS SetEfiVariable(IN PEFI_GUID Vendor,
IN PCWSTR VariableName,
IN PVOID VariableValue,
IN UINT_PTR Size);
STATIC XTCDECL EFI_STATUS ShutdownSystem();
STATIC XTCDECL VOID SleepExecution(IN ULONG_PTR Milliseconds);
STATIC XTCDECL EFI_STATUS StartEfiImage(IN EFI_HANDLE ImageHandle);
STATIC XTCDECL EFI_STATUS WaitForEfiEvent(IN UINT_PTR NumberOfEvents,
IN PEFI_EVENT Event,
OUT PUINT_PTR Index);
};
class Memory
{
public:
STATIC XTCDECL EFI_STATUS AllocatePages(IN EFI_ALLOCATE_TYPE AllocationType,
IN ULONGLONG NumberOfPages,
OUT PEFI_PHYSICAL_ADDRESS Memory);
STATIC XTCDECL EFI_STATUS AllocatePool(IN UINT_PTR Size,
OUT PVOID *Memory);
STATIC XTCDECL EFI_STATUS BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR SelfMapAddress);
STATIC XTCDECL EFI_STATUS FreePages(IN ULONGLONG NumberOfPages,
IN EFI_PHYSICAL_ADDRESS Memory);
STATIC XTCDECL EFI_STATUS FreePool(IN PVOID Memory);
STATIC XTCDECL VOID GetMappingsCount(IN PXTBL_PAGE_MAPPING PageMap,
OUT PULONG NumberOfMappings);
STATIC XTCDECL EFI_STATUS GetMemoryMap(OUT PEFI_MEMORY_MAP MemoryMap);
STATIC XTCDECL PVOID GetVirtualAddress(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID PhysicalAddress);
STATIC XTCDECL VOID InitializePageMap(OUT PXTBL_PAGE_MAPPING PageMap,
IN SHORT PageMapLevel,
IN PAGE_SIZE PageSize);
STATIC XTCDECL EFI_STATUS MapEfiMemory(IN OUT PXTBL_PAGE_MAPPING PageMap,
IN OUT PVOID *MemoryMapAddress,
IN PBL_GET_MEMTYPE_ROUTINE GetMemoryTypeRoutine);
STATIC XTCDECL EFI_STATUS MapPage(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR VirtualAddress,
IN ULONG_PTR PhysicalAddress,
IN ULONG NumberOfPages);
STATIC XTCDECL EFI_STATUS MapVirtualMemory(IN OUT PXTBL_PAGE_MAPPING PageMap,
IN PVOID VirtualAddress,
IN PVOID PhysicalAddress,
IN ULONGLONG NumberOfPages,
IN LOADER_MEMORY_TYPE MemoryType);
STATIC XTCDECL PVOID PhysicalAddressToVirtual(IN PVOID PhysicalAddress,
IN PVOID PhysicalBase,
IN PVOID VirtualBase);
STATIC XTCDECL EFI_STATUS PhysicalListToVirtual(IN PXTBL_PAGE_MAPPING PageMap,
IN OUT PLIST_ENTRY ListHead,
IN PVOID PhysicalBase,
IN PVOID VirtualBase);
private:
STATIC XTCDECL LOADER_MEMORY_TYPE GetLoaderMemoryType(IN EFI_MEMORY_TYPE EfiMemoryType);
STATIC XTCDECL EFI_STATUS GetNextPageTable(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID PageTable,
IN SIZE_T Entry,
OUT PVOID *NextPageTable);
STATIC XTCDECL EFI_STATUS SelfMapPml(IN PXTBL_PAGE_MAPPING PageMap,
IN ULONG_PTR SelfMapAddress);
};
class Protocol
{
private:
STATIC LIST_ENTRY BootProtocols;
STATIC XTBL_LOADER_PROTOCOL LoaderProtocol;
STATIC LIST_ENTRY LoadedModules;
public:
STATIC XTCDECL EFI_STATUS CloseProtocol(IN PEFI_HANDLE Handle,
IN PEFI_GUID ProtocolGuid);
STATIC XTCDECL EFI_STATUS FindBootProtocol(IN PCWSTR SystemType,
OUT PEFI_GUID BootProtocolGuid);
STATIC XTCDECL PLIST_ENTRY GetModulesList();
STATIC XTCDECL EFI_STATUS InstallProtocol(IN PVOID Interface,
IN PEFI_GUID Guid);
STATIC XTCDECL VOID InitializeProtocol();
STATIC XTCDECL EFI_STATUS InvokeBootProtocol(IN PWCHAR ShortName,
IN PLIST_ENTRY OptionsList);
STATIC XTCDECL EFI_STATUS LoadModule(IN PWCHAR ModuleName);
STATIC XTCDECL EFI_STATUS LoadModules(IN PWCHAR ModulesList);
STATIC XTCDECL EFI_STATUS LocateProtocolHandles(OUT PEFI_HANDLE *Handles,
OUT PUINT_PTR Count,
IN PEFI_GUID ProtocolGuid);
STATIC XTCDECL EFI_STATUS OpenProtocol(OUT PEFI_HANDLE Handle,
OUT PVOID *ProtocolHandler,
IN PEFI_GUID ProtocolGuid);
STATIC XTCDECL EFI_STATUS OpenProtocolHandle(IN EFI_HANDLE Handle,
OUT PVOID *ProtocolHandler,
IN PEFI_GUID ProtocolGuid);
STATIC XTCDECL EFI_STATUS RegisterBootProtocol(IN PCWSTR SystemType,
IN PEFI_GUID BootProtocolGuid);
STATIC XTCDECL EFI_STATUS InstallXtLoaderProtocol();
private:
STATIC XTCDECL EFI_STATUS GetModuleInformation(IN PWCHAR SectionData,
IN ULONG SectionSize,
OUT PXTBL_MODULE_INFO ModuleInfo);
STATIC XTCDECL EFI_STATUS GetModuleInfoStrings(IN PWCHAR SectionData,
IN ULONG SectionSize,
OUT PWCHAR **ModInfo,
OUT PULONG InfoCount);
};
class Shell
{
public:
STATIC XTCDECL VOID StartLoaderShell();
private:
STATIC XTCDECL VOID PrintPrompt();
};
class TextUi
{
public:
STATIC XTCDECL VOID DisplayBootMenu();
STATIC XTCDECL VOID DisplayErrorDialog(IN PCWSTR Caption,
IN PCWSTR Message);
STATIC XTCDECL VOID DisplayInfoDialog(IN PCWSTR Caption,
IN PCWSTR Message);
STATIC XTCDECL VOID DisplayInputDialog(IN PCWSTR Caption,
IN PCWSTR Message,
IN OUT PWCHAR *InputFieldText);
STATIC XTCDECL XTBL_DIALOG_HANDLE DisplayProgressDialog(IN PCWSTR Caption,
IN PCWSTR Message,
IN UCHAR Percentage);
STATIC XTCDECL VOID UpdateProgressBar(IN PXTBL_DIALOG_HANDLE Handle,
IN PCWSTR Message,
IN UCHAR Percentage);
private:
STATIC XTCDECL VOID DetermineDialogBoxSize(IN OUT PXTBL_DIALOG_HANDLE Handle,
IN PCWSTR Message);
STATIC XTCDECL VOID DisplayEditMenu(IN PXTBL_BOOTMENU_ITEM MenuEntry);
STATIC XTCDECL VOID DrawBootMenu(OUT PXTBL_DIALOG_HANDLE Handle);
STATIC XTCDECL VOID DrawBootMenuEntry(IN PXTBL_DIALOG_HANDLE Handle,
IN PWCHAR MenuEntry,
IN UINT Position,
IN BOOLEAN Highlighted);
STATIC XTCDECL VOID DrawDialogBox(IN OUT PXTBL_DIALOG_HANDLE Handle,
IN PCWSTR Caption,
IN PCWSTR Message);
STATIC XTCDECL VOID DrawButton(IN PXTBL_DIALOG_HANDLE Handle);
STATIC XTCDECL VOID DrawInputField(IN PXTBL_DIALOG_HANDLE Handle,
IN PWCHAR InputFieldText);
STATIC XTCDECL VOID DrawMessage(IN PXTBL_DIALOG_HANDLE Handle,
IN PCWSTR Message);
STATIC XTCDECL VOID DrawProgressBar(IN PXTBL_DIALOG_HANDLE Handle,
IN UCHAR Percentage);
STATIC XTCDECL VOID DrawEditMenu(OUT PXTBL_DIALOG_HANDLE Handle);
STATIC XTCDECL EFI_STATUS DrawEditMenuEntry(IN PXTBL_DIALOG_HANDLE Handle,
IN PCWSTR OptionName,
IN PCWSTR OptionValue,
IN UINT Position,
IN BOOLEAN Highlighted);
};
class Volume
{
private:
STATIC LIST_ENTRY EfiBlockDevices;
public:
STATIC XTCDECL EFI_STATUS CloseVolume(IN PEFI_HANDLE VolumeHandle);
STATIC XTCDECL EFI_STATUS EnumerateBlockDevices();
STATIC XTCDECL EFI_STATUS FindDevicePath(IN PEFI_DEVICE_PATH_PROTOCOL FsHandle,
IN CONST PWCHAR FileSystemPath,
OUT PEFI_DEVICE_PATH_PROTOCOL* DevicePath);
STATIC XTCDECL EFI_STATUS GetEfiPath(IN PWCHAR SystemPath,
OUT PWCHAR *EfiPath);
STATIC XTCDECL EFI_STATUS GetDevicePath(IN PWCHAR SystemPath,
OUT PEFI_DEVICE_PATH_PROTOCOL *DevicePath,
OUT PWCHAR *ArcName,
OUT PWCHAR *Path);
STATIC XTCDECL EFI_STATUS OpenVolume(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath,
OUT PEFI_HANDLE DiskHandle,
OUT PEFI_FILE_HANDLE *FsHandle);
STATIC XTCDECL EFI_STATUS ReadFile(IN PEFI_FILE_HANDLE DirHandle,
IN PCWSTR FileName,
OUT PVOID *FileData,
OUT PSIZE_T FileSize);
private:
STATIC XTCDECL EFI_STATUS DiscoverEfiBlockDevices(OUT PLIST_ENTRY BlockDevices);
STATIC XTCDECL EFI_STATUS DissectArcPath(IN PWCHAR SystemPath,
OUT PWCHAR *ArcName,
OUT PWCHAR *Path,
OUT PUSHORT DriveType,
OUT PULONG DriveNumber,
OUT PULONG PartNumber);
STATIC XTCDECL PEFI_DEVICE_PATH_PROTOCOL DuplicateDevicePath(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath);
STATIC XTCDECL EFI_STATUS FindLastBlockDeviceNode(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath,
OUT PEFI_DEVICE_PATH_PROTOCOL *LastNode);
STATIC XTCDECL BOOLEAN FindParentBlockDevice(IN PLIST_ENTRY BlockDevices,
IN PEFI_BLOCK_DEVICE_DATA ChildNode,
OUT PEFI_BLOCK_DEVICE_DATA *ParentNode);
};
class XtLoader
{
private:
STATIC PBL_XT_BOOT_MENU BootMenu;
STATIC EFI_HANDLE EfiImageHandle;
STATIC PEFI_SYSTEM_TABLE EfiSystemTable;
STATIC XTBL_STATUS LoaderStatus;
public:
STATIC XTCDECL VOID DisableBootServices();
STATIC XTCDECL BOOLEAN GetBootServicesStatus();
STATIC XTCDECL EFI_HANDLE GetEfiImageHandle();
STATIC XTCDECL PEFI_SYSTEM_TABLE GetEfiSystemTable();
STATIC XTCDECL VOID GetLoaderImageInformation(PVOID *LoaderBase,
PULONGLONG LoaderSize);
STATIC XTCDECL INT_PTR GetSecureBootStatus();
STATIC XTCDECL VOID InitializeBootLoader(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
STATIC XTCDECL VOID RegisterBootMenu(IN PVOID BootMenuRoutine);
STATIC XTCDECL VOID ShowBootMenu();
};
#endif /* __XTLDR_XTLDR_HH */

View File

@@ -0,0 +1,81 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/library/modproto.cc
* DESCRIPTION: XT Boot Loader protocol support for XTLDR modules
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* Finds and opens the XT Boot Loader protocol. This routine should be called by module to access XTLDR protocol.
*
* @param SystemTable
* Provides the EFI system table.
*
* @param ImageHandle
* Firmware-allocated handle that identifies the image.
*
* @param ProtocolHandler
* Receives the pointer to the XT Boot Loader protocol.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCLINK
XTCDECL
EFI_STATUS
BlGetXtLdrProtocol(IN PEFI_SYSTEM_TABLE SystemTable,
IN EFI_HANDLE ImageHandle,
OUT PXTBL_LOADER_PROTOCOL *ProtocolHandler)
{
EFI_GUID ProtocolGuid = XT_BOOT_LOADER_PROTOCOL_GUID;
PEFI_HANDLE Handles = NULLPTR;
EFI_STATUS Status;
UINT_PTR Count;
UINT Index;
/* Try to locate the handles */
Status = SystemTable->BootServices->LocateHandleBuffer(ByProtocol, &ProtocolGuid, NULLPTR, &Count, &Handles);
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to get handles */
return Status;
}
/* Check if any handles returned */
if(Count > 0)
{
/* Iterate through all given handles */
for(Index = 0; Index < Count; Index++)
{
/* Try to open protocol */
Status = SystemTable->BootServices->OpenProtocol(Handles[Index], &ProtocolGuid,
(PVOID*)ProtocolHandler, ImageHandle, NULLPTR,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
/* Check if successfully opened the loader protocol */
if(Status == STATUS_EFI_SUCCESS)
{
/* Protocol found and successfully opened */
break;
}
}
}
/* Free handles */
SystemTable->BootServices->FreePool(Handles);
/* Make sure the loaded protocol has been found */
if(*ProtocolHandler == NULLPTR)
{
/* Protocol not found */
return STATUS_EFI_NOT_FOUND;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}

746
boot/xtldr/memory.cc Normal file
View File

@@ -0,0 +1,746 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/memory.cc
* DESCRIPTION: XT Boot Loader memory management
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* This routine allocates one or more 4KB pages.
*
* @param NumberOfPages
* The number of contiguous 4KB pages to allocate.
*
* @param Memory
* The pointer to a physical address.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::AllocatePages(IN EFI_ALLOCATE_TYPE AllocationType,
IN ULONGLONG NumberOfPages,
OUT PEFI_PHYSICAL_ADDRESS Memory)
{
return XtLoader::GetEfiSystemTable()->BootServices->AllocatePages(AllocationType, EfiLoaderData,
NumberOfPages, Memory);
}
/**
* This routine allocates a pool memory.
*
* @param Size
* The number of bytes to allocate from the pool.
*
* @param Memory
* The pointer to a physical address.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::AllocatePool(IN UINT_PTR Size,
OUT PVOID *Memory)
{
/* Allocate pool */
return XtLoader::GetEfiSystemTable()->BootServices->AllocatePool(EfiLoaderData, Size, Memory);
}
/**
* This routine frees memory pages.
*
* @param NumberOfPages
* The number of contiguous 4 KB pages to free.
*
* @param Memory
* The base physical address of the pages to be freed.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::FreePages(IN ULONGLONG NumberOfPages,
IN EFI_PHYSICAL_ADDRESS Memory)
{
return XtLoader::GetEfiSystemTable()->BootServices->FreePages(Memory, NumberOfPages);
}
/**
* Returns pool memory to the system.
*
* @param Memory
* The pointer to the buffer to free.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::FreePool(IN PVOID Memory)
{
/* Free pool */
return XtLoader::GetEfiSystemTable()->BootServices->FreePool(Memory);
}
/**
* Converts EFI memory type to XTLDR memory type.
*
* @param EfiMemoryType
* Specifies EFI memory type.
*
* @return This routine returns a mapped XTLDR memory type.
*
* @since XT 1.0
*/
XTCDECL
LOADER_MEMORY_TYPE
Memory::GetLoaderMemoryType(IN EFI_MEMORY_TYPE EfiMemoryType)
{
LOADER_MEMORY_TYPE MemoryType;
/* Check EFI memory type and convert to XTLDR memory type */
switch(EfiMemoryType)
{
case EfiACPIMemoryNVS:
case EfiACPIReclaimMemory:
case EfiPalCode:
case EfiReservedMemoryType:
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 XTLDR memory type */
return MemoryType;
}
/**
* Returns the number of mappings in the page mapping structure.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param NumberOfMappings
* Supplies a pointer to memory area where the number of mappings is returned.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Memory::GetMappingsCount(IN PXTBL_PAGE_MAPPING PageMap,
OUT PULONG NumberOfMappings)
{
/* Return number of mappings */
*NumberOfMappings = PageMap->MapSize;
}
/**
* Returns the memory descriptors which define a memory map of all the physical memory ranges reserved by the UEFI.
*
* @param MemoryMap
* Supplies a pointer to the buffer where memory map will be written.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::GetMemoryMap(OUT PEFI_MEMORY_MAP MemoryMap)
{
EFI_STATUS Status;
if(MemoryMap == NULLPTR)
{
return STATUS_EFI_INVALID_PARAMETER;
}
MemoryMap->Map = NULLPTR;
MemoryMap->MapSize = 0;
/* Get memory map */
do
{
/* Attempt do get EFI memory map */
Status = XtLoader::GetEfiSystemTable()->BootServices->GetMemoryMap(&MemoryMap->MapSize,
MemoryMap->Map,
&MemoryMap->MapKey,
&MemoryMap->DescriptorSize,
&MemoryMap->DescriptorVersion);
if(Status == STATUS_EFI_SUCCESS)
{
/* Go further if succeeded */
break;
}
else if(Status != STATUS_EFI_BUFFER_TOO_SMALL)
{
/* Some error occurred */
if(MemoryMap->Map)
{
/* Free allocated memory */
FreePool(MemoryMap->Map);
}
return Status;
}
/* Allocate the desired amount of memory */
MemoryMap->MapSize += 2 * MemoryMap->DescriptorSize;
AllocatePool(MemoryMap->MapSize, (PVOID *)&MemoryMap->Map);
}
while(Status == STATUS_EFI_BUFFER_TOO_SMALL);
/* Make sure memory map is set */
if(MemoryMap->Map == NULLPTR)
{
/* Something went wrong */
return STATUS_EFI_NO_MAPPING;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Attempts to find a virtual address of the specified physical address in memory mappings.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param PhysicalAddress
* Supplies a physical address to search for in the mappings.
*
* @return This routine returns a corresponding virtual address found in the mappings.
*
* @since XT 1.0
*/
XTCDECL
PVOID
Memory::GetVirtualAddress(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID PhysicalAddress)
{
PXTBL_MEMORY_MAPPING Mapping;
PLIST_ENTRY ListEntry;
/* Iterate over memory mappings in order to find descriptor containing a physical address */
ListEntry = PageMap->MemoryMap.Flink;
while(ListEntry != &PageMap->MemoryMap)
{
/* Get mapping from linked list */
Mapping = CONTAIN_RECORD(ListEntry, XTBL_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(((UINT_PTR)PhysicalAddress >= (UINT_PTR)Mapping->PhysicalAddress) &&
((UINT_PTR)PhysicalAddress < ((UINT_PTR)Mapping->PhysicalAddress + (Mapping->NumberOfPages * EFI_PAGE_SIZE))))
{
/* Calculate virtual address based on the mapping and return it */
return (PVOID)(((UINT_PTR)PhysicalAddress - (UINT_PTR)Mapping->PhysicalAddress) + (UINT_PTR)Mapping->VirtualAddress);
}
}
/* Get next element from the list */
ListEntry = ListEntry->Flink;
}
/* Mapping not found, return 0 */
return 0;
}
/**
* Initializes the page mapping structures.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param PageMapLevel
* Specifies a number of of paging structures levels.
*
* @param PageSize
* Specifies a page size (currently it has no effect).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Memory::InitializePageMap(OUT PXTBL_PAGE_MAPPING PageMap,
IN SHORT PageMapLevel,
IN PAGE_SIZE PageSize)
{
/* Initialize memory mappings */
RTL::LinkedList::InitializeListHead(&PageMap->MemoryMap);
PageMap->MapSize = 0;
/* Set page map size/level and memory map address */
PageMap->PageMapLevel = PageMapLevel;
PageMap->PageSize = PageSize;
}
/**
* Adds EFI memory mapping to the page mapping structure.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param MemoryMapAddress
* Supplies a virtual address, where EFI memory will be mapped.
*
* @param GetMemoryTypeRoutine
* Supplies a pointer to the routine which will be used to match EFI memory type to the OS memory type.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::MapEfiMemory(IN OUT PXTBL_PAGE_MAPPING PageMap,
IN OUT PVOID *MemoryMapAddress,
IN PBL_GET_MEMTYPE_ROUTINE GetMemoryTypeRoutine)
{
PEFI_MEMORY_DESCRIPTOR Descriptor;
LOADER_MEMORY_TYPE MemoryType;
PEFI_MEMORY_MAP MemoryMap;
SIZE_T DescriptorCount;
PUCHAR VirtualAddress;
EFI_STATUS Status;
SIZE_T Index;
/* Set virtual address as specified in argument */
VirtualAddress = (PUCHAR)*MemoryMapAddress;
/* Check if custom memory type routine is specified */
if(GetMemoryTypeRoutine == NULLPTR)
{
/* Use default memory type routine */
GetMemoryTypeRoutine = GetLoaderMemoryType;
}
/* Allocate and zero-fill buffer for EFI memory map */
AllocatePool(sizeof(EFI_MEMORY_MAP), (PVOID*)&MemoryMap);
RTL::Memory::ZeroMemory(MemoryMap, sizeof(EFI_MEMORY_MAP));
/* Get EFI memory map */
Status = GetMemoryMap(MemoryMap);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get EFI memory map */
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 start beyond lowest physical page */
if(Descriptor->PhysicalStart <= MAXUINT_PTR)
{
/* Skip EFI reserved memory */
if(Descriptor->Type == EfiReservedMemoryType)
{
/* Go to the next descriptor */
Descriptor = (PEFI_MEMORY_DESCRIPTOR)((PUCHAR)Descriptor + MemoryMap->DescriptorSize);
continue;
}
/* Check if preparing page map level 2 (non-PAE i686) */
if(PageMap->PageMapLevel == 2)
{
/* Check if physical address starts beyond 4GB */
if(Descriptor->PhysicalStart > 0xFFFFFFFF)
{
/* Go to the next descriptor */
Descriptor = (PEFI_MEMORY_DESCRIPTOR)((PUCHAR)Descriptor + MemoryMap->DescriptorSize);
continue;
}
/* Check if memory descriptor exceeds the lowest physical page */
if(Descriptor->PhysicalStart + (Descriptor->NumberOfPages << EFI_PAGE_SHIFT) > MAXULONG)
{
/* Truncate memory descriptor to the 4GB */
Descriptor->NumberOfPages = (((ULONGLONG)MAXULONG + 1) - Descriptor->PhysicalStart) >> EFI_PAGE_SHIFT;
}
}
/* Convert EFI memory type into XTLDR memory type */
MemoryType = GetMemoryTypeRoutine((EFI_MEMORY_TYPE)Descriptor->Type);
/* Do memory mappings depending on memory type */
if(MemoryType == LoaderFirmwareTemporary)
{
/* Map EFI firmware code */
Status = MapVirtualMemory(PageMap, (PVOID)Descriptor->PhysicalStart,
(PVOID)Descriptor->PhysicalStart, Descriptor->NumberOfPages, MemoryType);
}
else if(MemoryType != LoaderFree)
{
/* Add any non-free memory mapping */
Status = MapVirtualMemory(PageMap, 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 = MapVirtualMemory(PageMap, NULLPTR, (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);
}
/* Always map first page */
Status = MapVirtualMemory(PageMap, NULLPTR, (PVOID)0, 1, LoaderFirmwarePermanent);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping failed */
return Status;
}
/* Map BIOS ROM and VRAM */
Status = MapVirtualMemory(PageMap, NULLPTR, (PVOID)0xA0000, 0x60, LoaderFirmwarePermanent);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping failed */
return Status;
}
/* Store next valid virtual address and return success */
*MemoryMapAddress = VirtualAddress;
return STATUS_EFI_SUCCESS;
}
/**
* Adds a physical to virtual address mappings.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @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 that will be mapped.
*
* @param MemoryType
* Supplies the type of mapped memory that will be assigned to the memory descriptor.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::MapVirtualMemory(IN OUT PXTBL_PAGE_MAPPING PageMap,
IN PVOID VirtualAddress,
IN PVOID PhysicalAddress,
IN ULONGLONG NumberOfPages,
IN LOADER_MEMORY_TYPE MemoryType)
{
PXTBL_MEMORY_MAPPING Mapping1, Mapping2, Mapping3;
PVOID PhysicalAddressEnd, PhysicalAddress2End;
PLIST_ENTRY ListEntry, MappingListEntry;
SIZE_T NumberOfMappedPages;
EFI_STATUS Status;
/* Allocate memory for new mapping */
Status = AllocatePool(sizeof(XTBL_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 = (PVOID)((ULONG_PTR)PhysicalAddress + (NumberOfPages * EFI_PAGE_SIZE) - 1);
/* Iterate through all the mappings already set to insert new mapping at the correct place */
ListEntry = PageMap->MemoryMap.Flink;
while(ListEntry != &PageMap->MemoryMap)
{
/* Take a mapping from the list and calculate its end of physical address */
Mapping2 = CONTAIN_RECORD(ListEntry, XTBL_MEMORY_MAPPING, ListEntry);
PhysicalAddress2End = (PVOID)((ULONG_PTR)Mapping2->PhysicalAddress + (Mapping2->NumberOfPages * EFI_PAGE_SIZE) - 1);
/* Check if new mapping is a subset of an existing mapping */
if(Mapping1->PhysicalAddress >= Mapping2->PhysicalAddress && PhysicalAddressEnd <= PhysicalAddress2End)
{
/* Make sure it's memory type is the same */
if(Mapping1->MemoryType == Mapping2->MemoryType)
{
/* It is already mapped */
return STATUS_EFI_SUCCESS;
}
}
/* 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 = ((PUCHAR)PhysicalAddress2End - (PUCHAR)PhysicalAddressEnd) / EFI_PAGE_SIZE;
if(NumberOfMappedPages > 0)
{
/* Pages associated to the mapping, allocate memory for it */
Status = AllocatePool(sizeof(XTBL_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 = (PUCHAR)PhysicalAddressEnd + 1;
Mapping3->VirtualAddress = NULLPTR;
Mapping3->NumberOfPages = NumberOfMappedPages;
Mapping3->MemoryType = Mapping2->MemoryType;
RTL::LinkedList::InsertHeadList(&Mapping2->ListEntry, &Mapping3->ListEntry);
}
/* Calculate number of pages and the end of the physical address */
Mapping2->NumberOfPages = ((PUCHAR)PhysicalAddressEnd + 1 -
(PUCHAR)Mapping2->PhysicalAddress) / EFI_PAGE_SIZE;
PhysicalAddress2End = (PVOID)((ULONG_PTR)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 = ((PUCHAR)PhysicalAddress2End + 1 - (PUCHAR)Mapping1->PhysicalAddress) / EFI_PAGE_SIZE;
if(NumberOfMappedPages > 0)
{
/* Pages associated to the mapping, allocate memory for it */
Status = AllocatePool(sizeof(XTBL_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 = NULLPTR;
Mapping3->NumberOfPages = NumberOfMappedPages;
Mapping3->MemoryType = Mapping2->MemoryType;
RTL::LinkedList::InsertHeadList(&Mapping2->ListEntry, &Mapping3->ListEntry);
}
/* Calculate number of pages and the end of the physical address */
Mapping2->NumberOfPages = ((PUCHAR)Mapping1->PhysicalAddress -
(PUCHAR)Mapping2->PhysicalAddress) / EFI_PAGE_SIZE;
PhysicalAddress2End = (PVOID)((ULONG_PTR)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 */
RTL::LinkedList::RemoveEntryList(&Mapping2->ListEntry);
Status = FreePool(Mapping2);
ListEntry = MappingListEntry;
/* Go to the next mapping */
continue;
}
/* Determine physical address order */
if(Mapping2->PhysicalAddress > Mapping1->PhysicalAddress)
{
/* Insert new mapping in front */
RTL::LinkedList::InsertHeadList(Mapping2->ListEntry.Blink, &Mapping1->ListEntry);
return STATUS_EFI_SUCCESS;
}
/* Get next mapping from the list */
ListEntry = ListEntry->Flink;
}
/* Insert new mapping to the list and increase page map size */
RTL::LinkedList::InsertTailList(&PageMap->MemoryMap, &Mapping1->ListEntry);
PageMap->MapSize++;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Converts physical address to virtual address based on physical base and virtual base.
*
* @param PhysicalAddress
* Specifies physical address that will be converted to virtual address.
*
* @param PhysicalBase
* Supplies a physical base address.
*
* @param VirtualBase
* Supplies a virtual base address.
*
* @return This routine returns a mapped virtual address.
*
* @since XT 1.0
*/
XTCDECL
PVOID
Memory::PhysicalAddressToVirtual(IN PVOID PhysicalAddress,
IN PVOID PhysicalBase,
IN PVOID VirtualBase)
{
/* Convert physical address to virtual address */
return (PUCHAR)VirtualBase + ((PUCHAR)PhysicalAddress - (PUCHAR)PhysicalBase);
}
/**
* Converts whole linked list addressing from physical to virtual for future use after enabling paging.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param ListHead
* Supplies a pointer to a structure that serves as the list header.
*
* @param PhysicalBase
* Supplies a physical base address.
*
* @param VirtualBase
* Supplies a virtual base address.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Memory::PhysicalListToVirtual(IN PXTBL_PAGE_MAPPING PageMap,
IN OUT PLIST_ENTRY ListHead,
IN PVOID PhysicalBase,
IN PVOID VirtualBase)
{
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 all elements */
ListEntry = ListHead->Flink;
while(ListEntry != ListHead)
{
/* Save physical address of the next element */
NextEntry = ListEntry->Flink;
/* Convert the address of this element to VirtualAddress */
if(ListEntry->Blink == ListHead)
{
/* Find virtual address of list head */
ListEntry->Blink = (PLIST_ENTRY)GetVirtualAddress(PageMap, ListEntry->Blink);
}
else
{
/* Convert list entry */
ListEntry->Blink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListEntry->Blink, (PVOID)PhysicalBase, VirtualBase);
}
if(ListEntry->Flink == ListHead)
{
/* Convert list head */
ListEntry->Flink = ListHead->Flink->Blink;
}
else
{
/* Convert list entry */
ListEntry->Flink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListEntry->Flink, (PVOID)PhysicalBase, VirtualBase);
}
/* Get to the next element*/
ListEntry = NextEntry;
}
/* Convert list head */
ListHead->Blink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListHead->Blink, (PVOID)PhysicalBase, VirtualBase);
ListHead->Flink = (PLIST_ENTRY)PhysicalAddressToVirtual(ListHead->Flink, (PVOID)PhysicalBase, VirtualBase);
/* Return success */
return STATUS_EFI_SUCCESS;
}

View File

@@ -0,0 +1,7 @@
add_subdirectory(acpi)
add_subdirectory(beep)
add_subdirectory(chainldr)
add_subdirectory(dummy)
add_subdirectory(framebuf)
add_subdirectory(pecoff)
add_subdirectory(xtos_o)

View File

@@ -0,0 +1,27 @@
# XT Boot Loader ACPI Support Module
PROJECT(XTLDR_ACPI)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_ACPI_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_ACPI_SOURCE
${XTLDR_ACPI_SOURCE_DIR}/acpi.cc
${XTLDR_ACPI_SOURCE_DIR}/data.cc)
# Link module executable
add_executable(acpi ${XTLDR_ACPI_SOURCE})
# Add linker libraries
target_link_libraries(acpi libxtldr libxtos)
# Set proper binary name and install target
set_target_properties(acpi PROPERTIES SUFFIX .efi)
set_install_target(acpi efi/boot/xtldr/modules)
# Set module entrypoint and subsystem
set_entrypoint(acpi "XtLdrModuleMain")
set_linker_map(acpi TRUE)
set_subsystem(acpi efi_boot_service_driver)

View File

@@ -0,0 +1,439 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/acpi/acpi.cc
* DESCRIPTION: XTLDR ACPI Support Module
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <acpi.hh>
/* ACPI module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
MODULE_DESCRIPTION(L"ACPI support");
MODULE_LICENSE(L"GPLv3");
MODULE_VERSION(L"0.1");
/**
* Attempts to get XSDP. If it is not found or checksum mismatch, it will try to get RSDP instead.
*
* @param AcpiTable
* Suplies a pointer to memory area where XSDP or RSRP address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetAcpiDescriptionPointer(OUT PVOID *AcpiTable)
{
PVOID Rsdp;
/* Try to get XSDP (ACPI 2.0) from system configuration tables */
if(GetXsdpTable(&Rsdp) == STATUS_EFI_SUCCESS)
{
/* XSDP found, return success */
*AcpiTable = Rsdp;
return STATUS_EFI_SUCCESS;
}
/* Try to get RSDP (ACPI 1.0) from system configuration tables */
if(GetRsdpTable(&Rsdp) == STATUS_EFI_SUCCESS)
{
/* RSDP found, return success */
*AcpiTable = Rsdp;
return STATUS_EFI_SUCCESS;
}
/* Neither XSDP nor RSDP found */
return STATUS_EFI_NOT_FOUND;
}
/**
* Finds ACPI description table with given signature.
*
* @param Signature
* Supplies the signature of the desired ACPI table.
*
* @param PreviousTable
* Supplies a pointer to the table to start searching from.
*
* @param AcpiTable
* Supplies a pointer to memory area where ACPI table address will be stored, or NULLPTR if not found.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetAcpiTable(IN CONST UINT Signature,
IN PVOID PreviousTable,
OUT PVOID *AcpiTable)
{
PACPI_DESCRIPTION_HEADER TableHeader;
SIZE_T RsdtIndex, TableIndex;
EFI_STATUS Status;
SIZE_T TableCount;
PACPI_RSDP Rsdp;
PACPI_RSDT Rsdt;
BOOLEAN Xsdp;
/* Return NULLPTR by default if requested table not found */
*AcpiTable = NULLPTR;
/* Get Root System Description Table Pointer */
Status = GetAcpiDescriptionPointer((PVOID*)&Rsdp);
if(Status != STATUS_EFI_SUCCESS)
{
/* ACPI tables not found, return error */
return Status;
}
/* Check if it is XSDP (ACPI 2.0) or RSDP (ACPI 1.0) */
if(Rsdp->Revision >= 2 && Rsdp->XsdtAddress)
{
/* XSDP (ACPI 2.0) */
Xsdp = TRUE;
Rsdt = (PACPI_RSDT)(UINT_PTR)Rsdp->XsdtAddress;
TableCount = (Rsdt->Header.Length - sizeof(ACPI_DESCRIPTION_HEADER)) / 8;
}
else
{
/* RSDP (ACPI 1.0) */
Xsdp = FALSE;
Rsdt = (PACPI_RSDT)(UINT_PTR)Rsdp->RsdtAddress;
TableCount = (Rsdt->Header.Length - sizeof(ACPI_DESCRIPTION_HEADER)) / 4;
}
/* Iterate over all ACPI tables */
for(TableIndex = 0; TableIndex < TableCount; TableIndex++)
{
/* Get table headers in reverse order */
RsdtIndex = TableCount - TableIndex - 1;
/* Check if XSDP or RSDT is used */
if(Xsdp)
{
/* Get table header from XSDT */
TableHeader = (PACPI_DESCRIPTION_HEADER)(ULONG_PTR)((PULONGLONG)Rsdt->Tables)[RsdtIndex];
}
else
{
/* Get table header from RSDT */
TableHeader = (PACPI_DESCRIPTION_HEADER)(ULONG_PTR)((PULONG)Rsdt->Tables)[RsdtIndex];
}
/* Check if previous table provided */
if(PreviousTable != NULLPTR)
{
/* Check if this is a table previously found */
if(TableHeader == (PVOID)PreviousTable)
{
/* Unset previous table */
PreviousTable = NULLPTR;
}
/* Skip to next ACPI table */
continue;
}
/* Verify table signature */
if((TableHeader->Signature == Signature))
{
/* Found requested ACPI table */
break;
}
}
/* Make sure table was found */
if(TableHeader->Signature != Signature)
{
/* ACPI table not found, return error */
return STATUS_EFI_NOT_FOUND;
}
/* Don't validate FADT on old, broken firmwares with ACPI 2.0 or older */
if(TableHeader->Signature != ACPI_FADT_SIGNATURE || TableHeader->Revision > 2)
{
/* Validate table checksum */
if(!ValidateAcpiTable(TableHeader, TableHeader->Length))
{
/* Checksum mismatch, return error */
return STATUS_EFI_CRC_ERROR;
}
}
/* Found valid ACPI table, return success */
*AcpiTable = TableHeader;
return STATUS_EFI_SUCCESS;
}
/**
* Gets the Advanced Programmable Interrupt Controller (APIC) base address.
*
* @param ApicBase
* Supplies a pointer to memory area where APIC base address will be stored.
*
* @return This routine returns an EFI status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetApicBase(OUT PVOID *ApicBase)
{
CPUID_REGISTERS CpuRegisters;
/* Prepare CPUID registers to query for APIC support */
XtLdrProtocol->Memory.ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
/* Query CPUID */
XtLdrProtocol->Cpu.CpuId(&CpuRegisters);
/* Check if APIC present */
if((CpuRegisters.Edx & CPUID_FEATURES_EDX_APIC) == 0)
{
/* APIC is not supported by the CPU */
return STATUS_EFI_UNSUPPORTED;
}
/* Get APIC base address */
*ApicBase = (PVOID)((UINT_PTR)XtLdrProtocol->Cpu.ReadModelSpecificRegister(0x1B) & 0xFFFFF000);
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Gets RSDP (ACPI 1.0) from EFI system configuration
*
* @param AcpiTable
* Suplies a pointer to memory area where RSDP address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetRsdpTable(OUT PVOID *AcpiTable)
{
EFI_GUID AcpiGuid = EFI_CONFIG_TABLE_ACPI_TABLE_GUID;
EFI_STATUS Status;
PVOID RsdpTable;
/* Get RSDP (ACPI 1.0) table from system configuration tables */
Status = XtLdrProtocol->Utils.GetConfigurationTable(&AcpiGuid, &RsdpTable);
if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(RsdpTable, 20))
{
/* RSDP not found or checksum mismatch */
*AcpiTable = NULLPTR;
return STATUS_EFI_NOT_FOUND;
}
/* RSDP found, return success */
*AcpiTable = RsdpTable;
return STATUS_EFI_SUCCESS;
}
/**
* Gets SMBIOS from EFI system configuration
*
* @param SmBiosTable
* Suplies a pointer to memory area where SMBIOS address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetSMBiosTable(OUT PVOID *SmBiosTable)
{
EFI_GUID SmBiosGuid = EFI_CONFIG_TABLE_SMBIOS_TABLE_GUID;
PSMBIOS_TABLE_HEADER SmBios;
EFI_STATUS Status;
/* Get SMBIOS table from system configuration tables */
Status = XtLdrProtocol->Utils.GetConfigurationTable(&SmBiosGuid, (PVOID*)&SmBios);
if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(SmBios, SmBios->Length))
{
/* SMBIOS not found or checksum mismatch */
*SmBiosTable = NULLPTR;
return STATUS_EFI_NOT_FOUND;
}
/* SMBIOS found, return success */
*SmBiosTable = SmBios;
return STATUS_EFI_SUCCESS;
}
/**
* Gets SMBIOS3 from EFI system configuration
*
* @param SmBiosTable
* Suplies a pointer to memory area where SMBIOS3 address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetSMBios3Table(OUT PVOID *SmBiosTable)
{
EFI_GUID SmBios3Guid = EFI_CONFIG_TABLE_SMBIOS3_TABLE_GUID;
PSMBIOS3_TABLE_HEADER SmBios;
EFI_STATUS Status;
/* Get SMBIOS3 table from system configuration tables */
Status = XtLdrProtocol->Utils.GetConfigurationTable(&SmBios3Guid, (PVOID*)&SmBios);
if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(SmBios, SmBios->Length))
{
/* SMBIOS3 not found or checksum mismatch */
*SmBiosTable = NULLPTR;
return STATUS_EFI_NOT_FOUND;
}
/* SMBIOS3 found, return success */
*SmBiosTable = SmBios;
return STATUS_EFI_SUCCESS;
}
/**
* Gets XSDP (ACPI 2.0) from EFI system configuration
*
* @param AcpiTable
* Suplies a pointer to memory area where XSDP address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Acpi::GetXsdpTable(OUT PVOID *AcpiTable)
{
EFI_GUID AcpiGuid = EFI_CONFIG_TABLE_ACPI20_TABLE_GUID;
EFI_STATUS Status;
PVOID XsdpTable;
/* Get XSDP (ACPI 2.0) from system configuration tables */
Status = XtLdrProtocol->Utils.GetConfigurationTable(&AcpiGuid, &XsdpTable);
if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(XsdpTable, 36))
{
/* XSDP not found or checksum mismatch */
*AcpiTable = NULLPTR;
return STATUS_EFI_NOT_FOUND;
}
/* XSDP found, return success */
*AcpiTable = XsdpTable;
return STATUS_EFI_SUCCESS;
}
/**
* Initializes ACPI module by opening XTLDR protocol and installing ACPI protocol.
*
* @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
Acpi::InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID Guid = XT_ACPI_PROTOCOL_GUID;
EFI_STATUS Status;
/* Open the XTLDR protocol */
Status = BlGetXtLdrProtocol(SystemTable, ImageHandle, &XtLdrProtocol);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open the protocol, return error */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Set routines available via ACPI protocol */
AcpiProtocol.GetAcpiDescriptionPointer = GetAcpiDescriptionPointer;
AcpiProtocol.GetAcpiTable = GetAcpiTable;
AcpiProtocol.GetApicBase = GetApicBase;
AcpiProtocol.GetRsdpTable = GetRsdpTable;
AcpiProtocol.GetSMBiosTable = GetSMBiosTable;
AcpiProtocol.GetSMBios3Table = GetSMBios3Table;
AcpiProtocol.GetXsdpTable = GetXsdpTable;
/* Install ACPI protocol */
return XtLdrProtocol->Protocol.Install(&AcpiProtocol, &Guid);
}
/**
* Validates given ACPI table by calculating its checksum.
*
* @param Buffer
* Supplies a pointer to the table to checksum.
*
* @param Size
* Supplies the size of the table, in bytes.
*
* @return This routine returns TRUE if the table is valid, or FALSE otherwise.
*
* @since XT 1.0
*/
XTCDECL
BOOLEAN
Acpi::ValidateAcpiTable(IN PVOID Buffer,
IN UINT_PTR Size)
{
PUCHAR Pointer;
UCHAR Sum;
/* Initialize variables */
Sum = 0;
Pointer = (PUCHAR)Buffer;
/* Calculate checksum of given table */
while(Size != 0)
{
Sum = (UCHAR)(Sum + *Pointer);
Pointer += 1;
Size -= 1;
}
/* Return calculated checksum */
return (Sum == 0) ? TRUE : FALSE;
}
/**
* 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 ACPI module */
return Acpi::InitializeModule(ImageHandle, SystemTable);
}

View File

@@ -0,0 +1,16 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/acpi/data.cc
* DESCRIPTION: ACPI module global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <acpi.hh>
/* ACPI Protocol */
XTBL_ACPI_PROTOCOL Acpi::AcpiProtocol;
/* XTLDR protocol handler */
PXTBL_LOADER_PROTOCOL Acpi::XtLdrProtocol;

View File

@@ -0,0 +1,40 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/acpi/includes/acpi.hh
* DESCRIPTION: XTLDR ACPI module header file
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_ACPI_ACPI_HH
#define __XTLDR_ACPI_ACPI_HH
#include <xtblapi.h>
/* ACPI module for XTLDR */
class Acpi
{
private:
STATIC XTBL_ACPI_PROTOCOL AcpiProtocol;
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC XTCDECL EFI_STATUS GetAcpiDescriptionPointer(OUT PVOID *AcpiTable);
STATIC XTCDECL EFI_STATUS GetAcpiTable(IN CONST UINT Signature,
IN PVOID PreviousTable,
OUT PVOID *AcpiTable);
STATIC XTCDECL EFI_STATUS GetApicBase(OUT PVOID *ApicBase);
STATIC XTCDECL EFI_STATUS GetRsdpTable(OUT PVOID *AcpiTable);
STATIC XTCDECL EFI_STATUS GetSMBiosTable(OUT PVOID *SmBiosTable);
STATIC XTCDECL EFI_STATUS GetSMBios3Table(OUT PVOID *SmBiosTable);
STATIC XTCDECL EFI_STATUS GetXsdpTable(OUT PVOID *AcpiTable);
STATIC XTCDECL EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
private:
STATIC XTCDECL BOOLEAN ValidateAcpiTable(IN PVOID Buffer,
IN UINT_PTR Size);
};
#endif /* __XTLDR_ACPI_ACPI_HH */

View File

@@ -0,0 +1,27 @@
# XT Boot Loader Beep Module
PROJECT(XTLDR_BEEP)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_BEEP_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_BEEP_SOURCE
${XTLDR_BEEP_SOURCE_DIR}/beep.cc
${XTLDR_BEEP_SOURCE_DIR}/data.cc)
# Link module executable
add_executable(beep ${XTLDR_BEEP_SOURCE})
# Add linker libraries
target_link_libraries(beep libxtldr libxtos)
# Set proper binary name and install target
set_target_properties(beep PROPERTIES SUFFIX .efi)
set_install_target(beep efi/boot/xtldr/modules)
# Set module entrypoint and subsystem
set_entrypoint(beep "XtLdrModuleMain")
set_linker_map(beep TRUE)
set_subsystem(beep efi_boot_service_driver)

View File

@@ -0,0 +1,238 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/beep/beep.cc
* DESCRIPTION: XTLDR Beep Module
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <beep.hh>
/* Beep module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
MODULE_DESCRIPTION(L"Plays a GRUB compatible tune via PC speaker");
MODULE_LICENSE(L"GPLv3");
MODULE_VERSION(L"0.1");
/**
* Disables the PC speaker.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Beep::DisableToneBeep()
{
UCHAR Status;
/* Stop the PC speaker */
Status = XtLdrProtocol->IoPort.Read8(0x61);
XtLdrProtocol->IoPort.Write8(0x61, Status & 0xFC);
}
/**
* Enables the PC speaker and plays a sound.
*
* @param Pitch
* Specifies a pitch (in Hz) of the sound.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Beep::EnableToneBeep(IN UINT Pitch)
{
UINT Counter;
UCHAR Status;
/* Pitch only in range of 20..20000 */
if(Pitch < 20)
{
Pitch = 20;
}
else if(Pitch > 20000)
{
Pitch = 20000;
}
/* Set the desired frequency of the PIT clock */
Counter = 0x1234DD / Pitch;
XtLdrProtocol->IoPort.Write8(0x43, 0xB6);
XtLdrProtocol->IoPort.Write8(0x43, 0xB6);
XtLdrProtocol->IoPort.Write8(0x42, (UCHAR) Counter & 0xFF);
XtLdrProtocol->IoPort.Write8(0x42, (UCHAR) (Counter >> 8) & 0xFF);
/* Start the PC speaker */
Status = XtLdrProtocol->IoPort.Read8(0x61);
XtLdrProtocol->IoPort.Write8(0x61, Status | 0x03);
}
/**
* Initializes BEEP module by opening XTLDR protocol and playing the tune.
*
* @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
Beep::InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_STATUS Status;
PWCHAR Tune;
/* Open the XTLDR protocol */
Status = BlGetXtLdrProtocol(SystemTable, ImageHandle, &XtLdrProtocol);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open the protocol, return error */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Play the tune set in the configuration */
XtLdrProtocol->Config.GetValue(L"TUNE", &Tune);
PlayTune(Tune);
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* This routine plays a tune.
*
* @param Arguments
* Optional list of parameters provided with the command.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Beep::PlayTune(IN PWCHAR Arguments)
{
LONG Pitch, Duration, Tempo;
PWCHAR Argument, LastArgument;
/* Reset pitch and duration */
Duration = -1;
Pitch = -1;
Tempo = -1;
/* Tokenize provided list of arguments */
Argument = XtLdrProtocol->WideString.Tokenize(Arguments, L" ", &LastArgument);
/* Iterate over all arguments */
while(Argument != NULLPTR)
{
/* Check if tempo, pitch and duration are set */
if(Tempo < 0)
{
/* Set the tempo */
Tempo = WideStringToNumber(Argument);
}
else if(Pitch < 0)
{
/* Set the pitch */
Pitch = WideStringToNumber(Argument);
}
else
{
/* Set the duration */
Duration = WideStringToNumber(Argument);
/* Check pitch value */
if(Pitch > 0)
{
/* Emit the beep tone */
EnableToneBeep(Pitch);
}
else
{
/* Stop emitting beep tone */
DisableToneBeep();
}
/* Wait for duration time */
XtLdrProtocol->Utils.SleepExecution(60000 * Duration / Tempo);
/* Reset pitch and duration */
Pitch = -1;
Duration = -1;
}
/* Get next argument */
Argument = XtLdrProtocol->WideString.Tokenize(NULLPTR, L" ", &LastArgument);
}
/* Stop emitting beep tone */
DisableToneBeep();
}
/**
* Converts a wide string into a number.
*
* @param String
* Supplies an input wide string.
*
* @return This routine returns the number that was converted from the wide string.
*
* @since XT 1.0
*/
XTCDECL
UINT
Beep::WideStringToNumber(IN PWCHAR String)
{
ULONG Number = 0;
/* Iterate over all characters until '\0' found */
do
{
/* Check if this is a digit */
if(*String - '0' < 10)
{
/* Add another digit to the number */
Number *= 10;
Number += *String - '0';
}
}
while(*++String != L'\0');
/* Return number */
return Number;
}
/**
* 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 BEEP module */
return Beep::InitializeModule(ImageHandle, SystemTable);
}

View File

@@ -0,0 +1,13 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/beep/data.cc
* DESCRIPTION: BEEP module global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <beep.hh>
/* XTLDR protocol handler */
PXTBL_LOADER_PROTOCOL Beep::XtLdrProtocol;

View File

@@ -0,0 +1,32 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/beep/includes/beep.hh
* DESCRIPTION: XTLDR Beep Module header file
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_BEEP_BEEP_HH
#define __XTLDR_BEEP_BEEP_HH
#include <xtblapi.h>
/* BEEP module for XTLDR */
class Beep
{
private:
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC XTCDECL EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
STATIC XTCDECL VOID PlayTune(IN PWCHAR Arguments);
private:
STATIC XTCDECL VOID DisableToneBeep();
STATIC XTCDECL VOID EnableToneBeep(IN UINT Pitch);
STATIC XTCDECL UINT WideStringToNumber(IN PWCHAR String);
};
#endif /* __XTLDR_BEEP_BEEP_HH */

View File

@@ -0,0 +1,27 @@
# XTLDR Chain Loader Module
PROJECT(XTLDR_CHAINLDR)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_CHAINLDR_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_CHAINLDR_SOURCE
${XTLDR_CHAINLDR_SOURCE_DIR}/chainldr.cc
${XTLDR_CHAINLDR_SOURCE_DIR}/data.cc)
# Link module executable
add_executable(chainldr ${XTLDR_CHAINLDR_SOURCE})
# Add linker libraries
target_link_libraries(chainldr libxtldr libxtos)
# Set proper binary name and install target
set_target_properties(chainldr PROPERTIES SUFFIX .efi)
set_install_target(chainldr efi/boot/xtldr/modules)
# Set module entrypoint and subsystem
set_entrypoint(chainldr "XtLdrModuleMain")
set_linker_map(chainldr TRUE)
set_subsystem(chainldr efi_boot_service_driver)

View File

@@ -0,0 +1,186 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/chainldr/chainldr.cc
* DESCRIPTION: XTLDR Chain Loader
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <chainldr.hh>
/* ChainLoader module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
MODULE_DESCRIPTION(L"XTLDR Chain Loader");
MODULE_LICENSE(L"GPLv3");
MODULE_VERSION(L"0.1");
/**
* Chainloads another boot loader.
*
* @param Parameters
* Input parameters with detailed system configuration.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
ChainLoader::BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters)
{
EFI_GUID LIPGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_MEMMAP_DEVICE_PATH MemoryDevicePath[2];
PEFI_LOADED_IMAGE_PROTOCOL LoadedImage;
EFI_HANDLE DiskHandle, LoaderHandle;
PEFI_FILE_HANDLE FsHandle, BootDir;
EFI_STATUS Status;
SIZE_T LoaderSize;
PVOID LoaderData;
/* Check if image file is provided */
if(Parameters->KernelFile == NULLPTR)
{
/* No image filename provided, return error code */
XtLdrProtocol->Debug.Print(L"ERROR: No EFI image filename provided\n");
return STATUS_EFI_INVALID_PARAMETER;
}
/* Open EFI volume */
Status = XtLdrProtocol->Disk.OpenVolume(Parameters->DevicePath, &DiskHandle, &FsHandle);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open a volume, return error code */
XtLdrProtocol->Debug.Print(L"ERROR: Unable to open boot volume (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Open boot directory and close FS handle */
Status = FsHandle->Open(FsHandle, &BootDir, Parameters->EfiPath, EFI_FILE_MODE_READ, 0);
FsHandle->Close(FsHandle);
/* Check if system path directory opened successfully */
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open directory */
XtLdrProtocol->Debug.Print(L"ERROR: Unable to open system boot directory (Status Code: 0x%zX)\n", Status);
/* Close volume and return error code */
XtLdrProtocol->Disk.CloseVolume(&DiskHandle);
return Status;
}
/* Read EFI image file from disk and close both directory and EFI volume */
Status = XtLdrProtocol->Disk.ReadFile(BootDir, Parameters->KernelFile, &LoaderData, &LoaderSize);
BootDir->Close(BootDir);
XtLdrProtocol->Disk.CloseVolume(&DiskHandle);
/* Setup device path for EFI image */
MemoryDevicePath[0].Header.Length[0] = sizeof(EFI_MEMMAP_DEVICE_PATH);
MemoryDevicePath[0].Header.Length[1] = sizeof(EFI_MEMMAP_DEVICE_PATH) >> 8;
MemoryDevicePath[0].Header.Type = EFI_HARDWARE_DEVICE_PATH;
MemoryDevicePath[0].Header.SubType = EFI_HARDWARE_MEMMAP_DP;
MemoryDevicePath[0].MemoryType = EfiLoaderData;
MemoryDevicePath[0].StartingAddress = (UINT_PTR)LoaderData;
MemoryDevicePath[0].EndingAddress = (UINT_PTR)LoaderData + LoaderSize;
MemoryDevicePath[1].Header.Length[0] = sizeof(EFI_DEVICE_PATH_PROTOCOL);
MemoryDevicePath[1].Header.Length[1] = sizeof(EFI_DEVICE_PATH_PROTOCOL) >> 8;
MemoryDevicePath[1].Header.Type = EFI_END_DEVICE_PATH;
MemoryDevicePath[1].Header.SubType = EFI_END_ENTIRE_DP;
/* Load EFI image */
Status = XtLdrProtocol->Utils.LoadEfiImage((PEFI_DEVICE_PATH_PROTOCOL)MemoryDevicePath,
LoaderData, LoaderSize, &LoaderHandle);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to chainload EFI binary, return error code */
XtLdrProtocol->Debug.Print(L"ERROR: Unable to chainload '%S' (Status Code: 0x%zX)\n",
Parameters->KernelFile, Status);
return Status;
}
/* Access loaded image protocol */
Status = XtLdrProtocol->Protocol.OpenHandle(LoaderHandle, (PVOID *)&LoadedImage, &LIPGuid);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open EFI_LOADED_IMAGE_PROTOCOL, return error code */
XtLdrProtocol->Debug.Print(L"ERROR: Unable to access binary interface (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Check if parameters provided */
if(Parameters->Parameters)
{
/* Pass arguments to chainloaded image */
LoadedImage->LoadOptionsSize = XtLdrProtocol->WideString.Length(Parameters->Parameters, 0) * sizeof(WCHAR);
LoadedImage->LoadOptions = Parameters->Parameters;
}
/* Set device handle as LoadImage() is not going to do it */
LoadedImage->DeviceHandle = DiskHandle;
/* Chainload EFI image */
return XtLdrProtocol->Utils.StartEfiImage(LoaderHandle);
}
/**
* Initializes CHAINLDR module by opening XTLDR protocol and installing CHAINLOADER protocol.
*
* @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
ChainLoader::InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID Guid = XT_CHAIN_BOOT_PROTOCOL_GUID;
EFI_STATUS Status;
/* Open the XTLDR protocol */
Status = BlGetXtLdrProtocol(SystemTable, ImageHandle, &XtLdrProtocol);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open the protocol, return error */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Set routines available via ChainLoader boot protocol */
BootProtocol.BootSystem = BootSystem;
/* Register XTOS boot protocol */
XtLdrProtocol->Boot.RegisterProtocol(L"CHAINLOADER", &Guid);
/* Install XTOS protocol */
return XtLdrProtocol->Protocol.Install(&BootProtocol, &Guid);
}
/**
* 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 CHAINLDR module */
return ChainLoader::InitializeModule(ImageHandle, SystemTable);
}

View File

@@ -0,0 +1,16 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/chainldr/data.cc
* DESCRIPTION: CHAINLDR module global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <chainldr.hh>
/* ChainLoader Boot Protocol */
XTBL_BOOT_PROTOCOL ChainLoader::BootProtocol;
/* XTLDR protocol handler */
PXTBL_LOADER_PROTOCOL ChainLoader::XtLdrProtocol;

View File

@@ -0,0 +1,28 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/chainldr/includes/chainldr.hh
* DESCRIPTION: XTLDR Chain Loader header file
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_CHAINLDR_CHAINLDR_HH
#define __XTLDR_CHAINLDR_CHAINLDR_HH
#include <xtblapi.h>
/* CHAINLDR module for XTLDR */
class ChainLoader
{
private:
STATIC XTBL_BOOT_PROTOCOL BootProtocol;
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC XTCDECL EFI_STATUS BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters);
STATIC XTCDECL EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
};
#endif /* __XTLDR_CHAINLDR_CHAINLDR_HH */

View File

@@ -0,0 +1,27 @@
# XT Boot Loader Dummy Module
PROJECT(XTLDR_DUMMY)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_DUMMY_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_DUMMY_SOURCE
${XTLDR_DUMMY_SOURCE_DIR}/dummy.cc
${XTLDR_DUMMY_SOURCE_DIR}/data.cc)
# Link module executable
add_executable(dummy ${XTLDR_DUMMY_SOURCE})
# Add linker libraries
target_link_libraries(dummy libxtldr)
# Set proper binary name and install target
set_target_properties(dummy PROPERTIES SUFFIX .efi)
set_install_target(dummy efi/boot/xtldr/modules)
# Set module entrypoint and subsystem
set_entrypoint(dummy "XtLdrModuleMain")
set_linker_map(dummy TRUE)
set_subsystem(dummy efi_boot_service_driver)

View File

@@ -0,0 +1,16 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/dummy/data.cc
* DESCRIPTION: Dummy XTLDR module global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <dummy.hh>
/* Dummy Boot Protocol handler */
XTBL_BOOT_PROTOCOL Dummy::DummyProtocol;
/* XTLDR protocol handler */
PXTBL_LOADER_PROTOCOL Dummy::XtLdrProtocol;

View File

@@ -0,0 +1,95 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/dummy/dummy.cc
* DESCRIPTION: XTLDR Dummy Module
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <dummy.hh>
/* Dummy module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
MODULE_DESCRIPTION(L"XTLDR Dummy Module");
MODULE_LICENSE(L"GPLv3");
MODULE_VERSION(L"0.1");
/**
* Stub boot routine.
*
* @param Parameters
* Supplies all parameters associated with the chosen boot menu entry.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Dummy::BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters)
{
return STATUS_EFI_SUCCESS;
}
/**
* Initializes DUMMY module by opening XTLDR protocol and installing DUMMY protocol.
*
* @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
Dummy::InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID DummyGuid = XT_DUMMY_BOOT_PROTOCOL_GUID;
EFI_STATUS Status;
/* Open the XTLDR protocol */
Status = BlGetXtLdrProtocol(SystemTable, ImageHandle, &XtLdrProtocol);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open the protocol, return error */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Set boot protocol routines */
DummyProtocol.BootSystem = BootSystem;
/* Register XTOS boot protocol */
XtLdrProtocol->Boot.RegisterProtocol(L"DUMMYOS", &DummyGuid);
/* Register DUMMY protocol as XTOS boot protocol */
return XtLdrProtocol->Protocol.Install(&DummyProtocol, &DummyGuid);
}
/**
* 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 a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
XtLdrModuleMain(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
/* Initialize DUMMY module */
return Dummy::InitializeModule(ImageHandle, SystemTable);
}

View File

@@ -0,0 +1,28 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/dummy/includes/dummy.hh
* DESCRIPTION: XTLDR Dummy Module header file
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_DUMMY_DUMMY_HH
#define __XTLDR_DUMMY_DUMMY_HH
#include <xtblapi.h>
/* DUMMY module for XTLDR */
class Dummy
{
private:
STATIC XTBL_BOOT_PROTOCOL DummyProtocol;
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC EFI_STATUS BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters);
STATIC EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
};
#endif/* __XTLDR_DUMMY_DUMMY_HH */

View File

@@ -0,0 +1,27 @@
# XTLDR FrameBuffer support module
PROJECT(XTLDR_FRAMEBUF)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_FRAMEBUF_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_FRAMEBUF_SOURCE
${XTLDR_FRAMEBUF_SOURCE_DIR}/framebuf.cc
${XTLDR_FRAMEBUF_SOURCE_DIR}/data.cc)
# Link bootloader executable
add_executable(framebuf ${XTLDR_FRAMEBUF_SOURCE})
# Add linker libraries
target_link_libraries(framebuf libxtldr)
# Set proper binary name and install target
set_target_properties(framebuf PROPERTIES SUFFIX .efi)
set_install_target(framebuf efi/boot/xtldr/modules)
# Set module entrypoint and subsystem
set_entrypoint(framebuf "XtLdrModuleMain")
set_linker_map(framebuf TRUE)
set_subsystem(framebuf efi_boot_service_driver)

View File

@@ -0,0 +1,19 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/framebuf/data.cc
* DESCRIPTION: EFI framebuffer module global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <framebuf.hh>
/* Framebuffer display information */
XTBL_FRAMEBUFFER_INFORMATION FrameBuffer::DisplayInfo;
/* Framebuffer protocol handler */
XTBL_FRAMEBUFFER_PROTOCOL FrameBuffer::FbProtocol;
/* XTLDR protocol handler */
PXTBL_LOADER_PROTOCOL FrameBuffer::XtLdrProtocol;

View File

@@ -0,0 +1,810 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/framebuf/framebuf.cc
* DESCRIPTION: EFI framebuffer support module for XTLDR
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <framebuf.hh>
/* PE/COFF_O module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
MODULE_DESCRIPTION(L"EFI FB (FrameBuffer) support");
MODULE_LICENSE(L"GPLv3");
MODULE_VERSION(L"0.2");
/**
* Finds a PCI Display Adapter and returns its framebuffer address.
*
* @param Address
* Supplies a pointer to the memory area where framebuffer address will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::FindFramebufferAddress(OUT PEFI_PHYSICAL_ADDRESS Address)
{
EFI_GUID PciIoGuid = EFI_PCI_IO_PROTOCOL_GUID;
PEFI_ACPI_ADDRESS_SPACE_DESCRIPTOR BarInfo;
PEFI_PCI_IO_PROTOCOL IoProtocol;
ULONGLONG FramebufAddressLength;
PCI_TYPE0_DEVICE PciDevice;
PVOID FramebufAddress;
UINT_PTR HandlesCount;
EFI_HANDLE *Handles;
EFI_STATUS Status;
UINT Index;
/* Initialize variables */
FramebufAddressLength = 0;
Handles = NULLPTR;
/* Locate EFI_PCI_IO_PROTOCOL handles */
Status = XtLdrProtocol->Protocol.LocateHandles(&Handles, &HandlesCount, &PciIoGuid);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get handles, return error code */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get handles (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Iterate through handles */
for(Index = 0; Index < HandlesCount; Index++)
{
/* Open EFI_PCI_IO_PROTOCOL handle */
Status = XtLdrProtocol->Protocol.OpenHandle(Handles[Index], (PVOID *)&IoProtocol, &PciIoGuid);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open protocol, continue with next handle */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to open protocol (Status Code: 0x%zX)\n", Status);
continue;
}
/* Read PCI controller registers from PCI configuration space */
Status = IoProtocol->Pci.Read(IoProtocol, EfiPciIoWidthUint32, 0, sizeof(PciDevice) / sizeof(UINT), &PciDevice);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to read PCI device class */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to read class (Status Code: 0x%zX)\n", Status);
/* Close protocol and continue with next handle */
XtLdrProtocol->Protocol.Close(&Handles[Index], &PciIoGuid);
continue;
}
/* Check if device is a graphics adapter */
if(PciDevice.Hdr.ClassCode[2] != 0x03)
{
/* Not a graphics adapter, close protocol and continue with next handle */
XtLdrProtocol->Protocol.Close(&Handles[Index], &PciIoGuid);
continue;
}
/* Iterate through all PCI device's Base Address Registers (BARs) */
for(UINT Bars = 0; Bars < 6; Bars++)
{
/* Get BAR attributes */
Status = IoProtocol->GetBarAttributes(IoProtocol, Bars, NULLPTR, (VOID **)&BarInfo);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get BAR attributes, continue with next BAR */
continue;
}
/* Check if this BAR is 'Memory Range' of 'ACPI QWORD Address Space' */
if(BarInfo->SpaceDescriptor == EFI_ACPI_ADDRESS64_SPACE_DESCRIPTOR &&
BarInfo->ResourceType == EFI_ACPI_ADDRESS_SPACE_TYPE_MEMORY)
{
/* Check if this BAR is the biggest we've seen so far */
if(BarInfo->AddressLength > FramebufAddressLength)
{
/* The biggest BAR should be the framebuffer; save its address and length */
FramebufAddress = (PVOID)(ULONG_PTR)(BarInfo->AddressRangeMin << 16);
FramebufAddressLength = BarInfo->AddressLength;
}
}
}
/* Close handle and continue with next one */
XtLdrProtocol->Protocol.Close(&Handles[Index], &PciIoGuid);
}
/* Set framebuffer address and return success */
*Address = (EFI_PHYSICAL_ADDRESS)FramebufAddress;
return STATUS_EFI_SUCCESS;
}
/**
* Calculates color mask and shift based upon pixel bit mask.
*
* @param PixelBitMask
* Provides a pixel bit mask.
*
* @param ColorSize
* Supplies a pointer to the memory area where the color size will be stored.
*
* @param ColorShift
* Supplies a pointer to the memory area where the color shift (position) will be stored.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
FrameBuffer::GetColorMask(IN UINT PixelBitMask,
OUT PUSHORT ColorSize,
OUT PUSHORT ColorShift)
{
UINT Shift, Size;
/* Initialize variables */
Shift = 0;
Size = 0;
/* Make sure EfiMask is not zero */
if(PixelBitMask)
{
/* Get color shift */
while((PixelBitMask & 1) == 0)
{
Shift++;
PixelBitMask >>= 1;
}
/* Get color size */
while((PixelBitMask & 1) == 1)
{
Size++;
PixelBitMask >>= 1;
}
}
/* Set color mask and shift */
*ColorShift = Shift;
*ColorSize = Size;
}
/**
* Provides an EFI Frame Buffer protocol driver name used for initialization.
*
* @param Protocol
* Supplies a pointer to the memory area where framebuffer driver information will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::GetDisplayDriver(OUT PEFI_GRAPHICS_PROTOCOL Protocol)
{
/* Check if framebuffer is initialized */
if(!DisplayInfo.Initialized)
{
/* Return error if framebuffer is not initialized */
return STATUS_EFI_NOT_READY;
}
/* Copy framebuffer driver information */
*Protocol = DisplayInfo.Protocol;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Returns information about EFI Frame Buffer.
*
* @param FbInfo
* Supplies a pointer to the memory area where framebuffer information will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::GetDisplayInformation(OUT PEFI_PHYSICAL_ADDRESS FrameBufferBase,
OUT PULONG_PTR FrameBufferSize,
OUT PXTBL_FRAMEBUFFER_MODE_INFORMATION ModeInfo)
{
/* Check if framebuffer is initialized */
if(!DisplayInfo.Initialized)
{
/* Return error if framebuffer is not initialized */
return STATUS_EFI_NOT_READY;
}
/* Set basic framebuffer information */
*FrameBufferBase = DisplayInfo.FrameBufferBase;
*FrameBufferSize = DisplayInfo.FrameBufferSize;
/* Set framebuffer mode information */
ModeInfo->Width = DisplayInfo.ModeInfo.Width;
ModeInfo->Height = DisplayInfo.ModeInfo.Height;
ModeInfo->Depth = DisplayInfo.ModeInfo.Depth;
ModeInfo->RefreshRate = DisplayInfo.ModeInfo.RefreshRate;
ModeInfo->BitsPerPixel = DisplayInfo.ModeInfo.BitsPerPixel;
ModeInfo->BytesPerPixel = DisplayInfo.ModeInfo.BytesPerPixel;
ModeInfo->PixelsPerScanLine = DisplayInfo.ModeInfo.PixelsPerScanLine;
ModeInfo->Pitch = DisplayInfo.ModeInfo.Pitch;
ModeInfo->PixelFormat = DisplayInfo.ModeInfo.PixelFormat;
ModeInfo->PixelInformation = DisplayInfo.ModeInfo.PixelInformation;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Gets information about the current display mode and stores it in internal structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::GetModeInformation()
{
PEFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInfo;
EFI_PIXEL_BITMASK PixelBitMask;
XTSTATUS Status;
UINT_PTR Size;
switch(DisplayInfo.Protocol)
{
case GOP:
/* Query GOP mode information */
Status = DisplayInfo.Driver.Gop->QueryMode(DisplayInfo.Driver.Gop,
DisplayInfo.Driver.Gop->Mode->Mode,
&Size, &ModeInfo);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get GOP mode information, return error */
return Status;
}
/* Get pixel bit mask information */
GetPixelInformation(&DisplayInfo.Driver.Gop->Mode->Info->PixelInformation);
/* Store GOP framebuffer information */
DisplayInfo.ModeInfo.Width = DisplayInfo.Driver.Gop->Mode->Info->HorizontalResolution;
DisplayInfo.ModeInfo.Height = DisplayInfo.Driver.Gop->Mode->Info->VerticalResolution;
DisplayInfo.ModeInfo.Depth = DisplayInfo.ModeInfo.BitsPerPixel;
DisplayInfo.ModeInfo.PixelsPerScanLine = DisplayInfo.Driver.Gop->Mode->Info->PixelsPerScanLine;
DisplayInfo.ModeInfo.Pitch = DisplayInfo.ModeInfo.PixelsPerScanLine *
(DisplayInfo.ModeInfo.BitsPerPixel / 8);
DisplayInfo.ModeInfo.RefreshRate = 0;
/* Store pixel format information and frame buffer size */
DisplayInfo.ModeInfo.PixelFormat = DisplayInfo.Driver.Gop->Mode->Info->PixelFormat;
DisplayInfo.FrameBufferSize = DisplayInfo.Driver.Gop->Mode->FrameBufferSize;
break;
case UGA:
/* Query UGA mode information */
Status = DisplayInfo.Driver.Uga->GetMode(DisplayInfo.Driver.Uga, &DisplayInfo.ModeInfo.Width,
&DisplayInfo.ModeInfo.Height, &DisplayInfo.ModeInfo.Depth,
&DisplayInfo.ModeInfo.RefreshRate);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get UGA mode information, return error */
return Status;
}
/* Get pixel bit mask information */
PixelBitMask = (EFI_PIXEL_BITMASK){0, 0, 0, 0};
GetPixelInformation(&PixelBitMask);
/* Store UGA framebuffer information */
DisplayInfo.ModeInfo.PixelsPerScanLine = DisplayInfo.ModeInfo.Width;
DisplayInfo.ModeInfo.Pitch = DisplayInfo.ModeInfo.PixelsPerScanLine *
(DisplayInfo.ModeInfo.BitsPerPixel / 8);
/* Store pixel format information and recalculate frame buffer size */
DisplayInfo.ModeInfo.PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
DisplayInfo.FrameBufferSize = DisplayInfo.ModeInfo.Width *
DisplayInfo.ModeInfo.Height *
DisplayInfo.ModeInfo.BytesPerPixel + 1024;
break;
default:
/* This should never be reached as no other display driver is supported */
break;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Gets pixel information based on the reported pixel format.
*
* @param FrameBufferInfo
* Supplies a pointer to the framebuffer information structure.
*
* @param PixelsBitMask
* Supplies a pointer to the pixel bit mask information provided by EFI graphics protocol.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
FrameBuffer::GetPixelInformation(IN PEFI_PIXEL_BITMASK PixelsBitMask)
{
UINT CompoundMask;
/* Check reported pixel format */
switch(DisplayInfo.ModeInfo.PixelFormat)
{
case PixelBlueGreenRedReserved8BitPerColor:
/* BGRR, 32 bits per pixel */
DisplayInfo.ModeInfo.BitsPerPixel = 32;
DisplayInfo.ModeInfo.PixelInformation.BlueShift = 0;
DisplayInfo.ModeInfo.PixelInformation.BlueSize = 8;
DisplayInfo.ModeInfo.PixelInformation.GreenShift = 8;
DisplayInfo.ModeInfo.PixelInformation.GreenSize = 8;
DisplayInfo.ModeInfo.PixelInformation.RedShift = 16;
DisplayInfo.ModeInfo.PixelInformation.RedSize = 8;
DisplayInfo.ModeInfo.PixelInformation.ReservedShift = 24;
DisplayInfo.ModeInfo.PixelInformation.ReservedSize = 8;
break;
case PixelRedGreenBlueReserved8BitPerColor:
/* RGBR, 32 bits per pixel */
DisplayInfo.ModeInfo.BitsPerPixel = 32;
DisplayInfo.ModeInfo.PixelInformation.BlueShift = 16;
DisplayInfo.ModeInfo.PixelInformation.BlueSize = 8;
DisplayInfo.ModeInfo.PixelInformation.GreenShift = 8;
DisplayInfo.ModeInfo.PixelInformation.GreenSize = 8;
DisplayInfo.ModeInfo.PixelInformation.RedShift = 0;
DisplayInfo.ModeInfo.PixelInformation.RedSize = 8;
DisplayInfo.ModeInfo.PixelInformation.ReservedShift = 24;
DisplayInfo.ModeInfo.PixelInformation.ReservedSize = 8;
break;
case PixelBitMask:
/* Assume 32 bits per pixel */
DisplayInfo.ModeInfo.BitsPerPixel = 32;
/* Calculate compound mask */
CompoundMask = PixelsBitMask->RedMask |
PixelsBitMask->GreenMask |
PixelsBitMask->BlueMask |
PixelsBitMask->ReservedMask;
/* Recalculate bits per pixel */
while((CompoundMask & (1 << 31)) == 0)
{
DisplayInfo.ModeInfo.BitsPerPixel--;
CompoundMask <<= 1;
}
/* Set pixel information */
GetColorMask(PixelsBitMask->RedMask, &DisplayInfo.ModeInfo.PixelInformation.RedSize,
&DisplayInfo.ModeInfo.PixelInformation.RedShift);
GetColorMask(PixelsBitMask->GreenMask, &DisplayInfo.ModeInfo.PixelInformation.GreenSize,
&DisplayInfo.ModeInfo.PixelInformation.GreenShift);
GetColorMask(PixelsBitMask->BlueMask, &DisplayInfo.ModeInfo.PixelInformation.BlueSize,
&DisplayInfo.ModeInfo.PixelInformation.BlueShift);
GetColorMask(PixelsBitMask->ReservedMask, &DisplayInfo.ModeInfo.PixelInformation.ReservedSize,
&DisplayInfo.ModeInfo.PixelInformation.ReservedShift);
break;
default:
/* Unknown pixel format */
DisplayInfo.ModeInfo.BitsPerPixel = 0;
DisplayInfo.ModeInfo.PixelInformation.BlueShift = 0;
DisplayInfo.ModeInfo.PixelInformation.BlueSize = 0;
DisplayInfo.ModeInfo.PixelInformation.GreenShift = 0;
DisplayInfo.ModeInfo.PixelInformation.GreenSize = 0;
DisplayInfo.ModeInfo.PixelInformation.RedShift = 0;
DisplayInfo.ModeInfo.PixelInformation.RedSize = 0;
DisplayInfo.ModeInfo.PixelInformation.ReservedShift = 0;
DisplayInfo.ModeInfo.PixelInformation.ReservedSize = 0;
break;
}
/* Calculate bytes per pixel based on bits per pixel */
DisplayInfo.ModeInfo.BytesPerPixel = DisplayInfo.ModeInfo.BitsPerPixel >> 3;
}
/**
* Determines the preferred (native) screen resolution from EDID. This works only with GOP.
*
* @param PreferredWidth
* Supplies a pointer to the memory area where preferred screen width will be stored.
*
* @param PreferredHeight
* Supplies a pointer to the memory area where preferred screen height will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::GetPreferredScreenResolution(OUT PUINT PreferredWidth,
OUT PUINT PreferredHeight)
{
EFI_GUID GopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GUID EdidGuid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
PEFI_EDID_ACTIVE_PROTOCOL ActiveEdid;
EFI_STATUS Status;
/* Check if framebuffer is initialized */
if(!DisplayInfo.Initialized)
{
/* Framebuffer not ready to use EDID protocol */
return STATUS_EFI_NOT_READY;
}
/* Check if GOP device driver is used */
if(DisplayInfo.Protocol != GOP)
{
/* Unsupported device driver */
return STATUS_EFI_UNSUPPORTED;
}
/* Open EDID protocol */
Status = XtLdrProtocol->Protocol.OpenHandle(DisplayInfo.Handle, (PVOID *)&ActiveEdid, &EdidGuid);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open EDID protocol, close GOP protocol and return */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &GopGuid);
return Status;
}
/* Return preferred screen resolution */
*PreferredWidth = ActiveEdid->Edid[0x38] | ((ActiveEdid->Edid[0x3A] & 0xF0) << 4);
*PreferredHeight = ActiveEdid->Edid[0x3B] | ((ActiveEdid->Edid[0x3D] & 0xF0) << 4);
/* Close EDID & GOP protocols */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &EdidGuid);
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Initializes FrameBuffer device on GOP and UGA compatible adapters.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::InitializeDisplay()
{
EFI_GUID GopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GUID UgaGuid = EFI_UNIVERSAL_GRAPHICS_ADAPTER_PROTOCOL_GUID;
PEFI_GRAPHICS_OUTPUT_MODE_INFORMATION GopModeInfo;
UINT Depth, QueryMode, Refresh;
UINT_PTR InfoSize;
EFI_STATUS Status;
/* Check if framebuffer already initialized */
if(!DisplayInfo.Initialized)
{
/* Print debug message */
XtLdrProtocol->Debug.Print(L"Initializing framebuffer device\n");
/* Attempt to open EFI GOP protocol */
Status = XtLdrProtocol->Protocol.Open(&DisplayInfo.Handle, (PVOID*)&DisplayInfo.Driver.Gop, &GopGuid);
/* Check if Graphics Output Protocol (GOP) is available */
if(Status == STATUS_EFI_SUCCESS)
{
/* Check if there are any video modes available */
if(DisplayInfo.Driver.Gop->Mode->MaxMode == 0)
{
/* No video modes available */
XtLdrProtocol->Debug.Print(L"ERROR: No GOP video mode available\n");
/* Close GOP protocol and return error */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &GopGuid);
return STATUS_EFI_UNSUPPORTED;
}
/* Query current graphics mode */
QueryMode = DisplayInfo.Driver.Gop->Mode == NULLPTR ? 0 : DisplayInfo.Driver.Gop->Mode->Mode;
Status = DisplayInfo.Driver.Gop->QueryMode(DisplayInfo.Driver.Gop, QueryMode, &InfoSize, &GopModeInfo);
if(Status == STATUS_EFI_NOT_STARTED)
{
/* Set the mode to circumvent buggy UEFI firmware */
Status = DisplayInfo.Driver.Gop->SetMode(DisplayInfo.Driver.Gop, 0);
}
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to query GOP modes */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get GOP native mode (Status Code: 0x%zX)\n");
/* Close GOP protocol and return error */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &GopGuid);
return STATUS_EFI_UNSUPPORTED;
}
/* Store frame buffer base address and protocol used */
DisplayInfo.FrameBufferBase = DisplayInfo.Driver.Gop->Mode->FrameBufferBase;
DisplayInfo.DefaultMode = DisplayInfo.Driver.Gop->Mode->Mode;
DisplayInfo.Protocol = GOP;
/* Get current mode information */
Status = GetModeInformation();
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to get mode information */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get GOP mode information (Status Code: 0x%zX)\n");
/* Close GOP protocol and return error */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &GopGuid);
return STATUS_EFI_UNSUPPORTED;
}
/* Found GOP */
XtLdrProtocol->Debug.Print(L"Found EFI-GOP compatible display adapter @ %P (%zu bytes)\n",
DisplayInfo.FrameBufferBase, DisplayInfo.FrameBufferSize);
/* Close GOP protocol */
Status = XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &GopGuid);
}
else
{
/* GOP is unavailable, attempt to open UGA protocol */
Status = XtLdrProtocol->Protocol.Open(&DisplayInfo.Handle, (PVOID*)&DisplayInfo.Driver.Uga, &UgaGuid);
/* Check if Universal Graphics Adapter (UGA) is available */
if(Status == STATUS_EFI_SUCCESS)
{
/* Get current video mode */
Status = DisplayInfo.Driver.Uga->GetMode(DisplayInfo.Driver.Uga, &DisplayInfo.ModeInfo.Width,
&DisplayInfo.ModeInfo.Height, &Depth, &Refresh);
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to get current UGA mode */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get current UGA mode (Status Code: 0x%zX)\n", Status);
/* Close UGA protocol and return error */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &UgaGuid);
return STATUS_EFI_DEVICE_ERROR;
}
/* Find framebuffer address */
Status = FindFramebufferAddress(&DisplayInfo.FrameBufferBase);
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to find framebuffer address */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get EFI FB address (Status Code: 0x%zX)\n", Status);
/* Close UGA protocol and return error */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &UgaGuid);
return STATUS_EFI_DEVICE_ERROR;
}
/* Store framebuffer protocol information */
DisplayInfo.DefaultMode = 0;
DisplayInfo.Protocol = UGA;
/* Get mode information */
Status = GetModeInformation();
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to get mode information */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get UGA mode information (Status Code: 0x%zX)\n");
return STATUS_EFI_UNSUPPORTED;
}
/* Found UGA */
XtLdrProtocol->Debug.Print(L"Found EFI-UGA compatible display adapter @ %P (%zu bytes)\n",
DisplayInfo.FrameBufferBase, DisplayInfo.FrameBufferSize);
/* Close UGA protocol */
XtLdrProtocol->Protocol.Close(&DisplayInfo.Handle, &UgaGuid);
}
}
/* Make sure framebuffer initialized properly */
if(DisplayInfo.Protocol == NONE)
{
/* GOP and UGA unavailable */
XtLdrProtocol->Debug.Print(L"WARNING: No display adapter found!\n");
return STATUS_EFI_NOT_FOUND;
}
XtLdrProtocol->Debug.Print(L"Current screen resolution is %ux%ux%u\n", DisplayInfo.ModeInfo.Width,
DisplayInfo.ModeInfo.Height, DisplayInfo.ModeInfo.BitsPerPixel);
/* Set framebuffer initialization flag */
DisplayInfo.Initialized = TRUE;
}
/* Return success */
return STATUS_SUCCESS;
}
/**
* Initializes FRAMEBUF module by opening XTLDR protocol and installing FRAMEBUF protocol.
*
* @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
FrameBuffer::InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID Guid = XT_FRAMEBUFFER_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 initial framebuffer state */
DisplayInfo.Protocol = NONE;
DisplayInfo.Initialized = FALSE;
/* Set routines available via XTLDR framebuffer protocol */
FbProtocol.GetDisplayDriver = GetDisplayDriver;
FbProtocol.GetDisplayInformation = GetDisplayInformation;
FbProtocol.GetPreferredScreenResolution = GetPreferredScreenResolution;
FbProtocol.Initialize = InitializeDisplay;
FbProtocol.SetScreenResolution = SetScreenResolution;
/* Register XTOS boot protocol */
return XtLdrProtocol->Protocol.Install(&FbProtocol, &Guid);
}
/**
* Sets custom screen resolution, based on the provided width and height.
*
* @param Width
* Supplies the width of the screen.
*
* @param Height
* Supplies the height of the screen.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
FrameBuffer::SetScreenResolution(IN UINT Width,
IN UINT Height)
{
PEFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInfo;
BOOLEAN ModeChanged;
EFI_STATUS Status;
UINT_PTR Size;
UINT Mode;
/* Check if framebuffer is initialized */
if(!DisplayInfo.Initialized)
{
/* Framebuffer not ready to change screen mode */
return STATUS_EFI_NOT_READY;
}
ModeChanged = FALSE;
/* Change screen mode depending on display adapter protocol */
switch(DisplayInfo.Protocol)
{
case GOP:
/* GOP available, check if user specified screen resolution */
if(Width == 0 || Height == 0)
{
/* No resolution specified, temporarily set lowest supported screen resolution */
Status = DisplayInfo.Driver.Gop->SetMode(DisplayInfo.Driver.Gop, 1);
if(Status == STATUS_EFI_SUCCESS)
{
/* Restore default graphics mode */
Status = DisplayInfo.Driver.Gop->SetMode(DisplayInfo.Driver.Gop, DisplayInfo.DefaultMode);
ModeChanged = (Status == STATUS_EFI_SUCCESS) ? TRUE : FALSE;
}
}
else
{
/* User specified screen resolution, find a corresponding mode */
Mode = 1;
while(Mode <= DisplayInfo.Driver.Gop->Mode->MaxMode)
{
/* Get mode information */
Status = DisplayInfo.Driver.Gop->QueryMode(DisplayInfo.Driver.Gop, Mode, &Size, &ModeInfo);
if(Status == STATUS_EFI_SUCCESS && Size >= sizeof(*ModeInfo) && ModeInfo != NULLPTR)
{
/* Check if match found */
if(ModeInfo->HorizontalResolution == Width && ModeInfo->VerticalResolution == Height)
{
/* Found corresponding mode, attempt to set it */
Status = DisplayInfo.Driver.Gop->SetMode(DisplayInfo.Driver.Gop, Mode);
if(Status == STATUS_EFI_SUCCESS)
{
/* New mode set correctly, use it */
ModeChanged = TRUE;
break;
}
}
}
/* Try with next mode */
Mode++;
}
}
break;
case UGA:
/* Set UGA screen mode, trying to keep current color depth and refresh rate */
Status = DisplayInfo.Driver.Uga->SetMode(DisplayInfo.Driver.Uga, Width, Height,
DisplayInfo.ModeInfo.Depth,
DisplayInfo.ModeInfo.RefreshRate);
if(Status == STATUS_EFI_SUCCESS)
{
/* New mode set correctly, use it */
ModeChanged = TRUE;
}
break;
default:
/* This should never be reached */
break;
}
if(!ModeChanged)
{
/* Failed to change screen mode */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to change screen mode to %ux%u (Status Code: 0x%zX)\n",
Width, Height, Status);
return STATUS_EFI_UNSUPPORTED;
}
/* Get new screen mode information */
Status = GetModeInformation();
if(Status == STATUS_EFI_SUCCESS)
{
XtLdrProtocol->Debug.Print(L"Changed screen resolution to %ux%ux%u\n", DisplayInfo.ModeInfo.Width,
DisplayInfo.ModeInfo.Height, DisplayInfo.ModeInfo.BitsPerPixel);
}
/* 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 FRAMEBUF module */
return FrameBuffer::InitializeModule(ImageHandle, SystemTable);
}

View File

@@ -0,0 +1,44 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/framebuf/includes/framebuf.hh
* DESCRIPTION: EFI Framebuffer support module header file
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_MODULES_FRAMEBUF_HH
#define __XTLDR_MODULES_FRAMEBUF_HH
#include <xtblapi.h>
class FrameBuffer
{
private:
STATIC XTBL_FRAMEBUFFER_INFORMATION DisplayInfo;
STATIC XTBL_FRAMEBUFFER_PROTOCOL FbProtocol;
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC XTCDECL EFI_STATUS GetDisplayDriver(OUT PEFI_GRAPHICS_PROTOCOL Protocol);
STATIC XTCDECL EFI_STATUS GetDisplayInformation(OUT PEFI_PHYSICAL_ADDRESS FrameBufferBase,
OUT PULONG_PTR FrameBufferSize,
OUT PXTBL_FRAMEBUFFER_MODE_INFORMATION ModeInfo);
STATIC XTCDECL EFI_STATUS GetPreferredScreenResolution(OUT PUINT PreferredWidth,
OUT PUINT PreferredHeight);
STATIC XTCDECL EFI_STATUS InitializeDisplay();
STATIC XTCDECL EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
STATIC XTCDECL EFI_STATUS SetScreenResolution(IN UINT Width,
IN UINT Height);
private:
STATIC EFI_STATUS FindFramebufferAddress(OUT PEFI_PHYSICAL_ADDRESS Address);
STATIC XTCDECL VOID GetColorMask(IN UINT EfiMask,
OUT PUSHORT ColorSize,
OUT PUSHORT ColorShift);
STATIC XTCDECL EFI_STATUS GetModeInformation();
STATIC XTCDECL VOID GetPixelInformation(IN PEFI_PIXEL_BITMASK PixelsBitMask);
};
#endif /* __XTLDR_MODULES_FRAMEBUF_HH */

View File

@@ -0,0 +1,27 @@
# XTLDR PE/COFF image support module
PROJECT(XTLDR_PECOFF)
# Specify include directories
include_directories(
${EXECTOS_SOURCE_DIR}/sdk/xtdk
${XTLDR_PECOFF_SOURCE_DIR}/includes)
# Specify list of source code files
list(APPEND XTLDR_PECOFF_SOURCE
${XTLDR_PECOFF_SOURCE_DIR}/data.cc
${XTLDR_PECOFF_SOURCE_DIR}/pecoff.cc)
# Link module executable
add_executable(pecoff ${XTLDR_PECOFF_SOURCE})
# Add linker libraries
target_link_libraries(pecoff libxtldr libxtos)
# Set proper binary name and install target
set_target_properties(pecoff PROPERTIES SUFFIX .efi)
set_install_target(pecoff efi/boot/xtldr/modules)
# Set module entrypoint and subsystem
set_entrypoint(pecoff "XtLdrModuleMain")
set_linker_map(pecoff TRUE)
set_subsystem(pecoff efi_boot_service_driver)

View File

@@ -0,0 +1,16 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/pecoff/globals.cc
* DESCRIPTION: Basic PE/COFF executable file format global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <pecoff.hh>
/* XTOS PE/COFF Image Protocol */
XTBL_EXECUTABLE_IMAGE_PROTOCOL PeCoff::PeProtocol;
/* EFI XT Loader Protocol */
PXTBL_LOADER_PROTOCOL PeCoff::XtLdrProtocol;

View File

@@ -0,0 +1,53 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/pecoff/includes/pecoff.hh
* DESCRIPTION: Basic PE/COFF executable file format support header
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_PECOFF_HH
#define __XTLDR_PECOFF_HH
#include <xtblapi.h>
/* PE/COFF module for XTLDR */
class PeCoff
{
private:
STATIC XTBL_EXECUTABLE_IMAGE_PROTOCOL PeProtocol;
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC XTCDECL EFI_STATUS GetEntryPoint(IN PVOID ImagePointer,
OUT PVOID *EntryPoint);
STATIC XTCDECL EFI_STATUS GetFileSize(IN PVOID ImagePointer,
OUT PULONGLONG FileSize);
STATIC XTCDECL EFI_STATUS GetImageSize(IN PVOID ImagePointer,
OUT PUINT ImageSize);
STATIC XTCDECL EFI_STATUS GetMachineType(IN PVOID ImagePointer,
OUT PUSHORT MachineType);
STATIC XTCDECL EFI_STATUS GetSection(IN PVOID ImagePointer,
IN PCHAR SectionName,
OUT PULONG *RawData);
STATIC XTCDECL EFI_STATUS GetSubSystem(IN PVOID ImagePointer,
OUT PUSHORT SubSystem);
STATIC XTCDECL EFI_STATUS GetVersion(IN PVOID ImagePointer,
OUT PUSHORT Version);
STATIC XTCDECL EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
STATIC XTCDECL EFI_STATUS LoadImage(IN PEFI_FILE_HANDLE FileHandle,
IN LOADER_MEMORY_TYPE MemoryType,
IN PVOID VirtualAddress,
OUT PVOID *ImagePointer);
STATIC XTCDECL EFI_STATUS RelocateImage(IN PVOID ImagePointer,
IN EFI_VIRTUAL_ADDRESS Address);
STATIC XTCDECL EFI_STATUS UnloadImage(IN PVOID ImagePointer);
STATIC XTCDECL EFI_STATUS VerifyImage(IN PVOID ImagePointer);
private:
STATIC XTCDECL EFI_STATUS RelocateLoadedImage(IN PPECOFF_IMAGE_CONTEXT Image);
};
#endif /* __XTLDR_PECOFF_HH */

View File

@@ -0,0 +1,923 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/pecoff/pecoff.cc
* DESCRIPTION: Basic PE/COFF executable file format support module
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <pecoff.hh>
/* PE/COFF_O module information */
MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
MODULE_DESCRIPTION(L"Basic PE/COFF executable file format support");
MODULE_LICENSE(L"GPLv3");
MODULE_VERSION(L"0.1");
/**
* Returns the address of the entry point.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param EntryPoint
* Supplies a pointer to the memory area where address of the image entry point will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetEntryPoint(IN PVOID ImagePointer,
OUT PVOID *EntryPoint)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->PeHeader)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Check PE/COFF image type */
if(Image->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Get entry point from 64-bit optional header */
*EntryPoint = (PUCHAR)Image->VirtualAddress + Image->PeHeader->OptionalHeader64.AddressOfEntryPoint;
}
else
{
/* Get entry point from 32-bit optional header */
*EntryPoint = (PUCHAR)Image->VirtualAddress + Image->PeHeader->OptionalHeader32.AddressOfEntryPoint;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Returns the size of the loaded PE/COFF file.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param ImageSize
* Supplies a pointer to the memory area where file size will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetFileSize(IN PVOID ImagePointer,
OUT PULONGLONG FileSize)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->ImageSize)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Get image size and return success */
*FileSize = Image->FileSize;
return STATUS_EFI_NOT_FOUND;
}
/**
* Returns the size of the loaded PE/COFF image.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param ImageSize
* Supplies a pointer to the memory area where image size will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetImageSize(IN PVOID ImagePointer,
OUT PUINT ImageSize)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->ImageSize)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Get image size and return success */
*ImageSize = Image->ImageSize;
return STATUS_EFI_NOT_FOUND;
}
/**
* Returns the machine type of the PE/COFF image.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param MachineType
* Supplies a pointer to the memory area where a value defined for the 'machine' field will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetMachineType(IN PVOID ImagePointer,
OUT PUSHORT MachineType)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->PeHeader)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Get image machine type and return success */
*MachineType = Image->PeHeader->FileHeader.Machine;
return STATUS_EFI_SUCCESS;
}
/**
* Returns an address to the specified section in the PE/COFF image.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param SectionName
* Supplies a name of the requested section.
*
* @param RawData
* Supplies a pointer to the memory area where the address of the requested section will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetSection(IN PVOID ImagePointer,
IN PCHAR SectionName,
OUT PULONG *RawData)
{
PPECOFF_IMAGE_SECTION_HEADER SectionHeader;
PPECOFF_IMAGE_CONTEXT Image;
SIZE_T SectionNameLength;
USHORT SectionIndex;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->PeHeader)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Check PE/COFF image type */
if(Image->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Find section header in 64-bit optional header */
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&Image->PeHeader->OptionalHeader64 +
Image->PeHeader->FileHeader.SizeOfOptionalHeader);
}
else
{
/* Find section header in 32-bit optional header */
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&Image->PeHeader->OptionalHeader32 +
Image->PeHeader->FileHeader.SizeOfOptionalHeader);
}
/* Get section name length */
SectionNameLength = XtLdrProtocol->String.Length(SectionName, 0);
/* Iterate through all image sections */
for(SectionIndex = 0; SectionIndex < Image->PeHeader->FileHeader.NumberOfSections; SectionIndex++)
{
/* Check section name */
if(XtLdrProtocol->String.Compare((PCHAR)SectionHeader[SectionIndex].Name, SectionName, SectionNameLength) == 0)
{
/* Store section address and return */
*RawData = (PULONG)((PUCHAR)Image->Data + SectionHeader[SectionIndex].PointerToRawData);
return STATUS_EFI_SUCCESS;
}
}
/* Section not found if reached here */
return STATUS_EFI_NOT_FOUND;
}
/**
* Returns an information about subsystem that is required to run PE/COFF image.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param SubSystem
* Supplies a pointer to the memory area storing a value defined for the 'subsystem' field of the image.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetSubSystem(IN PVOID ImagePointer,
OUT PUSHORT SubSystem)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->PeHeader)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Check PE/COFF image type */
if(Image->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Get image subsystem from 64-bit optional header */
*SubSystem = Image->PeHeader->OptionalHeader64.Subsystem;
}
else
{
/* Get image subsystem from 32-bit optional header */
*SubSystem = Image->PeHeader->OptionalHeader32.Subsystem;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Returns an information about major image version.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param Version
* Supplies a pointer to the memory area storing a major image version.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::GetVersion(IN PVOID ImagePointer,
OUT PUSHORT Version)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->PeHeader)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Check PE/COFF image type */
if(Image->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Get image major version from 64-bit optional header */
*Version = Image->PeHeader->OptionalHeader64.MajorImageVersion;
}
else
{
/* Get image major version from 32-bit optional header */
*Version = Image->PeHeader->OptionalHeader32.MajorImageVersion;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Initializes PECOFF module by opening XTLDR protocol and installing PECOFF protocol.
*
* @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
PeCoff::InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID Guid = XT_PECOFF_IMAGE_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 PE/COFF image protocol */
PeProtocol.GetEntryPoint = GetEntryPoint;
PeProtocol.GetFileSize = GetFileSize;
PeProtocol.GetImageSize = GetImageSize;
PeProtocol.GetMachineType = GetMachineType;
PeProtocol.GetSection = GetSection;
PeProtocol.GetSubSystem = GetSubSystem;
PeProtocol.GetVersion = GetVersion;
PeProtocol.LoadImage = LoadImage;
PeProtocol.RelocateImage = RelocateImage;
PeProtocol.UnloadImage = UnloadImage;
PeProtocol.VerifyImage = VerifyImage;
/* Register PE/COFF protocol */
return XtLdrProtocol->Protocol.Install(&PeProtocol, &Guid);
}
/**
* Loads a PE/COFF image file.
*
* @param FileHandle
* The handle of the opened portable executable (PE) file.
*
* @param MemoryType
* Supplies the type of memory to be assigned to the memory descriptor.
*
* @param VirtualAddress
* Optional virtual address pointing to the memory area where PE/COFF file will be loaded.
*
* @param Image
* 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
PeCoff::LoadImage(IN PEFI_FILE_HANDLE FileHandle,
IN LOADER_MEMORY_TYPE MemoryType,
IN PVOID VirtualAddress,
OUT PVOID *ImagePointer)
{
EFI_GUID FileInfoGuid = EFI_FILE_INFO_PROTOCOL_GUID;
PPECOFF_IMAGE_SECTION_HEADER SectionHeader;
PPECOFF_IMAGE_CONTEXT ImageData;
EFI_PHYSICAL_ADDRESS Address;
PEFI_FILE_INFO FileInfo;
UINT_PTR ReadSize;
EFI_STATUS Status;
UINT SectionSize;
SIZE_T Pages;
PUCHAR Data;
UINT Index;
/* Set required size for getting file information */
ReadSize = sizeof(EFI_FILE_INFO) + 32;
/* Allocate necessary amount of memory */
Status = XtLdrProtocol->Memory.AllocatePool(ReadSize, (PVOID *)&FileInfo);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
XtLdrProtocol->Debug.Print(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\n", Status);
return Status;
}
/* First attempt to get file information */
Status = FileHandle->GetInfo(FileHandle, &FileInfoGuid, &ReadSize, FileInfo);
if(Status == STATUS_EFI_BUFFER_TOO_SMALL)
{
/* Buffer it too small, but EFI tells the required size, let's reallocate */
XtLdrProtocol->Memory.FreePool(&FileInfo);
Status = XtLdrProtocol->Memory.AllocatePool(ReadSize, (PVOID *)&FileInfo);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
XtLdrProtocol->Debug.Print(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Second attempt to get file information */
Status = FileHandle->GetInfo(FileHandle, &FileInfoGuid, &ReadSize, FileInfo);
}
if(Status != STATUS_EFI_SUCCESS)
{
/* Unable to get file information */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to get PE/COFF file information (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Allocate memory for storing image data */
Status = XtLdrProtocol->Memory.AllocatePool(sizeof(PECOFF_IMAGE_CONTEXT), (PVOID *)&ImageData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
XtLdrProtocol->Debug.Print(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Store file size and memory type, nullify data and free up memory */
ImageData->Data = NULLPTR;
ImageData->FileSize = FileInfo->FileSize;
ImageData->MemoryType = MemoryType;
XtLdrProtocol->Memory.FreePool(FileInfo);
/* Calculate number of pages */
Pages = EFI_SIZE_TO_PAGES(ImageData->FileSize);
/* Allocate pages */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, Pages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Pages allocation failure */
XtLdrProtocol->Debug.Print(L"ERROR: Pages allocation failure (Status Code: 0x%zX)\n", Status);
XtLdrProtocol->Memory.FreePool(ImageData);
return Status;
}
/* Read PE/COFF image */
ReadSize = Pages * EFI_PAGE_SIZE;
Data = (PUCHAR)(UINT_PTR)Address;
Status = FileHandle->Read(FileHandle, &ReadSize, Data);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to read data */
XtLdrProtocol->Debug.Print(L"ERROR: Failed to read PE/COFF image file (Status Code: 0x%zX)\n", Status);
XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
XtLdrProtocol->Memory.FreePool(ImageData);
return Status;
}
/* Extract DOS and PE headers */
ImageData->DosHeader = (PPECOFF_IMAGE_DOS_HEADER)Data;
ImageData->PeHeader = (PPECOFF_IMAGE_PE_HEADER)((PUCHAR)Data + ImageData->DosHeader->PeHeaderOffset);
/* Validate headers */
Status = PeCoff::VerifyImage(ImageData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Header validation failed, probably broken or invalid PE/COFF image */
XtLdrProtocol->Debug.Print(L"ERROR: Invalid PE/COFF image headers (Status Code: 0x%zX)\n", Status);
XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
XtLdrProtocol->Memory.FreePool(ImageData);
return Status;
}
/* Make sure image is executable */
if (!(ImageData->PeHeader->FileHeader.Characteristics & PECOFF_IMAGE_FILE_EXECUTABLE_IMAGE))
{
/* Loaded image is not executable */
XtLdrProtocol->Debug.Print(L"ERROR: Non-executable PE/COFF image loaded\n");
XtLdrProtocol->Memory.FreePages(Pages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data);
XtLdrProtocol->Memory.FreePool(ImageData);
return STATUS_EFI_LOAD_ERROR;
}
/* Store image size depending on the PE/COFF image type */
if(ImageData->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Store 64-bit image size */
ImageData->ImageSize = ImageData->PeHeader->OptionalHeader64.SizeOfImage;
}
else
{
/* Store 32-bit image size */
ImageData->ImageSize = ImageData->PeHeader->OptionalHeader32.SizeOfImage;
}
/* Calculate number of image pages */
ImageData->ImagePages = EFI_SIZE_TO_PAGES(ImageData->ImageSize);
/* Allocate image pages */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, ImageData->ImagePages, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Pages reallocation failure */
XtLdrProtocol->Debug.Print(L"ERROR: Pages reallocation failure (Status Code: 0x%zX)\n", Status);
XtLdrProtocol->Memory.FreePool(ImageData);
return Status;
}
/* Store image data and virtual address */
ImageData->Data = (PUCHAR)(UINT_PTR)Address;
ImageData->PhysicalAddress = (PVOID)(UINT_PTR)Address;
if(VirtualAddress)
{
/* Virtual address passed to this routine */
ImageData->VirtualAddress = VirtualAddress;
}
else
{
/* Virtual address not specified, use physical address */
ImageData->VirtualAddress = (PVOID)(UINT_PTR)Address;
}
/* Check the PE/COFF image type */
if(ImageData->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Copy all PE32+ sections */
XtLdrProtocol->Memory.CopyMemory(ImageData->Data, Data, ImageData->PeHeader->OptionalHeader64.SizeOfHeaders);
/* Find PE32+ section header */
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&ImageData->PeHeader->OptionalHeader64 +
ImageData->PeHeader->FileHeader.SizeOfOptionalHeader);
}
else
{
/* Copy all PE32 sections */
XtLdrProtocol->Memory.CopyMemory(ImageData->Data, Data, ImageData->PeHeader->OptionalHeader64.SizeOfHeaders);
/* Find PE32 section header */
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&ImageData->PeHeader->OptionalHeader64 +
ImageData->PeHeader->FileHeader.SizeOfOptionalHeader);
}
/* Load each section into memory */
for(Index = 0; Index < ImageData->PeHeader->FileHeader.NumberOfSections; Index++)
{
/* Check section raw data size and section virtual size */
if(SectionHeader[Index].SizeOfRawData < SectionHeader[Index].Misc.VirtualSize)
{
/* Use raw data size if it is smaller than virtual size */
SectionSize = SectionHeader[Index].SizeOfRawData;
}
else
{
/* User virtual size otherwise */
SectionSize = SectionHeader[Index].Misc.VirtualSize;
}
/* Make sure section is available */
if(SectionSize > 0 && SectionHeader[Index].PointerToRawData != 0)
{
/* Copy section */
XtLdrProtocol->Memory.CopyMemory((PUCHAR)ImageData->Data + SectionHeader[Index].VirtualAddress,
Data + SectionHeader[Index].PointerToRawData, SectionSize);
}
/* Check if raw size is shorter than virtual size */
if(SectionSize < SectionHeader[Index].Misc.VirtualSize)
{
/* Fill remaining space with zeroes */
XtLdrProtocol->Memory.ZeroMemory((PUCHAR)ImageData->Data + SectionHeader[Index].VirtualAddress + SectionSize,
SectionHeader[Index].Misc.VirtualSize - SectionSize);
}
}
/* Free pages */
XtLdrProtocol->Memory.FreePages((EFI_PHYSICAL_ADDRESS)(UINT_PTR)Data, Pages);
/* Perform relocation fixups */
Status = PeCoff::RelocateLoadedImage(ImageData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to relocate image */
XtLdrProtocol->Debug.Print(L"ERROR: PE/COFF image relocation failed (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Store image data */
*ImagePointer = ImageData;
/* Return SUCCESS */
return STATUS_EFI_SUCCESS;
}
/**
* Relocates PE/COFF image to the specified address.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @param Address
* Specifies destination address of memory region, where image should be relocated.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::RelocateImage(IN PVOID ImagePointer,
IN EFI_VIRTUAL_ADDRESS Address)
{
PPECOFF_IMAGE_CONTEXT Image;
ULONGLONG ImageBase, OldVirtualAddress;
EFI_STATUS Status;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Store original virtual address */
OldVirtualAddress = (UINT_PTR)Image->VirtualAddress;
/* Check PE/COFF image type */
if(Image->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* This is 64-bit PE32+, store its image base address */
ImageBase = Image->PeHeader->OptionalHeader64.ImageBase;
}
else
{
/* This is 32-bit PE32, store its image base address */
ImageBase = Image->PeHeader->OptionalHeader32.ImageBase;
}
/* Overwrite virtual address and relocate image once again */
Image->VirtualAddress = (PVOID)(Address - OldVirtualAddress + ImageBase);
Status = PeCoff::RelocateLoadedImage(Image);
if(Status != STATUS_EFI_SUCCESS)
{
/* Relocation failed */
return Status;
}
/* Store new image virtual address */
Image->VirtualAddress = (PVOID)Address;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Relocates a loaded PE/COFF image.
*
* @param Image
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::RelocateLoadedImage(IN PPECOFF_IMAGE_CONTEXT Image)
{
PPECOFF_IMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
PPECOFF_IMAGE_DATA_DIRECTORY DataDirectory;
USHORT Offset, Type, Count;
PUSHORT TypeOffset;
ULONGLONG ImageBase;
PUINT Address;
PULONGLONG LongPtr;
PUINT ShortPtr;
/* Make sure image is not stripped */
if(Image->PeHeader->FileHeader.Characteristics & PECOFF_IMAGE_FILE_RELOCS_STRIPPED)
{
/* No relocation information found */
XtLdrProtocol->Debug.Print(L"WARNING: PE/COFF image is stripped and contains no information about relocations\n");
return STATUS_EFI_SUCCESS;
}
/* Check PE/COFF image type */
if(Image->PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Set relocation data directory and image base address */
DataDirectory = &Image->PeHeader->OptionalHeader64.DataDirectory[PECOFF_IMAGE_DIRECTORY_ENTRY_BASERELOC];
ImageBase = Image->PeHeader->OptionalHeader64.ImageBase;
/* Check if loaded 64-bit PE32+ image should be relocated */
if(Image->PeHeader->OptionalHeader64.NumberOfRvaAndSizes <= PECOFF_IMAGE_DIRECTORY_ENTRY_BASERELOC ||
DataDirectory->VirtualAddress == 0 || DataDirectory->Size < sizeof(PECOFF_IMAGE_BASE_RELOCATION))
{
/* No need to relocate the image */
return STATUS_EFI_SUCCESS;
}
}
else
{
/* Check if loaded 32-bit PE32 image should be relocated */
/* Set relocation data directory and image base address */
DataDirectory = &Image->PeHeader->OptionalHeader32.DataDirectory[PECOFF_IMAGE_DIRECTORY_ENTRY_BASERELOC];
ImageBase = Image->PeHeader->OptionalHeader32.ImageBase;
if(Image->PeHeader->OptionalHeader32.NumberOfRvaAndSizes <= PECOFF_IMAGE_DIRECTORY_ENTRY_BASERELOC ||
DataDirectory->VirtualAddress == 0 || DataDirectory->Size < sizeof(PECOFF_IMAGE_BASE_RELOCATION))
{
/* No need to relocate the image */
return STATUS_EFI_SUCCESS;
}
}
/* Set relocation pointers */
RelocationDir = (PPECOFF_IMAGE_BASE_RELOCATION)((ULONG_PTR)Image->Data + DataDirectory->VirtualAddress);
RelocationEnd = (PPECOFF_IMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + DataDirectory->Size);
/* Do relocations */
while(RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0)
{
/* Calculate number of relocations needed, address and type offset */
Count = (RelocationDir->SizeOfBlock - sizeof(PECOFF_IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
Address = (PUINT)((PUCHAR)Image->Data + RelocationDir->VirtualAddress);
TypeOffset = (PUSHORT)((PUCHAR)RelocationDir + sizeof(PECOFF_IMAGE_BASE_RELOCATION));
/* Do relocations */
while(Count--)
{
/* Calculate offset and relocation type */
Offset = *TypeOffset & 0xFFF;
Type = *TypeOffset >> 12;
/* Check if end of the loaded address reached */
if((PVOID)(PUSHORT)(Address + Offset) >= (PUCHAR)Image->Data + Image->ImageSize)
{
/* Do not relocate after the end of loaded image */
break;
}
/* Make sure we are not going to relocate into .reloc section */
if((ULONG_PTR)(Address + Offset) < (ULONG_PTR)RelocationDir ||
(ULONG_PTR)(Address + Offset) >= (ULONG_PTR)RelocationEnd)
{
/* Apply relocation fixup */
switch (Type)
{
case PECOFF_IMAGE_REL_BASED_ABSOLUTE:
/* No relocation required */
break;
case PECOFF_IMAGE_REL_BASED_DIR64:
/* 64-bit relocation */
LongPtr = (PULONGLONG)((PUCHAR)Address + Offset);
*LongPtr = *LongPtr - ImageBase + (UINT_PTR)Image->VirtualAddress;
break;
case PECOFF_IMAGE_REL_BASED_HIGHLOW:
/* 32-bit relocation of hight and low half of address */
ShortPtr = (PUINT)((PUCHAR)Address + Offset);
*ShortPtr = *ShortPtr - ImageBase + (UINT_PTR)Image->VirtualAddress;
break;
default:
/* Unknown or unsupported relocation type */
return STATUS_EFI_UNSUPPORTED;
}
}
/* Increment the type offset */
TypeOffset++;
}
/* Next relocation */
RelocationDir = (PPECOFF_IMAGE_BASE_RELOCATION)((PUCHAR)RelocationDir + RelocationDir->SizeOfBlock);
}
/* Return SUCCESS */
return STATUS_EFI_SUCCESS;
}
/**
* Unloads a PE/COFF image file and frees allocated memory.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::UnloadImage(IN PVOID ImagePointer)
{
PPECOFF_IMAGE_CONTEXT Image;
EFI_STATUS Status;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->Data)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Free memory allocated for the image */
Status = XtLdrProtocol->Memory.FreePages(Image->ImagePages, (EFI_PHYSICAL_ADDRESS)(UINT_PTR)Image->Data);
Status |= XtLdrProtocol->Memory.FreePool(Image);
/* Return status */
return Status;
}
/**
* Validates a PE/COFF image headers.
*
* @param ImagePointer
* Supplies a pointer to the PE/COFF context structure representing the loaded image.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
PeCoff::VerifyImage(IN PVOID ImagePointer)
{
PPECOFF_IMAGE_CONTEXT Image;
/* Get PE/COFF image pointer*/
Image = (PPECOFF_IMAGE_CONTEXT)ImagePointer;
/* Validate input data */
if(!Image || !Image->PeHeader)
{
/* Invalid parameter passed */
return STATUS_EFI_INVALID_PARAMETER;
}
/* Validate file size */
if(Image->FileSize < sizeof(PECOFF_IMAGE_DOS_HEADER))
{
/* PE/COFF image shorter than DOS header, return error*/
return STATUS_EFI_END_OF_FILE;
}
/* Validate DOS header */
if(Image->DosHeader->Magic != PECOFF_IMAGE_DOS_SIGNATURE)
{
/* Invalid DOS signature, return error */
return STATUS_EFI_INCOMPATIBLE_VERSION;
}
/* Validate PE header */
if(Image->PeHeader->Signature != PECOFF_IMAGE_NT_SIGNATURE &&
Image->PeHeader->Signature != PECOFF_IMAGE_XT_SIGNATURE)
{
/* Invalid PE signature, return error */
return STATUS_EFI_INCOMPATIBLE_VERSION;
}
/* Validate optional header */
if(Image->PeHeader->OptionalHeader32.Magic != PECOFF_IMAGE_PE_OPTIONAL_HDR32_MAGIC &&
Image->PeHeader->OptionalHeader64.Magic != PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
{
/* Invalid optional header signature, return error */
return STATUS_EFI_INCOMPATIBLE_VERSION;
}
/* 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 a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
XtLdrModuleMain(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
/* Initialize PECOFF module */
return PeCoff::InitializeModule(ImageHandle, SystemTable);
}

View File

@@ -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.cc
${XTLDR_XTOS_O_SOURCE_DIR}/data.cc
${XTLDR_XTOS_O_SOURCE_DIR}/xtos.cc)
# 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)

View File

@@ -0,0 +1,298 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/amd64/memory.cc
* DESCRIPTION: EFI memory management for AMD64 target
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
* Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
/**
* Determines the appropriate paging level (PML) for the AMD64 architecture.
*
* @param Parameters
* A pointer to the wide character string containing the kernel boot parameters.
*
* @return This routine returns the appropriate page map level (5 if LA57 is enabled, 4 otherwise).
*
* @since XT 1.0
*/
XTCDECL
ULONG
Xtos::DeterminePagingLevel(IN CONST PWCHAR Parameters)
{
CPUID_REGISTERS CpuRegisters;
/* Prepare CPUID registers to query for STD7 features */
XtLdrProtocol->Memory.ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
/* Query CPUID */
XtLdrProtocol->Cpu.CpuId(&CpuRegisters);
/* Verify if the CPU supports the STD7 feature leaf (0x00000007) */
if(CpuRegisters.Eax >= CPUID_GET_STANDARD7_FEATURES)
{
/* Prepare CPUID registers to query for LA57 support */
XtLdrProtocol->Memory.ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_STANDARD7_FEATURES;
/* Query CPUID */
XtLdrProtocol->Cpu.CpuId(&CpuRegisters);
/* Check if eXtended Physical Addressing (XPA) is enabled and if LA57 is supported by the CPU */
if((CpuRegisters.Ecx & CPUID_FEATURES_ECX_LA57) &&
!(XtLdrProtocol->BootUtils.GetBooleanParameter(Parameters, L"NOXPA")))
{
/* Enable LA57 (PML5) */
return 5;
}
}
/* Disable LA57 and use PML4 by default */
return 4;
}
/**
* Builds the actual memory mapping page table and enables paging. This routine exits EFI boot services as well.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::EnablePaging(IN PXTBL_PAGE_MAPPING PageMap)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS TrampolineAddress;
PXT_TRAMPOLINE_ENTRY TrampolineEntry;
ULONG_PTR TrampolineSize;
PVOID TrampolineCode;
/* Build page map */
Status = XtLdrProtocol->Memory.BuildPageMap(PageMap, (PageMap->PageMapLevel > 4) ? MM_P5E_LA57_BASE : MM_PXE_BASE);
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;
}
/* Map memory for hardware layer */
Status = MapHardwareMemoryPool(PageMap);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to map memory for hardware layer */
XtLdrProtocol->Debug.Print(L"Failed to map memory for hardware leyer (Status code: %zX)\n", Status);
return Status;
}
/* Check the configured page map level to set the LA57 state accordingly */
if(PageMap->PageMapLevel == 5)
{
/* Get the trampoline code information */
XtLdrProtocol->BootUtils.GetTrampolineInformation(TrampolineEnableXpa, &TrampolineCode, &TrampolineSize);
if(TrampolineCode == NULLPTR || TrampolineSize == 0)
{
/* Failed to get trampoline information */
XtLdrProtocol->Debug.Print(L"Failed to get trampoline information\n");
return STATUS_EFI_INVALID_PARAMETER;
}
/* Set the address of the trampoline code below 1MB */
TrampolineAddress = MM_TRAMPOLINE_ADDRESS;
/* Allocate pages for the trampoline */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAddress, EFI_SIZE_TO_PAGES(TrampolineSize), &TrampolineAddress);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to allocate memory for trampoline code */
XtLdrProtocol->Debug.Print(L"Failed to allocate memory for trampoline code (Status code: %zX)\n", Status);
return Status;
}
/* Set the trampoline entry point and copy its code into the allocated buffer */
TrampolineEntry = (PXT_TRAMPOLINE_ENTRY)(UINT_PTR)TrampolineAddress;
XtLdrProtocol->Memory.CopyMemory((PVOID)TrampolineEntry, TrampolineCode, TrampolineSize);
}
/* Exit EFI Boot Services */
XtLdrProtocol->Debug.Print(L"Exiting EFI boot services\n");
Status = XtLdrProtocol->Utils.ExitBootServices();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to exit boot services */
XtLdrProtocol->Debug.Print(L"Failed to exit boot services (Status code: %zX)\n", Status);
return STATUS_EFI_ABORTED;
}
/* Check the configured page map level to set the LA57 state accordingly */
if(PageMap->PageMapLevel == 5)
{
/* Enable Linear Address 57-bit (LA57) extension */
XtLdrProtocol->Debug.Print(L"Enabling Linear Address 57-bit (LA57)\n");
/* Execute the trampoline to enable LA57 and write PML5 to CR3 */
TrampolineEntry((UINT64)PageMap->PtePointer);
}
else
{
/* Disable Linear Address 57-bit (LA57) extension */
XtLdrProtocol->Debug.Print(L"Disabling Linear Address 57-bit (LA57)\n");
/* Write PML4 to CR3 and enable paging */
XtLdrProtocol->Cpu.WriteControlRegister(3, (UINT_PTR)PageMap->PtePointer);
XtLdrProtocol->Cpu.WriteControlRegister(0, XtLdrProtocol->Cpu.ReadControlRegister(0) | CR0_PG);
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Maps the page table for hardware layer addess space.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap)
{
PHARDWARE_PTE P5eBase, PdeBase, PpeBase, PxeBase;
EFI_PHYSICAL_ADDRESS Address;
EFI_STATUS Status;
if(PageMap->PageMapLevel == 5)
{
/* Get P5E (PML5) base address */
P5eBase = (PHARDWARE_PTE)PageMap->PtePointer;
/* Check if P5E entry already exists */
if(!P5eBase[(MM_HARDWARE_VA_START >> MM_P5I_SHIFT) & 0x1FF].Valid)
{
/* No valid P5E, allocate memory */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure, return error */
return Status;
}
/* Zero fill memory used by P5E */
XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE);
/* Make P5E valid */
P5eBase[(MM_HARDWARE_VA_START >> MM_P5I_SHIFT) & 0x1FF].Valid = 1;
P5eBase[(MM_HARDWARE_VA_START >> MM_P5I_SHIFT) & 0x1FF].PageFrameNumber = Address / EFI_PAGE_SIZE;
P5eBase[(MM_HARDWARE_VA_START >> MM_P5I_SHIFT) & 0x1FF].Writable = 1;
/* Set PXE base address */
PxeBase = (PHARDWARE_PTE)(UINT_PTR)Address;
}
else
{
/* Set PXE base address based on existing P5E */
PxeBase = (PHARDWARE_PTE)((P5eBase[(MM_HARDWARE_VA_START >> MM_P5I_SHIFT) & 0x1FF].PageFrameNumber) << EFI_PAGE_SHIFT);
}
}
else
{
/* Get PXE (PML4) base address */
PxeBase = (PHARDWARE_PTE)PageMap->PtePointer;
}
/* Check if PXE entry already exists */
if(!PxeBase[(MM_HARDWARE_VA_START >> MM_PXI_SHIFT) & 0x1FF].Valid)
{
/* No valid PXE, allocate memory */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure, return error */
return Status;
}
/* Zero fill memory used by PXE */
XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE);
/* Make PXE valid */
PxeBase[(MM_HARDWARE_VA_START >> MM_PXI_SHIFT) & 0x1FF].Valid = 1;
PxeBase[(MM_HARDWARE_VA_START >> MM_PXI_SHIFT) & 0x1FF].PageFrameNumber = Address / EFI_PAGE_SIZE;
PxeBase[(MM_HARDWARE_VA_START >> MM_PXI_SHIFT) & 0x1FF].Writable = 1;
/* Set PPE base address */
PpeBase = (PHARDWARE_PTE)(UINT_PTR)Address;
}
else
{
/* Set PPE base address based on existing PXE */
PpeBase = (PHARDWARE_PTE)((PxeBase[(MM_HARDWARE_VA_START >> MM_PXI_SHIFT) & 0x1FF].PageFrameNumber) << EFI_PAGE_SHIFT);
}
/* Check if PPE entry already exists */
if(!PpeBase[(MM_HARDWARE_VA_START >> MM_PPI_SHIFT) & 0x1FF].Valid)
{
/* No valid PPE, allocate memory */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure, return error */
return Status;
}
/* Zero fill memory used by PPE */
XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE);
/* Make PPE valid */
PpeBase[(MM_HARDWARE_VA_START >> MM_PPI_SHIFT) & 0x1FF].Valid = 1;
PpeBase[(MM_HARDWARE_VA_START >> MM_PPI_SHIFT) & 0x1FF].PageFrameNumber = Address / EFI_PAGE_SIZE;
PpeBase[(MM_HARDWARE_VA_START >> MM_PPI_SHIFT) & 0x1FF].Writable = 1;
/* Set PDE base address */
PdeBase = (PHARDWARE_PTE)Address;
}
else
{
/* Set PDE base address, based on existing PPE */
PdeBase = (PHARDWARE_PTE)((PpeBase[(MM_HARDWARE_VA_START >> MM_PPI_SHIFT) & 0x1FF].PageFrameNumber) << EFI_PAGE_SHIFT);
}
/* Loop through 2 PDE entries */
for(UINT Index = 0 ; Index < 2 ; Index++)
{
/* Check if PDE entry already exists */
if(!PdeBase[((MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF) + Index].Valid)
{
/* No valid PDE, allocate memory */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure, return error */
return Status;
}
/* Zero fill memory used by PDE */
XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE);
/* Make PDE valid */
PdeBase[((MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF) + Index].Valid = 1;
PdeBase[((MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF) + Index].PageFrameNumber = Address / EFI_PAGE_SIZE;
PdeBase[((MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF) + Index].Writable = 1;
}
}
/* Return success */
return STATUS_EFI_SUCCESS;
}

View File

@@ -0,0 +1,19 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/xtos/data.cc
* DESCRIPTION: XTOS module global and static data
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtos.hh>
/* XTOS Boot Protocol */
XTBL_BOOT_PROTOCOL Xtos::BootProtocol;
/* XTOS PE/COFF Image Protocol */
PXTBL_EXECUTABLE_IMAGE_PROTOCOL Xtos::PeCoffProtocol;
/* EFI XT Loader Protocol */
PXTBL_LOADER_PROTOCOL Xtos::XtLdrProtocol;

View File

@@ -0,0 +1,181 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/i686/memory.cc
* DESCRIPTION: EFI memory management for i686 target
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtos.hh>
/**
* Determines the appropriate paging level (PML) for the i686 architecture.
*
* @param Parameters
* A pointer to the wide character string containing the kernel boot parameters.
*
* @return This routine returns the appropriate page map level (3 if PAE is enabled, 2 otherwise).
*
* @since XT 1.0
*/
XTCDECL
ULONG
Xtos::DeterminePagingLevel(IN CONST PWCHAR Parameters)
{
CPUID_REGISTERS CpuRegisters;
/* Prepare CPUID registers to query for PAE support */
XtLdrProtocol->Memory.ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
/* Query CPUID */
XtLdrProtocol->Cpu.CpuId(&CpuRegisters);
/* Check if eXtended Physical Addressing (XPA) is enabled and if PAE is supported by the CPU */
if((CpuRegisters.Edx & CPUID_FEATURES_EDX_PAE) &&
!(XtLdrProtocol->BootUtils.GetBooleanParameter(Parameters, L"NOXPA")))
{
/* Enable PAE (PML3) */
return 3;
}
/* Disable PAE and use PML2 by default */
return 2;
}
/**
* Builds the actual memory mapping page table and enables paging. This routine exits EFI boot services as well.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::EnablePaging(IN PXTBL_PAGE_MAPPING PageMap)
{
EFI_STATUS Status;
/* Build page map */
Status = XtLdrProtocol->Memory.BuildPageMap(PageMap, MM_PTE_BASE);
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;
}
/* Map memory for hardware layer */
Status = MapHardwareMemoryPool(PageMap);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to map memory for hardware layer */
XtLdrProtocol->Debug.Print(L"Failed to map memory for hardware layer (Status code: %zX)\n", Status);
return Status;
}
/* Exit EFI Boot Services */
XtLdrProtocol->Debug.Print(L"Exiting EFI boot services\n");
Status = XtLdrProtocol->Utils.ExitBootServices();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to exit boot services */
XtLdrProtocol->Debug.Print(L"Failed to exit boot services (Status code: %zX)\n", Status);
return STATUS_EFI_ABORTED;
}
/* Disable paging */
XtLdrProtocol->Cpu.WriteControlRegister(0, XtLdrProtocol->Cpu.ReadControlRegister(0) & ~CR0_PG);
/* Check the configured page map level to set the PAE state accordingly */
if(PageMap->PageMapLevel == 3)
{
/* Enable Physical Address Extension (PAE) */
XtLdrProtocol->Debug.Print(L"Enabling Physical Address Extension (PAE)\n");
XtLdrProtocol->Cpu.WriteControlRegister(4, XtLdrProtocol->Cpu.ReadControlRegister(4) | CR4_PAE);
}
else
{
/* Disable Physical Address Extension (PAE) */
XtLdrProtocol->Debug.Print(L"Disabling Physical Address Extension (PAE)\n");
XtLdrProtocol->Cpu.WriteControlRegister(4, XtLdrProtocol->Cpu.ReadControlRegister(4) & ~CR4_PAE);
}
/* Write page mappings to CR3 */
XtLdrProtocol->Cpu.WriteControlRegister(3, (UINT_PTR)PageMap->PtePointer);
/* Enable paging */
XtLdrProtocol->Cpu.WriteControlRegister(0, XtLdrProtocol->Cpu.ReadControlRegister(0) | CR0_PG);
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Maps the page table for hardware layer addess space.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap)
{
EFI_PHYSICAL_ADDRESS Address;
PHARDWARE_LEGACY_PTE LegacyPdeBase;
PHARDWARE_MODERN_PTE PdeBase;
EFI_STATUS Status;
/* Allocate memory */
Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, 1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure, return error */
return Status;
}
/* Zero fill allocated memory */
XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE);
/* Check if PAE is enabled (3-level paging) */
if(PageMap->PageMapLevel == 3)
{
/* Get PDE base address (PAE enabled) */
PdeBase = (PHARDWARE_MODERN_PTE)(((PHARDWARE_MODERN_PTE)PageMap->PtePointer)[MM_HARDWARE_VA_START >> MM_PPI_SHIFT].PageFrameNumber << MM_PAGE_SHIFT);
/* Make PDE valid */
XtLdrProtocol->Memory.ZeroMemory(&PdeBase[(MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF], sizeof(HARDWARE_MODERN_PTE));
PdeBase[(MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF].PageFrameNumber = Address >> MM_PAGE_SHIFT;
PdeBase[(MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF].Valid = 1;
PdeBase[(MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF].Writable = 1;
}
else
{
/* Get PDE base address (PAE disabled) */
LegacyPdeBase = (PHARDWARE_LEGACY_PTE)PageMap->PtePointer;
/* Check for a conflicting PDE */
if(LegacyPdeBase[MM_HARDWARE_VA_START >> MM_PDI_LEGACY_SHIFT].Valid)
{
/* PDE already exists and is valid, nothing to do */
return STATUS_EFI_SUCCESS;
}
/* Make PDE valid */
XtLdrProtocol->Memory.ZeroMemory(&LegacyPdeBase[MM_HARDWARE_VA_START >> MM_PDI_LEGACY_SHIFT], sizeof(HARDWARE_LEGACY_PTE));
LegacyPdeBase[MM_HARDWARE_VA_START >> MM_PDI_LEGACY_SHIFT].Valid = 1;
LegacyPdeBase[MM_HARDWARE_VA_START >> MM_PDI_LEGACY_SHIFT].PageFrameNumber = Address >> MM_PAGE_SHIFT;
LegacyPdeBase[MM_HARDWARE_VA_START >> MM_PDI_LEGACY_SHIFT].Writable = 1;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}

View File

@@ -0,0 +1,78 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/modules/xtos/includes/xtos.hh
* DESCRIPTION: XTOS boot protocol support header
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#ifndef __XTLDR_MODULES_XTOS_HH
#define __XTLDR_MODULES_XTOS_HH
#include <xtblapi.h>
/* XTOS kernel entry point */
typedef VOID (XTAPI *PXT_ENTRY_POINT)(IN PKERNEL_INITIALIZATION_BLOCK BootParameters);
/* XTOS trampoline entry point */
typedef VOID (*PXT_TRAMPOLINE_ENTRY)(UINT64 PageMap);
/* XTOS module for XTLDR */
class Xtos
{
private:
STATIC XTBL_BOOT_PROTOCOL BootProtocol;
STATIC PXTBL_EXECUTABLE_IMAGE_PROTOCOL PeCoffProtocol;
STATIC PXTBL_LOADER_PROTOCOL XtLdrProtocol;
public:
STATIC XTCDECL EFI_STATUS BootSystem(IN PXTBL_BOOT_PARAMETERS Parameters);
STATIC XTCDECL EFI_STATUS InitializeModule(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable);
private:
STATIC XTCDECL EFI_STATUS AddVirtualMemoryMapping(IN PLIST_ENTRY MemoryMappings,
IN PVOID VirtualAddress,
IN PVOID PhysicalAddress,
IN UINT NumberOfPages,
IN LOADER_MEMORY_TYPE MemoryType);
STATIC XTCDECL LOADER_MEMORY_TYPE ConvertEfiMemoryType(IN EFI_MEMORY_TYPE EfiMemoryType);
STATIC XTCDECL ULONG DeterminePagingLevel(IN CONST PWCHAR Parameters);
STATIC XTCDECL EFI_STATUS EnablePaging(IN PXTBL_PAGE_MAPPING PageMap);
STATIC XTCDECL VOID GetDisplayInformation(OUT PSYSTEM_RESOURCE_FRAMEBUFFER FrameBufferResource,
IN PEFI_PHYSICAL_ADDRESS FrameBufferBase,
IN PULONG_PTR FrameBufferSize,
IN PXTBL_FRAMEBUFFER_MODE_INFORMATION FrameBufferModeInfo);
STATIC XTCDECL EFI_STATUS GetMemoryDescriptorList(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID *VirtualAddress,
OUT PLIST_ENTRY MemoryDescriptorList);
STATIC XTCDECL EFI_STATUS GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID *VirtualAddress,
OUT PLIST_ENTRY SystemResourcesList);
STATIC XTCDECL EFI_STATUS GetVirtualAddress(IN PLIST_ENTRY MemoryMappings,
IN PVOID PhysicalAddress,
OUT PVOID *VirtualAddress);
STATIC XTCDECL EFI_STATUS InitializeApicBase(IN PXTBL_PAGE_MAPPING PageMap);
STATIC XTCDECL EFI_STATUS InitializeLoaderBlock(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID *VirtualAddress,
IN PXTBL_BOOT_PARAMETERS Parameters);
STATIC XTCDECL EFI_STATUS InitializeVirtualMemory(IN OUT PLIST_ENTRY MemoryMappings,
IN OUT PVOID *MemoryMapAddress);
STATIC XTCDECL EFI_STATUS LoadModule(IN PEFI_FILE_HANDLE BootDir,
IN PWCHAR FileName,
IN PVOID VirtualAddress,
IN LOADER_MEMORY_TYPE MemoryType,
OUT PPECOFF_IMAGE_CONTEXT *ImageContext);
STATIC XTCDECL EFI_STATUS MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap);
STATIC XTCDECL EFI_STATUS MapVirtualMemory(IN PLIST_ENTRY MemoryMappings,
IN UINT_PTR VirtualAddress,
IN UINT_PTR PhysicalAddress,
IN UINT NumberOfPages,
IN OUT PVOID *PtePointer);
STATIC XTCDECL EFI_STATUS RunBootSequence(IN PEFI_FILE_HANDLE BootDir,
IN PXTBL_BOOT_PARAMETERS Parameters);
};
#endif /* __XTLDR_MODULES_XTOS_HH */

View File

@@ -0,0 +1,729 @@
/**
* 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,
IN PVOID *VirtualAddress,
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 = XtLdrProtocol->Memory.MapVirtualMemory(PageMap, *VirtualAddress, (PVOID)Address, Pages, LoaderMemoryData);
if(Status != STATUS_EFI_SUCCESS)
{
XtLdrProtocol->Memory.FreePages(Address, Pages);
return Status;
}
PVOID PhysicalBase = (PVOID)Address;
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)Address;
MemoryDescriptor->MemoryType = MemoryMapping->MemoryType;
MemoryDescriptor->BasePage = (UINT_PTR)MemoryMapping->PhysicalAddress / EFI_PAGE_SIZE;
MemoryDescriptor->PageCount = MemoryMapping->NumberOfPages;
XtLdrProtocol->LinkedList.InsertTail(MemoryDescriptorList, &MemoryDescriptor->ListEntry);
Address = Address + sizeof(LOADER_MEMORY_DESCRIPTOR);
ListEntry = ListEntry->Flink;
}
XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, MemoryDescriptorList, PhysicalBase, *VirtualAddress);
return STATUS_EFI_SUCCESS;
}
XTCDECL
EFI_STATUS
Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID *VirtualAddress,
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;
PVOID PhysicalBase, VirtualBase;
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 = XtLdrProtocol->Memory.MapVirtualMemory(PageMap, *VirtualAddress, (PVOID)Address, Pages, LoaderFirmwarePermanent);
if(Status != STATUS_EFI_SUCCESS)
{
XtLdrProtocol->Memory.FreePages(Address, Pages);
return Status;
}
PhysicalBase = (PVOID)Address;
VirtualBase = *VirtualAddress;
/* Calculate next valid virtual address */
*VirtualAddress = (PUINT8)*VirtualAddress + (Pages * EFI_PAGE_SIZE);
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(&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 = *VirtualAddress;
/* Map frame buffer memory */
XtLdrProtocol->Memory.MapVirtualMemory(PageMap, FrameBufferResource->Header.VirtualAddress,
FrameBufferResource->Header.PhysicalAddress,
FrameBufferPages, LoaderFirmwarePermanent);
/* Close FrameBuffer protocol */
XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid);
*VirtualAddress = (PUINT8)*VirtualAddress + (FrameBufferPages * EFI_PAGE_SIZE);
XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &FrameBufferResource->Header.ListEntry);
XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, SystemResourcesList, PhysicalBase, VirtualBase);
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, (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
Xtos::InitializeLoaderBlock(IN PXTBL_PAGE_MAPPING PageMap,
IN PVOID *VirtualAddress,
IN PXTBL_BOOT_PARAMETERS Parameters)
{
PKERNEL_INITIALIZATION_BLOCK LoaderBlock;
EFI_PHYSICAL_ADDRESS Address;
EFI_STATUS Status;
UINT BlockPages;
UINT ParametersSize;
/* 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;
/* Copy parameters to kernel initialization block */
LoaderBlock->KernelParameters = (PWCHAR)((UINT_PTR)*VirtualAddress + sizeof(KERNEL_INITIALIZATION_BLOCK));
XtLdrProtocol->Memory.CopyMemory((PVOID)((UINT_PTR)LoaderBlock + sizeof(KERNEL_INITIALIZATION_BLOCK)),
Parameters->Parameters,
ParametersSize);
/* Map kernel initialization block */
XtLdrProtocol->Memory.MapVirtualMemory(PageMap, *VirtualAddress, (PVOID)LoaderBlock,
BlockPages, LoaderSystemBlock);
/* Calculate next valid virtual address */
*VirtualAddress = (PUINT8)*VirtualAddress + (BlockPages * EFI_PAGE_SIZE);
XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->SystemResourcesListHead);
GetSystemResourcesList(PageMap, VirtualAddress, &LoaderBlock->SystemResourcesListHead);
/* Initialize memory descriptor list */
XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->MemoryDescriptorListHead);
GetMemoryDescriptorList(PageMap, VirtualAddress, &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 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, VirtualMemoryArea;
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);
/* Set base virtual memory area for the kernel mappings */
VirtualMemoryArea = (PVOID)KSEG0_BASE;
VirtualAddress = (PVOID)(KSEG0_BASE + KSEG0_KERNEL_BASE);
/* Initialize virtual memory mappings */
XtLdrProtocol->Memory.InitializePageMap(&PageMap, DeterminePagingLevel(Parameters->Parameters), Size4K);
Status = XtLdrProtocol->Memory.MapEfiMemory(&PageMap, &VirtualMemoryArea, NULLPTR);
if(Status != STATUS_EFI_SUCCESS)
{
return Status;
}
/* 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, ImageContext->VirtualAddress,
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;
}
/* 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;
}
/* 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);
}

1112
boot/xtldr/protocol.cc Normal file

File diff suppressed because it is too large Load Diff

50
boot/xtldr/shell.cc Normal file
View File

@@ -0,0 +1,50 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/shell.cc
* DESCRIPTION: XT Boot Loader shell
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* Starts XTLDR shell.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Shell::StartLoaderShell()
{
/* Initialize console */
Console::InitializeConsole();
/* Print prompt */
PrintPrompt();
for(;;);
}
/**
* Prints XTLDR shell prompt.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
Shell::PrintPrompt()
{
/* Set prompt color */
Console::SetAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_YELLOW);
/* Print prompt */
Console::Print(L"XTLDR> ");
/* Reset standard shell colors */
Console::SetAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
}

1815
boot/xtldr/textui.cc Normal file

File diff suppressed because it is too large Load Diff

1163
boot/xtldr/volume.cc Normal file

File diff suppressed because it is too large Load Diff

328
boot/xtldr/xtldr.cc Normal file
View File

@@ -0,0 +1,328 @@
/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/xtldr.cc
* DESCRIPTION: XTOS UEFI Boot Loader
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.hh>
/**
* Disables access to EFI Boot Services.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
XtLoader::DisableBootServices()
{
LoaderStatus.BootServices = FALSE;
}
/**
* Queries the availability of EFI Boot Services.
*
* @return This routine returns TRUE if EFI Boot Services are available, FALSE otherwise.
*
* @since XT 1.0
*/
XTCDECL
BOOLEAN
XtLoader::GetBootServicesStatus()
{
return LoaderStatus.BootServices;
}
/**
* Retrieves the EFI image handle.
*
* @return This routine returns a handle to the EFI-loaded image.
*
* @since XT 1.0
*/
XTCDECL
EFI_HANDLE
XtLoader::GetEfiImageHandle()
{
return XtLoader::EfiImageHandle;
}
/**
* Retrieves the EFI system table pointer.
*
* @return This routine returns a pointer to the EFI system table.
*
* @since XT 1.0
*/
XTCDECL
PEFI_SYSTEM_TABLE
XtLoader::GetEfiSystemTable()
{
return XtLoader::EfiSystemTable;
}
/**
* Provides base address and size of the XTLDR image.
*
* @param LoaderBase
* Supplies a pointer to a variable that receives the base address of the XTLDR image.
*
* @param LoaderSize
* Supplies a pointer to a variable that receives the size of the XTLDR image.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
XtLoader::GetLoaderImageInformation(PVOID *LoaderBase,
PULONGLONG LoaderSize)
{
*LoaderBase = XtLoader::LoaderStatus.LoaderBase;
*LoaderSize = XtLoader::LoaderStatus.LoaderSize;
}
/**
* Retrieves the Secure Boot status.
*
* @return This routine returns SecureBoot status.
*
* @since XT 1.0
*/
XTCDECL
INT_PTR
XtLoader::GetSecureBootStatus()
{
return LoaderStatus.SecureBoot;
}
/**
* Initializes EFI Boot Loader (XTLDR).
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
XtLoader::InitializeBootLoader(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_GUID LipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
PEFI_LOADED_IMAGE_PROTOCOL LoadedImage;
EFI_HANDLE Handle;
EFI_STATUS Status;
/* Set the system table and image handle */
EfiImageHandle = ImageHandle;
EfiSystemTable = SystemTable;
/* Set current XTLDR's EFI BootServices status */
LoaderStatus.BootServices = TRUE;
/* Initialize console */
Console::InitializeConsole();
/* Print XTLDR version */
Console::Print(L"XTLDR boot loader v%s\n", XTOS_VERSION);
/* Initialize XTLDR protocol */
Protocol::InitializeProtocol();
/* Initialize XTLDR configuration */
Configuration::InitializeConfiguration();
/* Store SecureBoot status */
LoaderStatus.SecureBoot = EfiUtils::GetSecureBootStatus();
/* Attempt to open EFI LoadedImage protocol */
Status = Protocol::OpenProtocol(&Handle, (PVOID *)&LoadedImage, &LipGuid);
if(Status == STATUS_EFI_SUCCESS)
{
/* Store boot loader image base and size */
LoaderStatus.LoaderBase = LoadedImage->ImageBase;
LoaderStatus.LoaderSize = LoadedImage->ImageSize;
/* Check if debug is enabled */
if(DEBUG)
{
/* Protocol opened successfully, print useful debug information */
Console::Print(L"\n---------- BOOTLOADER DEBUG ----------\n"
L"Pointer Size : %d\n"
L"Image Base Address : %P\n"
L"Image Base Size : 0x%lX\n"
L"Image Revision : 0x%lX\n"
L"Secure Boot Status : %zd\n"
L"--------------------------------------\n",
sizeof(PVOID),
LoadedImage->ImageBase,
LoadedImage->ImageSize,
LoadedImage->Revision,
LoaderStatus.SecureBoot);
EfiUtils::SleepExecution(3000);
}
/* Close EFI LoadedImage protocol */
Protocol::CloseProtocol(&Handle, &LipGuid);
}
}
/**
* Registers a boot menu callback routine, that will be used to display alternative boot menu.
*
* @param BootMenuRoutine
* Supplies a pointer to the boot menu callback routine.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
XtLoader::RegisterBootMenu(IN PVOID BootMenuRoutine)
{
/* Set boot menu routine */
BootMenu = (PBL_XT_BOOT_MENU)BootMenuRoutine;
}
/**
* Invokes either a custom boot menu handler, if one has been registered, or displays the default boot menu.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
XtLoader::ShowBootMenu()
{
/* Check if custom boot menu registered */
if(BootMenu != NULLPTR)
{
/* Display alternative boot menu */
BootMenu();
}
else
{
/* Display default boot menu */
TextUi::DisplayBootMenu();
}
}
/**
* This routine is the entry point of the XT EFI boot loader.
*
* @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
BlStartXtLoader(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
PWCHAR Modules;
EFI_STATUS Status;
/* Initialize XTLDR and */
XtLoader::InitializeBootLoader(ImageHandle, SystemTable);
/* Parse configuration options passed from UEFI shell */
Status = Configuration::ParseCommandLine();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to parse command line options */
TextUi::DisplayErrorDialog(L"XTLDR", L"Failed to parse command line parameters.");
}
/* Attempt to early initialize debug console */
if(DEBUG)
{
Status = Debug::InitializeDebugConsole();
if(Status != STATUS_EFI_SUCCESS)
{
/* Initialization failed, notify user on stdout */
TextUi::DisplayErrorDialog(L"XTLDR", L"Failed to initialize debug console.");
}
}
/* Load XTLDR configuration file */
Status = Configuration::LoadConfiguration();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load/parse config file */
TextUi::DisplayErrorDialog(L"XTLDR", L"Failed to load and parse configuration file ");
}
/* Reinitialize debug console if it was not initialized earlier */
if(DEBUG)
{
Status = Debug::InitializeDebugConsole();
if(Status != STATUS_EFI_SUCCESS)
{
/* Initialization failed, notify user on stdout */
TextUi::DisplayErrorDialog(L"XTLDR", L"Failed to initialize debug console.");
}
}
/* Disable watchdog timer */
Status = XtLoader::GetEfiSystemTable()->BootServices->SetWatchdogTimer(0, 0x10000, 0, NULLPTR);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to disable the timer, print message */
Debug::Print(L"WARNING: Failed to disable watchdog timer (Status Code: 0x%zX)\n", Status);
}
/* Install loader protocol */
Status = Protocol::InstallXtLoaderProtocol();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to register loader protocol */
Debug::Print(L"ERROR: Failed to register XTLDR loader protocol (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Load all necessary modules */
Configuration::GetValue(L"MODULES", &Modules);
Status = Protocol::LoadModules(Modules);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load modules */
Debug::Print(L"ERROR: Failed to load XTLDR modules (Status Code: 0x%zX)\n", Status);
TextUi::DisplayErrorDialog(L"XTLDR", L"Failed to load some XTLDR modules.");
}
/* Discover and enumerate EFI block devices */
Status = Volume::EnumerateBlockDevices();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to enumerate block devices */
Debug::Print(L"ERROR: Failed to discover and enumerate block devices (Status Code: 0x%zX)\n", Status);
return Status;
}
/* Main boot loader loop */
while(TRUE)
{
/* Show boot menu */
XtLoader::ShowBootMenu();
/* Fallback to shell, if boot menu returned */
Shell::StartLoaderShell();
}
/* This point should be never reached, if this happen return error code */
return STATUS_EFI_LOAD_ERROR;
}