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>
18 #include <Guid/ArmPlatformEvents.h>
20 extern BDS_LOAD_OPTION_SUPPORT
*BdsLoadOptionSupportList
;
23 Worker function that displays the list of boot options that is passed in.
25 The function loops over the entries of the list of boot options that is passed
26 in. For each entry, the boot option description is displayed on a single line
27 along with the position of the option in the list. In debug mode, the UEFI
28 device path and the arguments of the boot option are displayed as well in
31 @param[in] BootOptionsList List of the boot options
37 IN LIST_ENTRY
* BootOptionsList
41 UINTN BootOptionCount
;
43 BDS_LOAD_OPTION
*BdsLoadOption
;
47 for (Entry
= GetFirstNode (BootOptionsList
);
48 !IsNull (BootOptionsList
, Entry
);
49 Entry
= GetNextNode (BootOptionsList
, Entry
)
52 BdsLoadOption
= LOAD_OPTION_FROM_LINK (Entry
);
53 Print (L
"[%d] %s\n", ++BootOptionCount
, BdsLoadOption
->Description
);
56 CHAR16
* DevicePathTxt
;
57 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
58 ARM_BDS_LOADER_TYPE LoaderType
;
59 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
61 Status
= gBS
->LocateProtocol (
62 &gEfiDevicePathToTextProtocolGuid
,
64 (VOID
**)&DevicePathToTextProtocol
66 ASSERT_EFI_ERROR (Status
);
67 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
68 BdsLoadOption
->FilePathList
,
72 Print (L
"\t- %s\n", DevicePathTxt
);
74 OptionalData
= BdsLoadOption
->OptionalData
;
75 if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption
)) {
76 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
77 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) ||
78 (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) ) {
79 Print (L
"\t- Arguments: %a\n", &OptionalData
->Arguments
.LinuxArguments
+ 1);
81 } else if (OptionalData
!= NULL
) {
82 if (IsPrintableString (OptionalData
, &IsUnicode
)) {
84 Print (L
"\t- Arguments: %s\n", OptionalData
);
86 AsciiPrint ("\t- Arguments: %a\n", OptionalData
);
91 FreePool (DevicePathTxt
);
97 Worker function that asks for a boot option to be selected and returns a
98 pointer to the structure describing the selected boot option.
100 @param[in] BootOptionsList List of the boot options
102 @retval EFI_SUCCESS Selection succeeded
103 @retval !EFI_SUCCESS Input error or input cancelled
109 IN LIST_ENTRY
* BootOptionsList
,
110 IN CONST CHAR16
* InputStatement
,
111 OUT BDS_LOAD_OPTION_ENTRY
** BdsLoadOptionEntry
115 UINTN BootOptionCount
;
118 UINTN BootOptionSelected
;
121 // Get the number of boot options
122 Status
= GetGlobalEnvironmentVariable (
123 L
"BootOrder", NULL
, &BootOptionCount
, (VOID
**)&BootOrder
125 if (EFI_ERROR (Status
)) {
128 FreePool (BootOrder
);
129 BootOptionCount
/= sizeof (UINT16
);
131 // Check if a valid boot option(s) is found
132 if (BootOptionCount
== 0) {
133 if (StrCmp (InputStatement
, DELETE_BOOT_ENTRY
) == 0) {
134 Print (L
"Nothing to remove!\n");
135 } else if (StrCmp (InputStatement
, UPDATE_BOOT_ENTRY
) == 0) {
136 Print (L
"Nothing to update!\n");
137 } else if (StrCmp (InputStatement
, MOVE_BOOT_ENTRY
) == 0) {
138 Print (L
"Nothing to move!\n");
140 Print (L
"No supported Boot Entry.\n");
142 return EFI_NOT_FOUND
;
145 // Get the index of the boot device to delete
146 BootOptionSelected
= 0;
147 while (BootOptionSelected
== 0) {
148 Print (InputStatement
);
149 Status
= GetHIInputInteger (&BootOptionSelected
);
150 if (EFI_ERROR (Status
)) {
153 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
> BootOptionCount
)) {
154 Print (L
"Invalid input (max %d)\n", BootOptionCount
);
155 BootOptionSelected
= 0;
159 // Get the structure of the Boot device to delete
161 for (Entry
= GetFirstNode (BootOptionsList
);
162 !IsNull (BootOptionsList
, Entry
);
163 Entry
= GetNextNode (BootOptionsList
,Entry
)
166 if (Index
== BootOptionSelected
) {
167 *BdsLoadOptionEntry
= LOAD_OPTION_ENTRY_FROM_LINK (Entry
);
180 OUT BDS_SUPPORTED_DEVICE
** SupportedBootDevice
184 LIST_ENTRY SupportedDeviceList
;
185 UINTN SupportedDeviceCount
;
187 UINTN SupportedDeviceSelected
;
191 // List the Boot Devices supported
194 // Start all the drivers first
195 BdsConnectAllDrivers ();
197 // List the supported devices
198 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
199 ASSERT_EFI_ERROR(Status
);
201 SupportedDeviceCount
= 0;
202 for (Entry
= GetFirstNode (&SupportedDeviceList
);
203 !IsNull (&SupportedDeviceList
,Entry
);
204 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
207 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
208 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,(*SupportedBootDevice
)->Description
);
211 CHAR16
* DevicePathTxt
;
212 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
214 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
215 ASSERT_EFI_ERROR(Status
);
216 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText ((*SupportedBootDevice
)->DevicePathProtocol
,TRUE
,TRUE
);
218 Print(L
"\t- %s\n",DevicePathTxt
);
220 FreePool(DevicePathTxt
);
223 SupportedDeviceCount
++;
226 if (SupportedDeviceCount
== 0) {
227 Print(L
"There is no supported device.\n");
228 Status
= EFI_ABORTED
;
233 // Select the Boot Device
235 SupportedDeviceSelected
= 0;
236 while (SupportedDeviceSelected
== 0) {
237 Print(L
"Select the Boot Device: ");
238 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
239 if (EFI_ERROR(Status
)) {
240 Status
= EFI_ABORTED
;
242 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
243 Print(L
"Invalid input (max %d)\n",SupportedDeviceCount
);
244 SupportedDeviceSelected
= 0;
249 // Get the Device Path for the selected boot device
252 for (Entry
= GetFirstNode (&SupportedDeviceList
);
253 !IsNull (&SupportedDeviceList
,Entry
);
254 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
257 if (Index
== SupportedDeviceSelected
) {
258 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
265 BootDeviceListSupportedFree (&SupportedDeviceList
, *SupportedBootDevice
);
270 BootMenuAddBootOption (
271 IN LIST_ENTRY
*BootOptionsList
275 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
276 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
277 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
278 CHAR8 AsciiCmdLine
[BOOT_DEVICE_OPTION_MAX
];
279 CHAR16 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
281 ARM_BDS_LOADER_TYPE BootType
;
282 BDS_LOAD_OPTION_ENTRY
*BdsLoadOptionEntry
;
283 EFI_DEVICE_PATH
*DevicePath
;
284 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNodes
;
285 EFI_DEVICE_PATH_PROTOCOL
*InitrdPathNodes
;
286 EFI_DEVICE_PATH_PROTOCOL
*InitrdPath
;
288 BOOLEAN InitrdSupport
;
291 UINTN OptionalDataSize
;
294 SupportedBootDevice
= NULL
;
296 // List the Boot Devices supported
297 Status
= SelectBootDevice (&SupportedBootDevice
);
298 if (EFI_ERROR(Status
)) {
299 Status
= EFI_ABORTED
;
303 // Create the specific device path node
304 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application or the kernel", &DevicePathNodes
);
305 if (EFI_ERROR(Status
)) {
306 Status
= EFI_ABORTED
;
309 // Append the Device Path to the selected device path
310 DevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNodes
);
311 if (DevicePath
== NULL
) {
312 Status
= EFI_OUT_OF_RESOURCES
;
316 if (SupportedBootDevice
->Support
->RequestBootType
) {
317 Status
= BootDeviceGetType (DevicePath
, &BootType
, &Attributes
);
318 if (EFI_ERROR(Status
)) {
319 Status
= EFI_ABORTED
;
323 BootType
= BDS_LOADER_EFI_APPLICATION
;
326 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
327 Print(L
"Add an initrd: ");
328 Status
= GetHIInputBoolean (&InitrdSupport
);
329 if (EFI_ERROR(Status
)) {
330 Status
= EFI_ABORTED
;
335 // Create the specific device path node
336 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"initrd", &InitrdPathNodes
);
337 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
338 Status
= EFI_ABORTED
;
342 if (InitrdPathNodes
!= NULL
) {
343 // Append the Device Path to the selected device path
344 InitrdPath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNodes
);
345 // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
346 FreePool (InitrdPathNodes
);
348 if (InitrdPath
== NULL
) {
349 Status
= EFI_OUT_OF_RESOURCES
;
359 Print(L
"Arguments to pass to the binary: ");
360 Status
= GetHIInputAscii (AsciiCmdLine
, BOOT_DEVICE_OPTION_MAX
);
361 if (EFI_ERROR(Status
)) {
362 Status
= EFI_ABORTED
;
363 goto FREE_DEVICE_PATH
;
366 CmdLineSize
= AsciiStrSize (AsciiCmdLine
);
367 InitrdSize
= GetDevicePathSize (InitrdPath
);
369 OptionalDataSize
= sizeof(ARM_BDS_LOADER_ARGUMENTS
) + CmdLineSize
+ InitrdSize
;
370 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)AllocatePool (OptionalDataSize
);
372 BootArguments
->LinuxArguments
.CmdLineSize
= CmdLineSize
;
373 BootArguments
->LinuxArguments
.InitrdSize
= InitrdSize
;
374 CopyMem ((VOID
*)(&BootArguments
->LinuxArguments
+ 1), AsciiCmdLine
, CmdLineSize
);
375 CopyMem ((VOID
*)((UINTN
)(&BootArguments
->LinuxArguments
+ 1) + CmdLineSize
), InitrdPath
, InitrdSize
);
377 OptionalData
= (UINT8
*)BootArguments
;
379 Print (L
"Arguments to pass to the EFI Application: ");
380 Status
= GetHIInputStr (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
381 if (EFI_ERROR (Status
)) {
382 Status
= EFI_ABORTED
;
386 OptionalData
= (UINT8
*)CmdLine
;
387 OptionalDataSize
= StrSize (CmdLine
);
390 Print(L
"Description for this new Entry: ");
391 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
392 if (EFI_ERROR(Status
)) {
393 Status
= EFI_ABORTED
;
394 goto FREE_DEVICE_PATH
;
398 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY
));
399 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
, &BdsLoadOptionEntry
->BdsLoadOption
);
400 if (!EFI_ERROR(Status
)) {
401 InsertTailList (BootOptionsList
, &BdsLoadOptionEntry
->Link
);
405 FreePool (DevicePath
);
408 if (Status
== EFI_ABORTED
) {
411 FreePool(SupportedBootDevice
);
416 BootMenuRemoveBootOption (
417 IN LIST_ENTRY
*BootOptionsList
421 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
423 DisplayBootOptions (BootOptionsList
);
424 Status
= SelectBootOption (BootOptionsList
, DELETE_BOOT_ENTRY
, &BootOptionEntry
);
425 if (EFI_ERROR (Status
)) {
429 // If the Boot Option was attached to a list remove it
430 if (!IsListEmpty (&BootOptionEntry
->Link
)) {
431 // Remove the entry from the list
432 RemoveEntryList (&BootOptionEntry
->Link
);
435 // Delete the BDS Load option structures
436 BootOptionDelete (BootOptionEntry
->BdsLoadOption
);
442 BootMenuUpdateBootOption (
443 IN LIST_ENTRY
*BootOptionsList
447 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
448 BDS_LOAD_OPTION
*BootOption
;
449 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
450 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
451 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
452 CHAR8 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
453 CHAR16 UnicodeCmdLine
[BOOT_DEVICE_OPTION_MAX
];
454 EFI_DEVICE_PATH
*DevicePath
;
455 EFI_DEVICE_PATH
*TempInitrdPath
;
456 ARM_BDS_LOADER_TYPE BootType
;
457 ARM_BDS_LOADER_OPTIONAL_DATA
* LoaderOptionalData
;
458 ARM_BDS_LINUX_ARGUMENTS
* LinuxArguments
;
459 EFI_DEVICE_PATH
*InitrdPathNodes
;
460 EFI_DEVICE_PATH
*InitrdPath
;
463 BOOLEAN InitrdSupport
;
465 UINTN OptionalDataSize
;
469 DisplayBootOptions (BootOptionsList
);
470 Status
= SelectBootOption (BootOptionsList
, UPDATE_BOOT_ENTRY
, &BootOptionEntry
);
471 if (EFI_ERROR (Status
)) {
474 BootOption
= BootOptionEntry
->BdsLoadOption
;
476 // Get the device support for this Boot Option
477 Status
= BootDeviceGetDeviceSupport (BootOption
->FilePathList
, &DeviceSupport
);
478 if (EFI_ERROR(Status
)) {
479 Print(L
"Not possible to retrieve the supported device for the update\n");
480 return EFI_UNSUPPORTED
;
483 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application or the kernel", &DevicePath
);
484 if (EFI_ERROR(Status
)) {
485 Status
= EFI_ABORTED
;
489 if (DeviceSupport
->RequestBootType
) {
490 Status
= BootDeviceGetType (DevicePath
, &BootType
, &BootOption
->Attributes
);
491 if (EFI_ERROR(Status
)) {
492 Status
= EFI_ABORTED
;
497 LoaderOptionalData
= BootOption
->OptionalData
;
498 if (LoaderOptionalData
!= NULL
) {
499 BootType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((UINT32
*)(&LoaderOptionalData
->Header
.LoaderType
));
501 BootType
= BDS_LOADER_EFI_APPLICATION
;
504 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
505 LinuxArguments
= &LoaderOptionalData
->Arguments
.LinuxArguments
;
507 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
509 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
510 if (InitrdSize
> 0) {
511 Print(L
"Keep the initrd: ");
513 Print(L
"Add an initrd: ");
515 Status
= GetHIInputBoolean (&InitrdSupport
);
516 if (EFI_ERROR(Status
)) {
517 Status
= EFI_ABORTED
;
522 if (InitrdSize
> 0) {
523 // Case we update the initrd device path
524 Status
= DeviceSupport
->UpdateDevicePathNode ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
), L
"initrd", &InitrdPath
);
525 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
526 Status
= EFI_ABORTED
;
529 InitrdSize
= GetDevicePathSize (InitrdPath
);
531 // Case we create the initrd device path
533 Status
= DeviceSupport
->CreateDevicePathNode (L
"initrd", &InitrdPathNodes
);
534 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
535 Status
= EFI_ABORTED
;
539 if (InitrdPathNodes
!= NULL
) {
540 // Duplicate Linux kernel Device Path
541 TempInitrdPath
= DuplicateDevicePath (BootOption
->FilePathList
);
542 // Replace Linux kernel Node by EndNode
543 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath
));
544 // Append the Device Path to the selected device path
545 InitrdPath
= AppendDevicePath (TempInitrdPath
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNodes
);
546 FreePool (TempInitrdPath
);
547 // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
548 FreePool (InitrdPathNodes
);
549 if (InitrdPath
== NULL
) {
550 Status
= EFI_OUT_OF_RESOURCES
;
553 InitrdSize
= GetDevicePathSize (InitrdPath
);
562 Print(L
"Arguments to pass to the binary: ");
563 if (CmdLineSize
> 0) {
564 AsciiStrnCpy (CmdLine
, (CONST CHAR8
*)(LinuxArguments
+ 1), sizeof (CmdLine
));
565 CmdLine
[sizeof (CmdLine
) - 1] = '\0';
569 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
570 if (EFI_ERROR(Status
)) {
571 Status
= EFI_ABORTED
;
572 goto FREE_DEVICE_PATH
;
575 CmdLineSize
= AsciiStrSize (CmdLine
);
577 OptionalDataSize
= sizeof(ARM_BDS_LOADER_ARGUMENTS
) + CmdLineSize
+ InitrdSize
;
578 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)AllocatePool (OptionalDataSize
);
579 BootArguments
->LinuxArguments
.CmdLineSize
= CmdLineSize
;
580 BootArguments
->LinuxArguments
.InitrdSize
= InitrdSize
;
581 CopyMem (&BootArguments
->LinuxArguments
+ 1, CmdLine
, CmdLineSize
);
582 CopyMem ((VOID
*)((UINTN
)(&BootArguments
->LinuxArguments
+ 1) + CmdLineSize
), InitrdPath
, InitrdSize
);
584 OptionalData
= (UINT8
*)BootArguments
;
586 Print (L
"Arguments to pass to the EFI Application: ");
588 if (BootOption
->OptionalDataSize
> 0) {
589 IsPrintable
= IsPrintableString (BootOption
->OptionalData
, &IsUnicode
);
592 // The size in bytes of the string, final zero included, should
593 // be equal to or at least lower than "BootOption->OptionalDataSize"
594 // and the "IsPrintableString()" has already tested that the length
595 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
596 // final '\0' included. We can thus copy the string for editing
597 // using "CopyMem()". Furthermore, note that in the case of an Unicode
598 // string "StrnCpy()" and "StrCpy()" can not be used to copy the
599 // string because the data pointed to by "BootOption->OptionalData"
600 // is not necessarily 2-byte aligned.
604 UnicodeCmdLine
, BootOption
->OptionalData
,
605 MIN (sizeof (UnicodeCmdLine
),
606 BootOption
->OptionalDataSize
)
610 CmdLine
, BootOption
->OptionalData
,
611 MIN (sizeof (CmdLine
),
612 BootOption
->OptionalDataSize
)
617 UnicodeCmdLine
[0] = L
'\0';
622 // We do not request arguments for OptionalData that cannot be printed
625 Status
= EditHIInputStr (UnicodeCmdLine
, BOOT_DEVICE_OPTION_MAX
);
626 if (EFI_ERROR (Status
)) {
627 Status
= EFI_ABORTED
;
628 goto FREE_DEVICE_PATH
;
631 OptionalData
= (UINT8
*)UnicodeCmdLine
;
632 OptionalDataSize
= StrSize (UnicodeCmdLine
);
634 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
635 if (EFI_ERROR (Status
)) {
636 Status
= EFI_ABORTED
;
637 goto FREE_DEVICE_PATH
;
640 OptionalData
= (UINT8
*)CmdLine
;
641 OptionalDataSize
= AsciiStrSize (CmdLine
);
644 // We keep the former OptionalData
645 OptionalData
= BootOption
->OptionalData
;
646 OptionalDataSize
= BootOption
->OptionalDataSize
;
650 Print(L
"Description for this new Entry: ");
651 StrnCpy (BootDescription
, BootOption
->Description
, BOOT_DEVICE_DESCRIPTION_MAX
);
652 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
653 if (EFI_ERROR(Status
)) {
654 Status
= EFI_ABORTED
;
655 goto FREE_DEVICE_PATH
;
659 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
662 FreePool (DevicePath
);
665 if (Status
== EFI_ABORTED
) {
674 Ask for the boot option to move and then move it when up or down arrows
675 are pressed. This function is called when the user selects the "Reorder Boot
676 Device Entries" entry in the boot manager menu.
677 The order of the boot options in BootOptionList and in the UEFI BootOrder
678 global variable are kept coherent until the user confirm his reordering (ie:
679 he does not exit by pressing escape).
681 @param[in] BootOptionsList List of the boot devices constructed in
684 @retval EFI_SUCCESS No error encountered.
685 @retval !EFI_SUCCESS An error has occured either in the selection of the
686 boot option to move or while interacting with the user.
691 BootMenuReorderBootOptions (
692 IN LIST_ENTRY
*BootOptionsList
696 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
697 LIST_ENTRY
*SelectedEntry
;
698 LIST_ENTRY
*PrevEntry
;
704 LIST_ENTRY
*SecondEntry
;
710 DisplayBootOptions (BootOptionsList
);
712 // Ask to select the boot option to move
714 Status
= SelectBootOption (BootOptionsList
, MOVE_BOOT_ENTRY
, &BootOptionEntry
);
715 if (EFI_ERROR (Status
)) {
719 SelectedEntry
= &BootOptionEntry
->Link
;
721 // Note down the previous entry in the list to be able to cancel changes
722 PrevEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
724 // Start of interaction
727 L
"* Use up/down arrows to move the entry '%s'",
728 BootOptionEntry
->BdsLoadOption
->Description
731 // Wait for a move, save or cancel request
736 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
737 if (!EFI_ERROR (Status
)) {
738 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
740 if (EFI_ERROR (Status
)) {
745 switch (Key
.ScanCode
) {
747 Save
= (Key
.UnicodeChar
== CHAR_LINEFEED
) ||
748 (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) ||
749 (Key
.UnicodeChar
== 0x7f);
753 SecondEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
754 Move
= SecondEntry
!= BootOptionsList
;
758 SecondEntry
= GetNextNode (BootOptionsList
, SelectedEntry
);
759 Move
= SecondEntry
!= BootOptionsList
;
766 } while ((!Move
) && (!Save
) && (!Cancel
));
769 if ((SelectedEntry
!= NULL
) && (SecondEntry
!= NULL
)) {
770 SwapListEntries (SelectedEntry
, SecondEntry
);
774 Status
= GetGlobalEnvironmentVariable (
775 L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
777 BootOrderSize
/= sizeof (UINT16
);
779 if (!EFI_ERROR (Status
)) {
780 // The order of the boot options in the 'BootOptionsList' is the
781 // new order that has been just defined by the user. Save this new
782 // order in "BootOrder" UEFI global variable.
783 Entry
= GetFirstNode (BootOptionsList
);
784 for (Index
= 0; Index
< BootOrderSize
; Index
++) {
785 BootOrder
[Index
] = (LOAD_OPTION_FROM_LINK (Entry
))->LoadOptionIndex
;
786 Entry
= GetNextNode (BootOptionsList
, Entry
);
788 Status
= gRT
->SetVariable (
789 (CHAR16
*)L
"BootOrder",
790 &gEfiGlobalVariableGuid
,
791 EFI_VARIABLE_NON_VOLATILE
|
792 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
793 EFI_VARIABLE_RUNTIME_ACCESS
,
794 BootOrderSize
* sizeof (UINT16
),
797 FreePool (BootOrder
);
800 if (EFI_ERROR (Status
)) {
801 Print (L
"\nAn error occurred, move not completed!\n");
808 // Restore initial position of the selected boot option
810 RemoveEntryList (SelectedEntry
);
811 InsertHeadList (PrevEntry
, SelectedEntry
);
816 DisplayBootOptions (BootOptionsList
);
817 // Saved or cancelled, back to the choice of boot option to move
830 IN LIST_ENTRY
*BootOptionsList
834 UINTN FdtDevicePathSize
;
835 BDS_SUPPORTED_DEVICE
*SupportedBootDevice
;
836 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePathNodes
;
837 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePath
;
838 EFI_EVENT UpdateFdtEvent
;
840 Status
= SelectBootDevice (&SupportedBootDevice
);
841 if (EFI_ERROR(Status
)) {
842 Status
= EFI_ABORTED
;
846 // Create the specific device path node
847 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"FDT blob", &FdtDevicePathNodes
);
848 if (EFI_ERROR(Status
)) {
849 Status
= EFI_ABORTED
;
853 if (FdtDevicePathNodes
!= NULL
) {
854 // Append the Device Path node to the select device path
855 FdtDevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, FdtDevicePathNodes
);
856 // Free the FdtDevicePathNodes created by Support->CreateDevicePathNode()
857 FreePool (FdtDevicePathNodes
);
858 FdtDevicePathSize
= GetDevicePathSize (FdtDevicePath
);
859 Status
= gRT
->SetVariable (
861 &gArmGlobalVariableGuid
,
862 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
866 ASSERT_EFI_ERROR(Status
);
868 Status
= gRT
->SetVariable (
870 &gArmGlobalVariableGuid
,
871 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
875 ASSERT_EFI_ERROR(Status
);
878 if (!EFI_ERROR (Status
)) {
880 // Signal FDT has been updated
882 Status
= gBS
->CreateEventEx (
885 EmptyCallbackFunction
,
887 &gArmPlatformUpdateFdtEventGuid
,
890 if (!EFI_ERROR (Status
)) {
891 gBS
->SignalEvent (UpdateFdtEvent
);
896 if (Status
== EFI_ABORTED
) {
899 FreePool(SupportedBootDevice
);
906 Ask for the boot timeout in seconds and if the input succeeds assign the
907 input value to the UEFI global variable "Timeout". This function is called
908 when the user selects the "Set Boot Timeout" of the boot manager menu.
910 @param[in] BootOptionsList List of the boot devices, not used here
912 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
913 input and assigned to the UEFI "Timeout" global
915 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
916 variable "Timeout" has failed.
920 BootMenuSetBootTimeout (
921 IN LIST_ENTRY
*BootOptionsList
928 Print (L
"Timeout duration (in seconds): ");
929 Status
= GetHIInputInteger (&Input
);
930 if (EFI_ERROR (Status
)) {
936 Status
= gRT
->SetVariable (
938 &gEfiGlobalVariableGuid
,
939 EFI_VARIABLE_NON_VOLATILE
|
940 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
941 EFI_VARIABLE_RUNTIME_ACCESS
,
945 ASSERT_EFI_ERROR (Status
);
951 struct BOOT_MANAGER_ENTRY
{
952 CONST CHAR16
* Description
;
953 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
954 } BootManagerEntries
[] = {
955 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
956 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
957 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
958 { L
"Reorder Boot Device Entries", BootMenuReorderBootOptions
},
959 { L
"Update FDT path", UpdateFdtPath
},
960 { L
"Set Boot Timeout", BootMenuSetBootTimeout
},
965 IN LIST_ENTRY
*BootOptionsList
969 UINTN OptionSelected
;
970 UINTN BootManagerEntryCount
;
973 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
976 // Display Boot Manager menu
977 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
978 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
980 Print(L
"[%d] Return to main menu\n",Index
+1);
982 // Select which entry to call
984 Status
= GetHIInputInteger (&OptionSelected
);
985 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
986 if (EFI_ERROR(Status
)) {
990 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
991 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
994 // Should never go here
999 IN LIST_ENTRY
*BootOptionsList
1005 Status
= BdsLoadApplication (gImageHandle
, L
"Shell", 0, NULL
);
1006 if (Status
== EFI_NOT_FOUND
) {
1007 Print (L
"Error: EFI Application not found.\n");
1008 } else if (EFI_ERROR(Status
)) {
1009 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
1015 struct BOOT_MAIN_ENTRY
{
1016 CONST CHAR16
* Description
;
1017 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
1018 } BootMainEntries
[] = {
1019 { L
"Shell", BootShell
},
1020 { L
"Boot Manager", BootMenuManager
},
1029 LIST_ENTRY BootOptionsList
;
1031 UINTN BootOptionCount
;
1034 BDS_LOAD_OPTION
* BootOption
;
1035 UINTN BootOptionSelected
;
1037 UINTN BootMainEntryCount
;
1041 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
1044 // Get Boot#### list
1045 BootOptionList (&BootOptionsList
);
1049 // Display the Boot options
1050 for (Entry
= GetFirstNode (&BootOptionsList
);
1051 !IsNull (&BootOptionsList
,Entry
);
1052 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1055 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1057 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
1060 CHAR16
* DevicePathTxt
;
1061 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
1062 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
1064 ARM_BDS_LOADER_TYPE LoaderType
;
1066 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
1067 if (EFI_ERROR(Status
)) {
1068 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
1069 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
1072 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
1074 Print(L
"\t- %s\n",DevicePathTxt
);
1076 // If it is a supported BootEntry then print its details
1077 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
1078 OptionalData
= BootOption
->OptionalData
;
1079 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
1080 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
1081 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.InitrdSize
) > 0) {
1082 CmdLineSize
= ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
);
1083 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
1084 GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(&OptionalData
->Arguments
.LinuxArguments
+ 1) + CmdLineSize
)), TRUE
, TRUE
);
1085 Print(L
"\t- Initrd: %s\n", DevicePathTxt
);
1087 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
) > 0) {
1088 Print(L
"\t- Arguments: %a\n", (&OptionalData
->Arguments
.LinuxArguments
+ 1));
1092 switch (LoaderType
) {
1093 case BDS_LOADER_EFI_APPLICATION
:
1094 Print(L
"\t- LoaderType: EFI Application\n");
1097 case BDS_LOADER_KERNEL_LINUX_ATAG
:
1098 Print(L
"\t- LoaderType: Linux kernel with ATAG support\n");
1101 case BDS_LOADER_KERNEL_LINUX_FDT
:
1102 Print(L
"\t- LoaderType: Linux kernel with FDT support\n");
1106 Print(L
"\t- LoaderType: Not recognized (%d)\n", LoaderType
);
1108 } else if (BootOption
->OptionalData
!= NULL
) {
1109 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
1111 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
1113 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
1117 FreePool(DevicePathTxt
);
1122 BootOptionCount
= OptionCount
-1;
1124 // Display the hardcoded Boot entries
1125 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
1126 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
1130 // Request the boot entry from the user
1131 BootOptionSelected
= 0;
1132 while (BootOptionSelected
== 0) {
1134 Status
= GetHIInputInteger (&BootOptionSelected
);
1135 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
1136 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
1137 BootOptionSelected
= 0;
1141 // Start the selected entry
1142 if (BootOptionSelected
> BootOptionCount
) {
1143 // Start the hardcoded entry
1144 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
1146 // Find the selected entry from the Boot#### list
1148 for (Entry
= GetFirstNode (&BootOptionsList
);
1149 !IsNull (&BootOptionsList
,Entry
);
1150 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1153 if (Index
== BootOptionSelected
) {
1154 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1160 Status
= BootOptionStart (BootOption
);
1163 // Should never go here