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"
20 Worker function that displays the list of boot options that is passed in.
22 The function loops over the entries of the list of boot options that is passed
23 in. For each entry, the boot option description is displayed on a single line
24 along with the position of the option in the list. In debug mode, the UEFI
25 device path and the arguments of the boot option are displayed as well in
28 @param[in] BootOptionsList List of the boot options
34 IN LIST_ENTRY
* BootOptionsList
38 UINTN BootOptionCount
;
40 BDS_LOAD_OPTION
*BdsLoadOption
;
44 for (Entry
= GetFirstNode (BootOptionsList
);
45 !IsNull (BootOptionsList
, Entry
);
46 Entry
= GetNextNode (BootOptionsList
, Entry
)
49 BdsLoadOption
= LOAD_OPTION_FROM_LINK (Entry
);
50 Print (L
"[%d] %s\n", ++BootOptionCount
, BdsLoadOption
->Description
);
53 CHAR16
* DevicePathTxt
;
54 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
56 Status
= gBS
->LocateProtocol (
57 &gEfiDevicePathToTextProtocolGuid
,
59 (VOID
**)&DevicePathToTextProtocol
61 ASSERT_EFI_ERROR (Status
);
62 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
63 BdsLoadOption
->FilePathList
,
67 Print (L
"\t- %s\n", DevicePathTxt
);
69 if (IsPrintableString (BdsLoadOption
->OptionalData
, &IsUnicode
)) {
71 Print (L
"\t- Arguments: %s\n", BdsLoadOption
->OptionalData
);
73 AsciiPrint ("\t- Arguments: %a\n", BdsLoadOption
->OptionalData
);
77 FreePool (DevicePathTxt
);
83 Worker function that asks for a boot option to be selected and returns a
84 pointer to the structure describing the selected boot option.
86 @param[in] BootOptionsList List of the boot options
88 @retval EFI_SUCCESS Selection succeeded
89 @retval !EFI_SUCCESS Input error or input cancelled
95 IN LIST_ENTRY
* BootOptionsList
,
96 IN CONST CHAR16
* InputStatement
,
97 OUT BDS_LOAD_OPTION_ENTRY
** BdsLoadOptionEntry
101 UINTN BootOptionCount
;
104 UINTN BootOptionSelected
;
107 // Get the number of boot options
108 Status
= GetGlobalEnvironmentVariable (
109 L
"BootOrder", NULL
, &BootOptionCount
, (VOID
**)&BootOrder
111 if (EFI_ERROR (Status
)) {
114 FreePool (BootOrder
);
115 BootOptionCount
/= sizeof (UINT16
);
117 // Check if a valid boot option(s) is found
118 if (BootOptionCount
== 0) {
119 if (StrCmp (InputStatement
, DELETE_BOOT_ENTRY
) == 0) {
120 Print (L
"Nothing to remove!\n");
121 } else if (StrCmp (InputStatement
, UPDATE_BOOT_ENTRY
) == 0) {
122 Print (L
"Nothing to update!\n");
123 } else if (StrCmp (InputStatement
, MOVE_BOOT_ENTRY
) == 0) {
124 Print (L
"Nothing to move!\n");
126 Print (L
"No supported Boot Entry.\n");
128 return EFI_NOT_FOUND
;
131 // Get the index of the boot device to delete
132 BootOptionSelected
= 0;
133 while (BootOptionSelected
== 0) {
134 Print (InputStatement
);
135 Status
= GetHIInputInteger (&BootOptionSelected
);
136 if (EFI_ERROR (Status
)) {
139 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
> BootOptionCount
)) {
140 Print (L
"Invalid input (max %d)\n", BootOptionCount
);
141 BootOptionSelected
= 0;
145 // Get the structure of the Boot device to delete
147 for (Entry
= GetFirstNode (BootOptionsList
);
148 !IsNull (BootOptionsList
, Entry
);
149 Entry
= GetNextNode (BootOptionsList
,Entry
)
152 if (Index
== BootOptionSelected
) {
153 *BdsLoadOptionEntry
= LOAD_OPTION_ENTRY_FROM_LINK (Entry
);
166 OUT BDS_SUPPORTED_DEVICE
** SupportedBootDevice
170 LIST_ENTRY SupportedDeviceList
;
171 UINTN SupportedDeviceCount
;
173 UINTN SupportedDeviceSelected
;
177 // List the Boot Devices supported
180 // Start all the drivers first
181 BdsConnectAllDrivers ();
183 // List the supported devices
184 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
185 ASSERT_EFI_ERROR(Status
);
187 SupportedDeviceCount
= 0;
188 for (Entry
= GetFirstNode (&SupportedDeviceList
);
189 !IsNull (&SupportedDeviceList
,Entry
);
190 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
193 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
194 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,(*SupportedBootDevice
)->Description
);
197 CHAR16
* DevicePathTxt
;
198 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
200 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
201 ASSERT_EFI_ERROR(Status
);
202 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText ((*SupportedBootDevice
)->DevicePathProtocol
,TRUE
,TRUE
);
204 Print(L
"\t- %s\n",DevicePathTxt
);
206 FreePool(DevicePathTxt
);
209 SupportedDeviceCount
++;
212 if (SupportedDeviceCount
== 0) {
213 Print(L
"There is no supported device.\n");
214 Status
= EFI_ABORTED
;
219 // Select the Boot Device
221 SupportedDeviceSelected
= 0;
222 while (SupportedDeviceSelected
== 0) {
223 Print(L
"Select the Boot Device: ");
224 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
225 if (EFI_ERROR(Status
)) {
226 Status
= EFI_ABORTED
;
228 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
229 Print(L
"Invalid input (max %d)\n",SupportedDeviceCount
);
230 SupportedDeviceSelected
= 0;
235 // Get the Device Path for the selected boot device
238 for (Entry
= GetFirstNode (&SupportedDeviceList
);
239 !IsNull (&SupportedDeviceList
,Entry
);
240 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
243 if (Index
== SupportedDeviceSelected
) {
244 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
251 BootDeviceListSupportedFree (&SupportedDeviceList
, *SupportedBootDevice
);
256 BootMenuAddBootOption (
257 IN LIST_ENTRY
*BootOptionsList
261 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
262 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
263 CHAR16 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
265 BDS_LOAD_OPTION_ENTRY
*BdsLoadOptionEntry
;
266 EFI_DEVICE_PATH
*DevicePath
;
267 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNodes
;
269 UINTN OptionalDataSize
;
271 CHAR16
*LinuxDevicePath
;
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 if (FeaturePcdGet (PcdBdsLinuxSupport
) && mLinuxLoaderDevicePath
) {
285 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application or the kernel", &DevicePathNodes
);
287 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application", &DevicePathNodes
);
289 if (EFI_ERROR (Status
)) {
290 Status
= EFI_ABORTED
;
293 // Append the Device Path to the selected device path
294 DevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNodes
);
295 if (DevicePath
== NULL
) {
296 Status
= EFI_OUT_OF_RESOURCES
;
300 // Is it an EFI application?
301 if (FeaturePcdGet (PcdBdsLinuxSupport
) && mLinuxLoaderDevicePath
) {
302 Status
= IsEfiBinary (DevicePath
, &EfiBinary
);
303 if (EFI_ERROR (Status
)) {
304 Status
= EFI_ABORTED
;
308 if (EfiBinary
== FALSE
) {
309 Print (L
"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");
310 Print (L
"Supported command line formats by the embedded Linux Loader:\n");
311 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");
312 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");
313 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");
315 // Copy the Linux path into the command line
316 LinuxDevicePath
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
317 CopyMem (CmdLine
, LinuxDevicePath
, MAX (sizeof (CmdLine
), StrSize (LinuxDevicePath
)));
318 FreePool (LinuxDevicePath
);
320 // Free the generated Device Path
321 FreePool (DevicePath
);
322 // and use the embedded Linux Loader as the EFI application
323 DevicePath
= mLinuxLoaderDevicePath
;
331 Print (L
"Arguments to pass to the EFI Application: ");
332 Status
= EditHIInputStr (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
333 if (EFI_ERROR (Status
)) {
334 Status
= EFI_ABORTED
;
338 OptionalData
= (UINT8
*)CmdLine
;
339 OptionalDataSize
= StrSize (CmdLine
);
341 Print(L
"Description for this new Entry: ");
342 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
343 if (EFI_ERROR(Status
)) {
344 Status
= EFI_ABORTED
;
345 goto FREE_DEVICE_PATH
;
349 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY
));
350 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
, &BdsLoadOptionEntry
->BdsLoadOption
);
351 if (!EFI_ERROR(Status
)) {
352 InsertTailList (BootOptionsList
, &BdsLoadOptionEntry
->Link
);
356 FreePool (DevicePath
);
359 if (Status
== EFI_ABORTED
) {
362 FreePool(SupportedBootDevice
);
367 BootMenuRemoveBootOption (
368 IN LIST_ENTRY
*BootOptionsList
372 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
374 DisplayBootOptions (BootOptionsList
);
375 Status
= SelectBootOption (BootOptionsList
, DELETE_BOOT_ENTRY
, &BootOptionEntry
);
376 if (EFI_ERROR (Status
)) {
380 // If the Boot Option was attached to a list remove it
381 if (!IsListEmpty (&BootOptionEntry
->Link
)) {
382 // Remove the entry from the list
383 RemoveEntryList (&BootOptionEntry
->Link
);
386 // Delete the BDS Load option structures
387 BootOptionDelete (BootOptionEntry
->BdsLoadOption
);
393 BootMenuUpdateBootOption (
394 IN LIST_ENTRY
*BootOptionsList
398 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
399 BDS_LOAD_OPTION
*BootOption
;
400 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
401 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
402 CHAR8 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
403 CHAR16 UnicodeCmdLine
[BOOT_DEVICE_OPTION_MAX
];
404 CHAR16
*LinuxDevicePath
;
405 EFI_DEVICE_PATH
*DevicePath
;
407 UINTN OptionalDataSize
;
412 DisplayBootOptions (BootOptionsList
);
413 Status
= SelectBootOption (BootOptionsList
, UPDATE_BOOT_ENTRY
, &BootOptionEntry
);
414 if (EFI_ERROR (Status
)) {
417 BootOption
= BootOptionEntry
->BdsLoadOption
;
419 // Get the device support for this Boot Option
420 Status
= BootDeviceGetDeviceSupport (BootOption
->FilePathList
, &DeviceSupport
);
421 if (EFI_ERROR(Status
)) {
422 Print(L
"Not possible to retrieve the supported device for the update\n");
423 return EFI_UNSUPPORTED
;
427 if (FeaturePcdGet (PcdBdsLinuxSupport
) && mLinuxLoaderDevicePath
) {
428 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application or the kernel", &DevicePath
);
429 if (EFI_ERROR (Status
)) {
430 Status
= EFI_ABORTED
;
434 // Is it an EFI application?
435 Status
= IsEfiBinary (DevicePath
, &EfiBinary
);
436 if (EFI_ERROR (Status
)) {
437 Status
= EFI_ABORTED
;
441 if (EfiBinary
== FALSE
) {
442 Print (L
"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");
443 Print (L
"Supported command line formats by the embedded Linux Loader:\n");
444 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");
445 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");
446 Print (L
"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");
448 // Copy the Linux path into the command line
449 LinuxDevicePath
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
450 CopyMem (UnicodeCmdLine
, LinuxDevicePath
, MAX (sizeof (UnicodeCmdLine
), StrSize (LinuxDevicePath
)));
451 FreePool (LinuxDevicePath
);
453 // Free the generated Device Path
454 FreePool (DevicePath
);
455 // and use the embedded Linux Loader as the EFI application
456 DevicePath
= mLinuxLoaderDevicePath
;
458 // The command line is a unicode printable string
463 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application", &DevicePath
);
464 if (EFI_ERROR (Status
)) {
465 Status
= EFI_ABORTED
;
470 Print (L
"Arguments to pass to the EFI Application: ");
472 // When the command line has not been initialized by the embedded Linux loader earlier
474 if (BootOption
->OptionalDataSize
> 0) {
475 IsPrintable
= IsPrintableString (BootOption
->OptionalData
, &IsUnicode
);
478 // The size in bytes of the string, final zero included, should
479 // be equal to or at least lower than "BootOption->OptionalDataSize"
480 // and the "IsPrintableString()" has already tested that the length
481 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
482 // final '\0' included. We can thus copy the string for editing
483 // using "CopyMem()". Furthermore, note that in the case of an Unicode
484 // string "StrnCpy()" and "StrCpy()" can not be used to copy the
485 // string because the data pointed to by "BootOption->OptionalData"
486 // is not necessarily 2-byte aligned.
490 UnicodeCmdLine
, BootOption
->OptionalData
,
491 MIN (sizeof (UnicodeCmdLine
),
492 BootOption
->OptionalDataSize
)
496 CmdLine
, BootOption
->OptionalData
,
497 MIN (sizeof (CmdLine
),
498 BootOption
->OptionalDataSize
)
503 UnicodeCmdLine
[0] = L
'\0';
509 // We do not request arguments for OptionalData that cannot be printed
512 Status
= EditHIInputStr (UnicodeCmdLine
, BOOT_DEVICE_OPTION_MAX
);
513 if (EFI_ERROR (Status
)) {
514 Status
= EFI_ABORTED
;
515 goto FREE_DEVICE_PATH
;
518 OptionalData
= (UINT8
*)UnicodeCmdLine
;
519 OptionalDataSize
= StrSize (UnicodeCmdLine
);
521 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
522 if (EFI_ERROR (Status
)) {
523 Status
= EFI_ABORTED
;
524 goto FREE_DEVICE_PATH
;
527 OptionalData
= (UINT8
*)CmdLine
;
528 OptionalDataSize
= AsciiStrSize (CmdLine
);
531 // We keep the former OptionalData
532 OptionalData
= BootOption
->OptionalData
;
533 OptionalDataSize
= BootOption
->OptionalDataSize
;
536 Print(L
"Description for this new Entry: ");
537 StrnCpy (BootDescription
, BootOption
->Description
, BOOT_DEVICE_DESCRIPTION_MAX
);
538 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
539 if (EFI_ERROR(Status
)) {
540 Status
= EFI_ABORTED
;
541 goto FREE_DEVICE_PATH
;
545 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
);
548 FreePool (DevicePath
);
551 if (Status
== EFI_ABORTED
) {
560 Ask for the boot option to move and then move it when up or down arrows
561 are pressed. This function is called when the user selects the "Reorder Boot
562 Device Entries" entry in the boot manager menu.
563 The order of the boot options in BootOptionList and in the UEFI BootOrder
564 global variable are kept coherent until the user confirm his reordering (ie:
565 he does not exit by pressing escape).
567 @param[in] BootOptionsList List of the boot devices constructed in
570 @retval EFI_SUCCESS No error encountered.
571 @retval !EFI_SUCCESS An error has occured either in the selection of the
572 boot option to move or while interacting with the user.
577 BootMenuReorderBootOptions (
578 IN LIST_ENTRY
*BootOptionsList
582 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
583 LIST_ENTRY
*SelectedEntry
;
584 LIST_ENTRY
*PrevEntry
;
590 LIST_ENTRY
*SecondEntry
;
596 DisplayBootOptions (BootOptionsList
);
598 // Ask to select the boot option to move
600 Status
= SelectBootOption (BootOptionsList
, MOVE_BOOT_ENTRY
, &BootOptionEntry
);
601 if (EFI_ERROR (Status
)) {
605 SelectedEntry
= &BootOptionEntry
->Link
;
607 // Note down the previous entry in the list to be able to cancel changes
608 PrevEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
610 // Start of interaction
613 L
"* Use up/down arrows to move the entry '%s'",
614 BootOptionEntry
->BdsLoadOption
->Description
617 // Wait for a move, save or cancel request
622 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
623 if (!EFI_ERROR (Status
)) {
624 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
626 if (EFI_ERROR (Status
)) {
631 switch (Key
.ScanCode
) {
633 Save
= (Key
.UnicodeChar
== CHAR_LINEFEED
) ||
634 (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) ||
635 (Key
.UnicodeChar
== 0x7f);
639 SecondEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
640 Move
= SecondEntry
!= BootOptionsList
;
644 SecondEntry
= GetNextNode (BootOptionsList
, SelectedEntry
);
645 Move
= SecondEntry
!= BootOptionsList
;
652 } while ((!Move
) && (!Save
) && (!Cancel
));
655 if ((SelectedEntry
!= NULL
) && (SecondEntry
!= NULL
)) {
656 SwapListEntries (SelectedEntry
, SecondEntry
);
660 Status
= GetGlobalEnvironmentVariable (
661 L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
663 BootOrderSize
/= sizeof (UINT16
);
665 if (!EFI_ERROR (Status
)) {
666 // The order of the boot options in the 'BootOptionsList' is the
667 // new order that has been just defined by the user. Save this new
668 // order in "BootOrder" UEFI global variable.
669 Entry
= GetFirstNode (BootOptionsList
);
670 for (Index
= 0; Index
< BootOrderSize
; Index
++) {
671 BootOrder
[Index
] = (LOAD_OPTION_FROM_LINK (Entry
))->LoadOptionIndex
;
672 Entry
= GetNextNode (BootOptionsList
, Entry
);
674 Status
= gRT
->SetVariable (
675 (CHAR16
*)L
"BootOrder",
676 &gEfiGlobalVariableGuid
,
677 EFI_VARIABLE_NON_VOLATILE
|
678 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
679 EFI_VARIABLE_RUNTIME_ACCESS
,
680 BootOrderSize
* sizeof (UINT16
),
683 FreePool (BootOrder
);
686 if (EFI_ERROR (Status
)) {
687 Print (L
"\nAn error occurred, move not completed!\n");
694 // Restore initial position of the selected boot option
696 RemoveEntryList (SelectedEntry
);
697 InsertHeadList (PrevEntry
, SelectedEntry
);
702 DisplayBootOptions (BootOptionsList
);
703 // Saved or cancelled, back to the choice of boot option to move
716 IN LIST_ENTRY
*BootOptionsList
720 BDS_SUPPORTED_DEVICE
*SupportedBootDevice
;
721 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePathNodes
;
722 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePath
;
723 CHAR16
*FdtTextDevicePath
;
724 EFI_PHYSICAL_ADDRESS FdtBlobBase
;
727 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase
;
729 SupportedBootDevice
= NULL
;
731 Status
= SelectBootDevice (&SupportedBootDevice
);
732 if (EFI_ERROR (Status
)) {
733 Status
= EFI_ABORTED
;
737 // Create the specific device path node
738 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"FDT blob", &FdtDevicePathNodes
);
739 if (EFI_ERROR (Status
)) {
740 Status
= EFI_ABORTED
;
744 if (FdtDevicePathNodes
!= NULL
) {
745 Status
= EFI_OUT_OF_RESOURCES
;
747 FdtDevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, FdtDevicePathNodes
);
748 FreePool (FdtDevicePathNodes
);
749 if (FdtDevicePath
== NULL
) {
753 FdtTextDevicePath
= ConvertDevicePathToText (FdtDevicePath
, TRUE
, TRUE
);
754 if (FdtTextDevicePath
== NULL
) {
758 Status
= gRT
->SetVariable (
761 EFI_VARIABLE_RUNTIME_ACCESS
|
762 EFI_VARIABLE_NON_VOLATILE
|
763 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
764 StrSize (FdtTextDevicePath
),
767 ASSERT_EFI_ERROR (Status
);
768 FreePool (FdtTextDevicePath
);
770 Status
= gRT
->SetVariable (
773 EFI_VARIABLE_RUNTIME_ACCESS
|
774 EFI_VARIABLE_NON_VOLATILE
|
775 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
779 ASSERT_EFI_ERROR (Status
);
784 // Try to load FDT from the new EFI Device Path
788 // Load the FDT given its device path.
789 // This operation may fail if the device path is not supported.
793 Status
= BdsLoadImage (FdtDevicePath
, AllocateAnyPages
, &FdtBlobBase
, &FdtBlobSize
);
794 FreePool (FdtDevicePath
);
796 if (EFI_ERROR (Status
)) {
800 // Check the FDT header is valid. We only make this check in DEBUG mode in
801 // case the FDT header change on production device and this ASSERT() becomes
803 ASSERT (fdt_check_header ((VOID
*)(UINTN
)FdtBlobBase
) == 0);
806 // Ensure the Size of the Device Tree is smaller than the size of the read file
808 ASSERT ((UINTN
)fdt_totalsize ((VOID
*)(UINTN
)FdtBlobBase
) <= FdtBlobSize
);
811 // Store the FDT as Runtime Service Data to prevent the Kernel from
812 // overwritting its data.
814 NumPages
= EFI_SIZE_TO_PAGES (FdtBlobSize
);
815 Status
= gBS
->AllocatePages (
816 AllocateAnyPages
, EfiRuntimeServicesData
,
817 NumPages
, &FdtConfigurationTableBase
819 if (EFI_ERROR (Status
)) {
823 (VOID
*)(UINTN
)FdtConfigurationTableBase
,
824 (VOID
*)(UINTN
)FdtBlobBase
,
829 // Install the FDT into the Configuration Table
831 Status
= gBS
->InstallConfigurationTable (
833 (VOID
*)(UINTN
)FdtConfigurationTableBase
835 if (EFI_ERROR (Status
)) {
836 gBS
->FreePages (FdtConfigurationTableBase
, NumPages
);
840 if (EFI_ERROR (Status
)) {
841 Print (L
"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");
844 if (FdtBlobBase
!= 0) {
845 gBS
->FreePages (FdtBlobBase
, NumPages
);
849 if (Status
== EFI_ABORTED
) {
853 if (SupportedBootDevice
!= NULL
) {
854 FreePool (SupportedBootDevice
);
863 Ask for the boot timeout in seconds and if the input succeeds assign the
864 input value to the UEFI global variable "Timeout". This function is called
865 when the user selects the "Set Boot Timeout" of the boot manager menu.
867 @param[in] BootOptionsList List of the boot devices, not used here
869 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
870 input and assigned to the UEFI "Timeout" global
872 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
873 variable "Timeout" has failed.
877 BootMenuSetBootTimeout (
878 IN LIST_ENTRY
*BootOptionsList
885 Print (L
"Timeout duration (in seconds): ");
886 Status
= GetHIInputInteger (&Input
);
887 if (EFI_ERROR (Status
)) {
893 Status
= gRT
->SetVariable (
895 &gEfiGlobalVariableGuid
,
896 EFI_VARIABLE_NON_VOLATILE
|
897 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
898 EFI_VARIABLE_RUNTIME_ACCESS
,
902 ASSERT_EFI_ERROR (Status
);
908 struct BOOT_MANAGER_ENTRY
{
909 CONST CHAR16
* Description
;
910 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
911 } BootManagerEntries
[] = {
912 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
913 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
914 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
915 { L
"Reorder Boot Device Entries", BootMenuReorderBootOptions
},
916 { L
"Update FDT path", UpdateFdtPath
},
917 { L
"Set Boot Timeout", BootMenuSetBootTimeout
},
922 IN LIST_ENTRY
*BootOptionsList
926 UINTN OptionSelected
;
927 UINTN BootManagerEntryCount
;
930 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
933 // Display Boot Manager menu
934 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
935 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
937 Print(L
"[%d] Return to main menu\n",Index
+1);
939 // Select which entry to call
941 Status
= GetHIInputInteger (&OptionSelected
);
942 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
943 if (EFI_ERROR(Status
)) {
947 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
948 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
951 // Should never go here
956 IN LIST_ENTRY
*BootOptionsList
960 EFI_DEVICE_PATH
* EfiShellDevicePath
;
962 // Find the EFI Shell
963 Status
= LocateEfiApplicationInFvByName (L
"Shell", &EfiShellDevicePath
);
964 if (Status
== EFI_NOT_FOUND
) {
965 Print (L
"Error: EFI Application not found.\n");
967 } else if (EFI_ERROR (Status
)) {
968 Print (L
"Error: Status Code: 0x%X\n", (UINT32
)Status
);
971 // Need to connect every drivers to ensure no dependencies are missing for the application
972 Status
= BdsConnectAllDrivers ();
973 if (EFI_ERROR (Status
)) {
974 DEBUG ((EFI_D_ERROR
, "FAIL to connect all drivers\n"));
978 return BdsStartEfiApplication (gImageHandle
, EfiShellDevicePath
, 0, NULL
);
982 struct BOOT_MAIN_ENTRY
{
983 CONST CHAR16
* Description
;
984 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
985 } BootMainEntries
[] = {
986 { L
"Shell", BootShell
},
987 { L
"Boot Manager", BootMenuManager
},
995 LIST_ENTRY BootOptionsList
;
997 UINTN BootOptionCount
;
1000 BDS_LOAD_OPTION
* BootOption
;
1001 UINTN BootOptionSelected
;
1003 UINTN BootMainEntryCount
;
1007 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
1009 if (FeaturePcdGet (PcdBdsLinuxSupport
)) {
1010 // Check Linux Loader is present
1011 Status
= LocateEfiApplicationInFvByGuid (&mLinuxLoaderAppGuid
, &mLinuxLoaderDevicePath
);
1012 ASSERT_EFI_ERROR (Status
);
1016 // Get Boot#### list
1017 BootOptionList (&BootOptionsList
);
1021 // Display the Boot options
1022 for (Entry
= GetFirstNode (&BootOptionsList
);
1023 !IsNull (&BootOptionsList
,Entry
);
1024 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1027 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1029 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
1032 CHAR16
* DevicePathTxt
;
1033 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
1035 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
1036 if (EFI_ERROR(Status
)) {
1037 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
1038 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
1041 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
1043 Print(L
"\t- %s\n",DevicePathTxt
);
1045 if (BootOption
->OptionalData
!= NULL
) {
1046 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
1048 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
1050 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
1054 FreePool(DevicePathTxt
);
1059 BootOptionCount
= OptionCount
-1;
1061 // Display the hardcoded Boot entries
1062 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
1063 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
1067 // Request the boot entry from the user
1068 BootOptionSelected
= 0;
1069 while (BootOptionSelected
== 0) {
1071 Status
= GetHIInputInteger (&BootOptionSelected
);
1072 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
1073 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
1074 BootOptionSelected
= 0;
1078 // Start the selected entry
1079 if (BootOptionSelected
> BootOptionCount
) {
1080 // Start the hardcoded entry
1081 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
1083 // Find the selected entry from the Boot#### list
1085 for (Entry
= GetFirstNode (&BootOptionsList
);
1086 !IsNull (&BootOptionsList
,Entry
);
1087 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1090 if (Index
== BootOptionSelected
) {
1091 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1097 Status
= BootOptionStart (BootOption
);
1100 // Should never go here