summaryrefslogtreecommitdiff
path: root/ArmPlatformPkg/Bds/BootMenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'ArmPlatformPkg/Bds/BootMenu.c')
-rw-r--r--ArmPlatformPkg/Bds/BootMenu.c487
1 files changed, 487 insertions, 0 deletions
diff --git a/ArmPlatformPkg/Bds/BootMenu.c b/ArmPlatformPkg/Bds/BootMenu.c
new file mode 100644
index 0000000000..a2360d14f5
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BootMenu.c
@@ -0,0 +1,487 @@
+/** @file
+*
+* Copyright (c) 2011, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "BdsInternal.h"
+
+extern EFI_HANDLE mImageHandle;
+extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;
+
+EFI_STATUS
+BootMenuAddBootOption (
+ IN LIST_ENTRY *BootOptionsList
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY SupportedDeviceList;
+ UINTN SupportedDeviceCount;
+ BDS_SUPPORTED_DEVICE* SupportedBootDevice;
+ LIST_ENTRY* Entry;
+ UINTN SupportedDeviceSelected;
+ CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];
+ CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
+ CHAR16 *BootDescription;
+ UINT32 Attributes;
+ BDS_LOADER_TYPE BootType;
+ UINTN Index;
+ BDS_LOAD_OPTION *BdsLoadOption;
+ EFI_DEVICE_PATH* DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+
+ Attributes = 0;
+
+ //
+ // List the Boot Devices supported
+ //
+
+ // Start all the drivers first
+ BdsConnectAllDrivers ();
+
+ // List the supported devices
+ Status = BootDeviceListSupportedInit (&SupportedDeviceList);
+ ASSERT_EFI_ERROR(Status);
+
+ SupportedDeviceCount = 0;
+ for (Entry = GetFirstNode (&SupportedDeviceList);
+ !IsNull (&SupportedDeviceList,Entry);
+ Entry = GetNextNode (&SupportedDeviceList,Entry)
+ )
+ {
+ SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
+ Print(L"[%d] %s\n",SupportedDeviceCount+1,SupportedBootDevice->Description);
+
+ DEBUG_CODE_BEGIN();
+ CHAR16* DevicePathTxt;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+
+ Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(SupportedBootDevice->DevicePathProtocol,TRUE,TRUE);
+
+ Print(L"\t- %s\n",DevicePathTxt);
+
+ FreePool(DevicePathTxt);
+ DEBUG_CODE_END();
+
+ SupportedDeviceCount++;
+ }
+
+ if (SupportedDeviceCount == 0) {
+ Print(L"There is no supported device.\n");
+ Status = EFI_ABORTED;
+ goto EXIT;
+ }
+
+ //
+ // Select the Boot Device
+ //
+ SupportedDeviceSelected = 0;
+ while (SupportedDeviceSelected == 0) {
+ Print(L"Select the Boot Device: ");
+ Status = GetHIInputInteger (&SupportedDeviceSelected);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto EXIT;
+ } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {
+ Print(L"Invalid input (max %d)\n",SupportedDeviceSelected);
+ SupportedDeviceSelected = 0;
+ }
+ }
+
+ //
+ // Get the Device Path for the selected boot device
+ //
+ Index = 1;
+ for (Entry = GetFirstNode (&SupportedDeviceList);
+ !IsNull (&SupportedDeviceList,Entry);
+ Entry = GetNextNode (&SupportedDeviceList,Entry)
+ )
+ {
+ if (Index == SupportedDeviceSelected) {
+ SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
+ break;
+ }
+ Index++;
+ }
+
+ // Create the specific device path node
+ Status = SupportedBootDevice->Support->CreateDevicePathNode (SupportedBootDevice, &DevicePathNode, &BootType, &Attributes);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto EXIT;
+ }
+ // Append the Device Path node to the select device path
+ DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);
+
+ Print(L"Arguments to pass to the binary: ");
+ Status = GetHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto FREE_DEVICE_PATH;
+ }
+
+ Print(L"Description for this new Entry: ");
+ Status = GetHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto FREE_DEVICE_PATH;
+ }
+
+ // Convert Ascii into Unicode
+ BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));
+ AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);
+
+ // Create new entry
+ Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, AsciiBootOption, &BdsLoadOption);
+ if (!EFI_ERROR(Status)) {
+ InsertTailList (BootOptionsList,&BdsLoadOption->Link);
+ }
+
+ FreePool (BootDescription);
+
+FREE_DEVICE_PATH:
+ FreePool (DevicePath);
+
+EXIT:
+ BootDeviceListSupportedFree (&SupportedDeviceList);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+BootMenuSelectBootOption (
+ IN LIST_ENTRY *BootOptionsList,
+ IN CONST CHAR16* InputStatement,
+ OUT BDS_LOAD_OPTION **BdsLoadOption
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY* Entry;
+ BDS_LOAD_OPTION *BootOption;
+ UINTN BootOptionSelected;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ // Display the list of supported boot devices
+ BootOptionCount = 1;
+ for (Entry = GetFirstNode (BootOptionsList);
+ !IsNull (BootOptionsList,Entry);
+ Entry = GetNextNode (BootOptionsList,Entry)
+ )
+ {
+ BootOption = LOAD_OPTION_FROM_LINK(Entry);
+ Print(L"[%d] %s\n",BootOptionCount,BootOption->Description);
+
+ DEBUG_CODE_BEGIN();
+ CHAR16* DevicePathTxt;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+
+ Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
+
+ Print(L"\t- %s\n",DevicePathTxt);
+ if ((BootOption->OptionalData != NULL) && (BootOption->OptionalData->Arguments != NULL)) {
+ Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);
+ }
+
+ FreePool(DevicePathTxt);
+ DEBUG_CODE_END();
+
+ BootOptionCount++;
+ }
+
+ // 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) {
+ *BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);
+ break;
+ }
+ Index++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootMenuRemoveBootOption (
+ IN LIST_ENTRY *BootOptionsList
+ )
+{
+ EFI_STATUS Status;
+ BDS_LOAD_OPTION *BootOption;
+
+ Status = BootMenuSelectBootOption (BootOptionsList,L"Delete entry: ",&BootOption);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // Delete the BDS Load option structures
+ BootOptionDelete (BootOption);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootMenuUpdateBootOption (
+ IN LIST_ENTRY *BootOptionsList
+ )
+{
+ EFI_STATUS Status;
+ BDS_LOAD_OPTION *BootOption;
+ BDS_LOAD_OPTION_SUPPORT* DeviceSupport;
+ CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];
+ CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
+ CHAR16 *BootDescription;
+ EFI_DEVICE_PATH* DevicePath;
+ UINT32 Attributes;
+ BDS_LOADER_TYPE BootType;
+
+ Status = BootMenuSelectBootOption (BootOptionsList,L"Update entry: ",&BootOption);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // Get the device support for this Boot Option
+ Status = BootDeviceGetDeviceSupport (BootOption,&DeviceSupport);
+ if (EFI_ERROR(Status)) {
+ Print(L"Impossible to retrieve the supported device for the update\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = DeviceSupport->UpdateDevicePathNode (BootOption,&DevicePath,&BootType,&Attributes);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto EXIT;
+ }
+
+ Print(L"Arguments to pass to the binary: ");
+ if (BootOption->OptionalData) {
+ AsciiStrnCpy(AsciiBootOption,BootOption->OptionalData->Arguments,BOOT_DEVICE_FILEPATH_MAX);
+ } else {
+ AsciiBootOption[0] = '\0';
+ }
+ Status = EditHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto FREE_DEVICE_PATH;
+ }
+
+ Print(L"Description for this new Entry: ");
+ UnicodeStrToAsciiStr (BootOption->Description,AsciiBootDescription);
+ Status = EditHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);
+ if (EFI_ERROR(Status)) {
+ Status = EFI_ABORTED;
+ goto FREE_DEVICE_PATH;
+ }
+
+ // Convert Ascii into Unicode
+ BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));
+ AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);
+
+ // Update the entry
+ Status = BootOptionUpdate (BootOption, Attributes, BootDescription, DevicePath, BootType, AsciiBootOption);
+
+ FreePool (BootDescription);
+
+FREE_DEVICE_PATH:
+ FreePool (DevicePath);
+
+EXIT:
+ return Status;
+}
+
+struct BOOT_MANAGER_ENTRY {
+ CONST CHAR16* Description;
+ EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
+} BootManagerEntries[] = {
+ { L"Add Boot Device Entry", BootMenuAddBootOption },
+ { L"Update Boot Device Entry", BootMenuUpdateBootOption },
+ { L"Remove Boot Device Entry", BootMenuRemoveBootOption },
+};
+
+EFI_STATUS
+BootMenuManager (
+ IN LIST_ENTRY *BootOptionsList
+ )
+{
+ UINTN Index;
+ UINTN OptionSelected;
+ UINTN BootManagerEntryCount;
+ EFI_STATUS Status;
+
+ BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);
+
+ while (TRUE) {
+ // Display Boot Manager menu
+ for (Index = 0; Index < BootManagerEntryCount; Index++) {
+ Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);
+ }
+ Print(L"[%d] Return to main menu\n",Index+1);
+
+ // Select which entry to call
+ Print(L"Choice: ");
+ Status = GetHIInputInteger (&OptionSelected);
+ if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {
+ return EFI_SUCCESS;
+ } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {
+ Status = BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootEBL (
+ IN LIST_ENTRY *BootOptionsList
+ )
+{
+ EFI_STATUS Status;
+
+ // Start EFI Shell
+ Status = BdsLoadApplication(mImageHandle, L"Ebl");
+ if (Status == EFI_NOT_FOUND) {
+ Print (L"Error: EFI Application not found.\n");
+ } else if (EFI_ERROR(Status)) {
+ Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);
+ }
+
+ return Status;
+}
+
+struct BOOT_MAIN_ENTRY {
+ CONST CHAR16* Description;
+ EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
+} BootMainEntries[] = {
+ { L"EBL", BootEBL },
+ { L"Boot Manager", BootMenuManager },
+};
+
+
+EFI_STATUS
+BootMenuMain (
+ VOID
+ )
+{
+ LIST_ENTRY BootOptionsList;
+ UINTN OptionCount;
+ UINTN BootOptionCount;
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ BDS_LOAD_OPTION *BootOption;
+ UINTN BootOptionSelected;
+ UINTN Index;
+ UINTN BootMainEntryCount;
+
+ BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
+
+ // Get Boot#### list
+ BootOptionList (&BootOptionsList);
+
+ while (TRUE) {
+ OptionCount = 1;
+
+ // Display the Boot options
+ for (Entry = GetFirstNode (&BootOptionsList);
+ !IsNull (&BootOptionsList,Entry);
+ Entry = GetNextNode (&BootOptionsList,Entry)
+ )
+ {
+ BootOption = LOAD_OPTION_FROM_LINK(Entry);
+
+ Print(L"[%d] %s\n",OptionCount,BootOption->Description);
+
+ DEBUG_CODE_BEGIN();
+ CHAR16* DevicePathTxt;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+
+ Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
+
+ Print(L"\t- %s\n",DevicePathTxt);
+ if (BootOption->OptionalData != NULL) {
+ Print(L"\t- LoaderType: %d\n",BootOption->OptionalData->LoaderType);
+ if (BootOption->OptionalData->Arguments != NULL) {
+ Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);
+ }
+ }
+
+ FreePool(DevicePathTxt);
+ DEBUG_CODE_END();
+
+ OptionCount++;
+ }
+ BootOptionCount = OptionCount-1;
+
+ // Display the hardcoded Boot entries
+ for (Index = 0; Index < BootMainEntryCount; Index++) {
+ Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);
+ OptionCount++;
+ }
+
+ // Request the boot entry from the user
+ BootOptionSelected = 0;
+ while (BootOptionSelected == 0) {
+ Print(L"Start: ");
+ Status = GetHIInputInteger (&BootOptionSelected);
+ if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {
+ Print(L"Invalid input (max %d)\n",(OptionCount-1));
+ BootOptionSelected = 0;
+ }
+ }
+
+ // Start the selected entry
+ if (BootOptionSelected > BootOptionCount) {
+ // Start the hardcoded entry
+ Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);
+ } else {
+ // Find the selected entry from the Boot#### list
+ Index = 1;
+ for (Entry = GetFirstNode (&BootOptionsList);
+ !IsNull (&BootOptionsList,Entry);
+ Entry = GetNextNode (&BootOptionsList,Entry)
+ )
+ {
+ if (Index == BootOptionSelected) {
+ BootOption = LOAD_OPTION_FROM_LINK(Entry);
+ break;
+ }
+ Index++;
+ }
+
+ Status = BootOptionStart (BootOption);
+ }
+ }
+
+ return Status;
+}