exectos/xtldr2/xtldr.c
Rafal Kupiec fc3d236405
All checks were successful
Builds / ExectOS (amd64) (push) Successful in 30s
Builds / ExectOS (i686) (push) Successful in 29s
Load boot loader modules
2023-12-31 00:30:18 +01:00

373 lines
12 KiB
C

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/xtldr.c
* DESCRIPTION: XTOS UEFI Boot Loader
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.h>
/**
* Initializes a list of operating systems for XTLDR boot menu.
*
* @param MenuEntries
* Supplies a pointer to memory area where operating systems list will be stored.
*
* @param EntriesCount
* Supplies a pointer to memory area where number of menu entries will be stored.
*
* @param DefaultId
* Supplies a pointer to memory area where ID of default menu entry will be stored.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTCDECL
VOID
BlInitializeBootMenuList(OUT PXTBL_BOOTMENU_ITEM MenuEntries,
OUT PULONG EntriesCount,
OUT PULONG DefaultId)
{
PWCHAR DefaultMenuEntry, MenuEntryName;
PLIST_ENTRY MenuEntrySectionList, MenuEntryList;
PXTBL_CONFIG_SECTION MenuEntrySection;
PXTBL_CONFIG_ENTRY MenuEntryOption;
PXTBL_BOOTMENU_ITEM OsList;
ULONG DefaultOS, NumberOfEntries;
/* Set default values */
DefaultOS = 0;
NumberOfEntries = 0;
OsList = NULL;
/* Get default menu entry from configuration */
DefaultMenuEntry = BlGetConfigValue(L"DEFAULT");
/* Iterate through all menu sections */
MenuEntrySectionList = BlpMenuList->Flink;
while(MenuEntrySectionList != BlpMenuList)
{
/* NULLify menu entry name */
MenuEntryName = NULL;
/* Get menu section */
MenuEntrySection = CONTAIN_RECORD(MenuEntrySectionList, XTBL_CONFIG_SECTION, Flink);
/* Check if this is the default menu entry */
if(RtlCompareWideStringInsensitive(MenuEntrySection->SectionName, DefaultMenuEntry, 0) == 0)
{
/* Set default OS ID */
DefaultOS = NumberOfEntries;
}
/* Iterate through all entry parameters */
MenuEntryList = MenuEntrySection->Options.Flink;
while(MenuEntryList != &MenuEntrySection->Options)
{
/* Get menu entry parameter */
MenuEntryOption = CONTAIN_RECORD(MenuEntryList, XTBL_CONFIG_ENTRY, Flink);
/* Check if this is the menu entry display name */
if(RtlCompareWideStringInsensitive(MenuEntryOption->Name, L"SYSTEMNAME", 0) == 0)
{
/* Set menu entry display name */
MenuEntryName = MenuEntryOption->Value;
}
/* Get next parameter for this menu entry */
MenuEntryList = MenuEntryList->Flink;
}
/* Add OS to the boot menu list */
OsList[NumberOfEntries].EntryName = MenuEntryName;
OsList[NumberOfEntries].Options = &MenuEntrySection->Options;
/* Get next menu entry */
MenuEntrySectionList = MenuEntrySectionList->Flink;
NumberOfEntries++;
}
/* Set return values */
*DefaultId = DefaultOS;
*EntriesCount = NumberOfEntries;
MenuEntries = OsList;
}
/**
* Loads all necessary modules and invokes boot protocol.
*
* @param OptionsList
* Supplies a pointer to list of options associated with chosen boot menu entry.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlInvokeBootProtocol(IN PLIST_ENTRY OptionsList)
{
XTBL_BOOT_PARAMETERS BootParameters;
PXTBL_BOOT_PROTOCOL BootProtocol;
PLIST_ENTRY OptionsListEntry;
PXTBL_CONFIG_ENTRY Option;
EFI_GUID BootProtocolGuid;
SIZE_T ModuleListLength;
PWCHAR ModulesList;
EFI_STATUS Status;
/* Initialize boot parameters */
RtlZeroMemory(&BootParameters, sizeof(XTBL_BOOT_PARAMETERS));
/* Iterate through all options provided by boot menu entry and propagate boot parameters */
OptionsListEntry = OptionsList->Flink;
while(OptionsListEntry != OptionsList)
{
/* Get option */
Option = CONTAIN_RECORD(OptionsListEntry, XTBL_CONFIG_ENTRY, Flink);
/* Look for boot protocol and modules list */
if(RtlCompareWideStringInsensitive(Option->Name, L"BOOTMODULES", 0) == 0)
{
/* Check a length of modules list */
ModuleListLength = RtlWideStringLength(Option->Value, 0);
Status = BlMemoryAllocatePool(sizeof(PWCHAR) * ModuleListLength, (PVOID *)&ModulesList);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to allocate memory, print error message and return status code */
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%lx)\n");
return STATUS_EFI_OUT_OF_RESOURCES;
}
/* Make a copy of modules list */
RtlCopyMemory(ModulesList, Option->Value, sizeof(PWCHAR) * ModuleListLength);
}
else if(RtlCompareWideStringInsensitive(Option->Name, L"SYSTEMTYPE", 0) == 0)
{
/* Boot protocol found */
BootParameters.SystemType = Option->Value;
}
else if(RtlCompareWideStringInsensitive(Option->Name, L"SYSTEMPATH", 0) == 0)
{
/* System path found, get volume device path */
Status = BlGetVolumeDevicePath((PWCHAR)Option->Value, &BootParameters.DevicePath, &BootParameters.ArcName, &BootParameters.SystemPath);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to find volume */
BlDebugPrint(L"ERROR: Failed to find volume device path (Status Code: 0x%lx)\n", Status);
return Status;
}
}
else if(RtlCompareWideStringInsensitive(Option->Name, L"KERNELFILE", 0) == 0)
{
/* Kernel file name found */
BootParameters.KernelFile = Option->Value;
}
else if(RtlCompareWideStringInsensitive(Option->Name, L"INITRDFILE", 0) == 0)
{
/* Initrd file name found */
BootParameters.InitrdFile = Option->Value;
}
else if(RtlCompareWideStringInsensitive(Option->Name, L"HALFILE", 0) == 0)
{
/* Hal file name found */
BootParameters.HalFile = Option->Value;
}
else if(RtlCompareWideStringInsensitive(Option->Name, L"PARAMETERS", 0) == 0)
{
/* Kernel parameters found */
BootParameters.Parameters = Option->Value;
}
/* Move to the next option entry */
OptionsListEntry = OptionsListEntry->Flink;
}
/* Load all necessary modules */
Status = BlLoadModules(ModulesList);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load modules, print error message and return status code */
BlDebugPrint(L"ERROR: Failed to load XTLDR modules\n");
return STATUS_EFI_NOT_READY;
}
/* Attempt to get boot protocol GUID */
Status = BlFindBootProtocol(BootParameters.SystemType, &BootProtocolGuid);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to get boot protocol GUID */
BlDebugPrint(L"ERROR: Unable to find appropriate boot protocol (Status Code: 0x%lx)\n", Status);
return STATUS_EFI_UNSUPPORTED;
}
/* Open boot protocol */
Status = BlOpenXtProtocol((PVOID *)&BootProtocol, &BootProtocolGuid);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to open boot protocol */
BlDebugPrint(L"ERROR: Failed to open boot protocol (Status Code: 0x%lx)\n", Status);
return Status;
}
/* Boot Operating System */
return BootProtocol->BootSystem(&BootParameters);
}
/**
* This routine is the entry point of the XT EFI boot loader.
*
* @param ImageHandle
* Firmware-allocated handle that identifies the image.
*
* @param SystemTable
* Provides the EFI system table.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlStartXtLoader(IN EFI_HANDLE ImageHandle,
IN PEFI_SYSTEM_TABLE SystemTable)
{
EFI_STATUS Status;
/* Set the system table and image handle */
EfiImageHandle = ImageHandle;
EfiSystemTable = SystemTable;
/* Initialize XTLDR and */
BlpInitializeEfiBootLoader();
/* Parse configuration options passed from UEFI shell */
Status = BlpParseCommandLine();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to parse command line options */
BlDisplayErrorDialog(L"XTLDR", L"Failed to parse command line parameters.");
}
/* Attempt to early initialize debug console */
if(DEBUG)
{
Status = BlpInitializeDebugConsole();
if(Status != STATUS_EFI_SUCCESS)
{
/* Initialization failed, notify user on stdout */
BlDisplayErrorDialog(L"XTLDR", L"Failed to initialize debug console.");
}
}
/* Load XTLDR configuration file */
Status = BlpLoadConfiguration();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load/parse config file */
BlDisplayErrorDialog(L"XTLDR", L"Failed to load and parse configuration file.");
}
/* Reinitialize debug console if it was not initialized earlier */
if(DEBUG)
{
Status = BlpInitializeDebugConsole();
if(Status != STATUS_EFI_SUCCESS)
{
/* Initialization failed, notify user on stdout */
BlDisplayErrorDialog(L"XTLDR", L"Failed to initialize debug console.");
}
}
/* Disable watchdog timer */
Status = EfiSystemTable->BootServices->SetWatchdogTimer(0, 0x10000, 0, NULL);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to disable the timer, print message */
BlDebugPrint(L"WARNING: Failed to disable watchdog timer\n");
}
/* Register loader protocol */
Status = BlpRegisterXtLoaderProtocol();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to register loader protocol */
BlDebugPrint(L"ERROR: Failed to register XTLDR boot protocol\n");
return Status;
}
/* Load boot loader modules */
Status = BlLoadModules(BlGetConfigValue(L"MODULES"));
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load modules */
BlDebugPrint(L"ERROR: Failed to load XTLDR modules (Status Code: 0x%lx)\n", Status);
BlDisplayErrorDialog(L"XTLDR", L"Failed to load some XTLDR modules.");
}
/* Discover and enumerate EFI block devices */
Status = BlEnumerateBlockDevices();
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to enumerate block devices */
BlDebugPrint(L"ERROR: Failed to discover and enumerate block devices\n");
return Status;
}
BlConsolePrint(L"\n\n\n\n\n\n\n\nList of loaded modules:");
PLIST_ENTRY ModuleListEntry;
PXTBL_MODULE_INFO ModuleInfo;
ModuleListEntry = BlpLoadedModules.Flink;
while(ModuleListEntry != &BlpLoadedModules)
{
/* Get module information */
ModuleInfo = CONTAIN_RECORD(ModuleListEntry, XTBL_MODULE_INFO, Flink);
/* Module already loaded */
BlConsolePrint(L"\n%S", ModuleInfo->ModuleName);
if(ModuleInfo->ModuleDescription != 0)
{
BlConsolePrint(L" (%S)", ModuleInfo->ModuleDescription);
}
PLIST_ENTRY DepsListEntry;
PXTBL_MODULE_DEPS DepsInfo;
BlConsolePrint(L"\n - Uses: ");
DepsListEntry = ModuleInfo->Dependencies.Flink;
while(DepsListEntry != &ModuleInfo->Dependencies)
{
DepsInfo = CONTAIN_RECORD(DepsListEntry, XTBL_MODULE_DEPS, Flink);
BlConsolePrint(L"%S ", DepsInfo->ModuleName);
DepsListEntry = DepsListEntry->Flink;
}
/* Move to the module */
ModuleListEntry = ModuleListEntry->Flink;
}
BlConsolePrint(L"\n\n END OF LIST\n");
for(;;)
{
if(BlpStatus.BootMenu != NULL)
{
/* Display alternative boot menu */
BlpStatus.BootMenu();
}
else
{
/* Display default boot menu */
BlDisplayBootMenu();
}
}
/* This point should be never reached, if this happen return error code */
return STATUS_EFI_LOAD_ERROR;
}