Store all configuration in a linked list, read config from INI file and EFI shell
All checks were successful
Builds / ExectOS (amd64) (push) Successful in 46s
Builds / ExectOS (i686) (push) Successful in 25s

This commit is contained in:
2023-12-11 16:31:15 +01:00
parent 6ffedf6302
commit 0cea10ad42
9 changed files with 344 additions and 124 deletions

View File

@@ -9,19 +9,120 @@
#include <xtldr.h>
/**
* Returns a value of the specified configuration key.
*
* @param ConfigName
* Specifies the configuration key to return its value.
*
* @return This routine returns a pointer to the configuration value, or NULL if key was not found.
*
* @since XT 1.0
*/
XTCDECL
PWCHAR
BlGetConfigValue(IN CONST PWCHAR ConfigName)
{
PXTBL_CONFIG_ENTRY ConfigEntry;
PLIST_ENTRY ConfigListEntry;
SIZE_T Length;
/* Get config entry name length */
Length = RtlWideStringLength(ConfigName, 0);
/* Iterate through config entries */
ConfigListEntry = BlpConfig->Flink;
while(ConfigListEntry != BlpConfig)
{
/* Get config entry */
ConfigEntry = CONTAIN_RECORD(ConfigListEntry, XTBL_CONFIG_ENTRY, Flink);
/* Check if requested configuration found */
if(RtlCompareWideStringInsensitive(ConfigEntry->Name, ConfigName, Length) == 0)
{
/* Return config value */
return ConfigEntry->Value;
}
/* Move to the next config entry */
ConfigListEntry = ConfigListEntry->Flink;
}
/* Config entry not found, return NULL */
return NULL;
}
/**
* Updates existing configuration value.
*
* @param ConfigName
* Specifies the configuration key to update.
*
* @param ConfigValue
* Specifies the new configuration value.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlSetConfigValue(IN CONST PWCHAR ConfigName,
IN CONST PWCHAR ConfigValue)
{
PXTBL_CONFIG_ENTRY ConfigEntry;
PLIST_ENTRY ConfigListEntry;
SIZE_T Length;
/* Get config entry name length */
Length = RtlWideStringLength(ConfigName, 0);
/* Iterate through config entries */
ConfigListEntry = BlpConfig->Flink;
while(ConfigListEntry != BlpConfig)
{
/* Get config entry */
ConfigEntry = CONTAIN_RECORD(ConfigListEntry, XTBL_CONFIG_ENTRY, Flink);
/* Check if requested configuration found */
if(RtlCompareWideStringInsensitive(ConfigEntry->Name, ConfigName, Length) == 0)
{
/* Update config value */
ConfigEntry->Value = ConfigValue;
/* Return success */
return STATUS_EFI_SUCCESS;
}
/* Move to the next config entry */
ConfigListEntry = ConfigListEntry->Flink;
}
/* Config entry not found */
return STATUS_EFI_NOT_FOUND;
}
/**
* Loads and parses XTLDR configuration file.
*
* @return This routine returns status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlpLoadConfiguration()
{
PLIST_ENTRY SectionListEntry;
STATIC LIST_ENTRY Configuration;
EFI_STATUS Status;
PLIST_ENTRY Configuration;
PCHAR ConfigData;
/* Initialize configuration pointer */
Configuration = NULL;
RtlInitializeListHead(&Configuration);
/* Read data from configuration file */
Status = BlpReadConfigurationFile(L"\\EFI\\BOOT\\", L"XTLDR.INI", &ConfigData);
Status = BlpReadConfigFile(L"\\EFI\\BOOT\\", L"XTLDR.INI", &ConfigData);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to load configuration */
@@ -30,7 +131,7 @@ BlpLoadConfiguration()
}
/* Parse configuration data */
Status = BlpParseConfigurationFile(ConfigData, Configuration);
Status = BlpParseConfigFile(ConfigData, &Configuration);
if(Status != STATUS_EFI_SUCCESS)
{
/* Failed to parse configuration */
@@ -38,6 +139,31 @@ BlpLoadConfiguration()
return Status;
}
/* Iterate through config sections */
SectionListEntry = Configuration.Flink;
while(SectionListEntry != &Configuration)
{
/* Get config section */
PXTBL_CONFIG_SECTION Section = CONTAIN_RECORD(SectionListEntry, XTBL_CONFIG_SECTION, Flink);
/* Look for global XTLDR configuration section */
if(RtlCompareWideStringInsensitive(Section->SectionName, L"XTLDR", 5) == 0)
{
/* Update global configuration */
BlpUpdateConfiguration(&Section->Options);
/* Remove XTLDR section from the list */
RtlRemoveEntryList(SectionListEntry);
break;
}
/* Move to the next section */
SectionListEntry = SectionListEntry->Flink;
}
/* Update boot menu OS list */
BlpMenuList = &Configuration;
/* Return success */
return STATUS_EFI_SUCCESS;
}
@@ -50,12 +176,19 @@ BlpLoadConfiguration()
* @since XT 1.0
*/
XTCDECL
VOID
EFI_STATUS
BlpParseCommandLine(VOID)
{
EFI_GUID LIPGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
PEFI_LOADED_IMAGE_PROTOCOL LoadedImage;
PWCHAR Argument, Key, LastArg, Value;
PXTBL_CONFIG_ENTRY Option;
EFI_STATUS Status;
SIZE_T KeyLength, ValueLength;
LIST_ENTRY Config;
/* Initialize configuration list */
RtlInitializeListHead(&Config);
/* Handle loaded image protocol */
Status = EfiSystemTable->BootServices->HandleProtocol(EfiImageHandle, &LIPGuid, (PVOID *)&LoadedImage);
@@ -64,21 +197,113 @@ BlpParseCommandLine(VOID)
/* Check if launched from UEFI shell */
if(LoadedImage && LoadedImage->LoadOptions)
{
/* Update global boot loader configuration */
BlpUpdateGlobalConfiguration(LoadedImage->LoadOptions);
/* Tokenize provided options */
Argument = RtlTokenizeWideString(LoadedImage->LoadOptions, L" ", &LastArg);
/* Iterate over all arguments passed to boot loader */
while(Argument != NULL)
{
/* Store key name */
Key = Argument;
/* Find end of the key */
while(*Argument != '=' && *Argument != 0 && *Argument != '\n')
{
/* Advance to the next character */
Argument++;
}
/* Mark end of the key and advance to the next character */
*Argument = 0;
Argument++;
/* Store value */
Value = Argument;
/* Find end of the value */
while(*Argument != 0 && *Argument != '\n')
{
/* Advance to the next character */
Argument++;
}
/* Mark end of the value and advance to the next character */
*Argument = 0;
Argument++;
/* Get length of the key and its value */
KeyLength = RtlWideStringLength(Key, 0);
ValueLength = RtlWideStringLength(Value, 0);
/* Check if argument is valid */
if(KeyLength == 0 || ValueLength == 0)
{
/* Invalid argument, skip to the next one */
continue;
}
/* Allocate memory for new option */
Status = BlMemoryAllocatePool(sizeof(XTBL_CONFIG_ENTRY), (PVOID*)&Option);
if(Status == STATUS_EFI_SUCCESS)
{
/* Allocate more memory for option name */
Status = BlMemoryAllocatePool(sizeof(PWCHAR) * (KeyLength + 1), (PVOID*)&Option->Name);
if(Status == STATUS_EFI_SUCCESS)
{
/* Allocate even more memory for option value */
Status = BlMemoryAllocatePool(sizeof(PWCHAR) * (ValueLength + 1), (PVOID*)&Option->Value);
}
}
if(Status != STATUS_EFI_SUCCESS)
{
/* Some memory allocation failed */
return Status;
}
/* Set entry name and value */
RtlCopyMemory(Option->Name, Key, (KeyLength * sizeof(WCHAR)));
RtlCopyMemory(Option->Value, Value, (ValueLength * sizeof(WCHAR)));
Option->Name[KeyLength] = 0;
Option->Value[ValueLength] = 0;
/* Add entry to the list */
RtlInsertTailList(&Config, &Option->Flink);
/* Take next argument */
Argument = RtlTokenizeWideString(NULL, L" ", &LastArg);
}
/* Update global configuration */
BlpUpdateConfiguration(&Config);
}
}
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Parses configuration INI file.
*
* @param RawConfig
* Suplies a pointer to configuration INI file to be parsed.
*
* @param Configuration
* Supplies a pointer to memory region where parsed configuration will be stored.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlpParseConfigurationFile(IN CONST PCHAR RawConfig,
OUT PLIST_ENTRY Configuration)
BlpParseConfigFile(IN CONST PCHAR RawConfig,
OUT PLIST_ENTRY Configuration)
{
SIZE_T SectionLength, KeyLength, ValueLength;
PCHAR InputData, Key, SectionName, Value;
PXTBL_INI_SECTION Section;
PXTBL_INI_OPTION Option;
PXTBL_CONFIG_SECTION Section;
PXTBL_CONFIG_ENTRY Option;
EFI_STATUS Status;
/* Initialize pointers */
@@ -139,7 +364,7 @@ BlpParseConfigurationFile(IN CONST PCHAR RawConfig,
SectionLength = RtlStringLength(SectionName, 0);
/* Allocate memory for new section */
Status = BlMemoryAllocatePool(sizeof(XTBL_INI_SECTION), (PVOID*)&Section);
Status = BlMemoryAllocatePool(sizeof(XTBL_CONFIG_SECTION), (PVOID*)&Section);
if(Status == STATUS_EFI_SUCCESS)
{
/* Allocate more memory for section name */
@@ -209,7 +434,7 @@ BlpParseConfigurationFile(IN CONST PCHAR RawConfig,
ValueLength = RtlStringLength(Value, 0);
/* Allocate memory for new option */
Status = BlMemoryAllocatePool(sizeof(XTBL_INI_OPTION), (PVOID*)&Option);
Status = BlMemoryAllocatePool(sizeof(XTBL_CONFIG_ENTRY), (PVOID*)&Option);
if(Status == STATUS_EFI_SUCCESS)
{
/* Allocate more memory for option name */
@@ -255,9 +480,9 @@ BlpParseConfigurationFile(IN CONST PCHAR RawConfig,
*/
XTCDECL
EFI_STATUS
BlpReadConfigurationFile(IN CONST PWCHAR ConfigDirectory,
IN CONST PWCHAR ConfigFile,
OUT PCHAR *ConfigData)
BlpReadConfigFile(IN CONST PWCHAR ConfigDirectory,
IN CONST PWCHAR ConfigFile,
OUT PCHAR *ConfigData)
{
PEFI_FILE_HANDLE DirHandle, FsHandle;
EFI_HANDLE DiskHandle;
@@ -295,10 +520,10 @@ BlpReadConfigurationFile(IN CONST PWCHAR ConfigDirectory,
}
/**
* Updates XTLDR configuration based on provided options.
* Adds new XTLDR configuration entries to the global configuration list. Existing entries are not overwritten.
*
* @param Options
* Supplies a formatted list of options to be processed and stored in global configuration.
* @param NewConfig
* Supplies a pointer to a linked list containing new configuration entries.
*
* @return This routine does not return any value.
*
@@ -306,78 +531,29 @@ BlpReadConfigurationFile(IN CONST PWCHAR ConfigDirectory,
*/
XTCDECL
VOID
BlpUpdateGlobalConfiguration(IN PWCHAR Options)
BlpUpdateConfiguration(IN PLIST_ENTRY NewConfig)
{
PWCHAR Argument, LastArg;
SIZE_T Length;
PXTBL_CONFIG_ENTRY ConfigEntry;
PLIST_ENTRY ConfigListEntry, NextListEntry;
/* Tokenize provided options */
Argument = RtlTokenizeWideString(Options, L" ", &LastArg);
/* Iterate over all arguments passed to boot loader */
while(Argument != NULL)
/* Iterate through new config entries */
ConfigListEntry = NewConfig->Flink;
while(ConfigListEntry != NewConfig)
{
/* Check all provided parameters */
if(RtlCompareWideStringInsensitive(Argument, L"DEFAULT=", 8) == 0)
{
/* Skip to the argument value and calculate argument length */
Argument += 8;
Length = RtlWideStringLength(Argument, 0);
/* Get new config entry */
ConfigEntry = CONTAIN_RECORD(ConfigListEntry, XTBL_CONFIG_ENTRY, Flink);
/* Save default OS parameter in global configuration */
BlMemoryAllocatePool(Length, (PVOID *)&BlpConfiguration.Default);
RtlCopyMemory(BlpConfiguration.Default, Argument, (Length * sizeof(WCHAR)));
BlpConfiguration.Default[Length] = '\0';
}
else if(RtlCompareWideStringInsensitive(Argument, L"DEBUG=", 6) == 0)
{
/* Skip to the argument value */
Argument += 6;
Length = RtlWideStringLength(Argument, 0);
/* Get next config entry */
NextListEntry = ConfigListEntry->Flink;
/* Store debug port configuration if not set already */
if(BlpConfiguration.Debug == NULL)
{
/* Save debug port in global configuration */
BlMemoryAllocatePool(Length, (PVOID *)&BlpConfiguration.Debug);
RtlCopyMemory(BlpConfiguration.Debug, Argument, (Length * sizeof(WCHAR)));
BlpConfiguration.Debug[Length] = '\0';
}
}
else if(RtlCompareWideStringInsensitive(Argument, L"SHELL", 5) == 0)
/* Make sure config entry does not exist yet */
if(BlGetConfigValue(ConfigEntry->Name) == NULL)
{
/* Force shell mode */
BlpConfiguration.Shell = TRUE;
}
else if(RtlCompareWideStringInsensitive(Argument, L"TIMEOUT=", 8) == 0)
{
/* Skip to the argument value */
Argument += 8;
/* Zero the timeout */
BlpConfiguration.Timeout = 0;
/* Read the timeout value and store it in global configuration */
while(*Argument >= '0' && *Argument <= '9')
{
BlpConfiguration.Timeout *= 10;
BlpConfiguration.Timeout += *Argument - '0';
Argument++;
}
}
else if(RtlCompareWideStringInsensitive(Argument, L"TUNE=", 5) == 0)
{
/* Skip to the argument value */
Argument += 5;
Length = RtlWideStringLength(Argument, 0);
/* Save theme in global configuration */
BlMemoryAllocatePool(Length, (PVOID *)&BlpConfiguration.Tune);
RtlCopyMemory(BlpConfiguration.Tune, Argument, (Length * sizeof(WCHAR)));
BlpConfiguration.Tune[Length] = '\0';
/* Remove new config entry from input list and put it into global config list */
RtlInsertTailList(BlpConfig, &ConfigEntry->Flink);
}
/* Take next argument */
Argument = RtlTokenizeWideString(NULL, L" ", &LastArg);
/* Move to the next new config entry */
ConfigListEntry = NextListEntry;
}
}