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
;
273 CHAR16
*LinuxDevicePath
;
276 SupportedBootDevice
= NULL
;
278 // List the Boot Devices supported
279 Status
= SelectBootDevice (&SupportedBootDevice
);
280 if (EFI_ERROR(Status
)) {
281 Status
= EFI_ABORTED
;
285 // Create the specific device path node
286 if (FeaturePcdGet (PcdBdsLinuxSupport
) && mLinuxLoaderDevicePath
) {
287 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application or the kernel", &DevicePathNodes
);
289 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application", &DevicePathNodes
);
291 if (EFI_ERROR (Status
)) {
292 Status
= EFI_ABORTED
;
295 // Append the Device Path to the selected device path
296 DevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNodes
);
297 if (DevicePath
== NULL
) {
298 Status
= EFI_OUT_OF_RESOURCES
;
302 // Is it an EFI application?
303 if (FeaturePcdGet (PcdBdsLinuxSupport
) && mLinuxLoaderDevicePath
) {
304 Status
= IsEfiBinary (DevicePath
, &EfiBinary
);
305 if (EFI_ERROR (Status
)) {
306 Status
= EFI_ABORTED
;
310 if (EfiBinary
== FALSE
) {
311 Print (L
"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");
312 Print (L
"Supported command line formats by the embedded Linux Loader:\n");
313 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");
314 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");
315 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");
317 // Copy the Linux path into the command line
318 LinuxDevicePath
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
319 CopyMem (CmdLine
, LinuxDevicePath
, MAX (sizeof (CmdLine
), StrSize (LinuxDevicePath
)));
320 FreePool (LinuxDevicePath
);
322 // Free the generated Device Path
323 FreePool (DevicePath
);
324 // and use the embedded Linux Loader as the EFI application
325 DevicePath
= mLinuxLoaderDevicePath
;
333 Print (L
"Arguments to pass to the EFI Application: ");
334 Status
= EditHIInputStr (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
335 if (EFI_ERROR (Status
)) {
336 Status
= EFI_ABORTED
;
340 OptionalData
= (UINT8
*)CmdLine
;
341 OptionalDataSize
= StrSize (CmdLine
);
343 Print(L
"Description for this new Entry: ");
344 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
345 if (EFI_ERROR(Status
)) {
346 Status
= EFI_ABORTED
;
347 goto FREE_DEVICE_PATH
;
351 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY
));
352 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
, &BdsLoadOptionEntry
->BdsLoadOption
);
353 if (!EFI_ERROR(Status
)) {
354 InsertTailList (BootOptionsList
, &BdsLoadOptionEntry
->Link
);
358 FreePool (DevicePath
);
361 if (Status
== EFI_ABORTED
) {
364 FreePool(SupportedBootDevice
);
369 BootMenuRemoveBootOption (
370 IN LIST_ENTRY
*BootOptionsList
374 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
376 DisplayBootOptions (BootOptionsList
);
377 Status
= SelectBootOption (BootOptionsList
, DELETE_BOOT_ENTRY
, &BootOptionEntry
);
378 if (EFI_ERROR (Status
)) {
382 // If the Boot Option was attached to a list remove it
383 if (!IsListEmpty (&BootOptionEntry
->Link
)) {
384 // Remove the entry from the list
385 RemoveEntryList (&BootOptionEntry
->Link
);
388 // Delete the BDS Load option structures
389 BootOptionDelete (BootOptionEntry
->BdsLoadOption
);
395 BootMenuUpdateBootOption (
396 IN LIST_ENTRY
*BootOptionsList
400 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
401 BDS_LOAD_OPTION
*BootOption
;
402 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
403 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
404 CHAR8 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
405 CHAR16 UnicodeCmdLine
[BOOT_DEVICE_OPTION_MAX
];
406 CHAR16
*LinuxDevicePath
;
407 EFI_DEVICE_PATH
*DevicePath
;
409 UINTN OptionalDataSize
;
414 DisplayBootOptions (BootOptionsList
);
415 Status
= SelectBootOption (BootOptionsList
, UPDATE_BOOT_ENTRY
, &BootOptionEntry
);
416 if (EFI_ERROR (Status
)) {
419 BootOption
= BootOptionEntry
->BdsLoadOption
;
421 // Get the device support for this Boot Option
422 Status
= BootDeviceGetDeviceSupport (BootOption
->FilePathList
, &DeviceSupport
);
423 if (EFI_ERROR(Status
)) {
424 Print(L
"Not possible to retrieve the supported device for the update\n");
425 return EFI_UNSUPPORTED
;
429 if (FeaturePcdGet (PcdBdsLinuxSupport
) && mLinuxLoaderDevicePath
) {
430 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application or the kernel", &DevicePath
);
431 if (EFI_ERROR (Status
)) {
432 Status
= EFI_ABORTED
;
436 // Is it an EFI application?
437 Status
= IsEfiBinary (DevicePath
, &EfiBinary
);
438 if (EFI_ERROR (Status
)) {
439 Status
= EFI_ABORTED
;
443 if (EfiBinary
== FALSE
) {
444 Print (L
"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");
445 Print (L
"Supported command line formats by the embedded Linux Loader:\n");
446 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");
447 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");
448 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");
450 // Copy the Linux path into the command line
451 LinuxDevicePath
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
452 CopyMem (UnicodeCmdLine
, LinuxDevicePath
, MAX (sizeof (UnicodeCmdLine
), StrSize (LinuxDevicePath
)));
453 FreePool (LinuxDevicePath
);
455 // Free the generated Device Path
456 FreePool (DevicePath
);
457 // and use the embedded Linux Loader as the EFI application
458 DevicePath
= mLinuxLoaderDevicePath
;
460 // The command line is a unicode printable string
465 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application", &DevicePath
);
466 if (EFI_ERROR (Status
)) {
467 Status
= EFI_ABORTED
;
472 Print (L
"Arguments to pass to the EFI Application: ");
474 // When the command line has not been initialized by the embedded Linux loader earlier
476 if (BootOption
->OptionalDataSize
> 0) {
477 IsPrintable
= IsPrintableString (BootOption
->OptionalData
, &IsUnicode
);
480 // The size in bytes of the string, final zero included, should
481 // be equal to or at least lower than "BootOption->OptionalDataSize"
482 // and the "IsPrintableString()" has already tested that the length
483 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
484 // final '\0' included. We can thus copy the string for editing
485 // using "CopyMem()". Furthermore, note that in the case of an Unicode
486 // string "StrnCpy()" and "StrCpy()" can not be used to copy the
487 // string because the data pointed to by "BootOption->OptionalData"
488 // is not necessarily 2-byte aligned.
492 UnicodeCmdLine
, BootOption
->OptionalData
,
493 MIN (sizeof (UnicodeCmdLine
),
494 BootOption
->OptionalDataSize
)
498 CmdLine
, BootOption
->OptionalData
,
499 MIN (sizeof (CmdLine
),
500 BootOption
->OptionalDataSize
)
505 UnicodeCmdLine
[0] = L
'\0';
511 // We do not request arguments for OptionalData that cannot be printed
514 Status
= EditHIInputStr (UnicodeCmdLine
, BOOT_DEVICE_OPTION_MAX
);
515 if (EFI_ERROR (Status
)) {
516 Status
= EFI_ABORTED
;
517 goto FREE_DEVICE_PATH
;
520 OptionalData
= (UINT8
*)UnicodeCmdLine
;
521 OptionalDataSize
= StrSize (UnicodeCmdLine
);
523 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
524 if (EFI_ERROR (Status
)) {
525 Status
= EFI_ABORTED
;
526 goto FREE_DEVICE_PATH
;
529 OptionalData
= (UINT8
*)CmdLine
;
530 OptionalDataSize
= AsciiStrSize (CmdLine
);
533 // We keep the former OptionalData
534 OptionalData
= BootOption
->OptionalData
;
535 OptionalDataSize
= BootOption
->OptionalDataSize
;
538 Print(L
"Description for this new Entry: ");
539 StrnCpy (BootDescription
, BootOption
->Description
, BOOT_DEVICE_DESCRIPTION_MAX
);
540 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
541 if (EFI_ERROR(Status
)) {
542 Status
= EFI_ABORTED
;
543 goto FREE_DEVICE_PATH
;
547 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
);
550 FreePool (DevicePath
);
553 if (Status
== EFI_ABORTED
) {
562 Ask for the boot option to move and then move it when up or down arrows
563 are pressed. This function is called when the user selects the "Reorder Boot
564 Device Entries" entry in the boot manager menu.
565 The order of the boot options in BootOptionList and in the UEFI BootOrder
566 global variable are kept coherent until the user confirm his reordering (ie:
567 he does not exit by pressing escape).
569 @param[in] BootOptionsList List of the boot devices constructed in
572 @retval EFI_SUCCESS No error encountered.
573 @retval !EFI_SUCCESS An error has occured either in the selection of the
574 boot option to move or while interacting with the user.
579 BootMenuReorderBootOptions (
580 IN LIST_ENTRY
*BootOptionsList
584 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
585 LIST_ENTRY
*SelectedEntry
;
586 LIST_ENTRY
*PrevEntry
;
592 LIST_ENTRY
*SecondEntry
;
598 DisplayBootOptions (BootOptionsList
);
600 // Ask to select the boot option to move
602 Status
= SelectBootOption (BootOptionsList
, MOVE_BOOT_ENTRY
, &BootOptionEntry
);
603 if (EFI_ERROR (Status
)) {
607 SelectedEntry
= &BootOptionEntry
->Link
;
609 // Note down the previous entry in the list to be able to cancel changes
610 PrevEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
612 // Start of interaction
615 L
"* Use up/down arrows to move the entry '%s'",
616 BootOptionEntry
->BdsLoadOption
->Description
619 // Wait for a move, save or cancel request
624 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
625 if (!EFI_ERROR (Status
)) {
626 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
628 if (EFI_ERROR (Status
)) {
633 switch (Key
.ScanCode
) {
635 Save
= (Key
.UnicodeChar
== CHAR_LINEFEED
) ||
636 (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) ||
637 (Key
.UnicodeChar
== 0x7f);
641 SecondEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
642 Move
= SecondEntry
!= BootOptionsList
;
646 SecondEntry
= GetNextNode (BootOptionsList
, SelectedEntry
);
647 Move
= SecondEntry
!= BootOptionsList
;
654 } while ((!Move
) && (!Save
) && (!Cancel
));
657 if ((SelectedEntry
!= NULL
) && (SecondEntry
!= NULL
)) {
658 SwapListEntries (SelectedEntry
, SecondEntry
);
662 Status
= GetGlobalEnvironmentVariable (
663 L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
665 BootOrderSize
/= sizeof (UINT16
);
667 if (!EFI_ERROR (Status
)) {
668 // The order of the boot options in the 'BootOptionsList' is the
669 // new order that has been just defined by the user. Save this new
670 // order in "BootOrder" UEFI global variable.
671 Entry
= GetFirstNode (BootOptionsList
);
672 for (Index
= 0; Index
< BootOrderSize
; Index
++) {
673 BootOrder
[Index
] = (LOAD_OPTION_FROM_LINK (Entry
))->LoadOptionIndex
;
674 Entry
= GetNextNode (BootOptionsList
, Entry
);
676 Status
= gRT
->SetVariable (
677 (CHAR16
*)L
"BootOrder",
678 &gEfiGlobalVariableGuid
,
679 EFI_VARIABLE_NON_VOLATILE
|
680 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
681 EFI_VARIABLE_RUNTIME_ACCESS
,
682 BootOrderSize
* sizeof (UINT16
),
685 FreePool (BootOrder
);
688 if (EFI_ERROR (Status
)) {
689 Print (L
"\nAn error occurred, move not completed!\n");
696 // Restore initial position of the selected boot option
698 RemoveEntryList (SelectedEntry
);
699 InsertHeadList (PrevEntry
, SelectedEntry
);
704 DisplayBootOptions (BootOptionsList
);
705 // Saved or cancelled, back to the choice of boot option to move
718 IN LIST_ENTRY
*BootOptionsList
722 BDS_SUPPORTED_DEVICE
*SupportedBootDevice
;
723 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePathNodes
;
724 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePath
;
725 CHAR16
*FdtTextDevicePath
;
726 EFI_PHYSICAL_ADDRESS FdtBlobBase
;
729 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase
;
731 SupportedBootDevice
= NULL
;
733 Status
= SelectBootDevice (&SupportedBootDevice
);
734 if (EFI_ERROR (Status
)) {
735 Status
= EFI_ABORTED
;
739 // Create the specific device path node
740 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"FDT blob", &FdtDevicePathNodes
);
741 if (EFI_ERROR (Status
)) {
742 Status
= EFI_ABORTED
;
746 if (FdtDevicePathNodes
!= NULL
) {
747 Status
= EFI_OUT_OF_RESOURCES
;
749 FdtDevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, FdtDevicePathNodes
);
750 FreePool (FdtDevicePathNodes
);
751 if (FdtDevicePath
== NULL
) {
755 FdtTextDevicePath
= ConvertDevicePathToText (FdtDevicePath
, TRUE
, TRUE
);
756 if (FdtTextDevicePath
== NULL
) {
760 Status
= gRT
->SetVariable (
763 EFI_VARIABLE_RUNTIME_ACCESS
|
764 EFI_VARIABLE_NON_VOLATILE
|
765 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
766 StrSize (FdtTextDevicePath
),
769 ASSERT_EFI_ERROR (Status
);
770 FreePool (FdtTextDevicePath
);
772 Status
= gRT
->SetVariable (
775 EFI_VARIABLE_RUNTIME_ACCESS
|
776 EFI_VARIABLE_NON_VOLATILE
|
777 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
781 ASSERT_EFI_ERROR (Status
);
786 // Try to load FDT from the new EFI Device Path
790 // Load the FDT given its device path.
791 // This operation may fail if the device path is not supported.
795 Status
= BdsLoadImage (FdtDevicePath
, AllocateAnyPages
, &FdtBlobBase
, &FdtBlobSize
);
796 FreePool (FdtDevicePath
);
798 if (EFI_ERROR (Status
)) {
802 // Check the FDT header is valid. We only make this check in DEBUG mode in
803 // case the FDT header change on production device and this ASSERT() becomes
805 ASSERT (fdt_check_header ((VOID
*)(UINTN
)FdtBlobBase
) == 0);
808 // Ensure the Size of the Device Tree is smaller than the size of the read file
810 ASSERT ((UINTN
)fdt_totalsize ((VOID
*)(UINTN
)FdtBlobBase
) <= FdtBlobSize
);
813 // Store the FDT as Runtime Service Data to prevent the Kernel from
814 // overwritting its data.
816 NumPages
= EFI_SIZE_TO_PAGES (FdtBlobSize
);
817 Status
= gBS
->AllocatePages (
818 AllocateAnyPages
, EfiRuntimeServicesData
,
819 NumPages
, &FdtConfigurationTableBase
821 if (EFI_ERROR (Status
)) {
825 (VOID
*)(UINTN
)FdtConfigurationTableBase
,
826 (VOID
*)(UINTN
)FdtBlobBase
,
831 // Install the FDT into the Configuration Table
833 Status
= gBS
->InstallConfigurationTable (
835 (VOID
*)(UINTN
)FdtConfigurationTableBase
837 if (EFI_ERROR (Status
)) {
838 gBS
->FreePages (FdtConfigurationTableBase
, NumPages
);
842 if (EFI_ERROR (Status
)) {
843 Print (L
"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");
846 if (FdtBlobBase
!= 0) {
847 gBS
->FreePages (FdtBlobBase
, NumPages
);
851 if (Status
== EFI_ABORTED
) {
855 if (SupportedBootDevice
!= NULL
) {
856 FreePool (SupportedBootDevice
);
865 Ask for the boot timeout in seconds and if the input succeeds assign the
866 input value to the UEFI global variable "Timeout". This function is called
867 when the user selects the "Set Boot Timeout" of the boot manager menu.
869 @param[in] BootOptionsList List of the boot devices, not used here
871 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
872 input and assigned to the UEFI "Timeout" global
874 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
875 variable "Timeout" has failed.
879 BootMenuSetBootTimeout (
880 IN LIST_ENTRY
*BootOptionsList
887 Print (L
"Timeout duration (in seconds): ");
888 Status
= GetHIInputInteger (&Input
);
889 if (EFI_ERROR (Status
)) {
895 Status
= gRT
->SetVariable (
897 &gEfiGlobalVariableGuid
,
898 EFI_VARIABLE_NON_VOLATILE
|
899 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
900 EFI_VARIABLE_RUNTIME_ACCESS
,
904 ASSERT_EFI_ERROR (Status
);
910 struct BOOT_MANAGER_ENTRY
{
911 CONST CHAR16
* Description
;
912 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
913 } BootManagerEntries
[] = {
914 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
915 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
916 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
917 { L
"Reorder Boot Device Entries", BootMenuReorderBootOptions
},
918 { L
"Update FDT path", UpdateFdtPath
},
919 { L
"Set Boot Timeout", BootMenuSetBootTimeout
},
924 IN LIST_ENTRY
*BootOptionsList
928 UINTN OptionSelected
;
929 UINTN BootManagerEntryCount
;
932 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
935 // Display Boot Manager menu
936 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
937 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
939 Print(L
"[%d] Return to main menu\n",Index
+1);
941 // Select which entry to call
943 Status
= GetHIInputInteger (&OptionSelected
);
944 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
945 if (EFI_ERROR(Status
)) {
949 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
950 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
953 // Should never go here
958 IN LIST_ENTRY
*BootOptionsList
962 EFI_DEVICE_PATH
* EfiShellDevicePath
;
964 // Find the EFI Shell
965 Status
= LocateEfiApplicationInFvByName (L
"Shell", &EfiShellDevicePath
);
966 if (Status
== EFI_NOT_FOUND
) {
967 Print (L
"Error: EFI Application not found.\n");
969 } else if (EFI_ERROR (Status
)) {
970 Print (L
"Error: Status Code: 0x%X\n", (UINT32
)Status
);
973 // Need to connect every drivers to ensure no dependencies are missing for the application
974 Status
= BdsConnectAllDrivers ();
975 if (EFI_ERROR (Status
)) {
976 DEBUG ((EFI_D_ERROR
, "FAIL to connect all drivers\n"));
980 return BdsStartEfiApplication (gImageHandle
, EfiShellDevicePath
, 0, NULL
);
984 struct BOOT_MAIN_ENTRY
{
985 CONST CHAR16
* Description
;
986 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
987 } BootMainEntries
[] = {
988 { L
"Shell", BootShell
},
989 { L
"Boot Manager", BootMenuManager
},
997 LIST_ENTRY BootOptionsList
;
999 UINTN BootOptionCount
;
1002 BDS_LOAD_OPTION
* BootOption
;
1003 UINTN BootOptionSelected
;
1005 UINTN BootMainEntryCount
;
1009 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
1011 if (FeaturePcdGet (PcdBdsLinuxSupport
)) {
1012 // Check Linux Loader is present
1013 Status
= LocateEfiApplicationInFvByGuid (&mLinuxLoaderAppGuid
, &mLinuxLoaderDevicePath
);
1014 ASSERT_EFI_ERROR (Status
);
1018 // Get Boot#### list
1019 BootOptionList (&BootOptionsList
);
1023 // Display the Boot options
1024 for (Entry
= GetFirstNode (&BootOptionsList
);
1025 !IsNull (&BootOptionsList
,Entry
);
1026 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1029 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1031 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
1034 CHAR16
* DevicePathTxt
;
1035 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
1037 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
1038 if (EFI_ERROR(Status
)) {
1039 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
1040 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
1043 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
1045 Print(L
"\t- %s\n",DevicePathTxt
);
1047 if (BootOption
->OptionalData
!= NULL
) {
1048 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
1050 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
1052 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
1056 FreePool(DevicePathTxt
);
1061 BootOptionCount
= OptionCount
-1;
1063 // Display the hardcoded Boot entries
1064 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
1065 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
1069 // Request the boot entry from the user
1070 BootOptionSelected
= 0;
1071 while (BootOptionSelected
== 0) {
1073 Status
= GetHIInputInteger (&BootOptionSelected
);
1074 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
1075 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
1076 BootOptionSelected
= 0;
1080 // Start the selected entry
1081 if (BootOptionSelected
> BootOptionCount
) {
1082 // Start the hardcoded entry
1083 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
1085 // Find the selected entry from the Boot#### list
1087 for (Entry
= GetFirstNode (&BootOptionsList
);
1088 !IsNull (&BootOptionsList
,Entry
);
1089 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1092 if (Index
== BootOptionSelected
) {
1093 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1099 Status
= BootOptionStart (BootOption
);
1102 // Should never go here