ArmPlatformPkg/Bds: Added boot options reordering

Added the reordering of the boot options feature to the boot manager.
The BootMenuSelectBootOption() has been split into
DisplayBootOptions() that only displays the boot options and
SelectBootOptions() that asks to select one.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Reviewed-By: Olivier Martin <olivier.martin@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15718 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Ronald Cron 2014-07-29 14:19:57 +00:00 committed by oliviermartin
parent 22a50a13e5
commit 019680b3dc
2 changed files with 317 additions and 107 deletions

View File

@ -46,6 +46,7 @@
#define UPDATE_BOOT_ENTRY L"Update entry: "
#define DELETE_BOOT_ENTRY L"Delete entry: "
#define MOVE_BOOT_ENTRY L"Move entry: "
typedef enum {
BDS_LOADER_EFI_APPLICATION = 0,

View File

@ -19,7 +19,162 @@
extern EFI_HANDLE mImageHandle;
extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;
/**
Worker function that displays the list of boot options that is passed in.
The function loops over the entries of the list of boot options that is passed
in. For each entry, the boot option description is displayed on a single line
along with the position of the option in the list. In debug mode, the UEFI
device path and the arguments of the boot option are displayed as well in
subsequent lines.
@param[in] BootOptionsList List of the boot options
**/
STATIC
VOID
DisplayBootOptions (
IN LIST_ENTRY* BootOptionsList
)
{
EFI_STATUS Status;
UINTN BootOptionCount;
LIST_ENTRY *Entry;
BDS_LOAD_OPTION *BdsLoadOption;
BOOLEAN IsUnicode;
BootOptionCount = 0 ;
for (Entry = GetFirstNode (BootOptionsList);
!IsNull (BootOptionsList, Entry);
Entry = GetNextNode (BootOptionsList, Entry)
) {
BdsLoadOption = LOAD_OPTION_FROM_LINK (Entry);
Print (L"[%d] %s\n", ++BootOptionCount, BdsLoadOption->Description);
DEBUG_CODE_BEGIN ();
CHAR16* DevicePathTxt;
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
ARM_BDS_LOADER_TYPE LoaderType;
ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
Status = gBS->LocateProtocol (
&gEfiDevicePathToTextProtocolGuid,
NULL,
(VOID **)&DevicePathToTextProtocol
);
ASSERT_EFI_ERROR (Status);
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (
BdsLoadOption->FilePathList,
TRUE,
TRUE
);
Print (L"\t- %s\n", DevicePathTxt);
OptionalData = BdsLoadOption->OptionalData;
if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {
LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) ||
(LoaderType == BDS_LOADER_KERNEL_LINUX_FDT ) ) {
Print (L"\t- Arguments: %a\n", &OptionalData->Arguments.LinuxArguments + 1);
}
} else if (OptionalData != NULL) {
if (IsPrintableString (OptionalData, &IsUnicode)) {
if (IsUnicode) {
Print (L"\t- Arguments: %s\n", OptionalData);
} else {
AsciiPrint ("\t- Arguments: %a\n", OptionalData);
}
}
}
FreePool (DevicePathTxt);
DEBUG_CODE_END ();
}
}
/**
Worker function that asks for a boot option to be selected and returns a
pointer to the structure describing the selected boot option.
@param[in] BootOptionsList List of the boot options
@retval EFI_SUCCESS Selection succeeded
@retval !EFI_SUCCESS Input error or input cancelled
**/
STATIC
EFI_STATUS
SelectBootOption (
IN LIST_ENTRY* BootOptionsList,
IN CONST CHAR16* InputStatement,
OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry
)
{
EFI_STATUS Status;
UINTN BootOptionCount;
UINT16 *BootOrder;
LIST_ENTRY* Entry;
UINTN BootOptionSelected;
UINTN Index;
// Get the number of boot options
Status = GetGlobalEnvironmentVariable (
L"BootOrder", NULL, &BootOptionCount, (VOID**)&BootOrder
);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
FreePool (BootOrder);
BootOptionCount /= sizeof (UINT16);
// Check if a valid boot option(s) is found
if (BootOptionCount == 0) {
if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {
Print (L"Nothing to remove!\n");
} else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {
Print (L"Nothing to update!\n");
} else if (StrCmp (InputStatement, MOVE_BOOT_ENTRY) == 0) {
Print (L"Nothing to move!\n");
} else {
Print (L"No supported Boot Entry.\n");
}
return EFI_NOT_FOUND;
}
// Get the index of the boot device to delete
BootOptionSelected = 0;
while (BootOptionSelected == 0) {
Print (InputStatement);
Status = GetHIInputInteger (&BootOptionSelected);
if (EFI_ERROR (Status)) {
Print (L"\n");
goto ErrorExit;
} else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {
Print (L"Invalid input (max %d)\n", BootOptionCount);
BootOptionSelected = 0;
}
}
// Get the structure of the Boot device to delete
Index = 1;
for (Entry = GetFirstNode (BootOptionsList);
!IsNull (BootOptionsList, Entry);
Entry = GetNextNode (BootOptionsList,Entry)
)
{
if (Index == BootOptionSelected) {
*BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK (Entry);
break;
}
Index++;
}
ErrorExit:
return Status;
}
STATIC
EFI_STATUS
SelectBootDevice (
OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice
@ -254,109 +409,6 @@ EXIT:
return Status;
}
STATIC
EFI_STATUS
BootMenuSelectBootOption (
IN LIST_ENTRY* BootOptionsList,
IN CONST CHAR16* InputStatement,
OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry
)
{
EFI_STATUS Status;
LIST_ENTRY* Entry;
BDS_LOAD_OPTION* BdsLoadOption;
UINTN BootOptionSelected;
UINTN BootOptionCount;
UINTN Index;
BOOLEAN IsUnicode;
// Display the list of supported boot devices
BootOptionCount = 0;
for (Entry = GetFirstNode (BootOptionsList);
!IsNull (BootOptionsList,Entry);
Entry = GetNextNode (BootOptionsList, Entry)
)
{
BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);
Print (L"[%d] %s\n", (BootOptionCount + 1), BdsLoadOption->Description);
DEBUG_CODE_BEGIN();
CHAR16* DevicePathTxt;
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
ARM_BDS_LOADER_TYPE LoaderType;
ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
ASSERT_EFI_ERROR(Status);
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BdsLoadOption->FilePathList,TRUE,TRUE);
Print(L"\t- %s\n",DevicePathTxt);
OptionalData = BdsLoadOption->OptionalData;
if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {
LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
Print (L"\t- Arguments: %a\n",&OptionalData->Arguments.LinuxArguments + 1);
}
} else if (OptionalData != NULL) {
if (IsPrintableString (OptionalData, &IsUnicode)) {
if (IsUnicode) {
Print (L"\t- Arguments: %s\n", OptionalData);
} else {
AsciiPrint ("\t- Arguments: %a\n", OptionalData);
}
}
}
FreePool(DevicePathTxt);
DEBUG_CODE_END();
BootOptionCount++;
}
// Check if a valid boot option(s) is found
if (BootOptionCount == 0) {
if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {
Print (L"Nothing to remove!\n");
} else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {
Print (L"Couldn't find valid boot entries\n");
} else{
Print (L"No supported Boot Entry.\n");
}
return EFI_NOT_FOUND;
}
// Get the index of the boot device to delete
BootOptionSelected = 0;
while (BootOptionSelected == 0) {
Print(InputStatement);
Status = GetHIInputInteger (&BootOptionSelected);
if (EFI_ERROR(Status)) {
return Status;
} else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {
Print(L"Invalid input (max %d)\n",BootOptionCount);
BootOptionSelected = 0;
}
}
// Get the structure of the Boot device to delete
Index = 1;
for (Entry = GetFirstNode (BootOptionsList);
!IsNull (BootOptionsList, Entry);
Entry = GetNextNode (BootOptionsList,Entry)
)
{
if (Index == BootOptionSelected) {
*BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK(Entry);
break;
}
Index++;
}
return EFI_SUCCESS;
}
EFI_STATUS
BootMenuRemoveBootOption (
IN LIST_ENTRY *BootOptionsList
@ -365,8 +417,9 @@ BootMenuRemoveBootOption (
EFI_STATUS Status;
BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
Status = BootMenuSelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);
if (EFI_ERROR(Status)) {
DisplayBootOptions (BootOptionsList);
Status = SelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);
if (EFI_ERROR (Status)) {
return Status;
}
@ -410,8 +463,9 @@ BootMenuUpdateBootOption (
BOOLEAN IsPrintable;
BOOLEAN IsUnicode;
Status = BootMenuSelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);
if (EFI_ERROR(Status)) {
DisplayBootOptions (BootOptionsList);
Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);
if (EFI_ERROR (Status)) {
return Status;
}
BootOption = BootOptionEntry->BdsLoadOption;
@ -589,6 +643,160 @@ EXIT:
return Status;
}
/**
Reorder boot options
Ask for the boot option to move and then move it when up or down arrows
are pressed. This function is called when the user selects the "Reorder Boot
Device Entries" entry in the boot manager menu.
The order of the boot options in BootOptionList and in the UEFI BootOrder
global variable are kept coherent until the user confirm his reordering (ie:
he does not exit by pressing escape).
@param[in] BootOptionsList List of the boot devices constructed in
BootMenuMain()
@retval EFI_SUCCESS No error encountered.
@retval !EFI_SUCCESS An error has occured either in the selection of the
boot option to move or while interacting with the user.
**/
STATIC
EFI_STATUS
BootMenuReorderBootOptions (
IN LIST_ENTRY *BootOptionsList
)
{
EFI_STATUS Status;
BDS_LOAD_OPTION_ENTRY *BootOptionEntry;
LIST_ENTRY *SelectedEntry;
LIST_ENTRY *PrevEntry;
BOOLEAN Move;
BOOLEAN Save;
BOOLEAN Cancel;
UINTN WaitIndex;
EFI_INPUT_KEY Key;
LIST_ENTRY *SecondEntry;
UINTN BootOrderSize;
UINT16 *BootOrder;
LIST_ENTRY *Entry;
UINTN Index;
DisplayBootOptions (BootOptionsList);
// Ask to select the boot option to move
while (TRUE) {
Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
SelectedEntry = &BootOptionEntry->Link;
// Note down the previous entry in the list to be able to cancel changes
PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);
// Start of interaction
while (TRUE) {
Print (
L"* Use up/down arrows to move the entry '%s'",
BootOptionEntry->BdsLoadOption->Description
);
// Wait for a move, save or cancel request
Move = FALSE;
Save = FALSE;
Cancel = FALSE;
do {
Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
if (!EFI_ERROR (Status)) {
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
}
if (EFI_ERROR (Status)) {
Print (L"\n");
goto ErrorExit;
}
switch (Key.ScanCode) {
case SCAN_NULL:
Save = (Key.UnicodeChar == CHAR_LINEFEED) ||
(Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||
(Key.UnicodeChar == 0x7f);
break;
case SCAN_UP:
SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);
Move = SecondEntry != BootOptionsList;
break;
case SCAN_DOWN:
SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);
Move = SecondEntry != BootOptionsList;
break;
case SCAN_ESC:
Cancel = TRUE;
break;
}
} while ((!Move) && (!Save) && (!Cancel));
if (Move) {
SwapListEntries (SelectedEntry, SecondEntry);
} else {
if (Save) {
Status = GetGlobalEnvironmentVariable (
L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder
);
BootOrderSize /= sizeof (UINT16);
if (!EFI_ERROR (Status)) {
// The order of the boot options in the 'BootOptionsList' is the
// new order that has been just defined by the user. Save this new
// order in "BootOrder" UEFI global variable.
Entry = GetFirstNode (BootOptionsList);
for (Index = 0; Index < BootOrderSize; Index++) {
BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;
Entry = GetNextNode (BootOptionsList, Entry);
}
Status = gRT->SetVariable (
(CHAR16*)L"BootOrder",
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
BootOrderSize * sizeof (UINT16),
BootOrder
);
FreePool (BootOrder);
}
if (EFI_ERROR (Status)) {
Print (L"\nAn error occurred, move not completed!\n");
Cancel = TRUE;
}
}
if (Cancel) {
//
// Restore initial position of the selected boot option
//
RemoveEntryList (SelectedEntry);
InsertHeadList (PrevEntry, SelectedEntry);
}
}
Print (L"\n");
DisplayBootOptions (BootOptionsList);
// Saved or cancelled, back to the choice of boot option to move
if (!Move) {
break;
}
}
}
ErrorExit:
return Status ;
}
EFI_STATUS
UpdateFdtPath (
IN LIST_ENTRY *BootOptionsList
@ -699,6 +907,7 @@ struct BOOT_MANAGER_ENTRY {
{ L"Add Boot Device Entry", BootMenuAddBootOption },
{ L"Update Boot Device Entry", BootMenuUpdateBootOption },
{ L"Remove Boot Device Entry", BootMenuRemoveBootOption },
{ L"Reorder Boot Device Entries", BootMenuReorderBootOptions },
{ L"Update FDT path", UpdateFdtPath },
{ L"Set Boot Timeout", BootMenuSetBootTimeout },
};