mirror of https://github.com/acidanthera/audk.git
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:
parent
22a50a13e5
commit
019680b3dc
|
@ -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,
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue