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>
19 extern BDS_LOAD_OPTION_SUPPORT
*BdsLoadOptionSupportList
;
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
;
57 ARM_BDS_LOADER_TYPE LoaderType
;
58 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
60 Status
= gBS
->LocateProtocol (
61 &gEfiDevicePathToTextProtocolGuid
,
63 (VOID
**)&DevicePathToTextProtocol
65 ASSERT_EFI_ERROR (Status
);
66 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
67 BdsLoadOption
->FilePathList
,
71 Print (L
"\t- %s\n", DevicePathTxt
);
73 OptionalData
= BdsLoadOption
->OptionalData
;
74 if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption
)) {
75 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
76 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) ||
77 (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) ) {
78 Print (L
"\t- Arguments: %a\n", &OptionalData
->Arguments
.LinuxArguments
+ 1);
80 } else if (OptionalData
!= NULL
) {
81 if (IsPrintableString (OptionalData
, &IsUnicode
)) {
83 Print (L
"\t- Arguments: %s\n", OptionalData
);
85 AsciiPrint ("\t- Arguments: %a\n", OptionalData
);
90 FreePool (DevicePathTxt
);
96 Worker function that asks for a boot option to be selected and returns a
97 pointer to the structure describing the selected boot option.
99 @param[in] BootOptionsList List of the boot options
101 @retval EFI_SUCCESS Selection succeeded
102 @retval !EFI_SUCCESS Input error or input cancelled
108 IN LIST_ENTRY
* BootOptionsList
,
109 IN CONST CHAR16
* InputStatement
,
110 OUT BDS_LOAD_OPTION_ENTRY
** BdsLoadOptionEntry
114 UINTN BootOptionCount
;
117 UINTN BootOptionSelected
;
120 // Get the number of boot options
121 Status
= GetGlobalEnvironmentVariable (
122 L
"BootOrder", NULL
, &BootOptionCount
, (VOID
**)&BootOrder
124 if (EFI_ERROR (Status
)) {
127 FreePool (BootOrder
);
128 BootOptionCount
/= sizeof (UINT16
);
130 // Check if a valid boot option(s) is found
131 if (BootOptionCount
== 0) {
132 if (StrCmp (InputStatement
, DELETE_BOOT_ENTRY
) == 0) {
133 Print (L
"Nothing to remove!\n");
134 } else if (StrCmp (InputStatement
, UPDATE_BOOT_ENTRY
) == 0) {
135 Print (L
"Nothing to update!\n");
136 } else if (StrCmp (InputStatement
, MOVE_BOOT_ENTRY
) == 0) {
137 Print (L
"Nothing to move!\n");
139 Print (L
"No supported Boot Entry.\n");
141 return EFI_NOT_FOUND
;
144 // Get the index of the boot device to delete
145 BootOptionSelected
= 0;
146 while (BootOptionSelected
== 0) {
147 Print (InputStatement
);
148 Status
= GetHIInputInteger (&BootOptionSelected
);
149 if (EFI_ERROR (Status
)) {
152 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
> BootOptionCount
)) {
153 Print (L
"Invalid input (max %d)\n", BootOptionCount
);
154 BootOptionSelected
= 0;
158 // Get the structure of the Boot device to delete
160 for (Entry
= GetFirstNode (BootOptionsList
);
161 !IsNull (BootOptionsList
, Entry
);
162 Entry
= GetNextNode (BootOptionsList
,Entry
)
165 if (Index
== BootOptionSelected
) {
166 *BdsLoadOptionEntry
= LOAD_OPTION_ENTRY_FROM_LINK (Entry
);
179 OUT BDS_SUPPORTED_DEVICE
** SupportedBootDevice
183 LIST_ENTRY SupportedDeviceList
;
184 UINTN SupportedDeviceCount
;
186 UINTN SupportedDeviceSelected
;
190 // List the Boot Devices supported
193 // Start all the drivers first
194 BdsConnectAllDrivers ();
196 // List the supported devices
197 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
198 ASSERT_EFI_ERROR(Status
);
200 SupportedDeviceCount
= 0;
201 for (Entry
= GetFirstNode (&SupportedDeviceList
);
202 !IsNull (&SupportedDeviceList
,Entry
);
203 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
206 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
207 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,(*SupportedBootDevice
)->Description
);
210 CHAR16
* DevicePathTxt
;
211 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
213 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
214 ASSERT_EFI_ERROR(Status
);
215 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText ((*SupportedBootDevice
)->DevicePathProtocol
,TRUE
,TRUE
);
217 Print(L
"\t- %s\n",DevicePathTxt
);
219 FreePool(DevicePathTxt
);
222 SupportedDeviceCount
++;
225 if (SupportedDeviceCount
== 0) {
226 Print(L
"There is no supported device.\n");
227 Status
= EFI_ABORTED
;
232 // Select the Boot Device
234 SupportedDeviceSelected
= 0;
235 while (SupportedDeviceSelected
== 0) {
236 Print(L
"Select the Boot Device: ");
237 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
238 if (EFI_ERROR(Status
)) {
239 Status
= EFI_ABORTED
;
241 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
242 Print(L
"Invalid input (max %d)\n",SupportedDeviceCount
);
243 SupportedDeviceSelected
= 0;
248 // Get the Device Path for the selected boot device
251 for (Entry
= GetFirstNode (&SupportedDeviceList
);
252 !IsNull (&SupportedDeviceList
,Entry
);
253 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
256 if (Index
== SupportedDeviceSelected
) {
257 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
264 BootDeviceListSupportedFree (&SupportedDeviceList
, *SupportedBootDevice
);
269 BootMenuAddBootOption (
270 IN LIST_ENTRY
*BootOptionsList
274 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
275 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
276 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
277 CHAR8 AsciiCmdLine
[BOOT_DEVICE_OPTION_MAX
];
278 CHAR16 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
280 ARM_BDS_LOADER_TYPE BootType
;
281 BDS_LOAD_OPTION_ENTRY
*BdsLoadOptionEntry
;
282 EFI_DEVICE_PATH
*DevicePath
;
283 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNodes
;
284 EFI_DEVICE_PATH_PROTOCOL
*InitrdPathNodes
;
285 EFI_DEVICE_PATH_PROTOCOL
*InitrdPath
;
287 BOOLEAN InitrdSupport
;
290 UINTN OptionalDataSize
;
293 SupportedBootDevice
= NULL
;
295 // List the Boot Devices supported
296 Status
= SelectBootDevice (&SupportedBootDevice
);
297 if (EFI_ERROR(Status
)) {
298 Status
= EFI_ABORTED
;
302 // Create the specific device path node
303 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application or the kernel", &DevicePathNodes
);
304 if (EFI_ERROR(Status
)) {
305 Status
= EFI_ABORTED
;
308 // Append the Device Path to the selected device path
309 DevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNodes
);
310 if (DevicePath
== NULL
) {
311 Status
= EFI_OUT_OF_RESOURCES
;
315 if (SupportedBootDevice
->Support
->RequestBootType
) {
316 Status
= BootDeviceGetType (DevicePath
, &BootType
, &Attributes
);
317 if (EFI_ERROR(Status
)) {
318 Status
= EFI_ABORTED
;
322 BootType
= BDS_LOADER_EFI_APPLICATION
;
325 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
326 Print(L
"Add an initrd: ");
327 Status
= GetHIInputBoolean (&InitrdSupport
);
328 if (EFI_ERROR(Status
)) {
329 Status
= EFI_ABORTED
;
334 // Create the specific device path node
335 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"initrd", &InitrdPathNodes
);
336 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
337 Status
= EFI_ABORTED
;
341 if (InitrdPathNodes
!= NULL
) {
342 // Append the Device Path to the selected device path
343 InitrdPath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNodes
);
344 // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
345 FreePool (InitrdPathNodes
);
347 if (InitrdPath
== NULL
) {
348 Status
= EFI_OUT_OF_RESOURCES
;
358 Print(L
"Arguments to pass to the binary: ");
359 Status
= GetHIInputAscii (AsciiCmdLine
, BOOT_DEVICE_OPTION_MAX
);
360 if (EFI_ERROR(Status
)) {
361 Status
= EFI_ABORTED
;
362 goto FREE_DEVICE_PATH
;
365 CmdLineSize
= AsciiStrSize (AsciiCmdLine
);
366 InitrdSize
= GetDevicePathSize (InitrdPath
);
368 OptionalDataSize
= sizeof(ARM_BDS_LOADER_ARGUMENTS
) + CmdLineSize
+ InitrdSize
;
369 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)AllocatePool (OptionalDataSize
);
371 BootArguments
->LinuxArguments
.CmdLineSize
= CmdLineSize
;
372 BootArguments
->LinuxArguments
.InitrdSize
= InitrdSize
;
373 CopyMem ((VOID
*)(&BootArguments
->LinuxArguments
+ 1), AsciiCmdLine
, CmdLineSize
);
374 CopyMem ((VOID
*)((UINTN
)(&BootArguments
->LinuxArguments
+ 1) + CmdLineSize
), InitrdPath
, InitrdSize
);
376 OptionalData
= (UINT8
*)BootArguments
;
378 Print (L
"Arguments to pass to the EFI Application: ");
379 Status
= GetHIInputStr (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
380 if (EFI_ERROR (Status
)) {
381 Status
= EFI_ABORTED
;
385 OptionalData
= (UINT8
*)CmdLine
;
386 OptionalDataSize
= StrSize (CmdLine
);
389 Print(L
"Description for this new Entry: ");
390 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
391 if (EFI_ERROR(Status
)) {
392 Status
= EFI_ABORTED
;
393 goto FREE_DEVICE_PATH
;
397 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY
));
398 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
, &BdsLoadOptionEntry
->BdsLoadOption
);
399 if (!EFI_ERROR(Status
)) {
400 InsertTailList (BootOptionsList
, &BdsLoadOptionEntry
->Link
);
404 FreePool (DevicePath
);
407 if (Status
== EFI_ABORTED
) {
410 FreePool(SupportedBootDevice
);
415 BootMenuRemoveBootOption (
416 IN LIST_ENTRY
*BootOptionsList
420 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
422 DisplayBootOptions (BootOptionsList
);
423 Status
= SelectBootOption (BootOptionsList
, DELETE_BOOT_ENTRY
, &BootOptionEntry
);
424 if (EFI_ERROR (Status
)) {
428 // If the Boot Option was attached to a list remove it
429 if (!IsListEmpty (&BootOptionEntry
->Link
)) {
430 // Remove the entry from the list
431 RemoveEntryList (&BootOptionEntry
->Link
);
434 // Delete the BDS Load option structures
435 BootOptionDelete (BootOptionEntry
->BdsLoadOption
);
441 BootMenuUpdateBootOption (
442 IN LIST_ENTRY
*BootOptionsList
446 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
447 BDS_LOAD_OPTION
*BootOption
;
448 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
449 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
450 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
451 CHAR8 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
452 CHAR16 UnicodeCmdLine
[BOOT_DEVICE_OPTION_MAX
];
453 EFI_DEVICE_PATH
*DevicePath
;
454 EFI_DEVICE_PATH
*TempInitrdPath
;
455 ARM_BDS_LOADER_TYPE BootType
;
456 ARM_BDS_LOADER_OPTIONAL_DATA
* LoaderOptionalData
;
457 ARM_BDS_LINUX_ARGUMENTS
* LinuxArguments
;
458 EFI_DEVICE_PATH
*InitrdPathNodes
;
459 EFI_DEVICE_PATH
*InitrdPath
;
462 BOOLEAN InitrdSupport
;
464 UINTN OptionalDataSize
;
468 DisplayBootOptions (BootOptionsList
);
469 Status
= SelectBootOption (BootOptionsList
, UPDATE_BOOT_ENTRY
, &BootOptionEntry
);
470 if (EFI_ERROR (Status
)) {
473 BootOption
= BootOptionEntry
->BdsLoadOption
;
475 // Get the device support for this Boot Option
476 Status
= BootDeviceGetDeviceSupport (BootOption
->FilePathList
, &DeviceSupport
);
477 if (EFI_ERROR(Status
)) {
478 Print(L
"Not possible to retrieve the supported device for the update\n");
479 return EFI_UNSUPPORTED
;
482 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application or the kernel", &DevicePath
);
483 if (EFI_ERROR(Status
)) {
484 Status
= EFI_ABORTED
;
488 if (DeviceSupport
->RequestBootType
) {
489 Status
= BootDeviceGetType (DevicePath
, &BootType
, &BootOption
->Attributes
);
490 if (EFI_ERROR(Status
)) {
491 Status
= EFI_ABORTED
;
496 LoaderOptionalData
= BootOption
->OptionalData
;
497 if (LoaderOptionalData
!= NULL
) {
498 BootType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((UINT32
*)(&LoaderOptionalData
->Header
.LoaderType
));
500 BootType
= BDS_LOADER_EFI_APPLICATION
;
503 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
504 LinuxArguments
= &LoaderOptionalData
->Arguments
.LinuxArguments
;
506 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
508 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
509 if (InitrdSize
> 0) {
510 Print(L
"Keep the initrd: ");
512 Print(L
"Add an initrd: ");
514 Status
= GetHIInputBoolean (&InitrdSupport
);
515 if (EFI_ERROR(Status
)) {
516 Status
= EFI_ABORTED
;
521 if (InitrdSize
> 0) {
522 // Case we update the initrd device path
523 Status
= DeviceSupport
->UpdateDevicePathNode ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
), L
"initrd", &InitrdPath
);
524 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
525 Status
= EFI_ABORTED
;
528 InitrdSize
= GetDevicePathSize (InitrdPath
);
530 // Case we create the initrd device path
532 Status
= DeviceSupport
->CreateDevicePathNode (L
"initrd", &InitrdPathNodes
);
533 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
534 Status
= EFI_ABORTED
;
538 if (InitrdPathNodes
!= NULL
) {
539 // Duplicate Linux kernel Device Path
540 TempInitrdPath
= DuplicateDevicePath (BootOption
->FilePathList
);
541 // Replace Linux kernel Node by EndNode
542 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath
));
543 // Append the Device Path to the selected device path
544 InitrdPath
= AppendDevicePath (TempInitrdPath
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNodes
);
545 FreePool (TempInitrdPath
);
546 // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
547 FreePool (InitrdPathNodes
);
548 if (InitrdPath
== NULL
) {
549 Status
= EFI_OUT_OF_RESOURCES
;
552 InitrdSize
= GetDevicePathSize (InitrdPath
);
561 Print(L
"Arguments to pass to the binary: ");
562 if (CmdLineSize
> 0) {
563 AsciiStrnCpy (CmdLine
, (CONST CHAR8
*)(LinuxArguments
+ 1), sizeof (CmdLine
));
564 CmdLine
[sizeof (CmdLine
) - 1] = '\0';
568 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
569 if (EFI_ERROR(Status
)) {
570 Status
= EFI_ABORTED
;
571 goto FREE_DEVICE_PATH
;
574 CmdLineSize
= AsciiStrSize (CmdLine
);
576 OptionalDataSize
= sizeof(ARM_BDS_LOADER_ARGUMENTS
) + CmdLineSize
+ InitrdSize
;
577 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)AllocatePool (OptionalDataSize
);
578 BootArguments
->LinuxArguments
.CmdLineSize
= CmdLineSize
;
579 BootArguments
->LinuxArguments
.InitrdSize
= InitrdSize
;
580 CopyMem (&BootArguments
->LinuxArguments
+ 1, CmdLine
, CmdLineSize
);
581 CopyMem ((VOID
*)((UINTN
)(&BootArguments
->LinuxArguments
+ 1) + CmdLineSize
), InitrdPath
, InitrdSize
);
583 OptionalData
= (UINT8
*)BootArguments
;
585 Print (L
"Arguments to pass to the EFI Application: ");
587 if (BootOption
->OptionalDataSize
> 0) {
588 IsPrintable
= IsPrintableString (BootOption
->OptionalData
, &IsUnicode
);
591 // The size in bytes of the string, final zero included, should
592 // be equal to or at least lower than "BootOption->OptionalDataSize"
593 // and the "IsPrintableString()" has already tested that the length
594 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
595 // final '\0' included. We can thus copy the string for editing
596 // using "CopyMem()". Furthermore, note that in the case of an Unicode
597 // string "StrnCpy()" and "StrCpy()" can not be used to copy the
598 // string because the data pointed to by "BootOption->OptionalData"
599 // is not necessarily 2-byte aligned.
603 UnicodeCmdLine
, BootOption
->OptionalData
,
604 MIN (sizeof (UnicodeCmdLine
),
605 BootOption
->OptionalDataSize
)
609 CmdLine
, BootOption
->OptionalData
,
610 MIN (sizeof (CmdLine
),
611 BootOption
->OptionalDataSize
)
616 UnicodeCmdLine
[0] = L
'\0';
621 // We do not request arguments for OptionalData that cannot be printed
624 Status
= EditHIInputStr (UnicodeCmdLine
, BOOT_DEVICE_OPTION_MAX
);
625 if (EFI_ERROR (Status
)) {
626 Status
= EFI_ABORTED
;
627 goto FREE_DEVICE_PATH
;
630 OptionalData
= (UINT8
*)UnicodeCmdLine
;
631 OptionalDataSize
= StrSize (UnicodeCmdLine
);
633 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
634 if (EFI_ERROR (Status
)) {
635 Status
= EFI_ABORTED
;
636 goto FREE_DEVICE_PATH
;
639 OptionalData
= (UINT8
*)CmdLine
;
640 OptionalDataSize
= AsciiStrSize (CmdLine
);
643 // We keep the former OptionalData
644 OptionalData
= BootOption
->OptionalData
;
645 OptionalDataSize
= BootOption
->OptionalDataSize
;
649 Print(L
"Description for this new Entry: ");
650 StrnCpy (BootDescription
, BootOption
->Description
, BOOT_DEVICE_DESCRIPTION_MAX
);
651 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
652 if (EFI_ERROR(Status
)) {
653 Status
= EFI_ABORTED
;
654 goto FREE_DEVICE_PATH
;
658 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
661 FreePool (DevicePath
);
664 if (Status
== EFI_ABORTED
) {
673 Ask for the boot option to move and then move it when up or down arrows
674 are pressed. This function is called when the user selects the "Reorder Boot
675 Device Entries" entry in the boot manager menu.
676 The order of the boot options in BootOptionList and in the UEFI BootOrder
677 global variable are kept coherent until the user confirm his reordering (ie:
678 he does not exit by pressing escape).
680 @param[in] BootOptionsList List of the boot devices constructed in
683 @retval EFI_SUCCESS No error encountered.
684 @retval !EFI_SUCCESS An error has occured either in the selection of the
685 boot option to move or while interacting with the user.
690 BootMenuReorderBootOptions (
691 IN LIST_ENTRY
*BootOptionsList
695 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
696 LIST_ENTRY
*SelectedEntry
;
697 LIST_ENTRY
*PrevEntry
;
703 LIST_ENTRY
*SecondEntry
;
709 DisplayBootOptions (BootOptionsList
);
711 // Ask to select the boot option to move
713 Status
= SelectBootOption (BootOptionsList
, MOVE_BOOT_ENTRY
, &BootOptionEntry
);
714 if (EFI_ERROR (Status
)) {
718 SelectedEntry
= &BootOptionEntry
->Link
;
720 // Note down the previous entry in the list to be able to cancel changes
721 PrevEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
723 // Start of interaction
726 L
"* Use up/down arrows to move the entry '%s'",
727 BootOptionEntry
->BdsLoadOption
->Description
730 // Wait for a move, save or cancel request
735 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
736 if (!EFI_ERROR (Status
)) {
737 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
739 if (EFI_ERROR (Status
)) {
744 switch (Key
.ScanCode
) {
746 Save
= (Key
.UnicodeChar
== CHAR_LINEFEED
) ||
747 (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) ||
748 (Key
.UnicodeChar
== 0x7f);
752 SecondEntry
= GetPreviousNode (BootOptionsList
, SelectedEntry
);
753 Move
= SecondEntry
!= BootOptionsList
;
757 SecondEntry
= GetNextNode (BootOptionsList
, SelectedEntry
);
758 Move
= SecondEntry
!= BootOptionsList
;
765 } while ((!Move
) && (!Save
) && (!Cancel
));
768 if ((SelectedEntry
!= NULL
) && (SecondEntry
!= NULL
)) {
769 SwapListEntries (SelectedEntry
, SecondEntry
);
773 Status
= GetGlobalEnvironmentVariable (
774 L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
776 BootOrderSize
/= sizeof (UINT16
);
778 if (!EFI_ERROR (Status
)) {
779 // The order of the boot options in the 'BootOptionsList' is the
780 // new order that has been just defined by the user. Save this new
781 // order in "BootOrder" UEFI global variable.
782 Entry
= GetFirstNode (BootOptionsList
);
783 for (Index
= 0; Index
< BootOrderSize
; Index
++) {
784 BootOrder
[Index
] = (LOAD_OPTION_FROM_LINK (Entry
))->LoadOptionIndex
;
785 Entry
= GetNextNode (BootOptionsList
, Entry
);
787 Status
= gRT
->SetVariable (
788 (CHAR16
*)L
"BootOrder",
789 &gEfiGlobalVariableGuid
,
790 EFI_VARIABLE_NON_VOLATILE
|
791 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
792 EFI_VARIABLE_RUNTIME_ACCESS
,
793 BootOrderSize
* sizeof (UINT16
),
796 FreePool (BootOrder
);
799 if (EFI_ERROR (Status
)) {
800 Print (L
"\nAn error occurred, move not completed!\n");
807 // Restore initial position of the selected boot option
809 RemoveEntryList (SelectedEntry
);
810 InsertHeadList (PrevEntry
, SelectedEntry
);
815 DisplayBootOptions (BootOptionsList
);
816 // Saved or cancelled, back to the choice of boot option to move
830 Ask for the boot timeout in seconds and if the input succeeds assign the
831 input value to the UEFI global variable "Timeout". This function is called
832 when the user selects the "Set Boot Timeout" of the boot manager menu.
834 @param[in] BootOptionsList List of the boot devices, not used here
836 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
837 input and assigned to the UEFI "Timeout" global
839 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
840 variable "Timeout" has failed.
844 BootMenuSetBootTimeout (
845 IN LIST_ENTRY
*BootOptionsList
852 Print (L
"Timeout duration (in seconds): ");
853 Status
= GetHIInputInteger (&Input
);
854 if (EFI_ERROR (Status
)) {
860 Status
= gRT
->SetVariable (
862 &gEfiGlobalVariableGuid
,
863 EFI_VARIABLE_NON_VOLATILE
|
864 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
865 EFI_VARIABLE_RUNTIME_ACCESS
,
869 ASSERT_EFI_ERROR (Status
);
875 struct BOOT_MANAGER_ENTRY
{
876 CONST CHAR16
* Description
;
877 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
878 } BootManagerEntries
[] = {
879 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
880 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
881 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
882 { L
"Reorder Boot Device Entries", BootMenuReorderBootOptions
},
883 { L
"Set Boot Timeout", BootMenuSetBootTimeout
},
888 IN LIST_ENTRY
*BootOptionsList
892 UINTN OptionSelected
;
893 UINTN BootManagerEntryCount
;
896 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
899 // Display Boot Manager menu
900 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
901 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
903 Print(L
"[%d] Return to main menu\n",Index
+1);
905 // Select which entry to call
907 Status
= GetHIInputInteger (&OptionSelected
);
908 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
909 if (EFI_ERROR(Status
)) {
913 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
914 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
917 // Should never go here
922 IN LIST_ENTRY
*BootOptionsList
928 Status
= BdsLoadApplication (gImageHandle
, L
"Shell", 0, NULL
);
929 if (Status
== EFI_NOT_FOUND
) {
930 Print (L
"Error: EFI Application not found.\n");
931 } else if (EFI_ERROR(Status
)) {
932 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
938 struct BOOT_MAIN_ENTRY
{
939 CONST CHAR16
* Description
;
940 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
941 } BootMainEntries
[] = {
942 { L
"Shell", BootShell
},
943 { L
"Boot Manager", BootMenuManager
},
952 LIST_ENTRY BootOptionsList
;
954 UINTN BootOptionCount
;
957 BDS_LOAD_OPTION
* BootOption
;
958 UINTN BootOptionSelected
;
960 UINTN BootMainEntryCount
;
964 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
968 BootOptionList (&BootOptionsList
);
972 // Display the Boot options
973 for (Entry
= GetFirstNode (&BootOptionsList
);
974 !IsNull (&BootOptionsList
,Entry
);
975 Entry
= GetNextNode (&BootOptionsList
,Entry
)
978 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
980 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
983 CHAR16
* DevicePathTxt
;
984 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
985 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
987 ARM_BDS_LOADER_TYPE LoaderType
;
989 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
990 if (EFI_ERROR(Status
)) {
991 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
992 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
995 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
997 Print(L
"\t- %s\n",DevicePathTxt
);
999 // If it is a supported BootEntry then print its details
1000 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
1001 OptionalData
= BootOption
->OptionalData
;
1002 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
1003 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
1004 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.InitrdSize
) > 0) {
1005 CmdLineSize
= ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
);
1006 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
1007 GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(&OptionalData
->Arguments
.LinuxArguments
+ 1) + CmdLineSize
)), TRUE
, TRUE
);
1008 Print(L
"\t- Initrd: %s\n", DevicePathTxt
);
1010 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
) > 0) {
1011 Print(L
"\t- Arguments: %a\n", (&OptionalData
->Arguments
.LinuxArguments
+ 1));
1015 switch (LoaderType
) {
1016 case BDS_LOADER_EFI_APPLICATION
:
1017 Print(L
"\t- LoaderType: EFI Application\n");
1020 case BDS_LOADER_KERNEL_LINUX_ATAG
:
1021 Print(L
"\t- LoaderType: Linux kernel with ATAG support\n");
1024 case BDS_LOADER_KERNEL_LINUX_FDT
:
1025 Print(L
"\t- LoaderType: Linux kernel with FDT support\n");
1029 Print(L
"\t- LoaderType: Not recognized (%d)\n", LoaderType
);
1031 } else if (BootOption
->OptionalData
!= NULL
) {
1032 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
1034 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
1036 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
1040 FreePool(DevicePathTxt
);
1045 BootOptionCount
= OptionCount
-1;
1047 // Display the hardcoded Boot entries
1048 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
1049 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
1053 // Request the boot entry from the user
1054 BootOptionSelected
= 0;
1055 while (BootOptionSelected
== 0) {
1057 Status
= GetHIInputInteger (&BootOptionSelected
);
1058 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
1059 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
1060 BootOptionSelected
= 0;
1064 // Start the selected entry
1065 if (BootOptionSelected
> BootOptionCount
) {
1066 // Start the hardcoded entry
1067 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
1069 // Find the selected entry from the Boot#### list
1071 for (Entry
= GetFirstNode (&BootOptionsList
);
1072 !IsNull (&BootOptionsList
,Entry
);
1073 Entry
= GetNextNode (&BootOptionsList
,Entry
)
1076 if (Index
== BootOptionSelected
) {
1077 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
1083 Status
= BootOptionStart (BootOption
);
1086 // Should never go here