Move XTLDR under boot directory

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

@@ -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);
}