+++ /dev/null
-/** @file\r
-*\r
-* Copyright (c) 2011 - 2015, ARM Limited. All rights reserved.\r
-*\r
-* This program and the accompanying materials\r
-* are licensed and made available under the terms and conditions of the BSD License\r
-* which accompanies this distribution. The full text of the license may be found at\r
-* http://opensource.org/licenses/bsd-license.php\r
-*\r
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#include "BdsInternal.h"\r
-\r
-#include <libfdt.h>\r
-\r
-/**\r
- Worker function that displays the list of boot options that is passed in.\r
-\r
- The function loops over the entries of the list of boot options that is passed\r
- in. For each entry, the boot option description is displayed on a single line\r
- along with the position of the option in the list. In debug mode, the UEFI\r
- device path and the arguments of the boot option are displayed as well in\r
- subsequent lines.\r
-\r
- @param[in] BootOptionsList List of the boot options\r
-\r
-**/\r
-STATIC\r
-VOID\r
-DisplayBootOptions (\r
- IN LIST_ENTRY* BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN BootOptionCount;\r
- LIST_ENTRY *Entry;\r
- BDS_LOAD_OPTION *BdsLoadOption;\r
- BOOLEAN IsUnicode;\r
-\r
- BootOptionCount = 0 ;\r
- for (Entry = GetFirstNode (BootOptionsList);\r
- !IsNull (BootOptionsList, Entry);\r
- Entry = GetNextNode (BootOptionsList, Entry)\r
- ) {\r
-\r
- BdsLoadOption = LOAD_OPTION_FROM_LINK (Entry);\r
- Print (L"[%d] %s\n", ++BootOptionCount, BdsLoadOption->Description);\r
-\r
- DEBUG_CODE_BEGIN ();\r
- CHAR16* DevicePathTxt;\r
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
-\r
- Status = gBS->LocateProtocol (\r
- &gEfiDevicePathToTextProtocolGuid,\r
- NULL,\r
- (VOID **)&DevicePathToTextProtocol\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (\r
- BdsLoadOption->FilePathList,\r
- TRUE,\r
- TRUE\r
- );\r
- Print (L"\t- %s\n", DevicePathTxt);\r
-\r
- if (IsPrintableString (BdsLoadOption->OptionalData, &IsUnicode)) {\r
- if (IsUnicode) {\r
- Print (L"\t- Arguments: %s\n", BdsLoadOption->OptionalData);\r
- } else {\r
- AsciiPrint ("\t- Arguments: %a\n", BdsLoadOption->OptionalData);\r
- }\r
- }\r
-\r
- FreePool (DevicePathTxt);\r
- DEBUG_CODE_END ();\r
- }\r
-}\r
-\r
-/**\r
- Worker function that asks for a boot option to be selected and returns a\r
- pointer to the structure describing the selected boot option.\r
-\r
- @param[in] BootOptionsList List of the boot options\r
-\r
- @retval EFI_SUCCESS Selection succeeded\r
- @retval !EFI_SUCCESS Input error or input cancelled\r
-\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-SelectBootOption (\r
- IN LIST_ENTRY* BootOptionsList,\r
- IN CONST CHAR16* InputStatement,\r
- OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN BootOptionCount;\r
- UINT16 *BootOrder;\r
- LIST_ENTRY* Entry;\r
- UINTN BootOptionSelected;\r
- UINTN Index;\r
-\r
- // Get the number of boot options\r
- Status = GetGlobalEnvironmentVariable (\r
- L"BootOrder", NULL, &BootOptionCount, (VOID**)&BootOrder\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ErrorExit;\r
- }\r
- FreePool (BootOrder);\r
- BootOptionCount /= sizeof (UINT16);\r
-\r
- // Check if a valid boot option(s) is found\r
- if (BootOptionCount == 0) {\r
- if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {\r
- Print (L"Nothing to remove!\n");\r
- } else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {\r
- Print (L"Nothing to update!\n");\r
- } else if (StrCmp (InputStatement, MOVE_BOOT_ENTRY) == 0) {\r
- Print (L"Nothing to move!\n");\r
- } else {\r
- Print (L"No supported Boot Entry.\n");\r
- }\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- // Get the index of the boot device to delete\r
- BootOptionSelected = 0;\r
- while (BootOptionSelected == 0) {\r
- Print (InputStatement);\r
- Status = GetHIInputInteger (&BootOptionSelected);\r
- if (EFI_ERROR (Status)) {\r
- Print (L"\n");\r
- goto ErrorExit;\r
- } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {\r
- Print (L"Invalid input (max %d)\n", BootOptionCount);\r
- BootOptionSelected = 0;\r
- }\r
- }\r
-\r
- // Get the structure of the Boot device to delete\r
- Index = 1;\r
- for (Entry = GetFirstNode (BootOptionsList);\r
- !IsNull (BootOptionsList, Entry);\r
- Entry = GetNextNode (BootOptionsList,Entry)\r
- )\r
- {\r
- if (Index == BootOptionSelected) {\r
- *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK (Entry);\r
- break;\r
- }\r
- Index++;\r
- }\r
-\r
-ErrorExit:\r
- return Status;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-SelectBootDevice (\r
- OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice\r
- )\r
-{\r
- EFI_STATUS Status;\r
- LIST_ENTRY SupportedDeviceList;\r
- UINTN SupportedDeviceCount;\r
- LIST_ENTRY* Entry;\r
- UINTN SupportedDeviceSelected;\r
- UINTN Index;\r
-\r
- //\r
- // List the Boot Devices supported\r
- //\r
-\r
- // Start all the drivers first\r
- BdsConnectAllDrivers ();\r
-\r
- // List the supported devices\r
- Status = BootDeviceListSupportedInit (&SupportedDeviceList);\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- SupportedDeviceCount = 0;\r
- for (Entry = GetFirstNode (&SupportedDeviceList);\r
- !IsNull (&SupportedDeviceList,Entry);\r
- Entry = GetNextNode (&SupportedDeviceList,Entry)\r
- )\r
- {\r
- *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
- Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);\r
-\r
- DEBUG_CODE_BEGIN();\r
- CHAR16* DevicePathTxt;\r
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
-\r
- Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
- ASSERT_EFI_ERROR(Status);\r
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);\r
-\r
- Print(L"\t- %s\n",DevicePathTxt);\r
-\r
- FreePool(DevicePathTxt);\r
- DEBUG_CODE_END();\r
-\r
- SupportedDeviceCount++;\r
- }\r
-\r
- if (SupportedDeviceCount == 0) {\r
- Print(L"There is no supported device.\n");\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Select the Boot Device\r
- //\r
- SupportedDeviceSelected = 0;\r
- while (SupportedDeviceSelected == 0) {\r
- Print(L"Select the Boot Device: ");\r
- Status = GetHIInputInteger (&SupportedDeviceSelected);\r
- if (EFI_ERROR(Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {\r
- Print(L"Invalid input (max %d)\n",SupportedDeviceCount);\r
- SupportedDeviceSelected = 0;\r
- }\r
- }\r
-\r
- //\r
- // Get the Device Path for the selected boot device\r
- //\r
- Index = 1;\r
- for (Entry = GetFirstNode (&SupportedDeviceList);\r
- !IsNull (&SupportedDeviceList,Entry);\r
- Entry = GetNextNode (&SupportedDeviceList,Entry)\r
- )\r
- {\r
- if (Index == SupportedDeviceSelected) {\r
- *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
- break;\r
- }\r
- Index++;\r
- }\r
-\r
-EXIT:\r
- BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice);\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-BootMenuAddBootOption (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r
- CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
- CHAR16 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
- UINT32 Attributes;\r
- BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;\r
- EFI_DEVICE_PATH *DevicePath;\r
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNodes;\r
- UINT8* OptionalData;\r
- UINTN OptionalDataSize;\r
- BOOLEAN EfiBinary;\r
- CHAR16 *LinuxDevicePath;\r
-\r
- Attributes = 0;\r
- SupportedBootDevice = NULL;\r
-\r
- // List the Boot Devices supported\r
- Status = SelectBootDevice (&SupportedBootDevice);\r
- if (EFI_ERROR(Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- // Create the specific device path node\r
- if (FeaturePcdGet (PcdBdsLinuxSupport) && mLinuxLoaderDevicePath) {\r
- Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);\r
- } else {\r
- Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application", &DevicePathNodes);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
- // Append the Device Path to the selected device path\r
- DevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNodes);\r
- if (DevicePath == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- // Is it an EFI application?\r
- if (FeaturePcdGet (PcdBdsLinuxSupport) && mLinuxLoaderDevicePath) {\r
- Status = IsEfiBinary (DevicePath, &EfiBinary);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- if (EfiBinary == FALSE) {\r
- Print (L"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");\r
- Print (L"Supported command line formats by the embedded Linux Loader:\n");\r
- Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");\r
- Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");\r
- Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");\r
-\r
- // Copy the Linux path into the command line\r
- LinuxDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
- CopyMem (CmdLine, LinuxDevicePath, MAX (sizeof (CmdLine), StrSize (LinuxDevicePath)));\r
- FreePool (LinuxDevicePath);\r
-\r
- // Free the generated Device Path\r
- FreePool (DevicePath);\r
- // and use the embedded Linux Loader as the EFI application\r
- DevicePath = mLinuxLoaderDevicePath;\r
- } else {\r
- CmdLine[0] = L'\0';\r
- }\r
- } else {\r
- CmdLine[0] = L'\0';\r
- }\r
-\r
- Print (L"Arguments to pass to the EFI Application: ");\r
- Status = EditHIInputStr (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- OptionalData = (UINT8*)CmdLine;\r
- OptionalDataSize = StrSize (CmdLine);\r
-\r
- Print(L"Description for this new Entry: ");\r
- Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
- if (EFI_ERROR(Status)) {\r
- Status = EFI_ABORTED;\r
- goto FREE_DEVICE_PATH;\r
- }\r
-\r
- // Create new entry\r
- BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));\r
- Status = BootOptionCreate (Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);\r
- if (!EFI_ERROR(Status)) {\r
- InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);\r
- }\r
-\r
-FREE_DEVICE_PATH:\r
- FreePool (DevicePath);\r
-\r
-EXIT:\r
- if (Status == EFI_ABORTED) {\r
- Print(L"\n");\r
- }\r
- FreePool(SupportedBootDevice);\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-BootMenuRemoveBootOption (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
-\r
- DisplayBootOptions (BootOptionsList);\r
- Status = SelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // If the Boot Option was attached to a list remove it\r
- if (!IsListEmpty (&BootOptionEntry->Link)) {\r
- // Remove the entry from the list\r
- RemoveEntryList (&BootOptionEntry->Link);\r
- }\r
-\r
- // Delete the BDS Load option structures\r
- BootOptionDelete (BootOptionEntry->BdsLoadOption);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-BootMenuUpdateBootOption (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
- BDS_LOAD_OPTION *BootOption;\r
- BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
- CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
- CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
- CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];\r
- CHAR16 *LinuxDevicePath;\r
- EFI_DEVICE_PATH *DevicePath;\r
- UINT8* OptionalData;\r
- UINTN OptionalDataSize;\r
- BOOLEAN IsPrintable;\r
- BOOLEAN IsUnicode;\r
- BOOLEAN EfiBinary;\r
-\r
- DisplayBootOptions (BootOptionsList);\r
- Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- BootOption = BootOptionEntry->BdsLoadOption;\r
-\r
- // Get the device support for this Boot Option\r
- Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);\r
- if (EFI_ERROR(Status)) {\r
- Print(L"Not possible to retrieve the supported device for the update\n");\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- EfiBinary = TRUE;\r
- if (FeaturePcdGet (PcdBdsLinuxSupport) && mLinuxLoaderDevicePath) {\r
- Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- // Is it an EFI application?\r
- Status = IsEfiBinary (DevicePath, &EfiBinary);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- if (EfiBinary == FALSE) {\r
- Print (L"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");\r
- Print (L"Supported command line formats by the embedded Linux Loader:\n");\r
- Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");\r
- Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");\r
- Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");\r
-\r
- // Copy the Linux path into the command line\r
- LinuxDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
- CopyMem (UnicodeCmdLine, LinuxDevicePath, MAX (sizeof (UnicodeCmdLine), StrSize (LinuxDevicePath)));\r
- FreePool (LinuxDevicePath);\r
-\r
- // Free the generated Device Path\r
- FreePool (DevicePath);\r
- // and use the embedded Linux Loader as the EFI application\r
- DevicePath = mLinuxLoaderDevicePath;\r
-\r
- // The command line is a unicode printable string\r
- IsPrintable = TRUE;\r
- IsUnicode = TRUE;\r
- }\r
- } else {\r
- Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application", &DevicePath);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
- }\r
-\r
- Print (L"Arguments to pass to the EFI Application: ");\r
-\r
- // When the command line has not been initialized by the embedded Linux loader earlier\r
- if (EfiBinary) {\r
- if (BootOption->OptionalDataSize > 0) {\r
- IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);\r
- if (IsPrintable) {\r
- //\r
- // The size in bytes of the string, final zero included, should\r
- // be equal to or at least lower than "BootOption->OptionalDataSize"\r
- // and the "IsPrintableString()" has already tested that the length\r
- // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,\r
- // final '\0' included. We can thus copy the string for editing\r
- // using "CopyMem()". Furthermore, note that in the case of an Unicode\r
- // string "StrnCpy()" and "StrCpy()" can not be used to copy the\r
- // string because the data pointed to by "BootOption->OptionalData"\r
- // is not necessarily 2-byte aligned.\r
- //\r
- if (IsUnicode) {\r
- CopyMem (\r
- UnicodeCmdLine, BootOption->OptionalData,\r
- MIN (sizeof (UnicodeCmdLine),\r
- BootOption->OptionalDataSize)\r
- );\r
- } else {\r
- CopyMem (\r
- CmdLine, BootOption->OptionalData,\r
- MIN (sizeof (CmdLine),\r
- BootOption->OptionalDataSize)\r
- );\r
- }\r
- }\r
- } else {\r
- UnicodeCmdLine[0] = L'\0';\r
- IsPrintable = TRUE;\r
- IsUnicode = TRUE;\r
- }\r
- }\r
-\r
- // We do not request arguments for OptionalData that cannot be printed\r
- if (IsPrintable) {\r
- if (IsUnicode) {\r
- Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto FREE_DEVICE_PATH;\r
- }\r
-\r
- OptionalData = (UINT8*)UnicodeCmdLine;\r
- OptionalDataSize = StrSize (UnicodeCmdLine);\r
- } else {\r
- Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto FREE_DEVICE_PATH;\r
- }\r
-\r
- OptionalData = (UINT8*)CmdLine;\r
- OptionalDataSize = AsciiStrSize (CmdLine);\r
- }\r
- } else {\r
- // We keep the former OptionalData\r
- OptionalData = BootOption->OptionalData;\r
- OptionalDataSize = BootOption->OptionalDataSize;\r
- }\r
-\r
- Print(L"Description for this new Entry: ");\r
- StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);\r
- Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
- if (EFI_ERROR(Status)) {\r
- Status = EFI_ABORTED;\r
- goto FREE_DEVICE_PATH;\r
- }\r
-\r
- // Update the entry\r
- Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);\r
-\r
-FREE_DEVICE_PATH:\r
- FreePool (DevicePath);\r
-\r
-EXIT:\r
- if (Status == EFI_ABORTED) {\r
- Print(L"\n");\r
- }\r
- return Status;\r
-}\r
-\r
-/**\r
- Reorder boot options\r
-\r
- Ask for the boot option to move and then move it when up or down arrows\r
- are pressed. This function is called when the user selects the "Reorder Boot\r
- Device Entries" entry in the boot manager menu.\r
- The order of the boot options in BootOptionList and in the UEFI BootOrder\r
- global variable are kept coherent until the user confirm his reordering (ie:\r
- he does not exit by pressing escape).\r
-\r
- @param[in] BootOptionsList List of the boot devices constructed in\r
- BootMenuMain()\r
-\r
- @retval EFI_SUCCESS No error encountered.\r
- @retval !EFI_SUCCESS An error has occured either in the selection of the\r
- boot option to move or while interacting with the user.\r
-\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-BootMenuReorderBootOptions (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
- LIST_ENTRY *SelectedEntry;\r
- LIST_ENTRY *PrevEntry;\r
- BOOLEAN Move;\r
- BOOLEAN Save;\r
- BOOLEAN Cancel;\r
- UINTN WaitIndex;\r
- EFI_INPUT_KEY Key;\r
- LIST_ENTRY *SecondEntry;\r
- UINTN BootOrderSize;\r
- UINT16 *BootOrder;\r
- LIST_ENTRY *Entry;\r
- UINTN Index;\r
-\r
- DisplayBootOptions (BootOptionsList);\r
-\r
- // Ask to select the boot option to move\r
- while (TRUE) {\r
- Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);\r
- if (EFI_ERROR (Status)) {\r
- goto ErrorExit;\r
- }\r
-\r
- SelectedEntry = &BootOptionEntry->Link;\r
- SecondEntry = NULL;\r
- // Note down the previous entry in the list to be able to cancel changes\r
- PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
-\r
- // Start of interaction\r
- while (TRUE) {\r
- Print (\r
- L"* Use up/down arrows to move the entry '%s'",\r
- BootOptionEntry->BdsLoadOption->Description\r
- );\r
-\r
- // Wait for a move, save or cancel request\r
- Move = FALSE;\r
- Save = FALSE;\r
- Cancel = FALSE;\r
- do {\r
- Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);\r
- if (!EFI_ERROR (Status)) {\r
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- Print (L"\n");\r
- goto ErrorExit;\r
- }\r
-\r
- switch (Key.ScanCode) {\r
- case SCAN_NULL:\r
- Save = (Key.UnicodeChar == CHAR_LINEFEED) ||\r
- (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||\r
- (Key.UnicodeChar == 0x7f);\r
- break;\r
-\r
- case SCAN_UP:\r
- SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
- Move = SecondEntry != BootOptionsList;\r
- break;\r
-\r
- case SCAN_DOWN:\r
- SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);\r
- Move = SecondEntry != BootOptionsList;\r
- break;\r
-\r
- case SCAN_ESC:\r
- Cancel = TRUE;\r
- break;\r
- }\r
- } while ((!Move) && (!Save) && (!Cancel));\r
-\r
- if (Move) {\r
- if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {\r
- SwapListEntries (SelectedEntry, SecondEntry);\r
- }\r
- } else {\r
- if (Save) {\r
- Status = GetGlobalEnvironmentVariable (\r
- L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder\r
- );\r
- BootOrderSize /= sizeof (UINT16);\r
-\r
- if (!EFI_ERROR (Status)) {\r
- // The order of the boot options in the 'BootOptionsList' is the\r
- // new order that has been just defined by the user. Save this new\r
- // order in "BootOrder" UEFI global variable.\r
- Entry = GetFirstNode (BootOptionsList);\r
- for (Index = 0; Index < BootOrderSize; Index++) {\r
- BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;\r
- Entry = GetNextNode (BootOptionsList, Entry);\r
- }\r
- Status = gRT->SetVariable (\r
- (CHAR16*)L"BootOrder",\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_NON_VOLATILE |\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
- EFI_VARIABLE_RUNTIME_ACCESS,\r
- BootOrderSize * sizeof (UINT16),\r
- BootOrder\r
- );\r
- FreePool (BootOrder);\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- Print (L"\nAn error occurred, move not completed!\n");\r
- Cancel = TRUE;\r
- }\r
- }\r
-\r
- if (Cancel) {\r
- //\r
- // Restore initial position of the selected boot option\r
- //\r
- RemoveEntryList (SelectedEntry);\r
- InsertHeadList (PrevEntry, SelectedEntry);\r
- }\r
- }\r
-\r
- Print (L"\n");\r
- DisplayBootOptions (BootOptionsList);\r
- // Saved or cancelled, back to the choice of boot option to move\r
- if (!Move) {\r
- break;\r
- }\r
- }\r
- }\r
-\r
-ErrorExit:\r
- return Status ;\r
-}\r
-\r
-EFI_STATUS\r
-UpdateFdtPath (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BDS_SUPPORTED_DEVICE *SupportedBootDevice;\r
- EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;\r
- EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;\r
- CHAR16 *FdtTextDevicePath;\r
- EFI_PHYSICAL_ADDRESS FdtBlobBase;\r
- UINTN FdtBlobSize;\r
- UINTN NumPages;\r
- EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;\r
-\r
- SupportedBootDevice = NULL;\r
-\r
- Status = SelectBootDevice (&SupportedBootDevice);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- // Create the specific device path node\r
- Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_ABORTED;\r
- goto EXIT;\r
- }\r
-\r
- if (FdtDevicePathNodes != NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
-\r
- FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
- FreePool (FdtDevicePathNodes);\r
- if (FdtDevicePath == NULL) {\r
- goto EXIT;\r
- }\r
-\r
- FdtTextDevicePath = ConvertDevicePathToText (FdtDevicePath, TRUE, TRUE);\r
- if (FdtTextDevicePath == NULL) {\r
- goto EXIT;\r
- }\r
-\r
- Status = gRT->SetVariable (\r
- (CHAR16*)L"Fdt",\r
- &gFdtVariableGuid,\r
- EFI_VARIABLE_RUNTIME_ACCESS |\r
- EFI_VARIABLE_NON_VOLATILE |\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
- StrSize (FdtTextDevicePath),\r
- FdtTextDevicePath\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- FreePool (FdtTextDevicePath);\r
- } else {\r
- Status = gRT->SetVariable (\r
- (CHAR16*)L"Fdt",\r
- &gFdtVariableGuid,\r
- EFI_VARIABLE_RUNTIME_ACCESS |\r
- EFI_VARIABLE_NON_VOLATILE |\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
- 0,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- return Status;\r
- }\r
-\r
- //\r
- // Try to load FDT from the new EFI Device Path\r
- //\r
-\r
- //\r
- // Load the FDT given its device path.\r
- // This operation may fail if the device path is not supported.\r
- //\r
- FdtBlobBase = 0;\r
- NumPages = 0;\r
- Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
- FreePool (FdtDevicePath);\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto EXIT_LOAD_FDT;\r
- }\r
-\r
- // Check the FDT header is valid. We only make this check in DEBUG mode in\r
- // case the FDT header change on production device and this ASSERT() becomes\r
- // not valid.\r
- ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
-\r
- //\r
- // Ensure the Size of the Device Tree is smaller than the size of the read file\r
- //\r
- ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
-\r
- //\r
- // Store the FDT as Runtime Service Data to prevent the Kernel from\r
- // overwritting its data.\r
- //\r
- NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
- Status = gBS->AllocatePages (\r
- AllocateAnyPages, EfiRuntimeServicesData,\r
- NumPages, &FdtConfigurationTableBase\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto EXIT_LOAD_FDT;\r
- }\r
- gBS->CopyMem (\r
- (VOID*)(UINTN)FdtConfigurationTableBase,\r
- (VOID*)(UINTN)FdtBlobBase,\r
- FdtBlobSize\r
- );\r
-\r
- //\r
- // Install the FDT into the Configuration Table\r
- //\r
- Status = gBS->InstallConfigurationTable (\r
- &gFdtTableGuid,\r
- (VOID*)(UINTN)FdtConfigurationTableBase\r
- );\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
- }\r
-\r
-EXIT_LOAD_FDT:\r
- if (EFI_ERROR (Status)) {\r
- Print (L"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");\r
- }\r
-\r
- if (FdtBlobBase != 0) {\r
- gBS->FreePages (FdtBlobBase, NumPages);\r
- }\r
-\r
-EXIT:\r
- if (Status == EFI_ABORTED) {\r
- Print (L"\n");\r
- }\r
-\r
- if (SupportedBootDevice != NULL) {\r
- FreePool (SupportedBootDevice);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Set boot timeout\r
-\r
- Ask for the boot timeout in seconds and if the input succeeds assign the\r
- input value to the UEFI global variable "Timeout". This function is called\r
- when the user selects the "Set Boot Timeout" of the boot manager menu.\r
-\r
- @param[in] BootOptionsList List of the boot devices, not used here\r
-\r
- @retval EFI_SUCCESS Boot timeout in second retrieved from the standard\r
- input and assigned to the UEFI "Timeout" global\r
- variable\r
- @retval !EFI_SUCCESS Either the input or the setting of the UEFI global\r
- variable "Timeout" has failed.\r
-**/\r
-EFI_STATUS\r
-STATIC\r
-BootMenuSetBootTimeout (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Input;\r
- UINT16 Timeout;\r
-\r
- Print (L"Timeout duration (in seconds): ");\r
- Status = GetHIInputInteger (&Input);\r
- if (EFI_ERROR (Status)) {\r
- Print (L"\n");\r
- goto ErrorExit;\r
- }\r
-\r
- Timeout = Input;\r
- Status = gRT->SetVariable (\r
- (CHAR16*)L"Timeout",\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_NON_VOLATILE |\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
- EFI_VARIABLE_RUNTIME_ACCESS,\r
- sizeof (UINT16),\r
- &Timeout\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
-ErrorExit:\r
- return Status;\r
-}\r
-\r
-struct BOOT_MANAGER_ENTRY {\r
- CONST CHAR16* Description;\r
- EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
-} BootManagerEntries[] = {\r
- { L"Add Boot Device Entry", BootMenuAddBootOption },\r
- { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
- { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
- { L"Reorder Boot Device Entries", BootMenuReorderBootOptions },\r
- { L"Update FDT path", UpdateFdtPath },\r
- { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
-};\r
-\r
-EFI_STATUS\r
-BootMenuManager (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- UINTN Index;\r
- UINTN OptionSelected;\r
- UINTN BootManagerEntryCount;\r
- EFI_STATUS Status;\r
-\r
- BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
-\r
- while (TRUE) {\r
- // Display Boot Manager menu\r
- for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
- Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
- }\r
- Print(L"[%d] Return to main menu\n",Index+1);\r
-\r
- // Select which entry to call\r
- Print(L"Choice: ");\r
- Status = GetHIInputInteger (&OptionSelected);\r
- if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
- if (EFI_ERROR(Status)) {\r
- Print(L"\n");\r
- }\r
- return EFI_SUCCESS;\r
- } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
- BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
- }\r
- }\r
- // Should never go here\r
-}\r
-\r
-EFI_STATUS\r
-BootShell (\r
- IN LIST_ENTRY *BootOptionsList\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_DEVICE_PATH* EfiShellDevicePath;\r
-\r
- // Find the EFI Shell\r
- Status = LocateEfiApplicationInFvByName (L"Shell", &EfiShellDevicePath);\r
- if (Status == EFI_NOT_FOUND) {\r
- Print (L"Error: EFI Application not found.\n");\r
- return Status;\r
- } else if (EFI_ERROR (Status)) {\r
- Print (L"Error: Status Code: 0x%X\n", (UINT32)Status);\r
- return Status;\r
- } else {\r
- // Need to connect every drivers to ensure no dependencies are missing for the application\r
- Status = BdsConnectAllDrivers ();\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));\r
- return Status;\r
- }\r
-\r
- return BdsStartEfiApplication (gImageHandle, EfiShellDevicePath, 0, NULL);\r
- }\r
-}\r
-\r
-struct BOOT_MAIN_ENTRY {\r
- CONST CHAR16* Description;\r
- EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
-} BootMainEntries[] = {\r
- { L"Shell", BootShell },\r
- { L"Boot Manager", BootMenuManager },\r
-};\r
-\r
-EFI_STATUS\r
-BootMenuMain (\r
- VOID\r
- )\r
-{\r
- LIST_ENTRY BootOptionsList;\r
- UINTN OptionCount;\r
- UINTN BootOptionCount;\r
- EFI_STATUS Status;\r
- LIST_ENTRY* Entry;\r
- BDS_LOAD_OPTION* BootOption;\r
- UINTN BootOptionSelected;\r
- UINTN Index;\r
- UINTN BootMainEntryCount;\r
- BOOLEAN IsUnicode;\r
-\r
- BootOption = NULL;\r
- BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
-\r
- if (FeaturePcdGet (PcdBdsLinuxSupport)) {\r
- // Check Linux Loader is present\r
- Status = LocateEfiApplicationInFvByGuid (&mLinuxLoaderAppGuid, &mLinuxLoaderDevicePath);\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- while (TRUE) {\r
- // Get Boot#### list\r
- BootOptionList (&BootOptionsList);\r
-\r
- OptionCount = 1;\r
-\r
- // Display the Boot options\r
- for (Entry = GetFirstNode (&BootOptionsList);\r
- !IsNull (&BootOptionsList,Entry);\r
- Entry = GetNextNode (&BootOptionsList,Entry)\r
- )\r
- {\r
- BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
-\r
- Print(L"[%d] %s\n", OptionCount, BootOption->Description);\r
-\r
- DEBUG_CODE_BEGIN();\r
- CHAR16* DevicePathTxt;\r
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
-\r
- Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
- if (EFI_ERROR(Status)) {\r
- // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r
- DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r
- return Status;\r
- }\r
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);\r
-\r
- Print(L"\t- %s\n",DevicePathTxt);\r
-\r
- if (BootOption->OptionalData != NULL) {\r
- if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) {\r
- if (IsUnicode) {\r
- Print (L"\t- Arguments: %s\n", BootOption->OptionalData);\r
- } else {\r
- AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData);\r
- }\r
- }\r
- }\r
- FreePool(DevicePathTxt);\r
- DEBUG_CODE_END();\r
-\r
- OptionCount++;\r
- }\r
- BootOptionCount = OptionCount-1;\r
-\r
- // Display the hardcoded Boot entries\r
- for (Index = 0; Index < BootMainEntryCount; Index++) {\r
- Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
- OptionCount++;\r
- }\r
-\r
- // Request the boot entry from the user\r
- BootOptionSelected = 0;\r
- while (BootOptionSelected == 0) {\r
- Print(L"Start: ");\r
- Status = GetHIInputInteger (&BootOptionSelected);\r
- if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
- Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
- BootOptionSelected = 0;\r
- }\r
- }\r
-\r
- // Start the selected entry\r
- if (BootOptionSelected > BootOptionCount) {\r
- // Start the hardcoded entry\r
- Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
- } else {\r
- // Find the selected entry from the Boot#### list\r
- Index = 1;\r
- for (Entry = GetFirstNode (&BootOptionsList);\r
- !IsNull (&BootOptionsList,Entry);\r
- Entry = GetNextNode (&BootOptionsList,Entry)\r
- )\r
- {\r
- if (Index == BootOptionSelected) {\r
- BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
- break;\r
- }\r
- Index++;\r
- }\r
-\r
- Status = BootOptionStart (BootOption);\r
- }\r
- }\r
- // Should never go here\r
-}\r