3 * Copyright (c) 2011 - 2015, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "BdsInternal.h"
17 #include <Guid/ArmGlobalVariableHob.h>
22 Worker function that displays the list of boot options that is passed in.
24 The function loops over the entries of the list of boot options that is passed
25 in. For each entry, the boot option description is displayed on a single line
26 along with the position of the option in the list. In debug mode, the UEFI
27 device path and the arguments of the boot option are displayed as well in
30 @param[in] BootOptionsList List of the boot options
36 IN LIST_ENTRY
* BootOptionsList
40 UINTN BootOptionCount
;
42 BDS_LOAD_OPTION
*BdsLoadOption
;
46 for (Entry
= GetFirstNode (BootOptionsList
);
47 !IsNull (BootOptionsList
, Entry
);
48 Entry
= GetNextNode (BootOptionsList
, Entry
)
51 BdsLoadOption
= LOAD_OPTION_FROM_LINK (Entry
);
52 Print (L
"[%d] %s\n", ++BootOptionCount
, BdsLoadOption
->Description
);
55 CHAR16
* DevicePathTxt
;
56 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
58 Status
= gBS
->LocateProtocol (
59 &gEfiDevicePathToTextProtocolGuid
,
61 (VOID
**)&DevicePathToTextProtocol
63 ASSERT_EFI_ERROR (Status
);
64 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
65 BdsLoadOption
->FilePathList
,
69 Print (L
"\t- %s\n", DevicePathTxt
);
71 if (IsPrintableString (BdsLoadOption
->OptionalData
, &IsUnicode
)) {
73 Print (L
"\t- Arguments: %s\n", BdsLoadOption
->OptionalData
);
75 AsciiPrint ("\t- Arguments: %a\n", BdsLoadOption
->OptionalData
);
79 FreePool (DevicePathTxt
);
85 Worker function that asks for a boot option to be selected and returns a
86 pointer to the structure describing the selected boot option.
88 @param[in] BootOptionsList List of the boot options
90 @retval EFI_SUCCESS Selection succeeded
91 @retval !EFI_SUCCESS Input error or input cancelled
97 IN LIST_ENTRY
* BootOptionsList
,
98 IN CONST CHAR16
* InputStatement
,
99 OUT BDS_LOAD_OPTION_ENTRY
** BdsLoadOptionEntry
103 UINTN BootOptionCount
;
106 UINTN BootOptionSelected
;
109 // Get the number of boot options
110 Status
= GetGlobalEnvironmentVariable (
111 L
"BootOrder", NULL
, &BootOptionCount
, (VOID
**)&BootOrder
113 if (EFI_ERROR (Status
)) {
116 FreePool (BootOrder
);
117 BootOptionCount
/= sizeof (UINT16
);
119 // Check if a valid boot option(s) is found
120 if (BootOptionCount
== 0) {
121 if (StrCmp (InputStatement
, DELETE_BOOT_ENTRY
) == 0) {
122 Print (L
"Nothing to remove!\n");
123 } else if (StrCmp (InputStatement
, UPDATE_BOOT_ENTRY
) == 0) {
124 Print (L
"Nothing to update!\n");
125 } else if (StrCmp (InputStatement
, MOVE_BOOT_ENTRY
) == 0) {
126 Print (L
"Nothing to move!\n");
128 Print (L
"No supported Boot Entry.\n");
130 return EFI_NOT_FOUND
;
133 // Get the index of the boot device to delete
134 BootOptionSelected
= 0;
135 while (BootOptionSelected
== 0) {
136 Print (InputStatement
);
137 Status
= GetHIInputInteger (&BootOptionSelected
);
138 if (EFI_ERROR (Status
)) {
141 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
> BootOptionCount
)) {
142 Print (L
"Invalid input (max %d)\n", BootOptionCount
);
143 BootOptionSelected
= 0;
147 // Get the structure of the Boot device to delete
149 for (Entry
= GetFirstNode (BootOptionsList
);
150 !IsNull (BootOptionsList
, Entry
);
151 Entry
= GetNextNode (BootOptionsList
,Entry
)
154 if (Index
== BootOptionSelected
) {
155 *BdsLoadOptionEntry
= LOAD_OPTION_ENTRY_FROM_LINK (Entry
);
168 OUT BDS_SUPPORTED_DEVICE
** SupportedBootDevice
172 LIST_ENTRY SupportedDeviceList
;
173 UINTN SupportedDeviceCount
;
175 UINTN SupportedDeviceSelected
;
179 // List the Boot Devices supported
182 // Start all the drivers first
183 BdsConnectAllDrivers ();
185 // List the supported devices
186 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
187 ASSERT_EFI_ERROR(Status
);
189 SupportedDeviceCount
= 0;
190 for (Entry
= GetFirstNode (&SupportedDeviceList
);
191 !IsNull (&SupportedDeviceList
,Entry
);
192 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
195 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
196 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,(*SupportedBootDevice
)->Description
);
199 CHAR16
* DevicePathTxt
;
200 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
202 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
203 ASSERT_EFI_ERROR(Status
);
204 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText ((*SupportedBootDevice
)->DevicePathProtocol
,TRUE
,TRUE
);
206 Print(L
"\t- %s\n",DevicePathTxt
);
208 FreePool(DevicePathTxt
);
211 SupportedDeviceCount
++;
214 if (SupportedDeviceCount
== 0) {
215 Print(L
"There is no supported device.\n");
216 Status
= EFI_ABORTED
;
221 // Select the Boot Device
223 SupportedDeviceSelected
= 0;
224 while (SupportedDeviceSelected
== 0) {
225 Print(L
"Select the Boot Device: ");
226 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
227 if (EFI_ERROR(Status
)) {
228 Status
= EFI_ABORTED
;
230 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
231 Print(L
"Invalid input (max %d)\n",SupportedDeviceCount
);
232 SupportedDeviceSelected
= 0;
237 // Get the Device Path for the selected boot device
240 for (Entry
= GetFirstNode (&SupportedDeviceList
);
241 !IsNull (&SupportedDeviceList
,Entry
);
242 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
245 if (Index
== SupportedDeviceSelected
) {
246 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
253 BootDeviceListSupportedFree (&SupportedDeviceList
, *SupportedBootDevice
);
258 BootMenuAddBootOption (
259 IN LIST_ENTRY
*BootOptionsList
263 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
264 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
265 CHAR16 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
267 BDS_LOAD_OPTION_ENTRY
*BdsLoadOptionEntry
;
268 EFI_DEVICE_PATH
*DevicePath
;
269 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNodes
;
271 UINTN OptionalDataSize
;
274 SupportedBootDevice
= NULL
;
276 // List the Boot Devices supported
277 Status
= SelectBootDevice (&SupportedBootDevice
);
278 if (EFI_ERROR(Status
)) {
279 Status
= EFI_ABORTED
;
283 // Create the specific device path node
284 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application or the kernel", &DevicePathNodes
);
285 if (EFI_ERROR(Status
)) {
286 Status
= EFI_ABORTED
;
289 // Append the Device Path to the selected device path
290 DevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNodes
);
291 if (DevicePath
== NULL
) {
292 Status
= EFI_OUT_OF_RESOURCES
;
296 Print (L
"Arguments to pass to the EFI Application: ");
297 Status
= GetHIInputStr (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
298 if (EFI_ERROR (Status
)) {
299 Status
= EFI_ABORTED
;
303 OptionalData
= (UINT8
*)CmdLine
;
304 OptionalDataSize
= StrSize (CmdLine
);
306 Print(L
"Description for this new Entry: ");
307 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
308 if (EFI_ERROR(Status
)) {
309 Status
= EFI_ABORTED
;
310 goto FREE_DEVICE_PATH
;
314 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY
));
315 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
, &BdsLoadOptionEntry
->BdsLoadOption
);
316 if (!EFI_ERROR(Status
)) {
317 InsertTailList (BootOptionsList
, &BdsLoadOptionEntry
->Link
);
321 FreePool (DevicePath
);
324 if (Status
== EFI_ABORTED
) {
327 FreePool(SupportedBootDevice
);
332 BootMenuRemoveBootOption (
333 IN LIST_ENTRY
*BootOptionsList
337 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
339 DisplayBootOptions (BootOptionsList
);
340 Status
= SelectBootOption (BootOptionsList
, DELETE_BOOT_ENTRY
, &BootOptionEntry
);
341 if (EFI_ERROR (Status
)) {
345 // If the Boot Option was attached to a list remove it
346 if (!IsListEmpty (&BootOptionEntry
->Link
)) {
347 // Remove the entry from the list
348 RemoveEntryList (&BootOptionEntry
->Link
);
351 // Delete the BDS Load option structures
352 BootOptionDelete (BootOptionEntry
->BdsLoadOption
);
358 BootMenuUpdateBootOption (
359 IN LIST_ENTRY
*BootOptionsList
363 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
364 BDS_LOAD_OPTION
*BootOption
;
365 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
366 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
367 CHAR8 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
368 CHAR16 UnicodeCmdLine
[BOOT_DEVICE_OPTION_MAX
];
369 EFI_DEVICE_PATH
*DevicePath
;
371 UINTN OptionalDataSize
;
375 DisplayBootOptions (BootOptionsList
);
376 Status
= SelectBootOption (BootOptionsList
, UPDATE_BOOT_ENTRY
, &BootOptionEntry
);
377 if (EFI_ERROR (Status
)) {
380 BootOption
= BootOptionEntry
->BdsLoadOption
;
382 // Get the device support for this Boot Option
383 Status
= BootDeviceGetDeviceSupport (BootOption
->FilePathList
, &DeviceSupport
);
384 if (EFI_ERROR(Status
)) {
385 Print(L
"Not possible to retrieve the supported device for the update\n");
386 return EFI_UNSUPPORTED
;
389 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application or the kernel", &DevicePath
);
390 if (EFI_ERROR(Status
)) {
391 Status
= EFI_ABORTED
;
395 Print (L
"Arguments to pass to the EFI Application: ");
397 if (BootOption
->OptionalDataSize
> 0) {
398 IsPrintable
= IsPrintableString (BootOption
->OptionalData
, &IsUnicode
);
401 // The size in bytes of the string, final zero included, should
402 // be equal to or at least lower than "BootOption->OptionalDataSize"
403 // and the "IsPrintableString()" has already tested that the length
404 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
405 // final '\0' included. We can thus copy the string for editing
406 // using "CopyMem()". Furthermore, note that in the case of an Unicode
407 // string "StrnCpy()" and "StrCpy()" can not be used to copy the
408 // string because the data pointed to by "BootOption->OptionalData"
409 // is not necessarily 2-byte aligned.
413 UnicodeCmdLine
, BootOption
->OptionalData
,
414 MIN (sizeof (UnicodeCmdLine
),
415 BootOption
->OptionalDataSize
)
419 CmdLine
, BootOption
->OptionalData
,
420 MIN (sizeof (CmdLine
),
421 BootOption
->OptionalDataSize
)
426 UnicodeCmdLine
[0] = L
'\0';
431 // We do not request arguments for OptionalData that cannot be printed
434 Status
= EditHIInputStr (UnicodeCmdLine
, BOOT_DEVICE_OPTION_MAX
);
435 if (EFI_ERROR (Status
)) {
436 Status
= EFI_ABORTED
;
437 goto FREE_DEVICE_PATH
;
440 OptionalData
= (UINT8
*)UnicodeCmdLine
;
441 OptionalDataSize
= StrSize (UnicodeCmdLine
);
443 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
444 if (EFI_ERROR (Status
)) {
445 Status
= EFI_ABORTED
;
446 goto FREE_DEVICE_PATH
;
449 OptionalData
= (UINT8
*)CmdLine
;
450 OptionalDataSize
= AsciiStrSize (CmdLine
);
453 // We keep the former OptionalData
454 OptionalData
= BootOption
->OptionalData
;
455 OptionalDataSize
= BootOption
->OptionalDataSize
;
458 Print(L
"Description for this new Entry: ");
459 StrnCpy (BootDescription
, BootOption
->Description
, BOOT_DEVICE_DESCRIPTION_MAX
);
460 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
461 if (EFI_ERROR(Status
)) {
462 Status
= EFI_ABORTED
;
463 goto FREE_DEVICE_PATH
;
467 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
);
470 FreePool (DevicePath
);
473 if (Status
== EFI_ABORTED
) {
482 Ask for the boot option to move and then move it when up or down arrows
483 are pressed. This function is called when the user selects the "Reorder Boot
484 Device Entries" entry in the boot manager menu.
485 The order of the boot options in BootOptionList and in the UEFI BootOrder
486 global variable are kept coherent until the user confirm his reordering (ie:
487 he does not exit by pressing escape).
489 @param[in] BootOptionsList List of the boot devices constructed in
492 @retval EFI_SUCCESS No error encountered.
493 @retval !EFI_SUCCESS An error has occured either in the selection of the
494 boot option to move or while interacting with the user.
499 BootMenuReorderBootOptions (
500 IN LIST_ENTRY
*BootOptionsList
504 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
505 LIST_ENTRY
*SelectedEntry
;
506 LIST_ENTRY
*PrevEntry
;
512 LIST_ENTRY
*SecondEntry
;
518 DisplayBootOptions (BootOptionsList
);
520 // Ask to select the boot option to move
522 Status
= SelectBootOption (BootOptionsList
, MOVE_BOOT_ENTRY
, &BootOptionEntry
);
523 if (EFI_ERROR (Status
)) {
527 SelectedEntry
= &BootOptionEntry
->Link
;
529 // Note down the previous entry in the list to be able to cancel changes
530 PrevEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
532 // Start of interaction
535 L
"* Use up/down arrows to move the entry '%s'",
536 BootOptionEntry
->BdsLoadOption
->Description
539 // Wait for a move, save or cancel request
544 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
545 if (!EFI_ERROR (Status
)) {
546 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
548 if (EFI_ERROR (Status
)) {
553 switch (Key
.ScanCode
) {
555 Save
= (Key
.UnicodeChar
== CHAR_LINEFEED
) ||
556 (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) ||
557 (Key
.UnicodeChar
== 0x7f);
561 SecondEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
562 Move
= SecondEntry
!= BootOptionsList
;
566 SecondEntry
= GetNextNode (BootOptionsList
, SelectedEntry
);
567 Move
= SecondEntry
!= BootOptionsList
;
574 } while ((!Move
) && (!Save
) && (!Cancel
));
577 if ((SelectedEntry
!= NULL
) && (SecondEntry
!= NULL
)) {
578 SwapListEntries (SelectedEntry
, SecondEntry
);
582 Status
= GetGlobalEnvironmentVariable (
583 L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
585 BootOrderSize
/= sizeof (UINT16
);
587 if (!EFI_ERROR (Status
)) {
588 // The order of the boot options in the 'BootOptionsList' is the
589 // new order that has been just defined by the user. Save this new
590 // order in "BootOrder" UEFI global variable.
591 Entry
= GetFirstNode (BootOptionsList
);
592 for (Index
= 0; Index
< BootOrderSize
; Index
++) {
593 BootOrder
[Index
] = (LOAD_OPTION_FROM_LINK (Entry
))->LoadOptionIndex
;
594 Entry
= GetNextNode (BootOptionsList
, Entry
);
596 Status
= gRT
->SetVariable (
597 (CHAR16
*)L
"BootOrder",
598 &gEfiGlobalVariableGuid
,
599 EFI_VARIABLE_NON_VOLATILE
|
600 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
601 EFI_VARIABLE_RUNTIME_ACCESS
,
602 BootOrderSize
* sizeof (UINT16
),
605 FreePool (BootOrder
);
608 if (EFI_ERROR (Status
)) {
609 Print (L
"\nAn error occurred, move not completed!\n");
616 // Restore initial position of the selected boot option
618 RemoveEntryList (SelectedEntry
);
619 InsertHeadList (PrevEntry
, SelectedEntry
);
624 DisplayBootOptions (BootOptionsList
);
625 // Saved or cancelled, back to the choice of boot option to move
638 IN LIST_ENTRY
*BootOptionsList
642 BDS_SUPPORTED_DEVICE
*SupportedBootDevice
;
643 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePathNodes
;
644 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePath
;
645 CHAR16
*FdtTextDevicePath
;
646 EFI_PHYSICAL_ADDRESS FdtBlobBase
;
649 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase
;
651 SupportedBootDevice
= NULL
;
653 Status
= SelectBootDevice (&SupportedBootDevice
);
654 if (EFI_ERROR (Status
)) {
655 Status
= EFI_ABORTED
;
659 // Create the specific device path node
660 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"FDT blob", &FdtDevicePathNodes
);
661 if (EFI_ERROR (Status
)) {
662 Status
= EFI_ABORTED
;
666 if (FdtDevicePathNodes
!= NULL
) {
667 Status
= EFI_OUT_OF_RESOURCES
;
669 FdtDevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, FdtDevicePathNodes
);
670 FreePool (FdtDevicePathNodes
);
671 if (FdtDevicePath
== NULL
) {
675 FdtTextDevicePath
= ConvertDevicePathToText (FdtDevicePath
, TRUE
, TRUE
);
676 if (FdtTextDevicePath
== NULL
) {
680 Status
= gRT
->SetVariable (
683 EFI_VARIABLE_RUNTIME_ACCESS
|
684 EFI_VARIABLE_NON_VOLATILE
|
685 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
686 StrSize (FdtTextDevicePath
),
689 ASSERT_EFI_ERROR (Status
);
690 FreePool (FdtTextDevicePath
);
692 Status
= gRT
->SetVariable (
695 EFI_VARIABLE_RUNTIME_ACCESS
|
696 EFI_VARIABLE_NON_VOLATILE
|
697 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
701 ASSERT_EFI_ERROR (Status
);
706 // Try to load FDT from the new EFI Device Path
710 // Load the FDT given its device path.
711 // This operation may fail if the device path is not supported.
715 Status
= BdsLoadImage (FdtDevicePath
, AllocateAnyPages
, &FdtBlobBase
, &FdtBlobSize
);
716 FreePool (FdtDevicePath
);
718 if (EFI_ERROR (Status
)) {
722 // Check the FDT header is valid. We only make this check in DEBUG mode in
723 // case the FDT header change on production device and this ASSERT() becomes
725 ASSERT (fdt_check_header ((VOID
*)(UINTN
)FdtBlobBase
) == 0);
728 // Ensure the Size of the Device Tree is smaller than the size of the read file
730 ASSERT ((UINTN
)fdt_totalsize ((VOID
*)(UINTN
)FdtBlobBase
) <= FdtBlobSize
);
733 // Store the FDT as Runtime Service Data to prevent the Kernel from
734 // overwritting its data.
736 NumPages
= EFI_SIZE_TO_PAGES (FdtBlobSize
);
737 Status
= gBS
->AllocatePages (
738 AllocateAnyPages
, EfiRuntimeServicesData
,
739 NumPages
, &FdtConfigurationTableBase
741 if (EFI_ERROR (Status
)) {
745 (VOID
*)(UINTN
)FdtConfigurationTableBase
,
746 (VOID
*)(UINTN
)FdtBlobBase
,
751 // Install the FDT into the Configuration Table
753 Status
= gBS
->InstallConfigurationTable (
755 (VOID
*)(UINTN
)FdtConfigurationTableBase
757 if (EFI_ERROR (Status
)) {
758 gBS
->FreePages (FdtConfigurationTableBase
, NumPages
);
762 if (EFI_ERROR (Status
)) {
763 Print (L
"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");
766 if (FdtBlobBase
!= 0) {
767 gBS
->FreePages (FdtBlobBase
, NumPages
);
771 if (Status
== EFI_ABORTED
) {
775 if (SupportedBootDevice
!= NULL
) {
776 FreePool (SupportedBootDevice
);
785 Ask for the boot timeout in seconds and if the input succeeds assign the
786 input value to the UEFI global variable "Timeout". This function is called
787 when the user selects the "Set Boot Timeout" of the boot manager menu.
789 @param[in] BootOptionsList List of the boot devices, not used here
791 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
792 input and assigned to the UEFI "Timeout" global
794 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
795 variable "Timeout" has failed.
799 BootMenuSetBootTimeout (
800 IN LIST_ENTRY
*BootOptionsList
807 Print (L
"Timeout duration (in seconds): ");
808 Status
= GetHIInputInteger (&Input
);
809 if (EFI_ERROR (Status
)) {
815 Status
= gRT
->SetVariable (
817 &gEfiGlobalVariableGuid
,
818 EFI_VARIABLE_NON_VOLATILE
|
819 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
820 EFI_VARIABLE_RUNTIME_ACCESS
,
824 ASSERT_EFI_ERROR (Status
);
830 struct BOOT_MANAGER_ENTRY
{
831 CONST CHAR16
* Description
;
832 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
833 } BootManagerEntries
[] = {
834 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
835 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
836 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
837 { L
"Reorder Boot Device Entries", BootMenuReorderBootOptions
},
838 { L
"Update FDT path", UpdateFdtPath
},
839 { L
"Set Boot Timeout", BootMenuSetBootTimeout
},
844 IN LIST_ENTRY
*BootOptionsList
848 UINTN OptionSelected
;
849 UINTN BootManagerEntryCount
;
852 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
855 // Display Boot Manager menu
856 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
857 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
859 Print(L
"[%d] Return to main menu\n",Index
+1);
861 // Select which entry to call
863 Status
= GetHIInputInteger (&OptionSelected
);
864 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
865 if (EFI_ERROR(Status
)) {
869 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
870 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
873 // Should never go here
878 IN LIST_ENTRY
*BootOptionsList
882 EFI_DEVICE_PATH
* EfiShellDevicePath
;
884 // Find the EFI Shell
885 Status
= LocateEfiApplicationInFvByName (L
"Shell", &EfiShellDevicePath
);
886 if (Status
== EFI_NOT_FOUND
) {
887 Print (L
"Error: EFI Application not found.\n");
889 } else if (EFI_ERROR (Status
)) {
890 Print (L
"Error: Status Code: 0x%X\n", (UINT32
)Status
);
893 // Need to connect every drivers to ensure no dependencies are missing for the application
894 Status
= BdsConnectAllDrivers ();
895 if (EFI_ERROR (Status
)) {
896 DEBUG ((EFI_D_ERROR
, "FAIL to connect all drivers\n"));
900 return BdsStartEfiApplication (gImageHandle
, EfiShellDevicePath
, 0, NULL
);
904 struct BOOT_MAIN_ENTRY
{
905 CONST CHAR16
* Description
;
906 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
907 } BootMainEntries
[] = {
908 { L
"Shell", BootShell
},
909 { L
"Boot Manager", BootMenuManager
},
918 LIST_ENTRY BootOptionsList
;
920 UINTN BootOptionCount
;
923 BDS_LOAD_OPTION
* BootOption
;
924 UINTN BootOptionSelected
;
926 UINTN BootMainEntryCount
;
930 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
934 BootOptionList (&BootOptionsList
);
938 // Display the Boot options
939 for (Entry
= GetFirstNode (&BootOptionsList
);
940 !IsNull (&BootOptionsList
,Entry
);
941 Entry
= GetNextNode (&BootOptionsList
,Entry
)
944 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
946 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
949 CHAR16
* DevicePathTxt
;
950 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
952 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
953 if (EFI_ERROR(Status
)) {
954 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
955 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
958 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
960 Print(L
"\t- %s\n",DevicePathTxt
);
962 if (BootOption
->OptionalData
!= NULL
) {
963 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
965 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
967 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
971 FreePool(DevicePathTxt
);
976 BootOptionCount
= OptionCount
-1;
978 // Display the hardcoded Boot entries
979 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
980 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
984 // Request the boot entry from the user
985 BootOptionSelected
= 0;
986 while (BootOptionSelected
== 0) {
988 Status
= GetHIInputInteger (&BootOptionSelected
);
989 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
990 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
991 BootOptionSelected
= 0;
995 // Start the selected entry
996 if (BootOptionSelected
> BootOptionCount
) {
997 // Start the hardcoded entry
998 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
1000 // Find the selected entry from the Boot#### list
1002 for (Entry
= GetFirstNode (&BootOptionsList
);
1003 !IsNull (&BootOptionsList
,Entry
);
1004 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1007 if (Index
== BootOptionSelected
) {
1008 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1014 Status
= BootOptionStart (BootOption
);
1017 // Should never go here