Implement boot entry editor
This commit is contained in:
parent
b68514b176
commit
c6643125e1
229
xtldr/config.c
229
xtldr/config.c
@ -4,11 +4,84 @@
|
||||
* FILE: xtldr/config.c
|
||||
* DESCRIPTION: XT Boot Loader Configuration
|
||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
* Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtldr.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the value of a specific OS boot option from a list.
|
||||
*
|
||||
* @param Options
|
||||
* A pointer to the head of a list of XTBL_CONFIG_ENTRY structures.
|
||||
*
|
||||
* @param OptionName
|
||||
* A pointer to wide string that contains the name of the boot option to retrieve.
|
||||
*
|
||||
* @param OptionValue
|
||||
* A pointer to a variable that receives a pointer to the retrieved boot option's value.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlGetBootOptionValue(IN PLIST_ENTRY Options,
|
||||
IN CONST PWCHAR OptionName,
|
||||
OUT PWCHAR *OptionValue)
|
||||
{
|
||||
PXTBL_CONFIG_ENTRY ConfigEntry;
|
||||
PLIST_ENTRY ConfigList;
|
||||
ULONG KeyLength, ValueLength;
|
||||
EFI_STATUS Status;
|
||||
|
||||
/* Assume the option will not be found */
|
||||
*OptionValue = NULL;
|
||||
|
||||
/* Get the length of the option name we are looking for */
|
||||
KeyLength = RtlWideStringLength(OptionName, 0);
|
||||
|
||||
/* Start iterating from the first entry in the options list */
|
||||
ConfigList = Options->Flink;
|
||||
while(ConfigList != Options)
|
||||
{
|
||||
/* Get the container record for the current config entry */
|
||||
ConfigEntry = CONTAIN_RECORD(ConfigList, XTBL_CONFIG_ENTRY, Flink);
|
||||
|
||||
/* Compare the current entry's name with the requested option name */
|
||||
if(RtlCompareWideStringInsensitive(ConfigEntry->Name, OptionName, KeyLength) == 0)
|
||||
{
|
||||
/* Found the option, now prepare to copy its value */
|
||||
ValueLength = RtlWideStringLength(ConfigEntry->Value, 0);
|
||||
|
||||
/* Allocate memory for the output value string */
|
||||
Status = BlAllocateMemoryPool((ValueLength + 1) * sizeof(WCHAR), (PVOID *)OptionValue);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print debug message and return status code */
|
||||
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\n", Status);
|
||||
*OptionValue = NULL;
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy the value and NULL-terminate the new string */
|
||||
RtlCopyMemory(*OptionValue, ConfigEntry->Value, ValueLength * sizeof(WCHAR));
|
||||
(*OptionValue)[ValueLength] = L'\0';
|
||||
|
||||
/* Successfully retrieved the option value, return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Move to the next entry in the list */
|
||||
ConfigList = ConfigList->Flink;
|
||||
}
|
||||
|
||||
/* Option not found */
|
||||
return STATUS_EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value of the specified configuration key.
|
||||
*
|
||||
@ -101,6 +174,156 @@ BlGetConfigValue(IN CONST PWCHAR ConfigName)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of user-editable boot options.
|
||||
*
|
||||
* @param OptionsArray
|
||||
* A pointer to a variable that will receive the pointer to the array of editable option names.
|
||||
*
|
||||
* @param OptionsCount
|
||||
* A pointer to a variable that will be updated with the number of elements in the OptionsArray.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
VOID
|
||||
BlGetEditableOptions(OUT CONST PWCHAR **OptionsArray,
|
||||
OUT PSIZE_T OptionsCount)
|
||||
{
|
||||
ULONG Count = 0;
|
||||
|
||||
/* Return a pointer to the global array of editable options */
|
||||
*OptionsArray = BlpEditableConfigOptions;
|
||||
|
||||
/* Calculate the number of elements in the array */
|
||||
while(BlpEditableConfigOptions[Count])
|
||||
{
|
||||
Count++;
|
||||
}
|
||||
|
||||
/* Return the number of elements */
|
||||
*OptionsCount = Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a specific OS boot option in a list, or adds it if it doesn't exist.
|
||||
*
|
||||
* @param Options
|
||||
* A pointer to the head of a list of XTBL_CONFIG_ENTRY structures.
|
||||
*
|
||||
* @param OptionName
|
||||
* A pointer to a wide string that contains the name of the boot option to set.
|
||||
*
|
||||
* @param OptionValue
|
||||
* A pointer to a wide string that contains the new value for the boot option.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlSetBootOptionValue(IN PLIST_ENTRY Options,
|
||||
IN CONST PWCHAR OptionName,
|
||||
IN CONST PWCHAR OptionValue)
|
||||
{
|
||||
PXTBL_CONFIG_ENTRY ConfigEntry;
|
||||
PLIST_ENTRY ConfigList;
|
||||
ULONG Length;
|
||||
EFI_STATUS Status;
|
||||
|
||||
/* Get the length of the option name we are looking for */
|
||||
Length = RtlWideStringLength(OptionName, 0);
|
||||
|
||||
/* Start iterating from the first entry in the options list */
|
||||
ConfigList = Options->Flink;
|
||||
while(ConfigList != Options)
|
||||
{
|
||||
/* Get the container record for the current config entry */
|
||||
ConfigEntry = CONTAIN_RECORD(ConfigList, XTBL_CONFIG_ENTRY, Flink);
|
||||
|
||||
/* Compare the current entry's name with the requested option name */
|
||||
if(RtlCompareWideStringInsensitive(ConfigEntry->Name, OptionName, Length) == 0)
|
||||
{
|
||||
/* Found the option, get its length */
|
||||
Length = RtlWideStringLength(OptionValue, 0);
|
||||
|
||||
/* Reallocate memory for the new value */
|
||||
Status = BlFreeMemoryPool(ConfigEntry->Value);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to free memory, return status code */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Allocate new memory for the updated value */
|
||||
Status = BlAllocateMemoryPool((Length + 1) * sizeof(WCHAR), (PVOID *)&ConfigEntry->Value);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print debug message and return status code */
|
||||
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy the value and NULL-terminate the new string */
|
||||
RtlCopyMemory(ConfigEntry->Value, OptionValue, Length * sizeof(WCHAR));
|
||||
ConfigEntry->Value[Length] = L'\0';
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Move to the next entry in the list */
|
||||
ConfigList = ConfigList->Flink;
|
||||
}
|
||||
|
||||
/* Option not found, allocate memory for the new one */
|
||||
Status = BlAllocateMemoryPool(sizeof(XTBL_CONFIG_ENTRY), (PVOID *)&ConfigEntry);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print debug message and return status code */
|
||||
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Allocate memory for the option name */
|
||||
Length = RtlWideStringLength(OptionName, 0);
|
||||
Status = BlAllocateMemoryPool((Length + 1) * sizeof(WCHAR), (PVOID *)&ConfigEntry->Name);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print debug message and return status code */
|
||||
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\\n", Status);
|
||||
BlFreeMemoryPool(ConfigEntry);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy the option name and NULL-terminate the new string */
|
||||
RtlCopyMemory(ConfigEntry->Name, OptionName, Length * sizeof(WCHAR));
|
||||
ConfigEntry->Name[Length] = L'\0';
|
||||
|
||||
/* Allocate memory for the option value */
|
||||
Length = RtlWideStringLength(OptionValue, 0);
|
||||
Status = BlAllocateMemoryPool((Length + 1) * sizeof(WCHAR), (PVOID *)&ConfigEntry->Value);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print debug message and return status code */
|
||||
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\\n", Status);
|
||||
BlFreeMemoryPool(ConfigEntry->Name);
|
||||
BlFreeMemoryPool(ConfigEntry);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy the value and NULL-terminate the new string */
|
||||
RtlCopyMemory(ConfigEntry->Value, OptionValue, Length * sizeof(WCHAR));
|
||||
ConfigEntry->Value[Length] = L'\0';
|
||||
|
||||
/* Insert the new config entry at the end of the options list */
|
||||
RtlInsertTailList(Options, &ConfigEntry->Flink);
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates existing configuration value.
|
||||
*
|
||||
@ -110,7 +333,7 @@ BlGetConfigValue(IN CONST PWCHAR ConfigName)
|
||||
* @param ConfigValue
|
||||
* Specifies the new configuration value.
|
||||
*
|
||||
* @return This routine returns status code.
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
@ -174,7 +397,7 @@ BlSetConfigValue(IN CONST PWCHAR ConfigName,
|
||||
/**
|
||||
* Loads and parses XTLDR configuration file.
|
||||
*
|
||||
* @return This routine returns status code.
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
@ -568,7 +791,7 @@ BlpParseConfigFile(IN CONST PCHAR RawConfig,
|
||||
* @param ConfigData
|
||||
* Provides a buffer to store the data read from the configuration file.
|
||||
*
|
||||
* @return This routine returns status code.
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
|
@ -21,6 +21,13 @@ LIST_ENTRY BlpConfig;
|
||||
/* XT Boot Loader loaded configuration */
|
||||
LIST_ENTRY BlpConfigSections;
|
||||
|
||||
/* List of user-editable boot options */
|
||||
PWCHAR BlpEditableConfigOptions[] = {
|
||||
L"BootModules", L"SystemType", L"SystemPath",
|
||||
L"KernelFile", L"InitrdFile", L"HalFile",
|
||||
L"Parameters", NULL
|
||||
};
|
||||
|
||||
/* XT Boot Loader protocol */
|
||||
XTBL_LOADER_PROTOCOL BlpLdrProtocol;
|
||||
|
||||
@ -41,3 +48,4 @@ EFI_HANDLE EfiImageHandle;
|
||||
|
||||
/* EFI System Table */
|
||||
PEFI_SYSTEM_TABLE EfiSystemTable;
|
||||
|
||||
|
@ -24,6 +24,9 @@ EXTERN LIST_ENTRY BlpConfig;
|
||||
/* XT Boot Loader loaded configuration */
|
||||
EXTERN LIST_ENTRY BlpConfigSections;
|
||||
|
||||
/* List of user-editable boot options */
|
||||
EXTERN PWCHAR BlpEditableConfigOptions[];
|
||||
|
||||
/* XT Boot Loader protocol */
|
||||
EXTERN XTBL_LOADER_PROTOCOL BlpLdrProtocol;
|
||||
|
||||
|
@ -71,6 +71,10 @@ XTCDECL
|
||||
VOID
|
||||
BlDisplayBootMenu();
|
||||
|
||||
XTCDECL
|
||||
VOID
|
||||
BlDisplayEditMenu(IN PXTBL_BOOTMENU_ITEM MenuEntry);
|
||||
|
||||
XTCDECL
|
||||
VOID
|
||||
BlDisplayErrorDialog(IN PWCHAR Caption,
|
||||
@ -134,6 +138,12 @@ BOOLEAN
|
||||
BlGetBooleanParameter(IN CONST PWCHAR Parameters,
|
||||
IN CONST PWCHAR Needle);
|
||||
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlGetBootOptionValue(IN PLIST_ENTRY Options,
|
||||
IN CONST PWCHAR OptionName,
|
||||
OUT PWCHAR *OptionValue);
|
||||
|
||||
XTCDECL
|
||||
BOOLEAN
|
||||
BlGetConfigBooleanValue(IN CONST PWCHAR ConfigName);
|
||||
@ -147,6 +157,11 @@ EFI_STATUS
|
||||
BlGetConfigurationTable(IN PEFI_GUID TableGuid,
|
||||
OUT PVOID *Table);
|
||||
|
||||
XTCDECL
|
||||
VOID
|
||||
BlGetEditableOptions(OUT CONST PWCHAR **OptionsArray,
|
||||
OUT PSIZE_T OptionsCount);
|
||||
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlGetEfiPath(IN PWCHAR SystemPath,
|
||||
@ -332,6 +347,12 @@ XTCDECL
|
||||
VOID
|
||||
BlResetConsoleInputBuffer();
|
||||
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlSetBootOptionValue(IN PLIST_ENTRY Options,
|
||||
IN CONST PWCHAR OptionName,
|
||||
IN CONST PWCHAR OptionValue);
|
||||
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlSetConfigValue(IN CONST PWCHAR ConfigName,
|
||||
@ -456,6 +477,18 @@ VOID
|
||||
BlpDrawDialogProgressBar(IN PXTBL_DIALOG_HANDLE Handle,
|
||||
IN UCHAR Percentage);
|
||||
|
||||
XTCDECL
|
||||
VOID
|
||||
BlpDrawEditMenu(OUT PXTBL_DIALOG_HANDLE Handle);
|
||||
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlpDrawEditMenuEntry(IN PXTBL_DIALOG_HANDLE Handle,
|
||||
IN PWCHAR OptionName,
|
||||
IN PWCHAR OptionValue,
|
||||
IN UINT Position,
|
||||
IN BOOLEAN Highlighted);
|
||||
|
||||
XTCDECL
|
||||
PEFI_DEVICE_PATH_PROTOCOL
|
||||
BlpDuplicateDevicePath(IN PEFI_DEVICE_PATH_PROTOCOL DevicePath);
|
||||
|
456
xtldr/textui.c
456
xtldr/textui.c
@ -107,6 +107,8 @@ BlDisplayBootMenu()
|
||||
BlpDrawBootMenuEntry(&Handle, MenuEntries[TopVisibleEntry + Index].EntryName,
|
||||
Index, (TopVisibleEntry + Index) == HighligtedEntryId);
|
||||
}
|
||||
|
||||
/* Clear redraw entries flag */
|
||||
RedrawEntries = FALSE;
|
||||
}
|
||||
}
|
||||
@ -198,6 +200,7 @@ BlDisplayBootMenu()
|
||||
if(HighligtedEntryId > 0)
|
||||
{
|
||||
/* Highlight previous entry */
|
||||
OldHighligtedEntryId = HighligtedEntryId;
|
||||
HighligtedEntryId--;
|
||||
|
||||
/* Check if we need to scroll the view */
|
||||
@ -214,9 +217,6 @@ BlDisplayBootMenu()
|
||||
OldHighligtedEntryId - TopVisibleEntry, FALSE);
|
||||
BlpDrawBootMenuEntry(&Handle, MenuEntries[HighligtedEntryId].EntryName,
|
||||
HighligtedEntryId - TopVisibleEntry, TRUE);
|
||||
|
||||
/* Update old highlighted entry */
|
||||
OldHighligtedEntryId = HighligtedEntryId;
|
||||
}
|
||||
}
|
||||
else if(Key.ScanCode == 0x02)
|
||||
@ -225,6 +225,7 @@ BlDisplayBootMenu()
|
||||
if(HighligtedEntryId < NumberOfEntries - 1)
|
||||
{
|
||||
/* Highlight next entry */
|
||||
OldHighligtedEntryId = HighligtedEntryId;
|
||||
HighligtedEntryId++;
|
||||
|
||||
/* Check if we need to scroll the view */
|
||||
@ -241,9 +242,6 @@ BlDisplayBootMenu()
|
||||
OldHighligtedEntryId - TopVisibleEntry, FALSE);
|
||||
BlpDrawBootMenuEntry(&Handle, MenuEntries[HighligtedEntryId].EntryName,
|
||||
HighligtedEntryId - TopVisibleEntry, TRUE);
|
||||
|
||||
/* Update old highlighted entry */
|
||||
OldHighligtedEntryId = HighligtedEntryId;
|
||||
}
|
||||
}
|
||||
else if(Key.ScanCode == 0x09)
|
||||
@ -326,7 +324,7 @@ BlDisplayBootMenu()
|
||||
else if(Key.UnicodeChar == 0x65)
|
||||
{
|
||||
/* 'e' key pressed, edit the highlighted entry */
|
||||
BlDisplayErrorDialog(L"XTLDR", L"Editing boot menu entries is not implemented yet!");
|
||||
BlDisplayEditMenu(&MenuEntries[HighligtedEntryId]);
|
||||
RedrawBootMenu = TRUE;
|
||||
|
||||
/* Break from boot menu event loop to redraw whole boot menu */
|
||||
@ -379,6 +377,232 @@ BlDisplayBootMenu()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a simple TUI-based edit menu.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
VOID
|
||||
BlDisplayEditMenu(IN PXTBL_BOOTMENU_ITEM MenuEntry)
|
||||
{
|
||||
ULONG HighligtedOptionId, Index, NumberOfOptions, OldHighligtedOptionId, TopVisibleEntry, VisibleEntries;
|
||||
XTBL_DIALOG_HANDLE Handle;
|
||||
BOOLEAN RedrawEditMenu, RedrawEntries;
|
||||
EFI_INPUT_KEY Key;
|
||||
UINT_PTR EventIndex;
|
||||
PWCHAR NewValue, OptionName, OriginalValue, Value, ValueToEdit;
|
||||
CONST PWCHAR *EditableOptions;
|
||||
|
||||
/* Draw edit menu */
|
||||
BlpDrawEditMenu(&Handle);
|
||||
|
||||
/* Get the list of user editable options */
|
||||
BlGetEditableOptions(&EditableOptions, &NumberOfOptions);
|
||||
|
||||
/* Calculate how many entries can be visible in the menu box */
|
||||
VisibleEntries = Handle.Height - 2;
|
||||
|
||||
/* Assume the first option is highlighted by default */
|
||||
HighligtedOptionId = 0;
|
||||
OldHighligtedOptionId = 0;
|
||||
TopVisibleEntry = 0;
|
||||
|
||||
/* Set redraw flags to not redraw the menu itself, but fill it with entries */
|
||||
RedrawEditMenu = FALSE;
|
||||
RedrawEntries = TRUE;
|
||||
|
||||
/* Infinite edit menu loop */
|
||||
while(TRUE)
|
||||
{
|
||||
/* Redraw edit menu frame if requested */
|
||||
if(RedrawEditMenu)
|
||||
{
|
||||
BlpDrawEditMenu(&Handle);
|
||||
RedrawEditMenu = FALSE;
|
||||
RedrawEntries = TRUE;
|
||||
}
|
||||
|
||||
/* Sanity check to ensure we do not display more entries than possible */
|
||||
if(VisibleEntries > NumberOfOptions)
|
||||
{
|
||||
VisibleEntries = NumberOfOptions;
|
||||
}
|
||||
|
||||
/* Check if we need to redraw boot menu entries */
|
||||
if(RedrawEntries)
|
||||
{
|
||||
/* Iterate through all menu entries */
|
||||
for(Index = 0; Index < VisibleEntries; Index++)
|
||||
{
|
||||
/* Draw menu entry */
|
||||
BlGetBootOptionValue(MenuEntry->Options, EditableOptions[TopVisibleEntry + Index], &Value);
|
||||
BlpDrawEditMenuEntry(&Handle, EditableOptions[TopVisibleEntry + Index], Value, Index,
|
||||
(TopVisibleEntry + Index) == HighligtedOptionId);
|
||||
|
||||
/* Free allocated value string if needed */
|
||||
if(Value != NULL)
|
||||
{
|
||||
BlFreeMemoryPool(Value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear redraw entries flag */
|
||||
RedrawEntries = FALSE;
|
||||
}
|
||||
|
||||
/* Wait for EFI event and read key stroke */
|
||||
BlWaitForEfiEvent(1, &EfiSystemTable->ConIn->WaitForKey, &EventIndex);
|
||||
BlReadKeyStroke(&Key);
|
||||
|
||||
/* Check key press scan code */
|
||||
if(Key.UnicodeChar == 0x0D)
|
||||
{
|
||||
/* ENTER key pressed, edit the highlighted option */
|
||||
OptionName = EditableOptions[HighligtedOptionId];
|
||||
BlGetBootOptionValue(MenuEntry->Options, OptionName, &OriginalValue);
|
||||
|
||||
/* If the original value is NULL, use an empty string for editing */
|
||||
if(OriginalValue == NULL)
|
||||
{
|
||||
ValueToEdit = L"";
|
||||
}
|
||||
else
|
||||
{
|
||||
ValueToEdit = OriginalValue;
|
||||
}
|
||||
|
||||
/* Display input dialog to edit the option value */
|
||||
NewValue = ValueToEdit;
|
||||
BlDisplayInputDialog(OptionName, L"Enter new value:", &NewValue);
|
||||
|
||||
/* Check if the value was changed */
|
||||
if(NewValue != ValueToEdit)
|
||||
{
|
||||
/* Update the boot option with the new value and free the old value */
|
||||
BlSetBootOptionValue(MenuEntry->Options, OptionName, NewValue);
|
||||
BlFreeMemoryPool(NewValue);
|
||||
}
|
||||
|
||||
/* Free the original value if it was allocated */
|
||||
if(OriginalValue != NULL)
|
||||
{
|
||||
BlFreeMemoryPool(OriginalValue);
|
||||
}
|
||||
|
||||
/* Mark the edit menu for redraw */
|
||||
RedrawEditMenu = TRUE;
|
||||
}
|
||||
else if(Key.ScanCode == 0x01)
|
||||
{
|
||||
/* UpArrow key pressed, go to previous entry if possible */
|
||||
if(HighligtedOptionId > 0)
|
||||
{
|
||||
/* Highlight previous entry */
|
||||
OldHighligtedOptionId = HighligtedOptionId;
|
||||
HighligtedOptionId--;
|
||||
|
||||
/* Check if we need to scroll the view */
|
||||
if(HighligtedOptionId < TopVisibleEntry)
|
||||
{
|
||||
/* Scroll the view */
|
||||
TopVisibleEntry = HighligtedOptionId;
|
||||
RedrawEntries = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Redraw old highlighted entry */
|
||||
BlGetBootOptionValue(MenuEntry->Options, EditableOptions[OldHighligtedOptionId], &Value);
|
||||
BlpDrawEditMenuEntry(&Handle, EditableOptions[OldHighligtedOptionId], Value, OldHighligtedOptionId - TopVisibleEntry, FALSE);
|
||||
|
||||
/* Free allocated value string if needed */
|
||||
if(Value != NULL)
|
||||
{
|
||||
BlFreeMemoryPool(Value);
|
||||
}
|
||||
|
||||
/* Redraw new highlighted entry */
|
||||
BlGetBootOptionValue(MenuEntry->Options, EditableOptions[HighligtedOptionId], &Value);
|
||||
BlpDrawEditMenuEntry(&Handle, EditableOptions[HighligtedOptionId], Value, HighligtedOptionId - TopVisibleEntry, TRUE);
|
||||
|
||||
/* Free allocated value string if needed */
|
||||
if(Value != NULL)
|
||||
{
|
||||
BlFreeMemoryPool(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(Key.ScanCode == 0x02)
|
||||
{
|
||||
/* DownArrow key pressed, go to next entry if possible */
|
||||
if(HighligtedOptionId < NumberOfOptions - 1)
|
||||
{
|
||||
/* Highlight next entry */
|
||||
OldHighligtedOptionId = HighligtedOptionId;
|
||||
HighligtedOptionId++;
|
||||
|
||||
/* Check if we need to scroll the view */
|
||||
if(HighligtedOptionId >= TopVisibleEntry + VisibleEntries)
|
||||
{
|
||||
/* Scroll the view */
|
||||
TopVisibleEntry = HighligtedOptionId - VisibleEntries + 1;
|
||||
RedrawEntries = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Redraw old highlighted entry */
|
||||
BlGetBootOptionValue(MenuEntry->Options, EditableOptions[OldHighligtedOptionId], &Value);
|
||||
BlpDrawEditMenuEntry(&Handle, EditableOptions[OldHighligtedOptionId], Value, OldHighligtedOptionId - TopVisibleEntry, FALSE);
|
||||
|
||||
/* Free allocated value string if needed */
|
||||
if(Value != NULL)
|
||||
{
|
||||
BlFreeMemoryPool(Value);
|
||||
}
|
||||
|
||||
/* Redraw new highlighted entry */
|
||||
BlGetBootOptionValue(MenuEntry->Options, EditableOptions[HighligtedOptionId], &Value);
|
||||
BlpDrawEditMenuEntry(&Handle, EditableOptions[HighligtedOptionId], Value, HighligtedOptionId - TopVisibleEntry, TRUE);
|
||||
|
||||
/* Free allocated value string if needed */
|
||||
if(Value != NULL)
|
||||
{
|
||||
BlFreeMemoryPool(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(Key.ScanCode == 0x09)
|
||||
{
|
||||
/* PageUp key pressed, go to top entry */
|
||||
if(HighligtedOptionId != 0)
|
||||
{
|
||||
/* Highlight first entry */
|
||||
HighligtedOptionId = 0;
|
||||
TopVisibleEntry = 0;
|
||||
RedrawEntries = TRUE;
|
||||
}
|
||||
}
|
||||
else if(Key.ScanCode == 0x0A)
|
||||
{
|
||||
/* PageDown key pressed, go to bottom entry */
|
||||
if(HighligtedOptionId != NumberOfOptions - 1)
|
||||
{
|
||||
/* Highlight last entry */
|
||||
HighligtedOptionId = NumberOfOptions - 1;
|
||||
TopVisibleEntry = (NumberOfOptions > VisibleEntries) ? (NumberOfOptions - VisibleEntries) : 0;
|
||||
RedrawEntries = TRUE;
|
||||
}
|
||||
}
|
||||
else if(Key.ScanCode == 0x17)
|
||||
{
|
||||
/* ESC key pressed, exit edit menu */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a red error dialog box with the specified caption and message.
|
||||
*
|
||||
@ -505,12 +729,11 @@ XTCDECL
|
||||
VOID
|
||||
BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
IN PWCHAR Message,
|
||||
IN PWCHAR *InputFieldText)
|
||||
IN OUT PWCHAR *InputFieldText)
|
||||
{
|
||||
SIZE_T InputFieldLength, TextCursorPosition, TextIndex, TextPosition;
|
||||
XTBL_DIALOG_HANDLE Handle;
|
||||
PWCHAR InputFieldBuffer;
|
||||
SIZE_T BufferLength;
|
||||
EFI_INPUT_KEY Key;
|
||||
EFI_STATUS Status;
|
||||
UINT_PTR Index;
|
||||
@ -535,9 +758,11 @@ BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
Key.ScanCode = 0;
|
||||
Key.UnicodeChar = 0;
|
||||
|
||||
/* Get initial input text length and allocate a buffer */
|
||||
BufferLength = RtlWideStringLength(*InputFieldText, 0);
|
||||
Status = BlAllocateMemoryPool(BufferLength * sizeof(WCHAR), (PVOID *)&InputFieldBuffer);
|
||||
/* Determine input field length */
|
||||
InputFieldLength = RtlWideStringLength(*InputFieldText, 0);
|
||||
|
||||
/* Allocate a buffer for storing the input field text */
|
||||
Status = BlAllocateMemoryPool(2048 * sizeof(WCHAR), (PVOID *)&InputFieldBuffer);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print error message and return */
|
||||
@ -547,15 +772,8 @@ BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
}
|
||||
|
||||
/* Copy input text into edit buffer */
|
||||
RtlCopyMemory(InputFieldBuffer, *InputFieldText, BufferLength * sizeof(WCHAR));
|
||||
InputFieldBuffer[BufferLength] = L'\0';
|
||||
|
||||
/* Determine input field length */
|
||||
InputFieldLength = BufferLength;
|
||||
if(InputFieldLength > Handle.Width - 8)
|
||||
{
|
||||
InputFieldLength = Handle.Width - 8;
|
||||
}
|
||||
RtlCopyMemory(InputFieldBuffer, *InputFieldText, InputFieldLength * sizeof(WCHAR));
|
||||
InputFieldBuffer[InputFieldLength] = L'\0';
|
||||
|
||||
/* Start at first character */
|
||||
TextPosition = 0;
|
||||
@ -618,12 +836,16 @@ BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
/* DELETE key pressed, delete character */
|
||||
if(Handle.Attributes & XTBL_TUI_DIALOG_ACTIVE_INPUT)
|
||||
{
|
||||
/* Check if buffer is not empty */
|
||||
if(InputFieldLength > 0 && TextPosition < InputFieldLength)
|
||||
{
|
||||
/* Delete character */
|
||||
RtlMoveMemory(InputFieldBuffer + TextPosition, InputFieldBuffer + TextPosition + 1,
|
||||
(InputFieldLength - TextPosition) * sizeof(WCHAR));
|
||||
|
||||
/* Decrement length and null terminate string */
|
||||
InputFieldLength--;
|
||||
InputFieldBuffer[InputFieldLength] = 0;
|
||||
InputFieldBuffer[InputFieldLength] = L'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -632,13 +854,17 @@ BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
/* BACKSPACE key pressed, delete character */
|
||||
if(Handle.Attributes & XTBL_TUI_DIALOG_ACTIVE_INPUT)
|
||||
{
|
||||
/* Check if buffer is not empty */
|
||||
if(InputFieldLength > 0 && TextPosition > 0 && TextPosition <= InputFieldLength)
|
||||
{
|
||||
TextPosition--;
|
||||
/* Delete character */
|
||||
RtlMoveMemory(InputFieldBuffer + TextPosition, InputFieldBuffer + TextPosition + 1,
|
||||
(InputFieldLength - TextPosition) * sizeof(WCHAR));
|
||||
|
||||
/* Decrement length, position and null terminate string */
|
||||
TextPosition--;
|
||||
InputFieldLength--;
|
||||
InputFieldBuffer[InputFieldLength] = 0;
|
||||
InputFieldBuffer[InputFieldLength] = L'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -653,15 +879,23 @@ BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
/* Other key pressed, add character to the buffer */
|
||||
if(Handle.Attributes & XTBL_TUI_DIALOG_ACTIVE_INPUT && Key.UnicodeChar != 0)
|
||||
{
|
||||
RtlMoveMemory(InputFieldBuffer + TextPosition + 1, InputFieldBuffer + TextPosition,
|
||||
(InputFieldLength - TextPosition) * sizeof(WCHAR));
|
||||
InputFieldBuffer[TextPosition] = Key.UnicodeChar;
|
||||
TextPosition++;
|
||||
InputFieldLength++;
|
||||
InputFieldBuffer[InputFieldLength] = 0;
|
||||
/* Check if buffer is full */
|
||||
if(InputFieldLength < 2047)
|
||||
{
|
||||
/* Insert character at current position */
|
||||
RtlMoveMemory(InputFieldBuffer + TextPosition + 1, InputFieldBuffer + TextPosition,
|
||||
(InputFieldLength - TextPosition) * sizeof(WCHAR));
|
||||
InputFieldBuffer[TextPosition] = Key.UnicodeChar;
|
||||
|
||||
/* Increment length, position and null terminate string */
|
||||
TextPosition++;
|
||||
InputFieldLength++;
|
||||
InputFieldBuffer[InputFieldLength] = L'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate text index and cursor position */
|
||||
if(TextPosition > (Handle.Width - 9))
|
||||
{
|
||||
TextIndex = TextPosition - (Handle.Width - 9);
|
||||
@ -677,6 +911,7 @@ BlDisplayInputDialog(IN PWCHAR Caption,
|
||||
BlpDrawDialogButton(&Handle);
|
||||
BlpDrawDialogInputField(&Handle, &InputFieldBuffer[TextIndex]);
|
||||
|
||||
/* Set cursor position if input field is active */
|
||||
if(Handle.Attributes & XTBL_TUI_DIALOG_ACTIVE_INPUT)
|
||||
{
|
||||
BlSetCursorPosition(Handle.PosX + 4 + TextCursorPosition, Handle.PosY + Handle.Height - 4);
|
||||
@ -1395,3 +1630,164 @@ BlpDrawDialogProgressBar(IN PXTBL_DIALOG_HANDLE Handle,
|
||||
BlDisableConsoleCursor();
|
||||
BlConsoleWrite(ProgressBar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a text-based boot edition menu.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies a pointer to the edition menu handle.
|
||||
*
|
||||
* @return This function does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
VOID
|
||||
BlpDrawEditMenu(OUT PXTBL_DIALOG_HANDLE Handle)
|
||||
{
|
||||
/* Query console screen resolution */
|
||||
BlQueryConsoleMode(&Handle->ResX, &Handle->ResY);
|
||||
|
||||
/* Set boot menu parameters */
|
||||
Handle->Attributes = 0;
|
||||
Handle->DialogColor = EFI_TEXT_BGCOLOR_BLACK;
|
||||
Handle->TextColor = EFI_TEXT_FGCOLOR_LIGHTGRAY;
|
||||
Handle->PosX = 3;
|
||||
Handle->PosY = 3;
|
||||
Handle->Width = Handle->ResX - 6;
|
||||
Handle->Height = Handle->ResY - 10;
|
||||
|
||||
/* Clear screen and disable cursor */
|
||||
BlSetConsoleAttributes(Handle->DialogColor | Handle->TextColor);
|
||||
BlClearConsoleScreen();
|
||||
BlDisableConsoleCursor();
|
||||
|
||||
/* Check if debugging enabled */
|
||||
if(DEBUG)
|
||||
{
|
||||
/* Print debug version of XTLDR banner */
|
||||
BlSetCursorPosition((Handle->ResX - 44) / 2, 1);
|
||||
BlConsolePrint(L"XTLDR Boot Loader v%d.%d (%s-%s)\n",
|
||||
XTLDR_VERSION_MAJOR, XTLDR_VERSION_MINOR, XTOS_VERSION_DATE, XTOS_VERSION_HASH);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Print standard XTLDR banner */
|
||||
BlSetCursorPosition((Handle->ResX - 22) / 2, 1);
|
||||
BlConsolePrint(L"XTLDR Boot Loader v%d.%d\n", XTLDR_VERSION_MAJOR, XTLDR_VERSION_MINOR);
|
||||
}
|
||||
|
||||
/* Draw empty dialog box for boot menu */
|
||||
BlpDrawDialogBox(Handle, L"Edit Options", NULL);
|
||||
|
||||
/* Print help message below the edit menu */
|
||||
BlSetCursorPosition(0, Handle->PosY + Handle->Height);
|
||||
BlSetConsoleAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
|
||||
BlConsolePrint(L" Use cursors to change the selection. Press ENTER key to edit the chosen\n"
|
||||
L" option or ESC to return to the main boot menu.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws edit menu entry at the specified position.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies a pointer to the boot menu handle.
|
||||
*
|
||||
* @param OptionName
|
||||
* Supplies a pointer to the buffer containing a part of the menu entry name (an option name).
|
||||
*
|
||||
* @param OptionValue
|
||||
* Supplies a pointer to the buffer containing a part of the menu entry name (an option value).
|
||||
*
|
||||
* @param Position
|
||||
* Specifies entry position on the list in the boot menu.
|
||||
*
|
||||
* @param Highlighted
|
||||
* Specifies whether this entry should be highlighted or not.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlpDrawEditMenuEntry(IN PXTBL_DIALOG_HANDLE Handle,
|
||||
IN PWCHAR OptionName,
|
||||
IN PWCHAR OptionValue,
|
||||
IN UINT Position,
|
||||
IN BOOLEAN Highlighted)
|
||||
{
|
||||
BOOLEAN Allocation;
|
||||
PWCHAR DisplayValue, ShortValue;
|
||||
UINT Index;
|
||||
ULONG OptionNameLength, OptionValueLength, OptionWidth;
|
||||
EFI_STATUS Status;
|
||||
|
||||
/* Assume no allocation was made */
|
||||
Allocation = FALSE;
|
||||
|
||||
/* Set display value depending on input */
|
||||
DisplayValue = (OptionValue != NULL) ? OptionValue : L"";
|
||||
|
||||
/* Determine lengths */
|
||||
OptionNameLength = RtlWideStringLength(OptionName, 0);
|
||||
OptionValueLength = RtlWideStringLength(DisplayValue, 0);
|
||||
OptionWidth = Handle->Width - 4 - (OptionNameLength + 2);
|
||||
|
||||
/* Check if value needs to be truncated */
|
||||
if(OptionValueLength > OptionWidth)
|
||||
{
|
||||
/* Allocate buffer for new, shortened value */
|
||||
Status = BlAllocateMemoryPool((OptionWidth + 1) * sizeof(WCHAR), (PVOID *)&ShortValue);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure, print debug message and return */
|
||||
BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%zX)\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy a desired value length into the allocated buffer and append "..." */
|
||||
RtlCopyMemory(ShortValue, DisplayValue, (OptionWidth - 3) * sizeof(WCHAR));
|
||||
RtlCopyMemory(ShortValue + OptionWidth - 3, L"...", 3 * sizeof(WCHAR));
|
||||
ShortValue[OptionWidth] = L'\0';
|
||||
|
||||
/* Mark that allocation was made and set new display value */
|
||||
Allocation = TRUE;
|
||||
DisplayValue = ShortValue;
|
||||
}
|
||||
|
||||
/* Move cursor to the right position */
|
||||
BlSetCursorPosition(5, 4 + Position);
|
||||
|
||||
/* Check whether this entry should be highlighted */
|
||||
if(Highlighted)
|
||||
{
|
||||
/* Highlight this entry */
|
||||
BlSetConsoleAttributes(EFI_TEXT_BGCOLOR_LIGHTGRAY | EFI_TEXT_FGCOLOR_BLACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set default colors */
|
||||
BlSetConsoleAttributes(EFI_TEXT_BGCOLOR_BLACK | EFI_TEXT_FGCOLOR_LIGHTGRAY);
|
||||
}
|
||||
|
||||
/* Clear menu entry */
|
||||
for(Index = 0; Index < Handle->Width - 4; Index++)
|
||||
{
|
||||
BlConsolePrint(L" ");
|
||||
}
|
||||
|
||||
/* Print menu entry */
|
||||
BlSetCursorPosition(5, 4 + Position);
|
||||
BlConsolePrint(L"%S: %S", OptionName, DisplayValue);
|
||||
|
||||
/* Check if allocation was made */
|
||||
if(Allocation)
|
||||
{
|
||||
/* Free allocated memory */
|
||||
BlFreeMemoryPool(DisplayValue);
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user